Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a27f31d

Browse files
committed
Merge pull request libgit2#3513 from ethomson/merge_recursive
Recursive Merge
2 parents e0ab1ca + 5b9c63c commit a27f31d

File tree

175 files changed

+1237
-192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+1237
-192
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ v0.23 + 1
3434

3535
### Breaking API changes
3636

37+
* The `git_merge_tree_flag_t` is now `git_merge_flag_t`. Subsequently,
38+
its members are no longer prefixed with `GIT_MERGE_TREE_FLAG` but are
39+
now prefixed with `GIT_MERGE_FLAG`, and the `tree_flags` field of the
40+
`git_merge_options` structure is now named `flags`.
41+
42+
* The `git_merge_file_flags_t` enum is now `git_merge_file_flag_t` for
43+
consistency with other enum type names.
44+
3745
* `git_cert` descendent types now have a proper `parent` member
3846

3947
* It is the responsibility of the refdb backend to decide what to do

include/git2/merge.h

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,37 @@ GIT_EXTERN(int) git_merge_file_init_input(
6262
unsigned int version);
6363

6464
/**
65-
* Flags for `git_merge_tree` options. A combination of these flags can be
66-
* passed in via the `tree_flags` value in the `git_merge_options`.
65+
* Flags for `git_merge` options. A combination of these flags can be
66+
* passed in via the `flags` value in the `git_merge_options`.
6767
*/
6868
typedef enum {
6969
/**
7070
* Detect renames that occur between the common ancestor and the "ours"
7171
* side or the common ancestor and the "theirs" side. This will enable
7272
* the ability to merge between a modified and renamed file.
7373
*/
74-
GIT_MERGE_TREE_FIND_RENAMES = (1 << 0),
74+
GIT_MERGE_FIND_RENAMES = (1 << 0),
7575

7676
/**
7777
* If a conflict occurs, exit immediately instead of attempting to
7878
* continue resolving conflicts. The merge operation will fail with
7979
* GIT_EMERGECONFLICT and no index will be returned.
8080
*/
81-
GIT_MERGE_TREE_FAIL_ON_CONFLICT = (1 << 1),
81+
GIT_MERGE_FAIL_ON_CONFLICT = (1 << 1),
8282

8383
/**
8484
* Do not write the REUC extension on the generated index
8585
*/
86-
GIT_MERGE_TREE_SKIP_REUC = (1 << 2),
87-
} git_merge_tree_flag_t;
86+
GIT_MERGE_SKIP_REUC = (1 << 2),
87+
88+
/**
89+
* If the commits being merged have multiple merge bases, do not build
90+
* a recursive merge base (by merging the multiple merge bases),
91+
* instead simply use the first base. This flag provides a similar
92+
* merge base to `git-merge-resolve`.
93+
*/
94+
GIT_MERGE_NO_RECURSIVE = (1 << 3),
95+
} git_merge_flag_t;
8896

8997
/**
9098
* Merge file favor options for `git_merge_options` instruct the file-level
@@ -152,7 +160,7 @@ typedef enum {
152160

153161
/** Take extra time to find minimal diff */
154162
GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7),
155-
} git_merge_file_flags_t;
163+
} git_merge_file_flag_t;
156164

157165
/**
158166
* Options for merging a file
@@ -181,8 +189,8 @@ typedef struct {
181189
/** The file to favor in region conflicts. */
182190
git_merge_file_favor_t favor;
183191

184-
/** see `git_merge_file_flags_t` above */
185-
unsigned int flags;
192+
/** see `git_merge_file_flag_t` above */
193+
git_merge_file_flag_t flags;
186194
} git_merge_file_options;
187195

188196
#define GIT_MERGE_FILE_OPTIONS_VERSION 1
@@ -232,11 +240,13 @@ typedef struct {
232240
*/
233241
typedef struct {
234242
unsigned int version;
235-
git_merge_tree_flag_t tree_flags;
243+
244+
/** See `git_merge_flag_t` above */
245+
git_merge_flag_t flags;
236246

237247
/**
238248
* Similarity to consider a file renamed (default 50). If
239-
* `GIT_MERGE_TREE_FIND_RENAMES` is enabled, added files will be compared
249+
* `GIT_MERGE_FIND_RENAMES` is enabled, added files will be compared
240250
* with deleted files to determine their similarity. Files that are
241251
* more similar than the rename threshold (percentage-wise) will be
242252
* treated as a rename.
@@ -255,11 +265,19 @@ typedef struct {
255265
/** Pluggable similarity metric; pass NULL to use internal metric */
256266
git_diff_similarity_metric *metric;
257267

268+
/**
269+
* Maximum number of times to merge common ancestors to build a
270+
* virtual merge base when faced with criss-cross merges. When this
271+
* limit is reached, the next ancestor will simply be used instead of
272+
* attempting to merge it. The default is unlimited.
273+
*/
274+
unsigned int recursion_limit;
275+
258276
/** Flags for handling conflicting content. */
259277
git_merge_file_favor_t file_favor;
260278

261-
/** see `git_merge_file_flags_t` above */
262-
unsigned int file_flags;
279+
/** see `git_merge_file_flag_t` above */
280+
git_merge_file_flag_t file_flags;
263281
} git_merge_options;
264282

265283
#define GIT_MERGE_OPTIONS_VERSION 1

src/annotated_commit.c

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77

88
#include "common.h"
99
#include "annotated_commit.h"
10+
#include "refs.h"
11+
#include "cache.h"
1012

1113
#include "git2/commit.h"
1214
#include "git2/refs.h"
1315
#include "git2/repository.h"
1416
#include "git2/annotated_commit.h"
1517
#include "git2/revparse.h"
18+
#include "git2/tree.h"
19+
#include "git2/index.h"
1620

1721
static int annotated_commit_init(
1822
git_annotated_commit **out,
@@ -22,14 +26,17 @@ static int annotated_commit_init(
2226
const char *remote_url)
2327
{
2428
git_annotated_commit *annotated_commit;
29+
git_commit *commit = NULL;
2530
int error = 0;
2631

2732
assert(out && id);
2833

2934
*out = NULL;
3035

31-
annotated_commit = git__calloc(1, sizeof(git_annotated_commit));
32-
GITERR_CHECK_ALLOC(annotated_commit);
36+
if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
37+
(error = git_annotated_commit_from_commit(&annotated_commit,
38+
commit)) < 0)
39+
goto done;
3340

3441
if (ref_name) {
3542
annotated_commit->ref_name = git__strdup(ref_name);
@@ -41,15 +48,10 @@ static int annotated_commit_init(
4148
GITERR_CHECK_ALLOC(annotated_commit->remote_url);
4249
}
4350

44-
git_oid_fmt(annotated_commit->id_str, id);
45-
annotated_commit->id_str[GIT_OID_HEXSZ] = '\0';
46-
47-
if ((error = git_commit_lookup(&annotated_commit->commit, repo, id)) < 0) {
48-
git_annotated_commit_free(annotated_commit);
49-
return error;
50-
}
51-
5251
*out = annotated_commit;
52+
53+
done:
54+
git_commit_free(commit);
5355
return error;
5456
}
5557

@@ -75,6 +77,51 @@ int git_annotated_commit_from_ref(
7577
return error;
7678
}
7779

80+
int git_annotated_commit_from_head(
81+
git_annotated_commit **out,
82+
git_repository *repo)
83+
{
84+
git_reference *head;
85+
int error;
86+
87+
assert(out && repo);
88+
89+
*out = NULL;
90+
91+
if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
92+
return -1;
93+
94+
error = git_annotated_commit_from_ref(out, repo, head);
95+
96+
git_reference_free(head);
97+
return error;
98+
}
99+
100+
int git_annotated_commit_from_commit(
101+
git_annotated_commit **out,
102+
git_commit *commit)
103+
{
104+
git_annotated_commit *annotated_commit;
105+
106+
assert(out && commit);
107+
108+
*out = NULL;
109+
110+
annotated_commit = git__calloc(1, sizeof(git_annotated_commit));
111+
GITERR_CHECK_ALLOC(annotated_commit);
112+
113+
annotated_commit->type = GIT_ANNOTATED_COMMIT_REAL;
114+
115+
git_cached_obj_incref(commit);
116+
annotated_commit->commit = commit;
117+
118+
git_oid_fmt(annotated_commit->id_str, git_commit_id(commit));
119+
annotated_commit->id_str[GIT_OID_HEXSZ] = '\0';
120+
121+
*out = annotated_commit;
122+
return 0;
123+
}
124+
78125
int git_annotated_commit_lookup(
79126
git_annotated_commit **out,
80127
git_repository *repo,
@@ -136,14 +183,20 @@ void git_annotated_commit_free(git_annotated_commit *annotated_commit)
136183
if (annotated_commit == NULL)
137184
return;
138185

139-
if (annotated_commit->commit != NULL)
140-
git_commit_free(annotated_commit->commit);
141-
142-
if (annotated_commit->ref_name != NULL)
143-
git__free(annotated_commit->ref_name);
144-
145-
if (annotated_commit->remote_url != NULL)
146-
git__free(annotated_commit->remote_url);
186+
switch (annotated_commit->type) {
187+
case GIT_ANNOTATED_COMMIT_REAL:
188+
git_commit_free(annotated_commit->commit);
189+
git_tree_free(annotated_commit->tree);
190+
git__free(annotated_commit->ref_name);
191+
git__free(annotated_commit->remote_url);
192+
break;
193+
case GIT_ANNOTATED_COMMIT_VIRTUAL:
194+
git_index_free(annotated_commit->index);
195+
git_array_clear(annotated_commit->parents);
196+
break;
197+
default:
198+
abort();
199+
}
147200

148201
git__free(annotated_commit);
149202
}

src/annotated_commit.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,41 @@
77
#ifndef INCLUDE_annotated_commit_h__
88
#define INCLUDE_annotated_commit_h__
99

10+
#include "oidarray.h"
11+
1012
#include "git2/oid.h"
1113

12-
/** Internal structure for merge inputs */
14+
typedef enum {
15+
GIT_ANNOTATED_COMMIT_REAL = 1,
16+
GIT_ANNOTATED_COMMIT_VIRTUAL = 2,
17+
} git_annotated_commit_t;
18+
19+
/**
20+
* Internal structure for merge inputs. An annotated commit is generally
21+
* "real" and backed by an actual commit in the repository, but merge will
22+
* internally create "virtual" commits that are in-memory intermediate
23+
* commits backed by an index.
24+
*/
1325
struct git_annotated_commit {
26+
git_annotated_commit_t type;
27+
28+
/* real commit */
1429
git_commit *commit;
30+
git_tree *tree;
31+
32+
/* virtual commit structure */
33+
git_index *index;
34+
git_array_oid_t parents;
1535

1636
char *ref_name;
1737
char *remote_url;
1838

1939
char id_str[GIT_OID_HEXSZ+1];
2040
};
2141

42+
extern int git_annotated_commit_from_head(git_annotated_commit **out,
43+
git_repository *repo);
44+
extern int git_annotated_commit_from_commit(git_annotated_commit **out,
45+
git_commit *commit);
46+
2247
#endif

0 commit comments

Comments
 (0)