From fa78782f67d17c5b139a2bbe3ceefe54c8c71dd3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 22 Oct 2015 17:00:09 -0400 Subject: merge: rename `git_merge_tree_flags_t` -> `git_merge_flags_t` --- CHANGELOG.md | 8 ++++++++ include/git2/merge.h | 36 +++++++++++++++++++----------------- src/merge.c | 12 ++++++------ src/merge.h | 4 ++-- tests/cherrypick/workdir.c | 4 ++-- tests/merge/trees/commits.c | 2 +- tests/merge/trees/treediff.c | 2 +- tests/merge/workdir/renames.c | 6 +++--- tests/revert/workdir.c | 4 ++-- 9 files changed, 44 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5a4166a..196ad705a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,14 @@ v0.23 + 1 ### Breaking API changes +* The `git_merge_tree_flag_t` is now `git_merge_flag_t`. Subsequently, + its members are no longer prefixed with `GIT_MERGE_TREE_FLAG` but are + now prefixed with `GIT_MERGE_FLAG`, and the `tree_flags` field of the + `git_merge_options` structure is now named `flags`. + +* The `git_merge_file_flags_t` enum is now `git_merge_file_flag_t` for + consistency with other enum type names. + * `git_cert` descendent types now have a proper `parent` member * It is the responsibility of the refdb backend to decide what to do diff --git a/include/git2/merge.h b/include/git2/merge.h index b7da63e0e..de224aeac 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -62,8 +62,8 @@ GIT_EXTERN(int) git_merge_file_init_input( unsigned int version); /** - * Flags for `git_merge_tree` options. A combination of these flags can be - * passed in via the `tree_flags` value in the `git_merge_options`. + * Flags for `git_merge` options. A combination of these flags can be + * passed in via the `flags` value in the `git_merge_options`. */ typedef enum { /** @@ -71,20 +71,20 @@ typedef enum { * side or the common ancestor and the "theirs" side. This will enable * the ability to merge between a modified and renamed file. */ - GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), + GIT_MERGE_FIND_RENAMES = (1 << 0), /** - * If a conflict occurs, exit immediately instead of attempting to - * continue resolving conflicts. The merge operation will fail with - * GIT_EMERGECONFLICT and no index will be returned. + * Do not write the REUC extension on the generated index */ - GIT_MERGE_TREE_FAIL_ON_CONFLICT = (1 << 1), + GIT_MERGE_SKIP_REUC = (1 << 2), /** - * Do not write the REUC extension on the generated index + * If a conflict occurs, exit immediately instead of attempting to + * continue resolving conflicts. The merge operation will fail with + * GIT_EMERGECONFLICT and no index will be returned. */ - GIT_MERGE_TREE_SKIP_REUC = (1 << 2), -} git_merge_tree_flag_t; + GIT_MERGE_FAIL_ON_CONFLICT = (1 << 1), +} git_merge_flag_t; /** * Merge file favor options for `git_merge_options` instruct the file-level @@ -152,7 +152,7 @@ typedef enum { /** Take extra time to find minimal diff */ GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7), -} git_merge_file_flags_t; +} git_merge_file_flag_t; /** * Options for merging a file @@ -181,8 +181,8 @@ typedef struct { /** The file to favor in region conflicts. */ git_merge_file_favor_t favor; - /** see `git_merge_file_flags_t` above */ - unsigned int flags; + /** see `git_merge_file_flag_t` above */ + git_merge_file_flag_t flags; } git_merge_file_options; #define GIT_MERGE_FILE_OPTIONS_VERSION 1 @@ -232,11 +232,13 @@ typedef struct { */ typedef struct { unsigned int version; - git_merge_tree_flag_t tree_flags; + + /** See `git_merge_flag_t` above */ + git_merge_flag_t flags; /** * Similarity to consider a file renamed (default 50). If - * `GIT_MERGE_TREE_FIND_RENAMES` is enabled, added files will be compared + * `GIT_MERGE_FIND_RENAMES` is enabled, added files will be compared * with deleted files to determine their similarity. Files that are * more similar than the rename threshold (percentage-wise) will be * treated as a rename. @@ -258,8 +260,8 @@ typedef struct { /** Flags for handling conflicting content. */ git_merge_file_favor_t file_favor; - /** see `git_merge_file_flags_t` above */ - unsigned int file_flags; + /** see `git_merge_file_flag_t` above */ + git_merge_file_flag_t file_flags; } git_merge_options; #define GIT_MERGE_OPTIONS_VERSION 1 diff --git a/src/merge.c b/src/merge.c index bad5f9552..d7b23e2c8 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1296,7 +1296,7 @@ int git_merge_diff_list__find_renames( assert(diff_list && opts); - if ((opts->tree_flags & GIT_MERGE_TREE_FIND_RENAMES) == 0) + if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0) return 0; similarity_ours = git__calloc(diff_list->conflicts.length, @@ -1632,8 +1632,8 @@ static int merge_normalize_opts( git_merge_options init = GIT_MERGE_OPTIONS_INIT; memcpy(opts, &init, sizeof(init)); - opts->tree_flags = GIT_MERGE_TREE_FIND_RENAMES; - opts->rename_threshold = GIT_MERGE_TREE_RENAME_THRESHOLD; + opts->flags = GIT_MERGE_FIND_RENAMES; + opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD; } if (!opts->target_limit) { @@ -1643,7 +1643,7 @@ static int merge_normalize_opts( limit = git_config__get_int_force(cfg, "diff.renamelimit", 0); opts->target_limit = (limit <= 0) ? - GIT_MERGE_TREE_TARGET_LIMIT : (unsigned int)limit; + GIT_MERGE_DEFAULT_TARGET_LIMIT : (unsigned int)limit; } /* assign the internal metric with whitespace flag as payload */ @@ -1864,7 +1864,7 @@ int git_merge__iterators( goto done; if (!resolved) { - if ((opts.tree_flags & GIT_MERGE_TREE_FAIL_ON_CONFLICT)) { + if ((opts.flags & GIT_MERGE_FAIL_ON_CONFLICT)) { giterr_set(GITERR_MERGE, "merge conflicts exist"); error = GIT_EMERGECONFLICT; goto done; @@ -1875,7 +1875,7 @@ int git_merge__iterators( } error = index_from_diff_list(out, diff_list, - (opts.tree_flags & GIT_MERGE_TREE_SKIP_REUC)); + (opts.flags & GIT_MERGE_SKIP_REUC)); done: if (!given_opts || !given_opts->metric) diff --git a/src/merge.h b/src/merge.h index 3caf617c6..bd839be49 100644 --- a/src/merge.h +++ b/src/merge.h @@ -19,8 +19,8 @@ #define GIT_MERGE_MODE_FILE "MERGE_MODE" #define GIT_MERGE_FILE_MODE 0666 -#define GIT_MERGE_TREE_RENAME_THRESHOLD 50 -#define GIT_MERGE_TREE_TARGET_LIMIT 1000 +#define GIT_MERGE_DEFAULT_RENAME_THRESHOLD 50 +#define GIT_MERGE_DEFAULT_TARGET_LIMIT 1000 /** Types of changes when files are merged from branch to branch. */ typedef enum { diff --git a/tests/cherrypick/workdir.c b/tests/cherrypick/workdir.c index 787f1f4d4..2b45f5a33 100644 --- a/tests/cherrypick/workdir.c +++ b/tests/cherrypick/workdir.c @@ -300,7 +300,7 @@ void test_cherrypick_workdir__rename(void) { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 0, "file3.txt.renamed" }, }; - opts.merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); @@ -335,7 +335,7 @@ void test_cherrypick_workdir__both_renamed(void) { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 2, "file3.txt.renamed_on_branch" }, }; - opts.merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; git_oid_fromstr(&head_oid, "44cd2ed2052c9c68f9a439d208e9614dc2a55c70"); diff --git a/tests/merge/trees/commits.c b/tests/merge/trees/commits.c index 2e3c4578b..dd1e383ac 100644 --- a/tests/merge/trees/commits.c +++ b/tests/merge/trees/commits.c @@ -134,7 +134,7 @@ void test_merge_trees_commits__fail_on_conflict(void) git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; - opts.tree_flags |= GIT_MERGE_TREE_FAIL_ON_CONFLICT; + opts.flags |= GIT_MERGE_FAIL_ON_CONFLICT; cl_git_fail_with(GIT_EMERGECONFLICT, merge_trees_from_branches(&index, repo, "df_side1", "df_side2", &opts)); diff --git a/tests/merge/trees/treediff.c b/tests/merge/trees/treediff.c index f21d99b6d..3634568de 100644 --- a/tests/merge/trees/treediff.c +++ b/tests/merge/trees/treediff.c @@ -47,7 +47,7 @@ static void test_find_differences( git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; - opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.flags |= GIT_MERGE_FIND_RENAMES; opts.target_limit = 1000; opts.rename_threshold = 50; diff --git a/tests/merge/workdir/renames.c b/tests/merge/workdir/renames.c index 83006a703..fabcda2a8 100644 --- a/tests/merge/workdir/renames.c +++ b/tests/merge/workdir/renames.c @@ -63,7 +63,7 @@ void test_merge_workdir_renames__renames(void) { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "7-both-renamed.txt~rename_conflict_theirs" }, }; - merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + merge_opts.flags |= GIT_MERGE_FIND_RENAMES; merge_opts.rename_threshold = 50; cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &merge_opts, NULL)); @@ -99,7 +99,7 @@ void test_merge_workdir_renames__ours(void) { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "7-both-renamed.txt" }, }; - merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + merge_opts.flags |= GIT_MERGE_FIND_RENAMES; merge_opts.rename_threshold = 50; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; @@ -147,7 +147,7 @@ void test_merge_workdir_renames__similar(void) { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "7-both-renamed.txt~rename_conflict_theirs" }, }; - merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + merge_opts.flags |= GIT_MERGE_FIND_RENAMES; merge_opts.rename_threshold = 50; cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &merge_opts, NULL)); diff --git a/tests/revert/workdir.c b/tests/revert/workdir.c index 9f83bd842..802819c75 100644 --- a/tests/revert/workdir.c +++ b/tests/revert/workdir.c @@ -410,7 +410,7 @@ void test_revert_workdir__rename_1_of_2(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 2, "file6.txt" }, }; - opts.merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; git_oid_fromstr(&head_oid, "cef56612d71a6af8d8015691e4865f7fece905b5"); @@ -444,7 +444,7 @@ void test_revert_workdir__rename(void) { "file4.txt", "file5.txt", "" }, }; - opts.merge_opts.tree_flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; git_oid_fromstr(&head_oid, "55568c8de5322ff9a95d72747a239cdb64a19965"); -- cgit v1.2.1 From 86c8d02c071d3713e1c9f0b95d9f4599108d2c29 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 22 Oct 2015 20:20:07 -0400 Subject: merge: add simple recursive test Add a simple recursive test - where multiple ancestors exist and creating a virtual merge base from them would prevent a conflict. --- include/git2/merge.h | 16 ++- tests/merge/merge_helpers.c | 3 +- tests/merge/trees/recursive.c | 110 +++++++++++++++++++++ tests/resources/merge-recursive/.gitted/HEAD | 1 + tests/resources/merge-recursive/.gitted/config | 7 ++ tests/resources/merge-recursive/.gitted/index | Bin 0 -> 632 bytes tests/resources/merge-recursive/.gitted/info/refs | 1 + .../00/6b298c5702b04c00370d0414959765b82fd722 | Bin 0 -> 207 bytes .../01/6eef4a6fefd36bdcaa93ad773449ddc5c73cbb | Bin 0 -> 208 bytes .../05/c6a04ac101ab1a9836a95d5ec8d16b6f6304fd | Bin 0 -> 208 bytes .../07/10c3c796e0704361472ecb904413fca0107a25 | Bin 0 -> 208 bytes .../07/2d89dcf3a7671ac34a8e875bb72fb39bcf14d7 | Bin 0 -> 208 bytes .../0b/b7ed583d7e9ad507e8b902594f5c9126ea456b | Bin 0 -> 161 bytes .../12/4d4fe29d3433fdaa2f0f455d226f2c79d89cf3 | Bin 0 -> 208 bytes .../16/895aa5e13f8907d4adab81285557d938fad342 | Bin 0 -> 634 bytes .../3a/3f5a6ec1c968d1d2d5d20dee0d161a4351f279 | 1 + .../3b/919b6e8a575b4779c8243ebea3e3beb436e88f | Bin 0 -> 208 bytes .../3f/d41804a7906db846af5e868444782e546af46a | Bin 0 -> 206 bytes .../42/1b392106e079df6d412babd5636697938269ec | 2 + .../42/cdad903aef3e7b614675e6584a8be417941911 | Bin 0 -> 208 bytes .../43/2faca0c62dc556ad71a22f23e541a46a8b0f6f | 2 + .../43/5424798e5e1b21dd4588d1c291ba4eb179a838 | Bin 0 -> 208 bytes .../4b/7c5650008b2e747fe1809eeb5a1dde0e80850a | Bin 0 -> 615 bytes .../4c/49317a0912ca559d2048bc329994eb7d10474f | Bin 0 -> 183 bytes .../4e/21d2d63357bde5027d1625f5ec6b430cdeb143 | Bin 0 -> 662 bytes .../53/9bd011c4822c560c1d17cab095006b7a10f707 | Bin 0 -> 163 bytes .../65/bea8448ca5b3104628ffbca553c54bde54b0fc | 3 + .../66/6ffdfcf1eaa5641fa31064bf2607327e843c09 | Bin 0 -> 664 bytes .../68/af1fc7407fd9addf1701a87eb1c95c7494c598 | Bin 0 -> 443 bytes .../68/f6182f4c85d39e1309d97c7e456156dc9c0096 | Bin 0 -> 755 bytes .../71/3e438567b28543235faf265c4c5b02b437c7fd | Bin 0 -> 207 bytes .../72/3181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 | 2 + .../74/4df1bdf0f7bca20deb23e5a5eb8255fc237901 | Bin 0 -> 207 bytes .../7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f | 1 + .../7c/7e08f9559d9e1551b91e1cf68f1d0066109add | Bin 0 -> 443 bytes .../88/eb3f98849f4b8d0555395f514800900a01dc8f | Bin 0 -> 209 bytes .../8f/35f30bfe09513f96cf8aa4df0834ae34e93bae | 1 + .../94/d2c01087f48213bd157222d54edfefd77c9bba | Bin 0 -> 621 bytes .../95/78b04e2087976e382622322ba476aa40398dc7 | Bin 0 -> 620 bytes .../97/3b70322e758da87e1ce21d2195d86c5e4e9647 | 1 + .../9c/3f1c70db28c00ce74b22ba3edafe16d9cf03d4 | Bin 0 -> 208 bytes .../a0/65d3022e99a1943177c10a53cce38bc2127042 | Bin 0 -> 162 bytes .../a2/fa36ffc4a565a223e225d15b18774f87d0c4f0 | 3 + .../a3/4e5a16feabbd0335a633aadb8217c9f3dba58d | Bin 0 -> 164 bytes .../a7/b066537e6be7109abfe4ff97b675d4e077da20 | Bin 0 -> 621 bytes .../a8/2a121ea36b115548d6dad2cd86ec27f06f7b30 | Bin 0 -> 208 bytes .../b2/a81ead9e722af0099fccfb478cea88eea749a2 | Bin 0 -> 664 bytes .../b4/cefb3c75770e57bb8bb44e4a50d9578009e847 | Bin 0 -> 639 bytes .../c4/e6cca3ec6ae0148ed231f97257df8c311e015f | 1 + .../cb/49ad76147f5f9439cbd6133708b76142660660 | Bin 0 -> 641 bytes .../d0/dd5d9083bda65ec99aa8b9b64a5a278771b70a | Bin 0 -> 620 bytes .../de/a7215f259b2cced87d1bda6c72f8b4ce37a2ff | Bin 0 -> 357 bytes .../e2/93bfdddb81a853bbb16b8b58e68626f30841a4 | Bin 0 -> 207 bytes .../e2/c84bb33992a455b1a7a5019f0e38d883d3f475 | Bin 0 -> 208 bytes .../f1/3e1bc6ba935fce2efffa5be4c4832404034ef1 | Bin 0 -> 206 bytes .../f3/5f159ff5d44dfd9f52d63dd5b659f0521ff569 | Bin 0 -> 669 bytes .../f5/1658077d85f2264fa179b4d0848268cb3475c3 | 2 + .../fa/567f568ed72157c0c617438d077695b99d9aac | Bin 0 -> 662 bytes .../fd/8b5fe88cda995e70a22ed98701e65b843e05ec | Bin 0 -> 165 bytes .../fe/f01f3104c8047d05e8572e521c454f8fd4b8db | Bin 0 -> 207 bytes .../ff/b36e513f5fdf8a6ba850a20142676a2ac4807d | Bin 0 -> 355 bytes .../merge-recursive/.gitted/refs/heads/branchA-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchA-2 | 1 + .../merge-recursive/.gitted/refs/heads/branchB-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchB-2 | 1 + tests/resources/merge-recursive/asparagus.txt | 10 ++ tests/resources/merge-recursive/beef.txt | 22 +++++ tests/resources/merge-recursive/bouilli.txt | 18 ++++ tests/resources/merge-recursive/gravy.txt | 8 ++ tests/resources/merge-recursive/oyster.txt | 13 +++ tests/resources/merge-recursive/veal.txt | 18 ++++ 71 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 tests/merge/trees/recursive.c create mode 100644 tests/resources/merge-recursive/.gitted/HEAD create mode 100644 tests/resources/merge-recursive/.gitted/config create mode 100644 tests/resources/merge-recursive/.gitted/index create mode 100644 tests/resources/merge-recursive/.gitted/info/refs create mode 100644 tests/resources/merge-recursive/.gitted/objects/00/6b298c5702b04c00370d0414959765b82fd722 create mode 100644 tests/resources/merge-recursive/.gitted/objects/01/6eef4a6fefd36bdcaa93ad773449ddc5c73cbb create mode 100644 tests/resources/merge-recursive/.gitted/objects/05/c6a04ac101ab1a9836a95d5ec8d16b6f6304fd create mode 100644 tests/resources/merge-recursive/.gitted/objects/07/10c3c796e0704361472ecb904413fca0107a25 create mode 100644 tests/resources/merge-recursive/.gitted/objects/07/2d89dcf3a7671ac34a8e875bb72fb39bcf14d7 create mode 100644 tests/resources/merge-recursive/.gitted/objects/0b/b7ed583d7e9ad507e8b902594f5c9126ea456b create mode 100644 tests/resources/merge-recursive/.gitted/objects/12/4d4fe29d3433fdaa2f0f455d226f2c79d89cf3 create mode 100644 tests/resources/merge-recursive/.gitted/objects/16/895aa5e13f8907d4adab81285557d938fad342 create mode 100644 tests/resources/merge-recursive/.gitted/objects/3a/3f5a6ec1c968d1d2d5d20dee0d161a4351f279 create mode 100644 tests/resources/merge-recursive/.gitted/objects/3b/919b6e8a575b4779c8243ebea3e3beb436e88f create mode 100644 tests/resources/merge-recursive/.gitted/objects/3f/d41804a7906db846af5e868444782e546af46a create mode 100644 tests/resources/merge-recursive/.gitted/objects/42/1b392106e079df6d412babd5636697938269ec create mode 100644 tests/resources/merge-recursive/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 create mode 100644 tests/resources/merge-recursive/.gitted/objects/43/2faca0c62dc556ad71a22f23e541a46a8b0f6f create mode 100644 tests/resources/merge-recursive/.gitted/objects/43/5424798e5e1b21dd4588d1c291ba4eb179a838 create mode 100644 tests/resources/merge-recursive/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a create mode 100644 tests/resources/merge-recursive/.gitted/objects/4c/49317a0912ca559d2048bc329994eb7d10474f create mode 100644 tests/resources/merge-recursive/.gitted/objects/4e/21d2d63357bde5027d1625f5ec6b430cdeb143 create mode 100644 tests/resources/merge-recursive/.gitted/objects/53/9bd011c4822c560c1d17cab095006b7a10f707 create mode 100644 tests/resources/merge-recursive/.gitted/objects/65/bea8448ca5b3104628ffbca553c54bde54b0fc create mode 100644 tests/resources/merge-recursive/.gitted/objects/66/6ffdfcf1eaa5641fa31064bf2607327e843c09 create mode 100644 tests/resources/merge-recursive/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 create mode 100644 tests/resources/merge-recursive/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 create mode 100644 tests/resources/merge-recursive/.gitted/objects/71/3e438567b28543235faf265c4c5b02b437c7fd create mode 100644 tests/resources/merge-recursive/.gitted/objects/72/3181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 create mode 100644 tests/resources/merge-recursive/.gitted/objects/74/4df1bdf0f7bca20deb23e5a5eb8255fc237901 create mode 100644 tests/resources/merge-recursive/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f create mode 100644 tests/resources/merge-recursive/.gitted/objects/7c/7e08f9559d9e1551b91e1cf68f1d0066109add create mode 100644 tests/resources/merge-recursive/.gitted/objects/88/eb3f98849f4b8d0555395f514800900a01dc8f create mode 100644 tests/resources/merge-recursive/.gitted/objects/8f/35f30bfe09513f96cf8aa4df0834ae34e93bae create mode 100644 tests/resources/merge-recursive/.gitted/objects/94/d2c01087f48213bd157222d54edfefd77c9bba create mode 100644 tests/resources/merge-recursive/.gitted/objects/95/78b04e2087976e382622322ba476aa40398dc7 create mode 100644 tests/resources/merge-recursive/.gitted/objects/97/3b70322e758da87e1ce21d2195d86c5e4e9647 create mode 100644 tests/resources/merge-recursive/.gitted/objects/9c/3f1c70db28c00ce74b22ba3edafe16d9cf03d4 create mode 100644 tests/resources/merge-recursive/.gitted/objects/a0/65d3022e99a1943177c10a53cce38bc2127042 create mode 100644 tests/resources/merge-recursive/.gitted/objects/a2/fa36ffc4a565a223e225d15b18774f87d0c4f0 create mode 100644 tests/resources/merge-recursive/.gitted/objects/a3/4e5a16feabbd0335a633aadb8217c9f3dba58d create mode 100644 tests/resources/merge-recursive/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 create mode 100644 tests/resources/merge-recursive/.gitted/objects/a8/2a121ea36b115548d6dad2cd86ec27f06f7b30 create mode 100644 tests/resources/merge-recursive/.gitted/objects/b2/a81ead9e722af0099fccfb478cea88eea749a2 create mode 100644 tests/resources/merge-recursive/.gitted/objects/b4/cefb3c75770e57bb8bb44e4a50d9578009e847 create mode 100644 tests/resources/merge-recursive/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f create mode 100644 tests/resources/merge-recursive/.gitted/objects/cb/49ad76147f5f9439cbd6133708b76142660660 create mode 100644 tests/resources/merge-recursive/.gitted/objects/d0/dd5d9083bda65ec99aa8b9b64a5a278771b70a create mode 100644 tests/resources/merge-recursive/.gitted/objects/de/a7215f259b2cced87d1bda6c72f8b4ce37a2ff create mode 100644 tests/resources/merge-recursive/.gitted/objects/e2/93bfdddb81a853bbb16b8b58e68626f30841a4 create mode 100644 tests/resources/merge-recursive/.gitted/objects/e2/c84bb33992a455b1a7a5019f0e38d883d3f475 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f1/3e1bc6ba935fce2efffa5be4c4832404034ef1 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f3/5f159ff5d44dfd9f52d63dd5b659f0521ff569 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f5/1658077d85f2264fa179b4d0848268cb3475c3 create mode 100644 tests/resources/merge-recursive/.gitted/objects/fa/567f568ed72157c0c617438d077695b99d9aac create mode 100644 tests/resources/merge-recursive/.gitted/objects/fd/8b5fe88cda995e70a22ed98701e65b843e05ec create mode 100644 tests/resources/merge-recursive/.gitted/objects/fe/f01f3104c8047d05e8572e521c454f8fd4b8db create mode 100644 tests/resources/merge-recursive/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchA-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchA-2 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchB-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchB-2 create mode 100644 tests/resources/merge-recursive/asparagus.txt create mode 100644 tests/resources/merge-recursive/beef.txt create mode 100644 tests/resources/merge-recursive/bouilli.txt create mode 100644 tests/resources/merge-recursive/gravy.txt create mode 100644 tests/resources/merge-recursive/oyster.txt create mode 100644 tests/resources/merge-recursive/veal.txt diff --git a/include/git2/merge.h b/include/git2/merge.h index de224aeac..a272e8be4 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -73,17 +73,25 @@ typedef enum { */ GIT_MERGE_FIND_RENAMES = (1 << 0), + /** + * If a conflict occurs, exit immediately instead of attempting to + * continue resolving conflicts. The merge operation will fail with + * GIT_EMERGECONFLICT and no index will be returned. + */ + GIT_MERGE_FAIL_ON_CONFLICT = (1 << 1), + /** * Do not write the REUC extension on the generated index */ GIT_MERGE_SKIP_REUC = (1 << 2), /** - * If a conflict occurs, exit immediately instead of attempting to - * continue resolving conflicts. The merge operation will fail with - * GIT_EMERGECONFLICT and no index will be returned. + * If the commits being merged have multiple merge bases, do not build + * a recursive merge base (by merging the multiple merge bases), + * instead simply use the first base. This flag provides a similar + * merge base to `git-merge-resolve`. */ - GIT_MERGE_FAIL_ON_CONFLICT = (1 << 1), + GIT_MERGE_NO_RECURSIVE = (1 << 3), } git_merge_flag_t; /** diff --git a/tests/merge/merge_helpers.c b/tests/merge/merge_helpers.c index 986a365db..4b1b7d262 100644 --- a/tests/merge/merge_helpers.c +++ b/tests/merge/merge_helpers.c @@ -4,6 +4,7 @@ #include "tree.h" #include "merge_helpers.h" #include "merge.h" +#include "index.h" #include "git2/merge.h" #include "git2/sys/index.h" #include "git2/annotated_commit.h" @@ -239,7 +240,7 @@ int merge_test_index(git_index *index, const struct merge_index_entry expected[] const git_index_entry *index_entry; /* - dump_index_entries(&index->entries); + merge__dump_index_entries(&index->entries); */ if (git_index_entrycount(index) != expected_len) diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c new file mode 100644 index 000000000..1d3586162 --- /dev/null +++ b/tests/merge/trees/recursive.c @@ -0,0 +1,110 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "merge.h" +#include "../merge_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_merge_trees_recursive__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_recursive__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_recursive__one(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "dea7215f259b2cced87d1bda6c72f8b4ce37a2ff", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchA-1", "branchA-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__one_norecursive(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "dea7215f259b2cced87d1bda6c72f8b4ce37a2ff", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + + opts.flags |= GIT_MERGE_NO_RECURSIVE; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchA-1", "branchA-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__two(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "666ffdfcf1eaa5641fa31064bf2607327e843c09", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchB-1", "branchB-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__two_norecursive(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + opts.flags |= GIT_MERGE_NO_RECURSIVE; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "cb49ad76147f5f9439cbd6133708b76142660660", 1, "veal.txt" }, + { 0100644, "b2a81ead9e722af0099fccfb478cea88eea749a2", 2, "veal.txt" }, + { 0100644, "4e21d2d63357bde5027d1625f5ec6b430cdeb143", 3, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchB-1", "branchB-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + diff --git a/tests/resources/merge-recursive/.gitted/HEAD b/tests/resources/merge-recursive/.gitted/HEAD new file mode 100644 index 000000000..77e35742d --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/branchB-1 diff --git a/tests/resources/merge-recursive/.gitted/config b/tests/resources/merge-recursive/.gitted/config new file mode 100644 index 000000000..6c9406b7d --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/config @@ -0,0 +1,7 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true diff --git a/tests/resources/merge-recursive/.gitted/index b/tests/resources/merge-recursive/.gitted/index new file mode 100644 index 000000000..1e47851a5 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/index differ diff --git a/tests/resources/merge-recursive/.gitted/info/refs b/tests/resources/merge-recursive/.gitted/info/refs new file mode 100644 index 000000000..96482e6cb --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/info/refs @@ -0,0 +1 @@ +7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f refs/heads/master diff --git a/tests/resources/merge-recursive/.gitted/objects/00/6b298c5702b04c00370d0414959765b82fd722 b/tests/resources/merge-recursive/.gitted/objects/00/6b298c5702b04c00370d0414959765b82fd722 new file mode 100644 index 000000000..d3fb85fca Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/00/6b298c5702b04c00370d0414959765b82fd722 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/01/6eef4a6fefd36bdcaa93ad773449ddc5c73cbb b/tests/resources/merge-recursive/.gitted/objects/01/6eef4a6fefd36bdcaa93ad773449ddc5c73cbb new file mode 100644 index 000000000..90085847c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/01/6eef4a6fefd36bdcaa93ad773449ddc5c73cbb differ diff --git a/tests/resources/merge-recursive/.gitted/objects/05/c6a04ac101ab1a9836a95d5ec8d16b6f6304fd b/tests/resources/merge-recursive/.gitted/objects/05/c6a04ac101ab1a9836a95d5ec8d16b6f6304fd new file mode 100644 index 000000000..c6a3a3b8d Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/05/c6a04ac101ab1a9836a95d5ec8d16b6f6304fd differ diff --git a/tests/resources/merge-recursive/.gitted/objects/07/10c3c796e0704361472ecb904413fca0107a25 b/tests/resources/merge-recursive/.gitted/objects/07/10c3c796e0704361472ecb904413fca0107a25 new file mode 100644 index 000000000..9f48594b5 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/07/10c3c796e0704361472ecb904413fca0107a25 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/07/2d89dcf3a7671ac34a8e875bb72fb39bcf14d7 b/tests/resources/merge-recursive/.gitted/objects/07/2d89dcf3a7671ac34a8e875bb72fb39bcf14d7 new file mode 100644 index 000000000..69104c948 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/07/2d89dcf3a7671ac34a8e875bb72fb39bcf14d7 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/0b/b7ed583d7e9ad507e8b902594f5c9126ea456b b/tests/resources/merge-recursive/.gitted/objects/0b/b7ed583d7e9ad507e8b902594f5c9126ea456b new file mode 100644 index 000000000..e7b4ba10f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/0b/b7ed583d7e9ad507e8b902594f5c9126ea456b differ diff --git a/tests/resources/merge-recursive/.gitted/objects/12/4d4fe29d3433fdaa2f0f455d226f2c79d89cf3 b/tests/resources/merge-recursive/.gitted/objects/12/4d4fe29d3433fdaa2f0f455d226f2c79d89cf3 new file mode 100644 index 000000000..f0ea020fb Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/12/4d4fe29d3433fdaa2f0f455d226f2c79d89cf3 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/16/895aa5e13f8907d4adab81285557d938fad342 b/tests/resources/merge-recursive/.gitted/objects/16/895aa5e13f8907d4adab81285557d938fad342 new file mode 100644 index 000000000..4d3319bc7 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/16/895aa5e13f8907d4adab81285557d938fad342 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/3a/3f5a6ec1c968d1d2d5d20dee0d161a4351f279 b/tests/resources/merge-recursive/.gitted/objects/3a/3f5a6ec1c968d1d2d5d20dee0d161a4351f279 new file mode 100644 index 000000000..f39a1271f --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/3a/3f5a6ec1c968d1d2d5d20dee0d161a4351f279 @@ -0,0 +1 @@ +xO !*h@Bb?ׁ Xr&a}؁LfR]KqQ{ `Ozɚtɤk(gؓ+*+X[F8>EGkS~y˽CۥB4ƀNnPֈ)OWN: \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/3b/919b6e8a575b4779c8243ebea3e3beb436e88f b/tests/resources/merge-recursive/.gitted/objects/3b/919b6e8a575b4779c8243ebea3e3beb436e88f new file mode 100644 index 000000000..c85731d6b Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/3b/919b6e8a575b4779c8243ebea3e3beb436e88f differ diff --git a/tests/resources/merge-recursive/.gitted/objects/3f/d41804a7906db846af5e868444782e546af46a b/tests/resources/merge-recursive/.gitted/objects/3f/d41804a7906db846af5e868444782e546af46a new file mode 100644 index 000000000..4915b864f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/3f/d41804a7906db846af5e868444782e546af46a differ diff --git a/tests/resources/merge-recursive/.gitted/objects/42/1b392106e079df6d412babd5636697938269ec b/tests/resources/merge-recursive/.gitted/objects/42/1b392106e079df6d412babd5636697938269ec new file mode 100644 index 000000000..3a8324c1b --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/42/1b392106e079df6d412babd5636697938269ec @@ -0,0 +1,2 @@ +xQ +0D)re7D @ݥmFU3o`)u.zM[Dӽ,PH^w*)c&6,27JJADQ&KN)bT3~WENYZGj +RSj2I^'y51i0599`e5a z%潎U^XV Vtٙo]2Y~P1($bz7g\QdLɔ3Rsj/]3VLlg{W[ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/43/5424798e5e1b21dd4588d1c291ba4eb179a838 b/tests/resources/merge-recursive/.gitted/objects/43/5424798e5e1b21dd4588d1c291ba4eb179a838 new file mode 100644 index 000000000..58ab23917 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/43/5424798e5e1b21dd4588d1c291ba4eb179a838 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/merge-recursive/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a new file mode 100644 index 000000000..016398531 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a differ diff --git a/tests/resources/merge-recursive/.gitted/objects/4c/49317a0912ca559d2048bc329994eb7d10474f b/tests/resources/merge-recursive/.gitted/objects/4c/49317a0912ca559d2048bc329994eb7d10474f new file mode 100644 index 000000000..d7bb4d37c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/4c/49317a0912ca559d2048bc329994eb7d10474f differ diff --git a/tests/resources/merge-recursive/.gitted/objects/4e/21d2d63357bde5027d1625f5ec6b430cdeb143 b/tests/resources/merge-recursive/.gitted/objects/4e/21d2d63357bde5027d1625f5ec6b430cdeb143 new file mode 100644 index 000000000..34f183dd1 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/4e/21d2d63357bde5027d1625f5ec6b430cdeb143 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/53/9bd011c4822c560c1d17cab095006b7a10f707 b/tests/resources/merge-recursive/.gitted/objects/53/9bd011c4822c560c1d17cab095006b7a10f707 new file mode 100644 index 000000000..3fa1e1f94 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/53/9bd011c4822c560c1d17cab095006b7a10f707 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/65/bea8448ca5b3104628ffbca553c54bde54b0fc b/tests/resources/merge-recursive/.gitted/objects/65/bea8448ca5b3104628ffbca553c54bde54b0fc new file mode 100644 index 000000000..031c91359 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/65/bea8448ca5b3104628ffbca553c54bde54b0fc @@ -0,0 +1,3 @@ +x !D +а,3 jyL^\6h9qDLɒ~ + F'Qk$< !!2eְazlH}MEy^~Qïr- n`[Q+]eyBWyM \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/66/6ffdfcf1eaa5641fa31064bf2607327e843c09 b/tests/resources/merge-recursive/.gitted/objects/66/6ffdfcf1eaa5641fa31064bf2607327e843c09 new file mode 100644 index 000000000..8d6be4216 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/66/6ffdfcf1eaa5641fa31064bf2607327e843c09 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/merge-recursive/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 new file mode 100644 index 000000000..6aaf79fcb Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/merge-recursive/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 new file mode 100644 index 000000000..ed1de3ada Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/71/3e438567b28543235faf265c4c5b02b437c7fd b/tests/resources/merge-recursive/.gitted/objects/71/3e438567b28543235faf265c4c5b02b437c7fd new file mode 100644 index 000000000..8b1f688ca Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/71/3e438567b28543235faf265c4c5b02b437c7fd differ diff --git a/tests/resources/merge-recursive/.gitted/objects/72/3181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 b/tests/resources/merge-recursive/.gitted/objects/72/3181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 new file mode 100644 index 000000000..01d113eec --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/72/3181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 @@ -0,0 +1,2 @@ +x[ +1 E*Ağفȴ)#8SUowDž.˥E 8Bt6'<`bvh=I_ԍD)Bq}D )z6Z\{]B?Չ_Ku9Atl5jQcOznO6 \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/74/4df1bdf0f7bca20deb23e5a5eb8255fc237901 b/tests/resources/merge-recursive/.gitted/objects/74/4df1bdf0f7bca20deb23e5a5eb8255fc237901 new file mode 100644 index 000000000..c05cdad8f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/74/4df1bdf0f7bca20deb23e5a5eb8255fc237901 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f b/tests/resources/merge-recursive/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f new file mode 100644 index 000000000..fe8b15777 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f @@ -0,0 +1 @@ +xN0Dd' \V\~/1rw5m|0 tntƺ%kcnu a:K,^W555brx7Q \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/a3/4e5a16feabbd0335a633aadb8217c9f3dba58d b/tests/resources/merge-recursive/.gitted/objects/a3/4e5a16feabbd0335a633aadb8217c9f3dba58d new file mode 100644 index 000000000..00f9c2ddd Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/a3/4e5a16feabbd0335a633aadb8217c9f3dba58d differ diff --git a/tests/resources/merge-recursive/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 b/tests/resources/merge-recursive/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 new file mode 100644 index 000000000..54f9b6617 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/a8/2a121ea36b115548d6dad2cd86ec27f06f7b30 b/tests/resources/merge-recursive/.gitted/objects/a8/2a121ea36b115548d6dad2cd86ec27f06f7b30 new file mode 100644 index 000000000..e740872fa Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/a8/2a121ea36b115548d6dad2cd86ec27f06f7b30 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/b2/a81ead9e722af0099fccfb478cea88eea749a2 b/tests/resources/merge-recursive/.gitted/objects/b2/a81ead9e722af0099fccfb478cea88eea749a2 new file mode 100644 index 000000000..7a8ffe58a Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/b2/a81ead9e722af0099fccfb478cea88eea749a2 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/b4/cefb3c75770e57bb8bb44e4a50d9578009e847 b/tests/resources/merge-recursive/.gitted/objects/b4/cefb3c75770e57bb8bb44e4a50d9578009e847 new file mode 100644 index 000000000..836bb4edc Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/b4/cefb3c75770e57bb8bb44e4a50d9578009e847 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f b/tests/resources/merge-recursive/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f new file mode 100644 index 000000000..2bbf28f57 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f @@ -0,0 +1 @@ +x%P1n0 WCNEN7:*pԒ/WmI$=^^._?~|C6yTȄA(#1e鴓.(Hto@̸K-as1r6)&)8ŷTa<0ׇJ٢[K5IJcq͓쌫r_ۇ"u^@7~X)2 G,fR`B43vQH֩uab SwcJq)fƔOv; \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/cb/49ad76147f5f9439cbd6133708b76142660660 b/tests/resources/merge-recursive/.gitted/objects/cb/49ad76147f5f9439cbd6133708b76142660660 new file mode 100644 index 000000000..849668c8b Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/cb/49ad76147f5f9439cbd6133708b76142660660 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/d0/dd5d9083bda65ec99aa8b9b64a5a278771b70a b/tests/resources/merge-recursive/.gitted/objects/d0/dd5d9083bda65ec99aa8b9b64a5a278771b70a new file mode 100644 index 000000000..b0d951c9e Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/d0/dd5d9083bda65ec99aa8b9b64a5a278771b70a differ diff --git a/tests/resources/merge-recursive/.gitted/objects/de/a7215f259b2cced87d1bda6c72f8b4ce37a2ff b/tests/resources/merge-recursive/.gitted/objects/de/a7215f259b2cced87d1bda6c72f8b4ce37a2ff new file mode 100644 index 000000000..55c1983a8 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/de/a7215f259b2cced87d1bda6c72f8b4ce37a2ff differ diff --git a/tests/resources/merge-recursive/.gitted/objects/e2/93bfdddb81a853bbb16b8b58e68626f30841a4 b/tests/resources/merge-recursive/.gitted/objects/e2/93bfdddb81a853bbb16b8b58e68626f30841a4 new file mode 100644 index 000000000..fab55fea6 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/e2/93bfdddb81a853bbb16b8b58e68626f30841a4 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/e2/c84bb33992a455b1a7a5019f0e38d883d3f475 b/tests/resources/merge-recursive/.gitted/objects/e2/c84bb33992a455b1a7a5019f0e38d883d3f475 new file mode 100644 index 000000000..8c6686706 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/e2/c84bb33992a455b1a7a5019f0e38d883d3f475 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/f1/3e1bc6ba935fce2efffa5be4c4832404034ef1 b/tests/resources/merge-recursive/.gitted/objects/f1/3e1bc6ba935fce2efffa5be4c4832404034ef1 new file mode 100644 index 000000000..e115747a2 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/f1/3e1bc6ba935fce2efffa5be4c4832404034ef1 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/f3/5f159ff5d44dfd9f52d63dd5b659f0521ff569 b/tests/resources/merge-recursive/.gitted/objects/f3/5f159ff5d44dfd9f52d63dd5b659f0521ff569 new file mode 100644 index 000000000..5179f2ccf Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/f3/5f159ff5d44dfd9f52d63dd5b659f0521ff569 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/f5/1658077d85f2264fa179b4d0848268cb3475c3 b/tests/resources/merge-recursive/.gitted/objects/f5/1658077d85f2264fa179b4d0848268cb3475c3 new file mode 100644 index 000000000..3b4eb97e9 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/f5/1658077d85f2264fa179b4d0848268cb3475c3 @@ -0,0 +1,2 @@ +xERN1W,}D@Jsl^'3Ǯz}{@٘o^X3y';K8ęOlI)g7d3Q FABFtc9*~)@a1L. ݜĔXiV1a2tP*$%ɝ׭q$ET<< UP;uKu*T⤛ +&U-q̱*nѥ fgg:ע4!AASmĹiQށm E 43FgFғaD5 Y)G8@*g1NN;_ jw3*Fzv~y|s \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/fa/567f568ed72157c0c617438d077695b99d9aac b/tests/resources/merge-recursive/.gitted/objects/fa/567f568ed72157c0c617438d077695b99d9aac new file mode 100644 index 000000000..ad5a3cf4f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/fa/567f568ed72157c0c617438d077695b99d9aac differ diff --git a/tests/resources/merge-recursive/.gitted/objects/fd/8b5fe88cda995e70a22ed98701e65b843e05ec b/tests/resources/merge-recursive/.gitted/objects/fd/8b5fe88cda995e70a22ed98701e65b843e05ec new file mode 100644 index 000000000..b6f14634e Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/fd/8b5fe88cda995e70a22ed98701e65b843e05ec differ diff --git a/tests/resources/merge-recursive/.gitted/objects/fe/f01f3104c8047d05e8572e521c454f8fd4b8db b/tests/resources/merge-recursive/.gitted/objects/fe/f01f3104c8047d05e8572e521c454f8fd4b8db new file mode 100644 index 000000000..715b6a865 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/fe/f01f3104c8047d05e8572e521c454f8fd4b8db differ diff --git a/tests/resources/merge-recursive/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/merge-recursive/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d new file mode 100644 index 000000000..f655d12ea Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d differ diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchA-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchA-1 new file mode 100644 index 000000000..b55325c3e --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchA-1 @@ -0,0 +1 @@ +539bd011c4822c560c1d17cab095006b7a10f707 diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchA-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchA-2 new file mode 100644 index 000000000..d35574340 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchA-2 @@ -0,0 +1 @@ +0bb7ed583d7e9ad507e8b902594f5c9126ea456b diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchB-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchB-1 new file mode 100644 index 000000000..d2eecb741 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchB-1 @@ -0,0 +1 @@ +a34e5a16feabbd0335a633aadb8217c9f3dba58d diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchB-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchB-2 new file mode 100644 index 000000000..d5cfb2762 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchB-2 @@ -0,0 +1 @@ +723181f1bfd30e47a6d1d36a4d874e31e7a0a1a4 diff --git a/tests/resources/merge-recursive/asparagus.txt b/tests/resources/merge-recursive/asparagus.txt new file mode 100644 index 000000000..f51658077 --- /dev/null +++ b/tests/resources/merge-recursive/asparagus.txt @@ -0,0 +1,10 @@ +ASPARAGUS SOUP! + +Take four large bunches of asparagus, scrape it nicely, cut off one inch +of the tops, and lay them in water, chop the stalks and put them on the +fire with a piece of bacon, a large onion cut up, and pepper and salt; +add two quarts of water, boil them till the stalks are quite soft, then +pulp them through a sieve, and strain the water to it, which must be put +back in the pot; put into it a chicken cut up, with the tops of +asparagus which had been laid by, boil it until these last articles are +sufficiently done, thicken with flour, butter and milk, and serve it up. diff --git a/tests/resources/merge-recursive/beef.txt b/tests/resources/merge-recursive/beef.txt new file mode 100644 index 000000000..68f6182f4 --- /dev/null +++ b/tests/resources/merge-recursive/beef.txt @@ -0,0 +1,22 @@ +BEEF SOUP. + +Take the hind shin of beef, cut off all the flesh off the leg-bone, +which must be taken away entirely, or the soup will be greasy. Wash the +meat clean and lay it in a pot, sprinkle over it one small +table-spoonful of pounded black pepper, and two of salt; three onions +the size of a hen's egg, cut small, six small carrots scraped and cut +up, two small turnips pared and cut into dice; pour on three quarts of +water, cover the pot close, and keep it gently and steadily boiling five +hours, which will leave about three pints of clear soup; do not let the +pot boil over, but take off the scum carefully, as it rises. When it has +boiled four hours, put in a small bundle of thyme and parsley, and a +pint of celery cut small, or a tea-spoonful of celery seed pounded. +These latter ingredients would lose their delicate flavour if boiled too +much. Just before you take it up, brown it in the following manner: put +a small table-spoonful of nice brown sugar into an iron skillet, set it +on the fire and stir it till it melts and looks very dark, pour into it +a ladle full of the soup, a little at a time; stirring it all the while. +Strain this browning and mix it well with the soup; take out the bundle +of thyme and parsley, put the nicest pieces of meat in your tureen, and +pour on the soup and vegetables; put in some toasted bread cut in dice, +and serve it up. diff --git a/tests/resources/merge-recursive/bouilli.txt b/tests/resources/merge-recursive/bouilli.txt new file mode 100644 index 000000000..4b7c56500 --- /dev/null +++ b/tests/resources/merge-recursive/bouilli.txt @@ -0,0 +1,18 @@ +SOUP WITH BOUILLI. + +Take the nicest part of the thick brisket of beef, about eight pounds, +put it into a pot with every thing directed for the other soup; make it +exactly in the same way, only put it on an hour sooner, that you may +have time to prepare the bouilli; after it has boiled five hours, take +out the beef, cover up the soup and set it near the fire that it may +keep hot. Take the skin off the beef, have the yelk of an egg well +beaten, dip a feather in it and wash the top of your beef, sprinkle over +it the crumb of stale bread finely grated, put it in a Dutch oven +previously heated, put the top on with coals enough to brown, but not +burn the beef; let it stand nearly an hour, and prepare your gravy +thus:--Take a sufficient quantity of soup and the vegetables boiled in +it; add to it a table-spoonful of red wine, and two of mushroom catsup, +thicken with a little bit of butter and a little brown flour; make it +very hot, pour it in your dish, and put the beef on it. Garnish it with +green pickle, cut in thin slices, serve up the soup in a tureen with +bits of toasted bread. diff --git a/tests/resources/merge-recursive/gravy.txt b/tests/resources/merge-recursive/gravy.txt new file mode 100644 index 000000000..c4e6cca3e --- /dev/null +++ b/tests/resources/merge-recursive/gravy.txt @@ -0,0 +1,8 @@ +GRAVY SOUP. + +Get eight pounds of coarse lean beef--wash it clean and lay it in your +pot, put in the same ingredients as for the shin soup, with the same +quantity of water, and follow the process directed for that. Strain the +soup through a sieve, and serve it up clear, with nothing more than +toasted bread in it; two table-spoonsful of mushroom catsup will add a +fine flavour to the soup. diff --git a/tests/resources/merge-recursive/oyster.txt b/tests/resources/merge-recursive/oyster.txt new file mode 100644 index 000000000..68af1fc74 --- /dev/null +++ b/tests/resources/merge-recursive/oyster.txt @@ -0,0 +1,13 @@ +OYSTER SOUP. + +Wash and drain two quarts of oysters, put them on with three quarts of +water, three onions chopped up, two or three slices of lean ham, pepper +and salt; boil it till reduced one-half, strain it through a sieve, +return the liquid into the pot, put in one quart of fresh oysters, boil +it till they are sufficiently done, and thicken the soup with four +spoonsful of flour, two gills of rich cream, and the yelks of six new +laid eggs beaten well; boil it a few minutes after the thickening is put +in. Take care that it does not curdle, and that the flour is not in +lumps; serve it up with the last oysters that were put in. If the +flavour of thyme be agreeable, you may put in a little, but take care +that it does not boil in it long enough to discolour the soup. diff --git a/tests/resources/merge-recursive/veal.txt b/tests/resources/merge-recursive/veal.txt new file mode 100644 index 000000000..94d2c0108 --- /dev/null +++ b/tests/resources/merge-recursive/veal.txt @@ -0,0 +1,18 @@ +VEAL SOUP! + +Put into a pot three quarts of water, three onions cut small, one +spoonful of black pepper pounded, and two of salt, with two or three +slices of lean ham; let it boil steadily two hours; skim it +occasionally, then put into it a shin of veal, let it boil two hours +longer. take out the slices of ham, and skim off the grease if any +should rise, take a gill of good cream, mix with it two table-spoonsful +of flour very nicely, and the yelks of two eggs beaten well, strain this +mixture, and add some chopped parsley; pour some soup on by degrees, +stir it well, and pour it into the pot, continuing to stir until it has +boiled two or three minutes to take off the raw taste of the eggs. If +the cream be not perfectly sweet, and the eggs quite new, the thickening +will curdle in the soup. For a change you may put a dozen ripe tomatos +in, first taking off their skins, by letting them stand a few minutes in +hot water, when they may be easily peeled. When made in this way you +must thicken it with the flour only. Any part of the veal may be used, +but the shin or knuckle is the nicest. -- cgit v1.2.1 From 75dee59c94d39b308529d45dfb993b25d2e9a5f0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 26 Oct 2015 10:37:58 -0400 Subject: merge: build virtual base of multiple merge bases When the commits to merge have multiple common ancestors, build a "virtual" base tree by merging the common ancestors. --- src/merge.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 10 deletions(-) diff --git a/src/merge.c b/src/merge.c index d7b23e2c8..05ca3d0ec 100644 --- a/src/merge.c +++ b/src/merge.c @@ -27,6 +27,7 @@ #include "config.h" #include "oidarray.h" #include "annotated_commit.h" +#include "commit.h" #include "git2/types.h" #include "git2/repository.h" @@ -1922,6 +1923,117 @@ done: return error; } +#define INSERT_VIRTUAL_BASE_PARENT(commit, parent_id) \ + do { \ + id = git_array_alloc(commit->parent_ids); \ + GITERR_CHECK_ALLOC(id); \ + git_oid_cpy(id, parent_id); \ + } while(0) + +static int build_virtual_base( + git_commit **out, + git_repository *repo, + const git_commit *one, + bool one_is_virtual, + const git_oid *two_id) +{ + git_commit *two = NULL, *result; + git_index *index = NULL; + git_oid tree_id, *id; + int error; + + /* TODO: propagate merge options */ + if ((error = git_commit_lookup(&two, repo, two_id)) < 0 || + (error = git_merge_commits(&index, repo, one, two, NULL)) < 0) + goto done; + + if ((error = git_index_write_tree_to(&tree_id, index, repo)) < 0) + goto done; + + if ((result = git__calloc(1, sizeof(git_commit))) == NULL) + goto done; + + result->object.repo = repo; + + /* if the initial commit we were given is virtual, we are octopus + * merging - that virtual base's parents should actually be the + * parents that we use for our new virtual commit. otherwise, it + * is an actual parent. + */ + if (one_is_virtual) { + size_t i, cnt = git_commit_parentcount(one); + + for (i = 0; i < cnt; i++) + INSERT_VIRTUAL_BASE_PARENT(result, git_commit_parent_id(one, i)); + } else { + INSERT_VIRTUAL_BASE_PARENT(result, git_commit_id(one)); + } + + INSERT_VIRTUAL_BASE_PARENT(result, two_id); + + git_oid_cpy(&result->tree_id, &tree_id); + + *out = result; + +done: + git_index_free(index); + git_commit_free(two); + return error; +} + +#undef INSERT_VIRTUAL_BASE_PARENT + +static int compute_base_tree( + git_tree **out, + git_repository *repo, + const git_commit *our_commit, + const git_commit *their_commit, + bool recursive) +{ + git_commit_list *base_list; + git_revwalk *walk; + git_commit *base = NULL; + bool base_virtual = false; + int error = 0; + + *out = NULL; + + if ((error = merge_bases(&base_list, &walk, repo, + git_commit_id(our_commit), git_commit_id(their_commit))) < 0) + return error; + + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + goto done; + } + + if ((error = git_commit_lookup(&base, repo, &base_list->item->oid)) < 0) + goto done; + + while (recursive && base_list->next) { + git_commit *new_base; + + base_list = base_list->next; + + if ((error = build_virtual_base(&new_base, repo, base, base_virtual, + &base_list->item->oid)) < 0) + goto done; + + git_commit_free(base); + base = new_base; + base_virtual = true; + } + + error = git_commit_tree(out, base); + +done: + git_commit_free(base); + git_commit_list_free(&base_list); + git_revwalk_free(walk); + + return error; +} int git_merge_commits( git_index **out, @@ -1930,18 +2042,20 @@ int git_merge_commits( const git_commit *their_commit, const git_merge_options *opts) { - git_oid ancestor_oid; - git_commit *ancestor_commit = NULL; git_tree *our_tree = NULL, *their_tree = NULL, *ancestor_tree = NULL; + bool recursive; int error = 0; - if ((error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))) < 0 && - error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0 || - (error = git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)) < 0 || - (error = git_commit_tree(&ancestor_tree, ancestor_commit)) < 0) - goto done; + recursive = !opts || (opts->flags & GIT_MERGE_NO_RECURSIVE) == 0; + + if ((error = compute_base_tree(&ancestor_tree, repo, + our_commit, their_commit, recursive)) < 0) { + + if (error == GIT_ENOTFOUND) + giterr_clear(); + else + goto done; + } if ((error = git_commit_tree(&our_tree, our_commit)) < 0 || (error = git_commit_tree(&their_tree, their_commit)) < 0 || @@ -1949,7 +2063,6 @@ int git_merge_commits( goto done; done: - git_commit_free(ancestor_commit); git_tree_free(our_tree); git_tree_free(their_tree); git_tree_free(ancestor_tree); -- cgit v1.2.1 From cdb6c1c83dd6f0d30b798a7f62d4f3849a1f11a1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 26 Oct 2015 17:14:28 -0400 Subject: merge: add a second-level recursive merge --- tests/merge/trees/recursive.c | 50 ++++++++++++++++++++- .../0f/a6ead2731b9d138afe38c336c9727ea05027a7 | 1 + .../41/71bb8d40e9fc830d79b757dc06ec6c14548b78 | Bin 0 -> 207 bytes .../4e/70a6b06fc62481f80fbb74327849e7170eebff | Bin 0 -> 207 bytes .../68/a2e1ee61a23a4728fe6b35580fbbbf729df370 | Bin 0 -> 665 bytes .../75/c653822173a8e5795153ec3773dfe44bb9bb63 | 1 + .../81/5b5a1c80ca749d705c7aa0cb294a00cbedd340 | 5 +++ .../89/8d12687fb35be271c27c795a6b32c8b51da79e | Bin 0 -> 663 bytes .../ad/2ace9e15f66b3d1138922e6ffdc3ea3f967fa6 | Bin 0 -> 170 bytes .../c0/bd078a61d2cc22c52ca5ce04abdcdc5cc1829e | Bin 0 -> 207 bytes .../merge-recursive/.gitted/refs/heads/branchC-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchC-2 | 1 + 12 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/resources/merge-recursive/.gitted/objects/0f/a6ead2731b9d138afe38c336c9727ea05027a7 create mode 100644 tests/resources/merge-recursive/.gitted/objects/41/71bb8d40e9fc830d79b757dc06ec6c14548b78 create mode 100644 tests/resources/merge-recursive/.gitted/objects/4e/70a6b06fc62481f80fbb74327849e7170eebff create mode 100644 tests/resources/merge-recursive/.gitted/objects/68/a2e1ee61a23a4728fe6b35580fbbbf729df370 create mode 100644 tests/resources/merge-recursive/.gitted/objects/75/c653822173a8e5795153ec3773dfe44bb9bb63 create mode 100644 tests/resources/merge-recursive/.gitted/objects/81/5b5a1c80ca749d705c7aa0cb294a00cbedd340 create mode 100644 tests/resources/merge-recursive/.gitted/objects/89/8d12687fb35be271c27c795a6b32c8b51da79e create mode 100644 tests/resources/merge-recursive/.gitted/objects/ad/2ace9e15f66b3d1138922e6ffdc3ea3f967fa6 create mode 100644 tests/resources/merge-recursive/.gitted/objects/c0/bd078a61d2cc22c52ca5ce04abdcdc5cc1829e create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchC-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchC-2 diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index 1d3586162..a7358e7e3 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -88,8 +88,6 @@ void test_merge_trees_recursive__two_norecursive(void) git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; - opts.flags |= GIT_MERGE_NO_RECURSIVE; - struct merge_index_entry merge_index_entries[] = { { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, @@ -101,6 +99,8 @@ void test_merge_trees_recursive__two_norecursive(void) { 0100644, "4e21d2d63357bde5027d1625f5ec6b430cdeb143", 3, "veal.txt" }, }; + opts.flags |= GIT_MERGE_NO_RECURSIVE; + cl_git_pass(merge_commits_from_branches(&index, repo, "branchB-1", "branchB-2", &opts)); cl_assert(merge_test_index(index, merge_index_entries, 8)); @@ -108,3 +108,49 @@ void test_merge_trees_recursive__two_norecursive(void) git_index_free(index); } +void test_merge_trees_recursive__three(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "15faa0c9991f2d65686e844651faa2ff9827887b", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchC-1", "branchC-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__three_norecursive(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "b2a81ead9e722af0099fccfb478cea88eea749a2", 1, "veal.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 2, "veal.txt" }, + { 0100644, "68a2e1ee61a23a4728fe6b35580fbbbf729df370", 3, "veal.txt" }, + }; + + opts.flags |= GIT_MERGE_NO_RECURSIVE; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchC-1", "branchC-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + diff --git a/tests/resources/merge-recursive/.gitted/objects/0f/a6ead2731b9d138afe38c336c9727ea05027a7 b/tests/resources/merge-recursive/.gitted/objects/0f/a6ead2731b9d138afe38c336c9727ea05027a7 new file mode 100644 index 000000000..b06362dd8 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/0f/a6ead2731b9d138afe38c336c9727ea05027a7 @@ -0,0 +1 @@ +xJAE+*hk"bhTw8̴-\0/2<݌nKI\9D`5Tdϩ4Jm I)ꈼ"-鄱晴O'„3YG JAXSd#(NPxzmpg{q>e9ѱsӞ3=Y1pFe2oz \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/41/71bb8d40e9fc830d79b757dc06ec6c14548b78 b/tests/resources/merge-recursive/.gitted/objects/41/71bb8d40e9fc830d79b757dc06ec6c14548b78 new file mode 100644 index 000000000..5dc102d35 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/41/71bb8d40e9fc830d79b757dc06ec6c14548b78 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/4e/70a6b06fc62481f80fbb74327849e7170eebff b/tests/resources/merge-recursive/.gitted/objects/4e/70a6b06fc62481f80fbb74327849e7170eebff new file mode 100644 index 000000000..1dfcec50b Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/4e/70a6b06fc62481f80fbb74327849e7170eebff differ diff --git a/tests/resources/merge-recursive/.gitted/objects/68/a2e1ee61a23a4728fe6b35580fbbbf729df370 b/tests/resources/merge-recursive/.gitted/objects/68/a2e1ee61a23a4728fe6b35580fbbbf729df370 new file mode 100644 index 000000000..6d7c948c9 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/68/a2e1ee61a23a4728fe6b35580fbbbf729df370 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/75/c653822173a8e5795153ec3773dfe44bb9bb63 b/tests/resources/merge-recursive/.gitted/objects/75/c653822173a8e5795153ec3773dfe44bb9bb63 new file mode 100644 index 000000000..1495f70f4 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/75/c653822173a8e5795153ec3773dfe44bb9bb63 @@ -0,0 +1 @@ +xJ1);ՑLfrYdfSFbwヿm @WcRyh5V Date: Mon, 26 Oct 2015 17:25:42 -0400 Subject: merge: add a third-level recursive merge --- tests/merge/trees/recursive.c | 46 +++++++++++++++++++++ .../00/7f1ee2af8e5d99906867c4237510e1790a89b8 | 3 ++ .../15/faa0c9991f2d65686e844651faa2ff9827887b | Bin 0 -> 665 bytes .../4d/fc1be85a9d6c9898152444d32b238b4aecf8cc | Bin 0 -> 168 bytes .../50/e4facaafb746cfed89287206274193c1417288 | 2 + .../5e/8747f5200fac0f945a07daf6163ca9cb1a8da9 | Bin 0 -> 672 bytes .../5f/18576d464946eb2338daeb8b4030019961f505 | Bin 0 -> 208 bytes .../ad/1ea02c2cc4f55c1dff87b80a086206a73885eb | 2 + .../ca/49d1a8b6116ffeba22667bba265fa5261df7ab | 2 + .../e1/dcfc3038be54195a59817c89782b261e46cb05 | 1 + .../f1/b44c04989a3a1c14b036cfadfa328d53a7bc5e | Bin 0 -> 672 bytes .../merge-recursive/.gitted/refs/heads/branchD-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchD-2 | 1 + 13 files changed, 58 insertions(+) create mode 100644 tests/resources/merge-recursive/.gitted/objects/00/7f1ee2af8e5d99906867c4237510e1790a89b8 create mode 100644 tests/resources/merge-recursive/.gitted/objects/15/faa0c9991f2d65686e844651faa2ff9827887b create mode 100644 tests/resources/merge-recursive/.gitted/objects/4d/fc1be85a9d6c9898152444d32b238b4aecf8cc create mode 100644 tests/resources/merge-recursive/.gitted/objects/50/e4facaafb746cfed89287206274193c1417288 create mode 100644 tests/resources/merge-recursive/.gitted/objects/5e/8747f5200fac0f945a07daf6163ca9cb1a8da9 create mode 100644 tests/resources/merge-recursive/.gitted/objects/5f/18576d464946eb2338daeb8b4030019961f505 create mode 100644 tests/resources/merge-recursive/.gitted/objects/ad/1ea02c2cc4f55c1dff87b80a086206a73885eb create mode 100644 tests/resources/merge-recursive/.gitted/objects/ca/49d1a8b6116ffeba22667bba265fa5261df7ab create mode 100644 tests/resources/merge-recursive/.gitted/objects/e1/dcfc3038be54195a59817c89782b261e46cb05 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f1/b44c04989a3a1c14b036cfadfa328d53a7bc5e create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchD-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchD-2 diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index a7358e7e3..cd879677f 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -154,3 +154,49 @@ void test_merge_trees_recursive__three_norecursive(void) git_index_free(index); } +void test_merge_trees_recursive__four(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "d55e5dc038c52f1a36548625bcb666cbc06db9e6", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchD-2", "branchD-1", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__four_norecursive(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 1, "veal.txt" }, + { 0100644, "f1b44c04989a3a1c14b036cfadfa328d53a7bc5e", 2, "veal.txt" }, + { 0100644, "5e8747f5200fac0f945a07daf6163ca9cb1a8da9", 3, "veal.txt" }, + }; + + opts.flags |= GIT_MERGE_NO_RECURSIVE; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchD-2", "branchD-1", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + diff --git a/tests/resources/merge-recursive/.gitted/objects/00/7f1ee2af8e5d99906867c4237510e1790a89b8 b/tests/resources/merge-recursive/.gitted/objects/00/7f1ee2af8e5d99906867c4237510e1790a89b8 new file mode 100644 index 000000000..d9399d71c --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/00/7f1ee2af8e5d99906867c4237510e1790a89b8 @@ -0,0 +1,3 @@ +xNI +1<FtgA~WENYZGj +RSj2I^'y51i0599`e5a z%潎U^XV Vtٙo]2Y~P1($bz7g\QdLɔ3RsjD-89S^75#-ע3;\ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/5e/8747f5200fac0f945a07daf6163ca9cb1a8da9 b/tests/resources/merge-recursive/.gitted/objects/5e/8747f5200fac0f945a07daf6163ca9cb1a8da9 new file mode 100644 index 000000000..fa1c9e5dc Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/5e/8747f5200fac0f945a07daf6163ca9cb1a8da9 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/5f/18576d464946eb2338daeb8b4030019961f505 b/tests/resources/merge-recursive/.gitted/objects/5f/18576d464946eb2338daeb8b4030019961f505 new file mode 100644 index 000000000..d03742b92 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/5f/18576d464946eb2338daeb8b4030019961f505 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/ad/1ea02c2cc4f55c1dff87b80a086206a73885eb b/tests/resources/merge-recursive/.gitted/objects/ad/1ea02c2cc4f55c1dff87b80a086206a73885eb new file mode 100644 index 000000000..99207a9dd --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/ad/1ea02c2cc4f55c1dff87b80a086206a73885eb @@ -0,0 +1,2 @@ +x+)JMU022g040031QH,.H,JL/-+(a9/>~WENYZGj +RSj2I^'y51i0599`e5a z%潎U^XV Vtٙo]2Y~P1($bz7g\QdLɔ3Rsjݿ*~뛘R+<[{ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/ca/49d1a8b6116ffeba22667bba265fa5261df7ab b/tests/resources/merge-recursive/.gitted/objects/ca/49d1a8b6116ffeba22667bba265fa5261df7ab new file mode 100644 index 000000000..1ea596763 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/ca/49d1a8b6116ffeba22667bba265fa5261df7ab @@ -0,0 +1,2 @@ +xN1 D+8q^BH:{ݠ^=gFھ_8FWo* s]#ZR)Zl$N0ڔz bY4+ +VCE9>_=$#)hDf#fN-őYmlCy^ikk;F'Twel[@"2Yp6d2,71ˣg48 .hv>d?;No \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/e1/dcfc3038be54195a59817c89782b261e46cb05 b/tests/resources/merge-recursive/.gitted/objects/e1/dcfc3038be54195a59817c89782b261e46cb05 new file mode 100644 index 000000000..3668b546a --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/e1/dcfc3038be54195a59817c89782b261e46cb05 @@ -0,0 +1 @@ +xN1 :O:%/uݠ\OGTG5ܶ2yw7x-X1pM`#ؠ6%F]œᤙ"HyI)8Կy*X_CX\1VB9JAX[Aڶk$Rg>ܶ{nD2ZQk5Yn0hn,UV8e N;G>>MpM \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/f1/b44c04989a3a1c14b036cfadfa328d53a7bc5e b/tests/resources/merge-recursive/.gitted/objects/f1/b44c04989a3a1c14b036cfadfa328d53a7bc5e new file mode 100644 index 000000000..7cbaaeecf Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/f1/b44c04989a3a1c14b036cfadfa328d53a7bc5e differ diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchD-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchD-1 new file mode 100644 index 000000000..fa96ccb28 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchD-1 @@ -0,0 +1 @@ +4dfc1be85a9d6c9898152444d32b238b4aecf8cc diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchD-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchD-2 new file mode 100644 index 000000000..8a87f9868 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchD-2 @@ -0,0 +1 @@ +007f1ee2af8e5d99906867c4237510e1790a89b8 -- cgit v1.2.1 From 99d9d9a470ca9b693f6dbee05f1cfcd98a5d148d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 26 Oct 2015 17:44:36 -0400 Subject: merge: improve test names in recursive merge tests --- tests/merge/trees/recursive.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index cd879677f..bff5d7e39 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -18,7 +18,7 @@ void test_merge_trees_recursive__cleanup(void) cl_git_sandbox_cleanup(); } -void test_merge_trees_recursive__one(void) +void test_merge_trees_recursive__one_base_commit(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -39,7 +39,7 @@ void test_merge_trees_recursive__one(void) git_index_free(index); } -void test_merge_trees_recursive__one_norecursive(void) +void test_merge_trees_recursive__one_base_commit_norecursive(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -62,7 +62,7 @@ void test_merge_trees_recursive__one_norecursive(void) git_index_free(index); } -void test_merge_trees_recursive__two(void) +void test_merge_trees_recursive__two_base_commits(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -83,7 +83,7 @@ void test_merge_trees_recursive__two(void) git_index_free(index); } -void test_merge_trees_recursive__two_norecursive(void) +void test_merge_trees_recursive__two_base_commits_norecursive(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -108,7 +108,7 @@ void test_merge_trees_recursive__two_norecursive(void) git_index_free(index); } -void test_merge_trees_recursive__three(void) +void test_merge_trees_recursive__two_levels_of_multiple_bases(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -129,7 +129,7 @@ void test_merge_trees_recursive__three(void) git_index_free(index); } -void test_merge_trees_recursive__three_norecursive(void) +void test_merge_trees_recursive__two_levels_of_multiple_bases_norecursive(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -154,7 +154,7 @@ void test_merge_trees_recursive__three_norecursive(void) git_index_free(index); } -void test_merge_trees_recursive__four(void) +void test_merge_trees_recursive__three_levels_of_multiple_bases(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; @@ -175,7 +175,7 @@ void test_merge_trees_recursive__four(void) git_index_free(index); } -void test_merge_trees_recursive__four_norecursive(void) +void test_merge_trees_recursive__three_levels_of_multiple_bases_norecursive(void) { git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; -- cgit v1.2.1 From fccad82ee8f431e06097b3a1282228b40ae7128f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 27 Oct 2015 14:23:35 -0500 Subject: merge: add recursive test with three merge bases --- tests/merge/trees/recursive.c | 46 +++++++++++++++++++++ .../06/db153c36829fc656e05cdf5a3bf7183f3c10aa | 2 + .../0e/8126647ec607f0a14122cec4b15315d790c8ff | Bin 0 -> 208 bytes .../1c/1bdb80c04233d1a9b9755913ee233987be6175 | Bin 0 -> 208 bytes .../1e/8dff96faaaa24f84943d2d9601dde61cb0398a | Bin 0 -> 268 bytes .../43/6ea75c99f527e4b42fddb46abedf7726eb719d | 2 + .../5a/ba269b3be41fc8db38068d3948c8af543fe609 | Bin 0 -> 208 bytes .../73/b20c8e09fa2726d69ff66969186014165da3c3 | Bin 0 -> 208 bytes .../7e/3056f6765b3044ab09701077dbe1eb5b0e9ad0 | Bin 0 -> 208 bytes .../8a/bda8de114a93f2d3c5a975ee2960f31e24be58 | 2 + .../96/23368f0fc562d6d840372ae17dc4cc32d51a80 | 2 + .../9a/e63b4a8ce0f181b2d1d098971733a103226917 | Bin 0 -> 240 bytes .../9b/258ad4c39f40c24f66bf1faf48eb6202d59c85 | Bin 0 -> 240 bytes .../9e/12bce04446d097ae1782967a5888c2e2a0d35b | Bin 0 -> 268 bytes .../a2/8c21c90aa36580641b345011869d1a899a6783 | 2 + .../ad/98bfa4679fb00b89207a0a11b8bbf91a3e4de9 | Bin 0 -> 208 bytes .../bd/97980c22d122509cdd915fd9788d56c8d3ae20 | Bin 0 -> 163 bytes .../ca/224bba0a8a24f1768804fe5f565b1014af7ef2 | Bin 0 -> 170 bytes .../d2/682aaf9594080ce877b5eeee110850fd6e3480 | 1 + .../d8/dd349b78f19a4ebe3357bacb8138f00bf5ed41 | Bin 0 -> 277 bytes .../d8/e05a90b3c2240d71a20c2502c937d9b7d22777 | 2 + .../da/b7b53383a1fec46632e60a1d847ce4f9ae14f2 | Bin 0 -> 208 bytes .../e2/d185fa827d58134cea20b9e1df893833c6560e | Bin 0 -> 208 bytes .../e5/0fbbd701458757bdfe9815f58ed717c588d1b5 | 3 ++ .../f1/72517a8cf39e009ffff541ee52429b89e418f3 | Bin 0 -> 268 bytes .../merge-recursive/.gitted/refs/heads/branchE-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchE-2 | 1 + .../merge-recursive/.gitted/refs/heads/branchE-3 | 1 + 28 files changed, 65 insertions(+) create mode 100644 tests/resources/merge-recursive/.gitted/objects/06/db153c36829fc656e05cdf5a3bf7183f3c10aa create mode 100644 tests/resources/merge-recursive/.gitted/objects/0e/8126647ec607f0a14122cec4b15315d790c8ff create mode 100644 tests/resources/merge-recursive/.gitted/objects/1c/1bdb80c04233d1a9b9755913ee233987be6175 create mode 100644 tests/resources/merge-recursive/.gitted/objects/1e/8dff96faaaa24f84943d2d9601dde61cb0398a create mode 100644 tests/resources/merge-recursive/.gitted/objects/43/6ea75c99f527e4b42fddb46abedf7726eb719d create mode 100644 tests/resources/merge-recursive/.gitted/objects/5a/ba269b3be41fc8db38068d3948c8af543fe609 create mode 100644 tests/resources/merge-recursive/.gitted/objects/73/b20c8e09fa2726d69ff66969186014165da3c3 create mode 100644 tests/resources/merge-recursive/.gitted/objects/7e/3056f6765b3044ab09701077dbe1eb5b0e9ad0 create mode 100644 tests/resources/merge-recursive/.gitted/objects/8a/bda8de114a93f2d3c5a975ee2960f31e24be58 create mode 100644 tests/resources/merge-recursive/.gitted/objects/96/23368f0fc562d6d840372ae17dc4cc32d51a80 create mode 100644 tests/resources/merge-recursive/.gitted/objects/9a/e63b4a8ce0f181b2d1d098971733a103226917 create mode 100644 tests/resources/merge-recursive/.gitted/objects/9b/258ad4c39f40c24f66bf1faf48eb6202d59c85 create mode 100644 tests/resources/merge-recursive/.gitted/objects/9e/12bce04446d097ae1782967a5888c2e2a0d35b create mode 100644 tests/resources/merge-recursive/.gitted/objects/a2/8c21c90aa36580641b345011869d1a899a6783 create mode 100644 tests/resources/merge-recursive/.gitted/objects/ad/98bfa4679fb00b89207a0a11b8bbf91a3e4de9 create mode 100644 tests/resources/merge-recursive/.gitted/objects/bd/97980c22d122509cdd915fd9788d56c8d3ae20 create mode 100644 tests/resources/merge-recursive/.gitted/objects/ca/224bba0a8a24f1768804fe5f565b1014af7ef2 create mode 100644 tests/resources/merge-recursive/.gitted/objects/d2/682aaf9594080ce877b5eeee110850fd6e3480 create mode 100644 tests/resources/merge-recursive/.gitted/objects/d8/dd349b78f19a4ebe3357bacb8138f00bf5ed41 create mode 100644 tests/resources/merge-recursive/.gitted/objects/d8/e05a90b3c2240d71a20c2502c937d9b7d22777 create mode 100644 tests/resources/merge-recursive/.gitted/objects/da/b7b53383a1fec46632e60a1d847ce4f9ae14f2 create mode 100644 tests/resources/merge-recursive/.gitted/objects/e2/d185fa827d58134cea20b9e1df893833c6560e create mode 100644 tests/resources/merge-recursive/.gitted/objects/e5/0fbbd701458757bdfe9815f58ed717c588d1b5 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f1/72517a8cf39e009ffff541ee52429b89e418f3 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchE-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchE-2 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchE-3 diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index bff5d7e39..46effa5c2 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -200,3 +200,49 @@ void test_merge_trees_recursive__three_levels_of_multiple_bases_norecursive(void git_index_free(index); } +void test_merge_trees_recursive__three_base_commits(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4f7269b07c76d02755d75ccaf05c0b4c36cdc6c", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} + +void test_merge_trees_recursive__three_base_commits_norecursive(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "9e12bce04446d097ae1782967a5888c2e2a0d35b", 1, "gravy.txt" }, + { 0100644, "d8dd349b78f19a4ebe3357bacb8138f00bf5ed41", 2, "gravy.txt" }, + { 0100644, "e50fbbd701458757bdfe9815f58ed717c588d1b5", 3, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + + opts.flags |= GIT_MERGE_NO_RECURSIVE; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + diff --git a/tests/resources/merge-recursive/.gitted/objects/06/db153c36829fc656e05cdf5a3bf7183f3c10aa b/tests/resources/merge-recursive/.gitted/objects/06/db153c36829fc656e05cdf5a3bf7183f3c10aa new file mode 100644 index 000000000..85887e0f5 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/06/db153c36829fc656e05cdf5a3bf7183f3c10aa @@ -0,0 +1,2 @@ +x%Pn@ |_HN.}%)Qe819@R$&I!w6pF,Kң*HL s߯#0+300/`#Cib']l +RRqo,k>\vXɸPzIIM6iY],WzpBzPdF4V .xV!y~9ր0uhoU`$,_R:-a2%Sw^cJ>fFOv;+ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/0e/8126647ec607f0a14122cec4b15315d790c8ff b/tests/resources/merge-recursive/.gitted/objects/0e/8126647ec607f0a14122cec4b15315d790c8ff new file mode 100644 index 000000000..c99a6865c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/0e/8126647ec607f0a14122cec4b15315d790c8ff differ diff --git a/tests/resources/merge-recursive/.gitted/objects/1c/1bdb80c04233d1a9b9755913ee233987be6175 b/tests/resources/merge-recursive/.gitted/objects/1c/1bdb80c04233d1a9b9755913ee233987be6175 new file mode 100644 index 000000000..a2146496d Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/1c/1bdb80c04233d1a9b9755913ee233987be6175 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/1e/8dff96faaaa24f84943d2d9601dde61cb0398a b/tests/resources/merge-recursive/.gitted/objects/1e/8dff96faaaa24f84943d2d9601dde61cb0398a new file mode 100644 index 000000000..b6185f294 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/1e/8dff96faaaa24f84943d2d9601dde61cb0398a differ diff --git a/tests/resources/merge-recursive/.gitted/objects/43/6ea75c99f527e4b42fddb46abedf7726eb719d b/tests/resources/merge-recursive/.gitted/objects/43/6ea75c99f527e4b42fddb46abedf7726eb719d new file mode 100644 index 000000000..e8825d867 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/43/6ea75c99f527e4b42fddb46abedf7726eb719d @@ -0,0 +1,2 @@ +xKj1D)tncev@bFf,G U(i۶v}CՂft1RRf`$tNTcy6>t]Rǐ!=@̱T\ +ǔW_aGm϶۳WOi"Q%  :v}s|Ϋp_Dž7QA \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/5a/ba269b3be41fc8db38068d3948c8af543fe609 b/tests/resources/merge-recursive/.gitted/objects/5a/ba269b3be41fc8db38068d3948c8af543fe609 new file mode 100644 index 000000000..85bc8f569 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/5a/ba269b3be41fc8db38068d3948c8af543fe609 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/73/b20c8e09fa2726d69ff66969186014165da3c3 b/tests/resources/merge-recursive/.gitted/objects/73/b20c8e09fa2726d69ff66969186014165da3c3 new file mode 100644 index 000000000..6559958c5 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/73/b20c8e09fa2726d69ff66969186014165da3c3 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/7e/3056f6765b3044ab09701077dbe1eb5b0e9ad0 b/tests/resources/merge-recursive/.gitted/objects/7e/3056f6765b3044ab09701077dbe1eb5b0e9ad0 new file mode 100644 index 000000000..c4b835518 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/7e/3056f6765b3044ab09701077dbe1eb5b0e9ad0 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/8a/bda8de114a93f2d3c5a975ee2960f31e24be58 b/tests/resources/merge-recursive/.gitted/objects/8a/bda8de114a93f2d3c5a975ee2960f31e24be58 new file mode 100644 index 000000000..a03624d81 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/8a/bda8de114a93f2d3c5a975ee2960f31e24be58 @@ -0,0 +1,2 @@ +xN; +1)r"6[y "Y#^(@b>0j-+k}'⤒#(,HmK 2 ZNǝ=%!QEa^p޹% $Y||N'~[[}hvoSGl̥1I!pNΰkK%  \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/96/23368f0fc562d6d840372ae17dc4cc32d51a80 b/tests/resources/merge-recursive/.gitted/objects/96/23368f0fc562d6d840372ae17dc4cc32d51a80 new file mode 100644 index 000000000..70bf8fbb0 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/96/23368f0fc562d6d840372ae17dc4cc32d51a80 @@ -0,0 +1,2 @@ +xK +1D]H>πYId1oo ԢuJ7"BthuՊ2ypH@bhܡ2IXPIat8OYx6Whֺ=O4][vH| t Tr˸0L#S; \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/9a/e63b4a8ce0f181b2d1d098971733a103226917 b/tests/resources/merge-recursive/.gitted/objects/9a/e63b4a8ce0f181b2d1d098971733a103226917 new file mode 100644 index 000000000..0cbd00d53 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/9a/e63b4a8ce0f181b2d1d098971733a103226917 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/9b/258ad4c39f40c24f66bf1faf48eb6202d59c85 b/tests/resources/merge-recursive/.gitted/objects/9b/258ad4c39f40c24f66bf1faf48eb6202d59c85 new file mode 100644 index 000000000..305e1f3e9 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/9b/258ad4c39f40c24f66bf1faf48eb6202d59c85 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/9e/12bce04446d097ae1782967a5888c2e2a0d35b b/tests/resources/merge-recursive/.gitted/objects/9e/12bce04446d097ae1782967a5888c2e2a0d35b new file mode 100644 index 000000000..0940d09c2 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/9e/12bce04446d097ae1782967a5888c2e2a0d35b differ diff --git a/tests/resources/merge-recursive/.gitted/objects/a2/8c21c90aa36580641b345011869d1a899a6783 b/tests/resources/merge-recursive/.gitted/objects/a2/8c21c90aa36580641b345011869d1a899a6783 new file mode 100644 index 000000000..91ffb4b88 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/a2/8c21c90aa36580641b345011869d1a899a6783 @@ -0,0 +1,2 @@ +xN@ ۥ:\I x^dQ WDg3i\<7le*MbB0 Ji%XTUV[6CԠՔQR0ZjB/TD OmDr% bxR> +jra,hWwY=wo;[nk1'D1Ó/~xmrrmѝROa \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/ad/98bfa4679fb00b89207a0a11b8bbf91a3e4de9 b/tests/resources/merge-recursive/.gitted/objects/ad/98bfa4679fb00b89207a0a11b8bbf91a3e4de9 new file mode 100644 index 000000000..457f9da1f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/ad/98bfa4679fb00b89207a0a11b8bbf91a3e4de9 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/bd/97980c22d122509cdd915fd9788d56c8d3ae20 b/tests/resources/merge-recursive/.gitted/objects/bd/97980c22d122509cdd915fd9788d56c8d3ae20 new file mode 100644 index 000000000..71295e071 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/bd/97980c22d122509cdd915fd9788d56c8d3ae20 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/ca/224bba0a8a24f1768804fe5f565b1014af7ef2 b/tests/resources/merge-recursive/.gitted/objects/ca/224bba0a8a24f1768804fe5f565b1014af7ef2 new file mode 100644 index 000000000..0dd861f2c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/ca/224bba0a8a24f1768804fe5f565b1014af7ef2 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/d2/682aaf9594080ce877b5eeee110850fd6e3480 b/tests/resources/merge-recursive/.gitted/objects/d2/682aaf9594080ce877b5eeee110850fd6e3480 new file mode 100644 index 000000000..c79a3bb0f --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/d2/682aaf9594080ce877b5eeee110850fd6e3480 @@ -0,0 +1 @@ +x%Pn@ |_IPS)SХ$2ʶp>'9F:gH$it]p:?p``dΝBzBE)aۅt@4+FC{b]& yl`(p9[*mx`?t2.Ԩ^ReMEZVE ƕd;z@>+r^[fFOvۅЋ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/d8/dd349b78f19a4ebe3357bacb8138f00bf5ed41 b/tests/resources/merge-recursive/.gitted/objects/d8/dd349b78f19a4ebe3357bacb8138f00bf5ed41 new file mode 100644 index 000000000..ade33f7f5 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/d8/dd349b78f19a4ebe3357bacb8138f00bf5ed41 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/d8/e05a90b3c2240d71a20c2502c937d9b7d22777 b/tests/resources/merge-recursive/.gitted/objects/d8/e05a90b3c2240d71a20c2502c937d9b7d22777 new file mode 100644 index 000000000..b157ba17c --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/d8/e05a90b3c2240d71a20c2502c937d9b7d22777 @@ -0,0 +1,2 @@ +x%Pn@ |_IQS)SХ$2ʶp>'9F:gH$it]p:oB8u0L2N!=ZĔ0B: !ѽ1.s Ӽ60FvZMA^ +Vn-yb6<0ׇq -jT/)ɲʦ"-[UOgz@>+r^[fFOvۄ𶋅 \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/da/b7b53383a1fec46632e60a1d847ce4f9ae14f2 b/tests/resources/merge-recursive/.gitted/objects/da/b7b53383a1fec46632e60a1d847ce4f9ae14f2 new file mode 100644 index 000000000..cc4f24369 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/da/b7b53383a1fec46632e60a1d847ce4f9ae14f2 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/e2/d185fa827d58134cea20b9e1df893833c6560e b/tests/resources/merge-recursive/.gitted/objects/e2/d185fa827d58134cea20b9e1df893833c6560e new file mode 100644 index 000000000..fc80c0851 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/e2/d185fa827d58134cea20b9e1df893833c6560e differ diff --git a/tests/resources/merge-recursive/.gitted/objects/e5/0fbbd701458757bdfe9815f58ed717c588d1b5 b/tests/resources/merge-recursive/.gitted/objects/e5/0fbbd701458757bdfe9815f58ed717c588d1b5 new file mode 100644 index 000000000..96467c106 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/e5/0fbbd701458757bdfe9815f58ed717c588d1b5 @@ -0,0 +1,3 @@ +x%P1n0 Wݡ@SKCCG%QXr}&IKi*ݡRKl8͆Uj2*HLx>3?03RKXNXPZɩ9[-=\߷_밓q9El-ҳ*X7n\$ +C: hVe^[<ᨐżԄE +7LH[@Wvfw.0u:Ժ.U=Ld{L 4 0m$ox \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/f1/72517a8cf39e009ffff541ee52429b89e418f3 b/tests/resources/merge-recursive/.gitted/objects/f1/72517a8cf39e009ffff541ee52429b89e418f3 new file mode 100644 index 000000000..3d29a0fe8 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/f1/72517a8cf39e009ffff541ee52429b89e418f3 differ diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchE-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-1 new file mode 100644 index 000000000..b8d011e2d --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-1 @@ -0,0 +1 @@ +ca224bba0a8a24f1768804fe5f565b1014af7ef2 diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchE-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-2 new file mode 100644 index 000000000..5e1e1acd9 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-2 @@ -0,0 +1 @@ +436ea75c99f527e4b42fddb46abedf7726eb719d diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchE-3 b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-3 new file mode 100644 index 000000000..eaec8d81a --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchE-3 @@ -0,0 +1 @@ +9b258ad4c39f40c24f66bf1faf48eb6202d59c85 -- cgit v1.2.1 From 1b82f7b6a218080df8ff292ab12de744226a9979 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 27 Oct 2015 14:24:51 -0500 Subject: merge: compute octopus merge bases --- src/merge.c | 189 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 100 insertions(+), 89 deletions(-) diff --git a/src/merge.c b/src/merge.c index 05ca3d0ec..0a837b5f4 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1923,83 +1923,41 @@ done: return error; } -#define INSERT_VIRTUAL_BASE_PARENT(commit, parent_id) \ - do { \ - id = git_array_alloc(commit->parent_ids); \ - GITERR_CHECK_ALLOC(id); \ - git_oid_cpy(id, parent_id); \ - } while(0) - -static int build_virtual_base( - git_commit **out, +static int merge_trees_with_heads( + git_index **out, git_repository *repo, - const git_commit *one, - bool one_is_virtual, - const git_oid *two_id) -{ - git_commit *two = NULL, *result; - git_index *index = NULL; - git_oid tree_id, *id; - int error; - - /* TODO: propagate merge options */ - if ((error = git_commit_lookup(&two, repo, two_id)) < 0 || - (error = git_merge_commits(&index, repo, one, two, NULL)) < 0) - goto done; - - if ((error = git_index_write_tree_to(&tree_id, index, repo)) < 0) - goto done; - - if ((result = git__calloc(1, sizeof(git_commit))) == NULL) - goto done; - - result->object.repo = repo; - - /* if the initial commit we were given is virtual, we are octopus - * merging - that virtual base's parents should actually be the - * parents that we use for our new virtual commit. otherwise, it - * is an actual parent. - */ - if (one_is_virtual) { - size_t i, cnt = git_commit_parentcount(one); - - for (i = 0; i < cnt; i++) - INSERT_VIRTUAL_BASE_PARENT(result, git_commit_parent_id(one, i)); - } else { - INSERT_VIRTUAL_BASE_PARENT(result, git_commit_id(one)); - } - - INSERT_VIRTUAL_BASE_PARENT(result, two_id); - - git_oid_cpy(&result->tree_id, &tree_id); - - *out = result; - -done: - git_index_free(index); - git_commit_free(two); - return error; -} - -#undef INSERT_VIRTUAL_BASE_PARENT + const git_tree *ours, + const git_tree *theirs, + const git_oid heads[], + size_t heads_len, + const git_merge_options *opts); + +#define INSERT_ID(_ar, _id) do { \ + git_oid *_alloced = git_array_alloc(_ar); \ + GITERR_CHECK_ALLOC(_alloced); \ + git_oid_cpy(_alloced, _id); \ + } while(0) -static int compute_base_tree( +static int compute_base( git_tree **out, git_repository *repo, - const git_commit *our_commit, - const git_commit *their_commit, - bool recursive) + const git_oid heads[], + size_t heads_len, + const git_merge_options *opts) { - git_commit_list *base_list; - git_revwalk *walk; - git_commit *base = NULL; - bool base_virtual = false; + git_commit_list *base_list = NULL; + git_revwalk *walk = NULL; + git_commit *base_commit = NULL, *next_commit = NULL; + git_tree *base_tree = NULL, *next_tree = NULL; + git_array_t(git_oid) base_ids = GIT_ARRAY_INIT; + git_index *index = NULL; + bool recursive = !opts || (opts->flags & GIT_MERGE_NO_RECURSIVE) == 0; int error = 0; *out = NULL; - if ((error = merge_bases(&base_list, &walk, repo, - git_commit_id(our_commit), git_commit_id(their_commit))) < 0) + if ((error = merge_bases_many(&base_list, &walk, repo, + heads_len, heads)) < 0) return error; if (error == GIT_ENOTFOUND) { @@ -2008,64 +1966,117 @@ static int compute_base_tree( goto done; } - if ((error = git_commit_lookup(&base, repo, &base_list->item->oid)) < 0) + if ((error = git_commit_lookup(&base_commit, repo, + &base_list->item->oid)) < 0 || + (error = git_commit_tree(&base_tree, base_commit)) < 0) goto done; + INSERT_ID(base_ids, git_commit_id(base_commit)); + while (recursive && base_list->next) { - git_commit *new_base; + git_tree *new_tree; + git_oid new_tree_id; base_list = base_list->next; - if ((error = build_virtual_base(&new_base, repo, base, base_virtual, - &base_list->item->oid)) < 0) + if ((error = git_commit_lookup(&next_commit, repo, + &base_list->item->oid)) < 0 || + (error = git_commit_tree(&next_tree, next_commit)) < 0) goto done; - git_commit_free(base); - base = new_base; - base_virtual = true; + INSERT_ID(base_ids, git_commit_id(next_commit)); + + if ((error = merge_trees_with_heads(&index, repo, base_tree, + next_tree, base_ids.ptr, base_ids.size, opts)) < 0) + goto done; + + /* TODO: conflicts!! */ + + if ((error = git_index_write_tree_to(&new_tree_id, index, repo)) < 0 || + (error = git_tree_lookup(&new_tree, repo, &new_tree_id)) < 0) + goto done; + + git_index_free(index); + index = NULL; + + git_tree_free(next_tree); + next_tree = NULL; + + git_commit_free(next_commit); + next_commit = NULL; + + git_tree_free(base_tree); + base_tree = new_tree; } - error = git_commit_tree(out, base); + *out = base_tree; + base_tree = NULL; done: - git_commit_free(base); + git_index_free(index); + git_tree_free(next_tree); + git_tree_free(base_tree); + git_commit_free(next_commit); + git_commit_free(base_commit); git_commit_list_free(&base_list); git_revwalk_free(walk); + git_array_clear(base_ids); return error; } -int git_merge_commits( +static int merge_trees_with_heads( git_index **out, git_repository *repo, - const git_commit *our_commit, - const git_commit *their_commit, + const git_tree *ours, + const git_tree *theirs, + const git_oid heads[], + size_t heads_len, const git_merge_options *opts) { - git_tree *our_tree = NULL, *their_tree = NULL, *ancestor_tree = NULL; - bool recursive; + git_tree *ancestor = NULL; int error = 0; - recursive = !opts || (opts->flags & GIT_MERGE_NO_RECURSIVE) == 0; - - if ((error = compute_base_tree(&ancestor_tree, repo, - our_commit, their_commit, recursive)) < 0) { - + if ((error = compute_base(&ancestor, repo, heads, heads_len, opts)) < 0) { if (error == GIT_ENOTFOUND) giterr_clear(); else goto done; } + error = git_merge_trees(out, repo, ancestor, ours, theirs, opts); + +done: + git_tree_free(ancestor); + + return error; +} + +int git_merge_commits( + git_index **out, + git_repository *repo, + const git_commit *our_commit, + const git_commit *their_commit, + const git_merge_options *opts) +{ + git_tree *our_tree = NULL, *their_tree = NULL; + git_oid heads[2]; + int error = 0; + + *out = NULL; + + git_oid_cpy(&heads[0], git_commit_id(our_commit)); + git_oid_cpy(&heads[1], git_commit_id(their_commit)); + if ((error = git_commit_tree(&our_tree, our_commit)) < 0 || (error = git_commit_tree(&their_tree, their_commit)) < 0 || - (error = git_merge_trees(out, repo, ancestor_tree, our_tree, their_tree, opts)) < 0) + (error = merge_trees_with_heads(out, repo, our_tree, their_tree, + heads, 2, opts)) < 0) goto done; done: git_tree_free(our_tree); git_tree_free(their_tree); - git_tree_free(ancestor_tree); return error; } -- cgit v1.2.1 From b1eef912cffb9e3ce9792b6aee816c1a45c85fb0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 27 Oct 2015 18:00:30 -0500 Subject: merge: add recursive test with conflicting contents --- tests/merge/trees/recursive.c | 23 +++++++++++++++++++++ .../21/950d5e4e4d1a871b4dfcf72ecb6b9c162c434e | Bin 0 -> 670 bytes .../38/55170cef875708da06ab9ad7fc6a73b531cda1 | Bin 0 -> 664 bytes .../5b/8e1e56cb99e8b99ac22eec8aebf6422ecd08c0 | Bin 0 -> 208 bytes .../78/3d6539dde96b8873c5b5da3e79cc14cd64830b | 4 ++++ .../ca/7d316d6d9af99d2481e980d68b77e572d80fe7 | Bin 0 -> 207 bytes .../ef/1783444b61a8671beea4ce1f4d0202677dfbfb | 3 +++ .../merge-recursive/.gitted/refs/heads/branchF-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchF-2 | 1 + 9 files changed, 32 insertions(+) create mode 100644 tests/resources/merge-recursive/.gitted/objects/21/950d5e4e4d1a871b4dfcf72ecb6b9c162c434e create mode 100644 tests/resources/merge-recursive/.gitted/objects/38/55170cef875708da06ab9ad7fc6a73b531cda1 create mode 100644 tests/resources/merge-recursive/.gitted/objects/5b/8e1e56cb99e8b99ac22eec8aebf6422ecd08c0 create mode 100644 tests/resources/merge-recursive/.gitted/objects/78/3d6539dde96b8873c5b5da3e79cc14cd64830b create mode 100644 tests/resources/merge-recursive/.gitted/objects/ca/7d316d6d9af99d2481e980d68b77e572d80fe7 create mode 100644 tests/resources/merge-recursive/.gitted/objects/ef/1783444b61a8671beea4ce1f4d0202677dfbfb create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchF-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchF-2 diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index 46effa5c2..abca01727 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -246,3 +246,26 @@ void test_merge_trees_recursive__three_base_commits_norecursive(void) git_index_free(index); } +void test_merge_trees_recursive__conflict(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "fa567f568ed72157c0c617438d077695b99d9aac", 1, "veal.txt" }, + { 0100644, "21950d5e4e4d1a871b4dfcf72ecb6b9c162c434e", 2, "veal.txt" }, + { 0100644, "3855170cef875708da06ab9ad7fc6a73b531cda1", 3, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchF-1", "branchF-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + diff --git a/tests/resources/merge-recursive/.gitted/objects/21/950d5e4e4d1a871b4dfcf72ecb6b9c162c434e b/tests/resources/merge-recursive/.gitted/objects/21/950d5e4e4d1a871b4dfcf72ecb6b9c162c434e new file mode 100644 index 000000000..a87732611 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/21/950d5e4e4d1a871b4dfcf72ecb6b9c162c434e differ diff --git a/tests/resources/merge-recursive/.gitted/objects/38/55170cef875708da06ab9ad7fc6a73b531cda1 b/tests/resources/merge-recursive/.gitted/objects/38/55170cef875708da06ab9ad7fc6a73b531cda1 new file mode 100644 index 000000000..7da945e6f Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/38/55170cef875708da06ab9ad7fc6a73b531cda1 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/5b/8e1e56cb99e8b99ac22eec8aebf6422ecd08c0 b/tests/resources/merge-recursive/.gitted/objects/5b/8e1e56cb99e8b99ac22eec8aebf6422ecd08c0 new file mode 100644 index 000000000..c3e6d31ca Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/5b/8e1e56cb99e8b99ac22eec8aebf6422ecd08c0 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/78/3d6539dde96b8873c5b5da3e79cc14cd64830b b/tests/resources/merge-recursive/.gitted/objects/78/3d6539dde96b8873c5b5da3e79cc14cd64830b new file mode 100644 index 000000000..e2f34d6bb --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/78/3d6539dde96b8873c5b5da3e79cc14cd64830b @@ -0,0 +1,4 @@ +xk +0S*y4/DO6ٍ-Fj[ofrvrf(G"IAq \H޳,٢r1%Xt R +Z6g'zBp3xuos\=18#tJ)Vmg8ֹ +L8wZU \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/ca/7d316d6d9af99d2481e980d68b77e572d80fe7 b/tests/resources/merge-recursive/.gitted/objects/ca/7d316d6d9af99d2481e980d68b77e572d80fe7 new file mode 100644 index 000000000..0733fa232 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/ca/7d316d6d9af99d2481e980d68b77e572d80fe7 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/ef/1783444b61a8671beea4ce1f4d0202677dfbfb b/tests/resources/merge-recursive/.gitted/objects/ef/1783444b61a8671beea4ce1f4d0202677dfbfb new file mode 100644 index 000000000..67e6e8a5e --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/ef/1783444b61a8671beea4ce1f4d0202677dfbfb @@ -0,0 +1,3 @@ +xO[ +0; TI " l-Fj3Pr+(+7ue~0bxL4A;TpJDŽcZqd#FmD kdGg +5e*Qqs?৶=1Vmc+Y#eI9yv5 70U \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchF-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchF-1 new file mode 100644 index 000000000..5f2ca915b --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchF-1 @@ -0,0 +1 @@ +783d6539dde96b8873c5b5da3e79cc14cd64830b diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchF-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchF-2 new file mode 100644 index 000000000..abe2ea947 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchF-2 @@ -0,0 +1 @@ +ef1783444b61a8671beea4ce1f4d0202677dfbfb -- cgit v1.2.1 From 3f2bb387a43185991d7e077fa5e6c0bb467f2abc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 28 Oct 2015 11:00:55 -0400 Subject: merge: octopus merge common ancestors when >2 When there are more than two common ancestors, continue merging the virtual base with the additional common ancestors, effectively octopus merging a new virtual base. --- src/annotated_commit.c | 21 ++++ src/annotated_commit.h | 3 + src/merge.c | 284 ++++++++++++++++++++++++++++--------------------- 3 files changed, 189 insertions(+), 119 deletions(-) diff --git a/src/annotated_commit.c b/src/annotated_commit.c index 3f2d2ed17..036e601c1 100644 --- a/src/annotated_commit.c +++ b/src/annotated_commit.c @@ -7,6 +7,7 @@ #include "common.h" #include "annotated_commit.h" +#include "refs.h" #include "git2/commit.h" #include "git2/refs.h" @@ -75,6 +76,26 @@ int git_annotated_commit_from_ref( return error; } +int git_annotated_commit_from_head( + git_annotated_commit **out, + git_repository *repo) +{ + git_reference *head; + int error; + + assert(out && repo); + + *out = NULL; + + if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) + return -1; + + error = git_annotated_commit_from_ref(out, repo, head); + + git_reference_free(head); + return error; +} + int git_annotated_commit_lookup( git_annotated_commit **out, git_repository *repo, diff --git a/src/annotated_commit.h b/src/annotated_commit.h index e873184ae..37e3d9951 100644 --- a/src/annotated_commit.h +++ b/src/annotated_commit.h @@ -19,4 +19,7 @@ struct git_annotated_commit { char id_str[GIT_OID_HEXSZ+1]; }; +extern int git_annotated_commit_from_head(git_annotated_commit **out, + git_repository *repo); + #endif diff --git a/src/merge.c b/src/merge.c index 0a837b5f4..ce6f4a6ff 100644 --- a/src/merge.c +++ b/src/merge.c @@ -28,6 +28,7 @@ #include "oidarray.h" #include "annotated_commit.h" #include "commit.h" +#include "oidarray.h" #include "git2/types.h" #include "git2/repository.h" @@ -1925,6 +1926,7 @@ done: static int merge_trees_with_heads( git_index **out, + git_commit **base_commit_out, git_repository *repo, const git_tree *ours, const git_tree *theirs, @@ -1938,24 +1940,62 @@ static int merge_trees_with_heads( git_oid_cpy(_alloced, _id); \ } while(0) -static int compute_base( +static int create_virtual_base( git_tree **out, git_repository *repo, + git_tree *base_tree, + git_array_oid_t base_ids, + git_oid *next_commit_id, + const git_merge_options *opts) +{ + git_commit *next_commit = NULL, *intermediate_base = NULL; + git_tree *next_tree = NULL; + git_index *index = NULL; + git_oid new_tree_id; + int error; + + if ((error = git_commit_lookup(&next_commit, repo, next_commit_id)) < 0 || + (error = git_commit_tree(&next_tree, next_commit)) < 0) + goto done; + + INSERT_ID(base_ids, git_commit_id(next_commit)); + + if ((error = merge_trees_with_heads(&index, &intermediate_base, repo, + base_tree, next_tree, base_ids.ptr, base_ids.size, opts)) < 0) + goto done; + + /* TODO: conflicts!! */ + + if ((error = git_index_write_tree_to(&new_tree_id, index, repo)) < 0) + goto done; + + error = git_tree_lookup(out, repo, &new_tree_id); + +done: + git_index_free(index); + git_tree_free(next_tree); + git_commit_free(intermediate_base); + git_commit_free(next_commit); + + return error; +} + +static int compute_base( + git_tree **tree_out, + git_commit **commit_out, + git_repository *repo, const git_oid heads[], size_t heads_len, const git_merge_options *opts) { - git_commit_list *base_list = NULL; + git_commit_list *base_list = NULL, *base_iter; git_revwalk *walk = NULL; - git_commit *base_commit = NULL, *next_commit = NULL; + git_commit *base_commit = NULL; git_tree *base_tree = NULL, *next_tree = NULL; - git_array_t(git_oid) base_ids = GIT_ARRAY_INIT; - git_index *index = NULL; + git_array_oid_t base_ids = GIT_ARRAY_INIT; bool recursive = !opts || (opts->flags & GIT_MERGE_NO_RECURSIVE) == 0; int error = 0; - *out = NULL; - if ((error = merge_bases_many(&base_list, &walk, repo, heads_len, heads)) < 0) return error; @@ -1966,58 +2006,40 @@ static int compute_base( goto done; } + base_iter = base_list; + if ((error = git_commit_lookup(&base_commit, repo, - &base_list->item->oid)) < 0 || + &base_iter->item->oid)) < 0 || (error = git_commit_tree(&base_tree, base_commit)) < 0) goto done; INSERT_ID(base_ids, git_commit_id(base_commit)); - while (recursive && base_list->next) { - git_tree *new_tree; - git_oid new_tree_id; - - base_list = base_list->next; - - if ((error = git_commit_lookup(&next_commit, repo, - &base_list->item->oid)) < 0 || - (error = git_commit_tree(&next_tree, next_commit)) < 0) - goto done; - - INSERT_ID(base_ids, git_commit_id(next_commit)); - - if ((error = merge_trees_with_heads(&index, repo, base_tree, - next_tree, base_ids.ptr, base_ids.size, opts)) < 0) - goto done; - - /* TODO: conflicts!! */ + while (recursive && base_iter->next) { + base_iter = base_iter->next; - if ((error = git_index_write_tree_to(&new_tree_id, index, repo)) < 0 || - (error = git_tree_lookup(&new_tree, repo, &new_tree_id)) < 0) + if ((error = create_virtual_base(&next_tree, repo, base_tree, + base_ids, &base_iter->item->oid, opts)) < 0) goto done; - git_index_free(index); - index = NULL; - - git_tree_free(next_tree); + git_tree_free(base_tree); + base_tree = next_tree; next_tree = NULL; - git_commit_free(next_commit); - next_commit = NULL; - - git_tree_free(base_tree); - base_tree = new_tree; + git_commit_free(base_commit); + base_commit = NULL; } - *out = base_tree; - base_tree = NULL; + *tree_out = base_tree; + *commit_out = base_commit; done: - git_index_free(index); + if (error < 0) { + git_tree_free(base_tree); + git_commit_free(base_commit); + } + git_tree_free(next_tree); - git_tree_free(base_tree); - git_commit_free(next_commit); - git_commit_free(base_commit); git_commit_list_free(&base_list); git_revwalk_free(walk); git_array_clear(base_ids); @@ -2025,35 +2047,52 @@ done: return error; } +#undef INSERT_ID + static int merge_trees_with_heads( git_index **out, + git_commit **base_out, git_repository *repo, - const git_tree *ours, - const git_tree *theirs, + const git_tree *our_tree, + const git_tree *their_tree, const git_oid heads[], size_t heads_len, const git_merge_options *opts) { - git_tree *ancestor = NULL; + git_commit *ancestor_commit = NULL; + git_tree *ancestor_tree = NULL; int error = 0; - if ((error = compute_base(&ancestor, repo, heads, heads_len, opts)) < 0) { + *out = NULL; + *base_out = NULL; + + if ((error = compute_base(&ancestor_tree, &ancestor_commit, repo, + heads, heads_len, opts)) < 0) { + if (error == GIT_ENOTFOUND) giterr_clear(); else goto done; } - error = git_merge_trees(out, repo, ancestor, ours, theirs, opts); + if ((error = git_merge_trees(out, + repo, ancestor_tree, our_tree, their_tree, opts)) < 0) + goto done; + + *base_out = ancestor_commit; done: - git_tree_free(ancestor); + if (error < 0) + git_commit_free(ancestor_commit); + + git_tree_free(ancestor_tree); return error; } -int git_merge_commits( +static int merge_commits( git_index **out, + git_commit **base_out, git_repository *repo, const git_commit *our_commit, const git_commit *their_commit, @@ -2070,8 +2109,8 @@ int git_merge_commits( if ((error = git_commit_tree(&our_tree, our_commit)) < 0 || (error = git_commit_tree(&their_tree, their_commit)) < 0 || - (error = merge_trees_with_heads(out, repo, our_tree, their_tree, - heads, 2, opts)) < 0) + (error = merge_trees_with_heads(out, base_out, repo, + our_tree, their_tree, heads, 2, opts)) < 0) goto done; done: @@ -2081,6 +2120,23 @@ done: return error; } +int git_merge_commits( + git_index **out, + git_repository *repo, + const git_commit *our_commit, + const git_commit *their_commit, + const git_merge_options *opts) +{ + git_commit *base_commit = NULL; + int error; + + error = merge_commits(out, &base_commit, repo, + our_commit, their_commit, opts); + + git_commit_free(base_commit); + return error; +} + /* Merge setup / cleanup */ static int write_merge_head( @@ -2511,49 +2567,51 @@ const char *merge_their_label(const char *branchname) } static int merge_normalize_checkout_opts( + git_checkout_options *out, git_repository *repo, - git_checkout_options *checkout_opts, const git_checkout_options *given_checkout_opts, - const git_annotated_commit *ancestor_head, + unsigned int checkout_strategy, + git_commit *ancestor_commit, const git_annotated_commit *our_head, - size_t their_heads_len, - const git_annotated_commit **their_heads) + const git_annotated_commit **their_heads, + size_t their_heads_len) { + git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; int error = 0; GIT_UNUSED(repo); if (given_checkout_opts != NULL) - memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options)); - else { - git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + memcpy(out, given_checkout_opts, sizeof(git_checkout_options)); + else + memcpy(out, &default_checkout_opts, sizeof(git_checkout_options)); - memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options)); - } + out->checkout_strategy = checkout_strategy; - /* TODO: for multiple ancestors in merge-recursive, this is "merged common ancestors" */ - if (!checkout_opts->ancestor_label) { - if (ancestor_head && ancestor_head->commit) - checkout_opts->ancestor_label = git_commit_summary(ancestor_head->commit); + /* TODO: disambiguate between merged common ancestors and no common + * ancestor (although git.git does not!) + */ + if (!out->ancestor_label) { + if (ancestor_commit) + out->ancestor_label = git_commit_summary(ancestor_commit); else - checkout_opts->ancestor_label = "ancestor"; + out->ancestor_label = "merged common ancestors"; } - if (!checkout_opts->our_label) { + if (!out->our_label) { if (our_head && our_head->ref_name) - checkout_opts->our_label = our_head->ref_name; + out->our_label = our_head->ref_name; else - checkout_opts->our_label = "ours"; + out->our_label = "ours"; } - if (!checkout_opts->their_label) { + if (!out->their_label) { if (their_heads_len == 1 && their_heads[0]->ref_name) - checkout_opts->their_label = merge_their_label(their_heads[0]->ref_name); + out->their_label = merge_their_label(their_heads[0]->ref_name); else if (their_heads_len == 1) - checkout_opts->their_label = their_heads[0]->id_str; + out->their_label = their_heads[0]->id_str; else - checkout_opts->their_label = "theirs"; + out->their_label = "theirs"; } return error; @@ -2906,11 +2964,11 @@ int git_merge( { git_reference *our_ref = NULL; git_checkout_options checkout_opts; - git_annotated_commit *ancestor_head = NULL, *our_head = NULL; - git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL; + git_annotated_commit *our_head = NULL; + git_commit *base_commit = NULL; git_index *index = NULL; git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; - size_t i; + unsigned int checkout_strategy; int error = 0; assert(repo && their_heads); @@ -2920,61 +2978,49 @@ int git_merge( return -1; } - their_trees = git__calloc(their_heads_len, sizeof(git_tree *)); - GITERR_CHECK_ALLOC(their_trees); - - if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0 || - (error = merge_normalize_checkout_opts(repo, &checkout_opts, given_checkout_opts, - ancestor_head, our_head, their_heads_len, their_heads)) < 0 || - (error = git_indexwriter_init_for_operation(&indexwriter, repo, &checkout_opts.checkout_strategy)) < 0) - goto on_error; + if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0) + goto done; - /* Write the merge files to the repository. */ - if ((error = git_merge__setup(repo, our_head, their_heads, their_heads_len)) < 0) - goto on_error; + checkout_strategy = given_checkout_opts ? + given_checkout_opts->checkout_strategy : + GIT_CHECKOUT_SAFE; - if (ancestor_head != NULL && - (error = git_commit_tree(&ancestor_tree, ancestor_head->commit)) < 0) - goto on_error; - - if ((error = git_commit_tree(&our_tree, our_head->commit)) < 0) - goto on_error; + if ((error = git_indexwriter_init_for_operation(&indexwriter, repo, + &checkout_strategy)) < 0) + goto done; - for (i = 0; i < their_heads_len; i++) { - if ((error = git_commit_tree(&their_trees[i], their_heads[i]->commit)) < 0) - goto on_error; - } + /* Write the merge setup files to the repository. */ + if ((error = git_annotated_commit_from_head(&our_head, repo)) < 0 || + (error = git_merge__setup(repo, our_head, their_heads, + their_heads_len)) < 0) + goto done; - /* TODO: recursive, octopus, etc... */ + /* TODO: octopus */ - if ((error = git_merge_trees(&index, repo, ancestor_tree, our_tree, their_trees[0], merge_opts)) < 0 || + if ((error = merge_commits(&index, &base_commit, repo, + our_head->commit, their_heads[0]->commit, merge_opts)) < 0 || (error = git_merge__check_result(repo, index)) < 0 || - (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0 || - (error = git_checkout_index(repo, index, &checkout_opts)) < 0 || - (error = git_indexwriter_commit(&indexwriter)) < 0) - goto on_error; + (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0) + goto done; - goto done; + /* check out the merge results */ -on_error: - merge_state_cleanup(repo); + if ((error = merge_normalize_checkout_opts(&checkout_opts, repo, + given_checkout_opts, checkout_strategy, + base_commit, our_head, their_heads, their_heads_len)) < 0 || + (error = git_checkout_index(repo, index, &checkout_opts)) < 0) + goto done; + + error = git_indexwriter_commit(&indexwriter); done: - git_indexwriter_cleanup(&indexwriter); + if (error < 0) + merge_state_cleanup(repo); + git_indexwriter_cleanup(&indexwriter); git_index_free(index); - - git_tree_free(ancestor_tree); - git_tree_free(our_tree); - - for (i = 0; i < their_heads_len; i++) - git_tree_free(their_trees[i]); - - git__free(their_trees); - git_annotated_commit_free(our_head); - git_annotated_commit_free(ancestor_head); - + git_commit_free(base_commit); git_reference_free(our_ref); return error; -- cgit v1.2.1 From 7730fe8e9cda1e160bff1e78dfa2a898799d4365 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Nov 2015 13:01:48 -0500 Subject: merge: merge annotated commits instead of regular commits --- src/annotated_commit.c | 42 ++++++-- src/annotated_commit.h | 2 + src/merge.c | 281 ++++++++++++++++++++++--------------------------- 3 files changed, 159 insertions(+), 166 deletions(-) diff --git a/src/annotated_commit.c b/src/annotated_commit.c index 036e601c1..3998a1af1 100644 --- a/src/annotated_commit.c +++ b/src/annotated_commit.c @@ -8,6 +8,7 @@ #include "common.h" #include "annotated_commit.h" #include "refs.h" +#include "cache.h" #include "git2/commit.h" #include "git2/refs.h" @@ -23,14 +24,17 @@ static int annotated_commit_init( const char *remote_url) { git_annotated_commit *annotated_commit; + git_commit *commit = NULL; int error = 0; assert(out && id); *out = NULL; - annotated_commit = git__calloc(1, sizeof(git_annotated_commit)); - GITERR_CHECK_ALLOC(annotated_commit); + if ((error = git_commit_lookup(&commit, repo, id)) < 0 || + (error = git_annotated_commit_from_commit(&annotated_commit, + commit)) < 0) + goto done; if (ref_name) { annotated_commit->ref_name = git__strdup(ref_name); @@ -42,15 +46,10 @@ static int annotated_commit_init( GITERR_CHECK_ALLOC(annotated_commit->remote_url); } - git_oid_fmt(annotated_commit->id_str, id); - annotated_commit->id_str[GIT_OID_HEXSZ] = '\0'; - - if ((error = git_commit_lookup(&annotated_commit->commit, repo, id)) < 0) { - git_annotated_commit_free(annotated_commit); - return error; - } - *out = annotated_commit; + +done: + git_commit_free(commit); return error; } @@ -96,6 +95,29 @@ int git_annotated_commit_from_head( return error; } +int git_annotated_commit_from_commit( + git_annotated_commit **out, + git_commit *commit) +{ + git_annotated_commit *annotated_commit; + + assert(out && commit); + + *out = NULL; + + annotated_commit = git__calloc(1, sizeof(git_annotated_commit)); + GITERR_CHECK_ALLOC(annotated_commit); + + git_cached_obj_incref(commit); + annotated_commit->commit = commit; + + git_oid_fmt(annotated_commit->id_str, git_commit_id(commit)); + annotated_commit->id_str[GIT_OID_HEXSZ] = '\0'; + + *out = annotated_commit; + return 0; +} + int git_annotated_commit_lookup( git_annotated_commit **out, git_repository *repo, diff --git a/src/annotated_commit.h b/src/annotated_commit.h index 37e3d9951..9a041176e 100644 --- a/src/annotated_commit.h +++ b/src/annotated_commit.h @@ -21,5 +21,7 @@ struct git_annotated_commit { extern int git_annotated_commit_from_head(git_annotated_commit **out, git_repository *repo); +extern int git_annotated_commit_from_commit(git_annotated_commit **out, + git_commit *commit); #endif diff --git a/src/merge.c b/src/merge.c index ce6f4a6ff..59ac8e1ed 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1924,202 +1924,166 @@ done: return error; } -static int merge_trees_with_heads( - git_index **out, - git_commit **base_commit_out, +static int merge_annotated_commits( + git_index **index_out, + git_annotated_commit **base_out, git_repository *repo, - const git_tree *ours, - const git_tree *theirs, - const git_oid heads[], - size_t heads_len, + const git_annotated_commit *our_commit, + const git_annotated_commit *their_commit, + size_t recursion_level, const git_merge_options *opts); -#define INSERT_ID(_ar, _id) do { \ - git_oid *_alloced = git_array_alloc(_ar); \ - GITERR_CHECK_ALLOC(_alloced); \ - git_oid_cpy(_alloced, _id); \ - } while(0) - static int create_virtual_base( - git_tree **out, + git_annotated_commit **out, git_repository *repo, - git_tree *base_tree, - git_array_oid_t base_ids, - git_oid *next_commit_id, - const git_merge_options *opts) + const git_annotated_commit *one, + const git_annotated_commit *two, + size_t recursion_level) { - git_commit *next_commit = NULL, *intermediate_base = NULL; - git_tree *next_tree = NULL; git_index *index = NULL; - git_oid new_tree_id; + git_tree *tree = NULL; + git_commit *commit = NULL; + git_oid id, tree_id; + const git_commit *parents[2]; + git_signature *signature = NULL; int error; - if ((error = git_commit_lookup(&next_commit, repo, next_commit_id)) < 0 || - (error = git_commit_tree(&next_tree, next_commit)) < 0) - goto done; - - INSERT_ID(base_ids, git_commit_id(next_commit)); - - if ((error = merge_trees_with_heads(&index, &intermediate_base, repo, - base_tree, next_tree, base_ids.ptr, base_ids.size, opts)) < 0) - goto done; - - /* TODO: conflicts!! */ - - if ((error = git_index_write_tree_to(&new_tree_id, index, repo)) < 0) + parents[0] = one->commit; + parents[1] = two->commit; + + if ((error = merge_annotated_commits(&index, NULL, repo, one, two, + recursion_level + 1, NULL)) < 0 || + (error = git_index_write_tree_to(&tree_id, index, repo)) < 0 || + (error = git_tree_lookup(&tree, repo, &tree_id)) < 0 || + (error = git_signature_now(&signature, "Virtual", "virtual")) < 0 || + (error = git_commit_create(&id, repo, NULL, signature, signature, + NULL, "virtual merged tree", tree, 2, parents)) < 0 || + (error = git_commit_lookup(&commit, repo, &id)) < 0) goto done; - error = git_tree_lookup(out, repo, &new_tree_id); + error = git_annotated_commit_from_commit(out, commit); done: + git_commit_free(commit); + git_tree_free(tree); git_index_free(index); - git_tree_free(next_tree); - git_commit_free(intermediate_base); - git_commit_free(next_commit); + git_signature_free(signature); return error; } -static int compute_base( - git_tree **tree_out, - git_commit **commit_out, - git_repository *repo, - const git_oid heads[], - size_t heads_len, - const git_merge_options *opts) +GIT_INLINE(int) insert_head_ids( + git_array_oid_t *ids, + const git_annotated_commit *annotated_commit) { - git_commit_list *base_list = NULL, *base_iter; - git_revwalk *walk = NULL; - git_commit *base_commit = NULL; - git_tree *base_tree = NULL, *next_tree = NULL; - git_array_oid_t base_ids = GIT_ARRAY_INIT; - bool recursive = !opts || (opts->flags & GIT_MERGE_NO_RECURSIVE) == 0; - int error = 0; + git_oid *id = git_array_alloc(*ids); + GITERR_CHECK_ALLOC(id); - if ((error = merge_bases_many(&base_list, &walk, repo, - heads_len, heads)) < 0) - return error; + git_oid_cpy(id, git_commit_id(annotated_commit->commit)); + return 0; +} - if (error == GIT_ENOTFOUND) { - giterr_clear(); - error = 0; - goto done; - } +static int compute_base( + git_annotated_commit **out, + git_repository *repo, + const git_annotated_commit *one, + const git_annotated_commit *two, + bool recurse, + size_t recursion_level) +{ + git_array_oid_t head_ids = GIT_ARRAY_INIT; + git_oidarray bases = {0}; + git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL; + size_t i; + int error; - base_iter = base_list; + *out = NULL; - if ((error = git_commit_lookup(&base_commit, repo, - &base_iter->item->oid)) < 0 || - (error = git_commit_tree(&base_tree, base_commit)) < 0) + if ((error = insert_head_ids(&head_ids, one)) < 0 || + (error = insert_head_ids(&head_ids, two)) < 0) goto done; - INSERT_ID(base_ids, git_commit_id(base_commit)); + if ((error = git_merge_bases_many(&bases, repo, + head_ids.size, head_ids.ptr)) < 0 || + (error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 || + !recurse) + goto done; - while (recursive && base_iter->next) { - base_iter = base_iter->next; + for (i = 1; i < bases.count; i++) { + recursion_level++; - if ((error = create_virtual_base(&next_tree, repo, base_tree, - base_ids, &base_iter->item->oid, opts)) < 0) + if ((error = git_annotated_commit_lookup(&other, repo, + &bases.ids[i])) < 0 || + (error = create_virtual_base(&new_base, repo, base, other, + recursion_level)) < 0) goto done; - git_tree_free(base_tree); - base_tree = next_tree; - next_tree = NULL; + git_annotated_commit_free(base); + git_annotated_commit_free(other); - git_commit_free(base_commit); - base_commit = NULL; + base = new_base; + new_base = NULL; + other = NULL; } - *tree_out = base_tree; - *commit_out = base_commit; - done: - if (error < 0) { - git_tree_free(base_tree); - git_commit_free(base_commit); - } - - git_tree_free(next_tree); - git_commit_list_free(&base_list); - git_revwalk_free(walk); - git_array_clear(base_ids); + if (error == 0) + *out = base; + else + git_annotated_commit_free(base); + git_annotated_commit_free(other); + git_annotated_commit_free(new_base); + git_oidarray_free(&bases); + git_array_clear(head_ids); return error; } -#undef INSERT_ID - -static int merge_trees_with_heads( - git_index **out, - git_commit **base_out, +static int merge_annotated_commits( + git_index **index_out, + git_annotated_commit **base_out, git_repository *repo, - const git_tree *our_tree, - const git_tree *their_tree, - const git_oid heads[], - size_t heads_len, + const git_annotated_commit *our_commit, + const git_annotated_commit *their_commit, + size_t recursion_level, const git_merge_options *opts) { - git_commit *ancestor_commit = NULL; - git_tree *ancestor_tree = NULL; - int error = 0; + git_annotated_commit *base = NULL; + git_tree *base_tree = NULL, *our_tree = NULL, *their_tree = NULL; + bool recurse = !opts || !(opts->flags & GIT_MERGE_NO_RECURSIVE); + int error; - *out = NULL; - *base_out = NULL; + if ((error = compute_base(&base, repo, our_commit, their_commit, + recurse, recursion_level)) < 0) { - if ((error = compute_base(&ancestor_tree, &ancestor_commit, repo, - heads, heads_len, opts)) < 0) { + if (error != GIT_ENOTFOUND) + goto done; - if (error == GIT_ENOTFOUND) - giterr_clear(); - else - goto done; + giterr_clear(); + } else if ((error = git_commit_tree(&base_tree, base->commit)) < 0) { + goto done; } - if ((error = git_merge_trees(out, - repo, ancestor_tree, our_tree, their_tree, opts)) < 0) + if ((error = git_commit_tree(&our_tree, our_commit->commit)) < 0 || + (error = git_commit_tree(&their_tree, their_commit->commit)) < 0 || + (error = git_merge_trees(index_out, repo, base_tree, our_tree, + their_tree, opts)) < 0) goto done; - *base_out = ancestor_commit; - -done: - if (error < 0) - git_commit_free(ancestor_commit); - - git_tree_free(ancestor_tree); - - return error; -} - -static int merge_commits( - git_index **out, - git_commit **base_out, - git_repository *repo, - const git_commit *our_commit, - const git_commit *their_commit, - const git_merge_options *opts) -{ - git_tree *our_tree = NULL, *their_tree = NULL; - git_oid heads[2]; - int error = 0; - - *out = NULL; - - git_oid_cpy(&heads[0], git_commit_id(our_commit)); - git_oid_cpy(&heads[1], git_commit_id(their_commit)); - - if ((error = git_commit_tree(&our_tree, our_commit)) < 0 || - (error = git_commit_tree(&their_tree, their_commit)) < 0 || - (error = merge_trees_with_heads(out, base_out, repo, - our_tree, their_tree, heads, 2, opts)) < 0) - goto done; + if (base_out) { + *base_out = base; + base = NULL; + } done: + git_annotated_commit_free(base); git_tree_free(our_tree); git_tree_free(their_tree); - + git_tree_free(base_tree); return error; } + int git_merge_commits( git_index **out, git_repository *repo, @@ -2127,13 +2091,19 @@ int git_merge_commits( const git_commit *their_commit, const git_merge_options *opts) { - git_commit *base_commit = NULL; - int error; + git_annotated_commit *ours = NULL, *theirs = NULL, *base = NULL; + int error = 0; + + if ((error = git_annotated_commit_from_commit(&ours, (git_commit *)our_commit)) < 0 || + (error = git_annotated_commit_from_commit(&theirs, (git_commit *)their_commit)) < 0) + goto done; - error = merge_commits(out, &base_commit, repo, - our_commit, their_commit, opts); + error = merge_annotated_commits(out, &base, repo, ours, theirs, 0, opts); - git_commit_free(base_commit); +done: + git_annotated_commit_free(ours); + git_annotated_commit_free(theirs); + git_annotated_commit_free(base); return error; } @@ -2571,7 +2541,7 @@ static int merge_normalize_checkout_opts( git_repository *repo, const git_checkout_options *given_checkout_opts, unsigned int checkout_strategy, - git_commit *ancestor_commit, + git_annotated_commit *ancestor, const git_annotated_commit *our_head, const git_annotated_commit **their_heads, size_t their_heads_len) @@ -2592,8 +2562,8 @@ static int merge_normalize_checkout_opts( * ancestor (although git.git does not!) */ if (!out->ancestor_label) { - if (ancestor_commit) - out->ancestor_label = git_commit_summary(ancestor_commit); + if (ancestor) + out->ancestor_label = git_commit_summary(ancestor->commit); else out->ancestor_label = "merged common ancestors"; } @@ -2964,8 +2934,7 @@ int git_merge( { git_reference *our_ref = NULL; git_checkout_options checkout_opts; - git_annotated_commit *our_head = NULL; - git_commit *base_commit = NULL; + git_annotated_commit *our_head = NULL, *base = NULL; git_index *index = NULL; git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; unsigned int checkout_strategy; @@ -2997,8 +2966,8 @@ int git_merge( /* TODO: octopus */ - if ((error = merge_commits(&index, &base_commit, repo, - our_head->commit, their_heads[0]->commit, merge_opts)) < 0 || + if ((error = merge_annotated_commits(&index, &base, repo, our_head, + their_heads[0], 0, merge_opts)) < 0 || (error = git_merge__check_result(repo, index)) < 0 || (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0) goto done; @@ -3007,7 +2976,7 @@ int git_merge( if ((error = merge_normalize_checkout_opts(&checkout_opts, repo, given_checkout_opts, checkout_strategy, - base_commit, our_head, their_heads, their_heads_len)) < 0 || + base, our_head, their_heads, their_heads_len)) < 0 || (error = git_checkout_index(repo, index, &checkout_opts)) < 0) goto done; @@ -3020,7 +2989,7 @@ done: git_indexwriter_cleanup(&indexwriter); git_index_free(index); git_annotated_commit_free(our_head); - git_commit_free(base_commit); + git_annotated_commit_free(base); git_reference_free(our_ref); return error; -- cgit v1.2.1 From 76ade3a0b87e279935eba54be2485105396edb7f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 10 Nov 2015 21:21:26 -0800 Subject: merge: use annotated commits for recursion Use annotated commits to act as our virtual bases, instead of regular commits, to avoid polluting the odb with virtual base commits and trees. Instead, build an annotated commit with an index and pointers to the commits that it was merged from. --- src/annotated_commit.c | 26 ++++++--- src/annotated_commit.h | 22 +++++++- src/merge.c | 142 +++++++++++++++++++++++++++++-------------------- 3 files changed, 122 insertions(+), 68 deletions(-) diff --git a/src/annotated_commit.c b/src/annotated_commit.c index 3998a1af1..e53b95dee 100644 --- a/src/annotated_commit.c +++ b/src/annotated_commit.c @@ -15,6 +15,8 @@ #include "git2/repository.h" #include "git2/annotated_commit.h" #include "git2/revparse.h" +#include "git2/tree.h" +#include "git2/index.h" static int annotated_commit_init( git_annotated_commit **out, @@ -108,6 +110,8 @@ int git_annotated_commit_from_commit( annotated_commit = git__calloc(1, sizeof(git_annotated_commit)); GITERR_CHECK_ALLOC(annotated_commit); + annotated_commit->type = GIT_ANNOTATED_COMMIT_REAL; + git_cached_obj_incref(commit); annotated_commit->commit = commit; @@ -179,14 +183,20 @@ void git_annotated_commit_free(git_annotated_commit *annotated_commit) if (annotated_commit == NULL) return; - if (annotated_commit->commit != NULL) - git_commit_free(annotated_commit->commit); - - if (annotated_commit->ref_name != NULL) - git__free(annotated_commit->ref_name); - - if (annotated_commit->remote_url != NULL) - git__free(annotated_commit->remote_url); + switch (annotated_commit->type) { + case GIT_ANNOTATED_COMMIT_REAL: + git_commit_free(annotated_commit->commit); + git_tree_free(annotated_commit->tree); + git__free(annotated_commit->ref_name); + git__free(annotated_commit->remote_url); + break; + case GIT_ANNOTATED_COMMIT_VIRTUAL: + git_index_free(annotated_commit->index); + git_array_clear(annotated_commit->parents); + break; + default: + abort(); + } git__free(annotated_commit); } diff --git a/src/annotated_commit.h b/src/annotated_commit.h index 9a041176e..cbb88fd22 100644 --- a/src/annotated_commit.h +++ b/src/annotated_commit.h @@ -7,11 +7,31 @@ #ifndef INCLUDE_annotated_commit_h__ #define INCLUDE_annotated_commit_h__ +#include "oidarray.h" + #include "git2/oid.h" -/** Internal structure for merge inputs */ +typedef enum { + GIT_ANNOTATED_COMMIT_REAL = 1, + GIT_ANNOTATED_COMMIT_VIRTUAL = 2, +} git_annotated_commit_t; + +/** + * Internal structure for merge inputs. An annotated commit is generally + * "real" and backed by an actual commit in the repository, but merge will + * internally create "virtual" commits that are in-memory intermediate + * commits backed by an index. + */ struct git_annotated_commit { + git_annotated_commit_t type; + + /* real commit */ git_commit *commit; + git_tree *tree; + + /* virtual commit structure */ + git_index *index; + git_array_oid_t parents; char *ref_name; char *remote_url; diff --git a/src/merge.c b/src/merge.c index 59ac8e1ed..64c8f1116 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1928,58 +1928,59 @@ static int merge_annotated_commits( git_index **index_out, git_annotated_commit **base_out, git_repository *repo, - const git_annotated_commit *our_commit, - const git_annotated_commit *their_commit, + git_annotated_commit *our_commit, + git_annotated_commit *their_commit, size_t recursion_level, const git_merge_options *opts); +GIT_INLINE(int) insert_head_ids( + git_array_oid_t *ids, + const git_annotated_commit *annotated_commit) +{ + git_oid *id; + size_t i; + + if (annotated_commit->type == GIT_ANNOTATED_COMMIT_REAL) { + id = git_array_alloc(*ids); + GITERR_CHECK_ALLOC(id); + + git_oid_cpy(id, git_commit_id(annotated_commit->commit)); + } else { + for (i = 0; i < annotated_commit->parents.size; i++) { + id = git_array_alloc(*ids); + GITERR_CHECK_ALLOC(id); + + git_oid_cpy(id, &annotated_commit->parents.ptr[i]); + } + } + + return 0; +} + static int create_virtual_base( git_annotated_commit **out, git_repository *repo, - const git_annotated_commit *one, - const git_annotated_commit *two, + git_annotated_commit *one, + git_annotated_commit *two, size_t recursion_level) { + git_annotated_commit *result = NULL; git_index *index = NULL; - git_tree *tree = NULL; - git_commit *commit = NULL; - git_oid id, tree_id; - const git_commit *parents[2]; - git_signature *signature = NULL; - int error; - - parents[0] = one->commit; - parents[1] = two->commit; - - if ((error = merge_annotated_commits(&index, NULL, repo, one, two, - recursion_level + 1, NULL)) < 0 || - (error = git_index_write_tree_to(&tree_id, index, repo)) < 0 || - (error = git_tree_lookup(&tree, repo, &tree_id)) < 0 || - (error = git_signature_now(&signature, "Virtual", "virtual")) < 0 || - (error = git_commit_create(&id, repo, NULL, signature, signature, - NULL, "virtual merged tree", tree, 2, parents)) < 0 || - (error = git_commit_lookup(&commit, repo, &id)) < 0) - goto done; - error = git_annotated_commit_from_commit(out, commit); + result = git__calloc(1, sizeof(git_annotated_commit)); + GITERR_CHECK_ALLOC(result); -done: - git_commit_free(commit); - git_tree_free(tree); - git_index_free(index); - git_signature_free(signature); + if ((merge_annotated_commits(&index, NULL, repo, one, two, + recursion_level + 1, NULL)) < 0) + return -1; - return error; -} + result->type = GIT_ANNOTATED_COMMIT_VIRTUAL; + result->index = index; -GIT_INLINE(int) insert_head_ids( - git_array_oid_t *ids, - const git_annotated_commit *annotated_commit) -{ - git_oid *id = git_array_alloc(*ids); - GITERR_CHECK_ALLOC(id); + insert_head_ids(&result->parents, one); + insert_head_ids(&result->parents, two); - git_oid_cpy(id, git_commit_id(annotated_commit->commit)); + *out = result; return 0; } @@ -2039,35 +2040,59 @@ done: return error; } +static int iterator_for_annotated_commit( + git_iterator **out, + git_annotated_commit *commit) +{ + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + int error; + + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + + if (commit == NULL) { + error = git_iterator_for_nothing(out, &opts); + } else if (commit->type == GIT_ANNOTATED_COMMIT_VIRTUAL) { + error = git_iterator_for_index(out, commit->index, &opts); + } else { + if (!commit->tree && + (error = git_commit_tree(&commit->tree, commit->commit)) < 0) + goto done; + + error = git_iterator_for_tree(out, commit->tree, &opts); + } + +done: + return error; +} + static int merge_annotated_commits( git_index **index_out, git_annotated_commit **base_out, git_repository *repo, - const git_annotated_commit *our_commit, - const git_annotated_commit *their_commit, + git_annotated_commit *ours, + git_annotated_commit *theirs, size_t recursion_level, const git_merge_options *opts) { git_annotated_commit *base = NULL; - git_tree *base_tree = NULL, *our_tree = NULL, *their_tree = NULL; + git_iterator *base_iter = NULL, *our_iter = NULL, *their_iter = NULL; bool recurse = !opts || !(opts->flags & GIT_MERGE_NO_RECURSIVE); int error; - if ((error = compute_base(&base, repo, our_commit, their_commit, - recurse, recursion_level)) < 0) { + if ((error = compute_base(&base, repo, ours, theirs, recurse, + recursion_level)) < 0) { if (error != GIT_ENOTFOUND) goto done; giterr_clear(); - } else if ((error = git_commit_tree(&base_tree, base->commit)) < 0) { - goto done; - } + } - if ((error = git_commit_tree(&our_tree, our_commit->commit)) < 0 || - (error = git_commit_tree(&their_tree, their_commit->commit)) < 0 || - (error = git_merge_trees(index_out, repo, base_tree, our_tree, - their_tree, opts)) < 0) + if ((error = iterator_for_annotated_commit(&base_iter, base)) < 0 || + (error = iterator_for_annotated_commit(&our_iter, ours)) < 0 || + (error = iterator_for_annotated_commit(&their_iter, theirs)) < 0 || + (error = git_merge__iterators(index_out, repo, base_iter, our_iter, + their_iter, opts)) < 0) goto done; if (base_out) { @@ -2077,9 +2102,9 @@ static int merge_annotated_commits( done: git_annotated_commit_free(base); - git_tree_free(our_tree); - git_tree_free(their_tree); - git_tree_free(base_tree); + git_iterator_free(base_iter); + git_iterator_free(our_iter); + git_iterator_free(their_iter); return error; } @@ -2558,14 +2583,13 @@ static int merge_normalize_checkout_opts( out->checkout_strategy = checkout_strategy; - /* TODO: disambiguate between merged common ancestors and no common - * ancestor (although git.git does not!) - */ if (!out->ancestor_label) { - if (ancestor) + if (ancestor && ancestor->type == GIT_ANNOTATED_COMMIT_REAL) out->ancestor_label = git_commit_summary(ancestor->commit); - else + else if (ancestor) out->ancestor_label = "merged common ancestors"; + else + out->ancestor_label = "empty base"; } if (!out->our_label) { @@ -2967,7 +2991,7 @@ int git_merge( /* TODO: octopus */ if ((error = merge_annotated_commits(&index, &base, repo, our_head, - their_heads[0], 0, merge_opts)) < 0 || + (git_annotated_commit *)their_heads[0], 0, merge_opts)) < 0 || (error = git_merge__check_result(repo, index)) < 0 || (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0) goto done; -- cgit v1.2.1 From dcde5720424961f526e8c070b7d99191d7ef75c1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Nov 2015 08:23:27 -0500 Subject: merge tests: move expected data into own file --- tests/merge/conflict_data.h | 42 ++++++++++++++++++++++++++++++++++++++++++ tests/merge/files.c | 1 + tests/merge/merge_helpers.h | 43 ------------------------------------------- tests/merge/trees/automerge.c | 3 ++- tests/merge/trees/commits.c | 1 + tests/merge/workdir/simple.c | 1 + 6 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 tests/merge/conflict_data.h diff --git a/tests/merge/conflict_data.h b/tests/merge/conflict_data.h new file mode 100644 index 000000000..173892d95 --- /dev/null +++ b/tests/merge/conflict_data.h @@ -0,0 +1,42 @@ +#define AUTOMERGEABLE_MERGED_FILE \ + "this file is changed in master\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is changed in branch\n" + +#define AUTOMERGEABLE_MERGED_FILE_CRLF \ + "this file is changed in master\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is changed in branch\r\n" + +#define CONFLICTING_MERGE_FILE \ + "<<<<<<< HEAD\n" \ + "this file is changed in master and branch\n" \ + "=======\n" \ + "this file is changed in branch and master\n" \ + ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n" + +#define CONFLICTING_DIFF3_FILE \ + "<<<<<<< HEAD\n" \ + "this file is changed in master and branch\n" \ + "||||||| initial\n" \ + "this file is a conflict\n" \ + "=======\n" \ + "this file is changed in branch and master\n" \ + ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n" + +#define CONFLICTING_UNION_FILE \ + "this file is changed in master and branch\n" \ + "this file is changed in branch and master\n" + diff --git a/tests/merge/files.c b/tests/merge/files.c index 2d55df2b2..daa73fada 100644 --- a/tests/merge/files.c +++ b/tests/merge/files.c @@ -4,6 +4,7 @@ #include "buffer.h" #include "merge.h" #include "merge_helpers.h" +#include "conflict_data.h" #include "refs.h" #include "fileops.h" #include "diff_xdiff.h" diff --git a/tests/merge/merge_helpers.h b/tests/merge/merge_helpers.h index 554c24b7c..e407c7d13 100644 --- a/tests/merge/merge_helpers.h +++ b/tests/merge/merge_helpers.h @@ -4,49 +4,6 @@ #include "merge.h" #include "git2/merge.h" -#define AUTOMERGEABLE_MERGED_FILE \ - "this file is changed in master\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is automergeable\n" \ - "this file is changed in branch\n" - -#define AUTOMERGEABLE_MERGED_FILE_CRLF \ - "this file is changed in master\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is automergeable\r\n" \ - "this file is changed in branch\r\n" - -#define CONFLICTING_MERGE_FILE \ - "<<<<<<< HEAD\n" \ - "this file is changed in master and branch\n" \ - "=======\n" \ - "this file is changed in branch and master\n" \ - ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n" - -#define CONFLICTING_DIFF3_FILE \ - "<<<<<<< HEAD\n" \ - "this file is changed in master and branch\n" \ - "||||||| initial\n" \ - "this file is a conflict\n" \ - "=======\n" \ - "this file is changed in branch and master\n" \ - ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n" - -#define CONFLICTING_UNION_FILE \ - "this file is changed in master and branch\n" \ - "this file is changed in branch and master\n" - - struct merge_index_entry { uint16_t mode; char oid_str[GIT_OID_HEXSZ+1]; diff --git a/tests/merge/trees/automerge.c b/tests/merge/trees/automerge.c index c18881d7c..67f2cf786 100644 --- a/tests/merge/trees/automerge.c +++ b/tests/merge/trees/automerge.c @@ -3,8 +3,9 @@ #include "git2/merge.h" #include "buffer.h" #include "merge.h" -#include "../merge_helpers.h" #include "fileops.h" +#include "../merge_helpers.h" +#include "../conflict_data.h" static git_repository *repo; diff --git a/tests/merge/trees/commits.c b/tests/merge/trees/commits.c index dd1e383ac..786a77a8b 100644 --- a/tests/merge/trees/commits.c +++ b/tests/merge/trees/commits.c @@ -3,6 +3,7 @@ #include "git2/merge.h" #include "merge.h" #include "../merge_helpers.h" +#include "../conflict_data.h" static git_repository *repo; diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c index abc0777f7..3cdd15b5a 100644 --- a/tests/merge/workdir/simple.c +++ b/tests/merge/workdir/simple.c @@ -4,6 +4,7 @@ #include "buffer.h" #include "merge.h" #include "../merge_helpers.h" +#include "../conflict_data.h" #include "refs.h" #include "fileops.h" -- cgit v1.2.1 From 651bfd699c8eaa8ca36de0d0d992a1832d71df8f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Nov 2015 08:24:47 -0500 Subject: recursive: test conflict output during recursive merge --- tests/merge/conflict_data.h | 30 ++++++++++++++++++++++++ tests/merge/workdir/recursive.c | 51 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/merge/workdir/recursive.c diff --git a/tests/merge/conflict_data.h b/tests/merge/conflict_data.h index 173892d95..b6c51332f 100644 --- a/tests/merge/conflict_data.h +++ b/tests/merge/conflict_data.h @@ -40,3 +40,33 @@ "this file is changed in master and branch\n" \ "this file is changed in branch and master\n" +#define CONFLICTING_RECURSIVE_F1_TO_F2 \ + "VEAL SOUP.\n" \ + "\n" \ + "<<<<<<< HEAD\n" \ + "PUT INTO A POT THREE QUARTS OF WATER, three onions cut small, ONE\n" \ + "=======\n" \ + "PUT INTO A POT THREE QUARTS OF WATER, three onions cut not too small, one\n" \ + ">>>>>>> branchF-2\n" \ + "spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "slices of lean ham; let it boil steadily two hours; skim it\n" \ + "occasionally, then put into it a shin of veal, let it boil two hours\n" \ + "longer; take out the slices of ham, and skim off the grease if any\n" \ + "should rise, take a gill of good cream, mix with it two table-spoonsful\n" \ + "of flour very nicely, and the yelks of two eggs beaten well, strain this\n" \ + "mixture, and add some chopped parsley; pour some soup on by degrees,\n" \ + "stir it well, and pour it into the pot, continuing to stir until it has\n" \ + "boiled two or three minutes to take off the raw taste of the eggs. If\n" \ + "the cream be not perfectly sweet, and the eggs quite new, the thickening\n" \ + "will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + "in, first taking off their skins, by letting them stand a few minutes in\n" \ + "hot water, when they may be easily peeled. When made in this way you\n" \ + "must thicken it with the flour only. Any part of the veal may be used,\n" \ + "but the shin or knuckle is the nicest.\n" \ + "\n" \ + "<<<<<<< HEAD\n" \ + "This certainly is a mighty fine recipe.\n" \ + "=======\n" \ + "This is a mighty fine recipe!\n" \ + ">>>>>>> branchF-2\n" + diff --git a/tests/merge/workdir/recursive.c b/tests/merge/workdir/recursive.c new file mode 100644 index 000000000..a7326009a --- /dev/null +++ b/tests/merge/workdir/recursive.c @@ -0,0 +1,51 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "../conflict_data.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_merge_workdir_recursive__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_workdir_recursive__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_workdir_recursive__writes_conflict_with_virtual_base(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + git_buf conflicting_buf = GIT_BUF_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "fa567f568ed72157c0c617438d077695b99d9aac", 1, "veal.txt" }, + { 0100644, "21950d5e4e4d1a871b4dfcf72ecb6b9c162c434e", 2, "veal.txt" }, + { 0100644, "3855170cef875708da06ab9ad7fc6a73b531cda1", 3, "veal.txt" }, + }; + + + cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchF-1", GIT_REFS_HEADS_DIR "branchF-2", &opts, NULL)); + + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + cl_git_pass(git_futils_readbuffer(&conflicting_buf, "merge-recursive/veal.txt")); + + cl_assert_equal_s(CONFLICTING_RECURSIVE_F1_TO_F2, conflicting_buf.ptr); + + git_index_free(index); + git_buf_free(&conflicting_buf); +} -- cgit v1.2.1 From 34a51428a121800509c2bea94137a17802e37982 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Nov 2015 11:55:26 -0500 Subject: merge tests: add complex recursive example --- tests/merge/trees/recursive.c | 28 +++++++++++++++++++++ tests/resources/merge-recursive/.gitted/HEAD | 2 +- tests/resources/merge-recursive/.gitted/index | Bin 632 -> 619 bytes .../34/8f16ffaeb73f319a75cec5b16a0a47d2d5e27c | Bin 0 -> 208 bytes .../48/3065df53c0f4a02cdc6b2910b05d388fc17ffb | Bin 0 -> 165 bytes .../c4/83ca4bb087174af5cb51d7caa9c09fe4a28ccb | 1 + .../d7/1c24b3b113fd1d1909998c5bfe33b86a65ee03 | Bin 0 -> 240 bytes .../merge-recursive/.gitted/refs/heads/branchG-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchG-2 | 1 + tests/resources/merge-recursive/asparagus.txt | 2 +- tests/resources/merge-recursive/oyster.txt | 2 +- tests/resources/merge-recursive/veal.txt | 8 +++--- 12 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 tests/resources/merge-recursive/.gitted/objects/34/8f16ffaeb73f319a75cec5b16a0a47d2d5e27c create mode 100644 tests/resources/merge-recursive/.gitted/objects/48/3065df53c0f4a02cdc6b2910b05d388fc17ffb create mode 100644 tests/resources/merge-recursive/.gitted/objects/c4/83ca4bb087174af5cb51d7caa9c09fe4a28ccb create mode 100644 tests/resources/merge-recursive/.gitted/objects/d7/1c24b3b113fd1d1909998c5bfe33b86a65ee03 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchG-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchG-2 diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index abca01727..1e5f61391 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -269,3 +269,31 @@ void test_merge_trees_recursive__conflict(void) git_index_free(index); } +/* + * Branch G-1 and G-2 have three common ancestors (815b5a1, ad2ace9, 483065d). + * The merge-base of the first two has two common ancestors (723181f, a34e5a1) + * which themselves have two common ancestors (8f35f30, 3a3f5a6), which + * finally has a common ancestor of 7c7bf85. This virtual merge base will + * be computed and merged with 483065d which also has a common ancestor of + * 7c7bf85. + */ +void test_merge_trees_recursive__oh_so_many_levels_of_recursion(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "7c7e08f9559d9e1551b91e1cf68f1d0066109add", 0, "oyster.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchG-1", "branchG-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} diff --git a/tests/resources/merge-recursive/.gitted/HEAD b/tests/resources/merge-recursive/.gitted/HEAD index 77e35742d..d7cef11aa 100644 --- a/tests/resources/merge-recursive/.gitted/HEAD +++ b/tests/resources/merge-recursive/.gitted/HEAD @@ -1 +1 @@ -ref: refs/heads/branchB-1 +ref: refs/heads/branchG-2 diff --git a/tests/resources/merge-recursive/.gitted/index b/tests/resources/merge-recursive/.gitted/index index 1e47851a5..571cfd02f 100644 Binary files a/tests/resources/merge-recursive/.gitted/index and b/tests/resources/merge-recursive/.gitted/index differ diff --git a/tests/resources/merge-recursive/.gitted/objects/34/8f16ffaeb73f319a75cec5b16a0a47d2d5e27c b/tests/resources/merge-recursive/.gitted/objects/34/8f16ffaeb73f319a75cec5b16a0a47d2d5e27c new file mode 100644 index 000000000..bd1b1f69a Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/34/8f16ffaeb73f319a75cec5b16a0a47d2d5e27c differ diff --git a/tests/resources/merge-recursive/.gitted/objects/48/3065df53c0f4a02cdc6b2910b05d388fc17ffb b/tests/resources/merge-recursive/.gitted/objects/48/3065df53c0f4a02cdc6b2910b05d388fc17ffb new file mode 100644 index 000000000..298251b3c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/48/3065df53c0f4a02cdc6b2910b05d388fc17ffb differ diff --git a/tests/resources/merge-recursive/.gitted/objects/c4/83ca4bb087174af5cb51d7caa9c09fe4a28ccb b/tests/resources/merge-recursive/.gitted/objects/c4/83ca4bb087174af5cb51d7caa9c09fe4a28ccb new file mode 100644 index 000000000..643a98280 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/c4/83ca4bb087174af5cb51d7caa9c09fe4a28ccb @@ -0,0 +1 @@ +xPKN@ cS̮d#!+v\ d[E}E\`۱lɼ-0.cW5熱5Қ\sX(V#$V;g1H y±ڂP!HmzXb-X \^)\+15WP!g`JHw~Uy㘷<'b^m9oӮ~y\-o˽AdC2}C3g3 GCq;zl<{ \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/d7/1c24b3b113fd1d1909998c5bfe33b86a65ee03 b/tests/resources/merge-recursive/.gitted/objects/d7/1c24b3b113fd1d1909998c5bfe33b86a65ee03 new file mode 100644 index 000000000..66720086c Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/d7/1c24b3b113fd1d1909998c5bfe33b86a65ee03 differ diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchG-1 b/tests/resources/merge-recursive/.gitted/refs/heads/branchG-1 new file mode 100644 index 000000000..af511439b --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchG-1 @@ -0,0 +1 @@ +c483ca4bb087174af5cb51d7caa9c09fe4a28ccb diff --git a/tests/resources/merge-recursive/.gitted/refs/heads/branchG-2 b/tests/resources/merge-recursive/.gitted/refs/heads/branchG-2 new file mode 100644 index 000000000..24177a247 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/refs/heads/branchG-2 @@ -0,0 +1 @@ +d71c24b3b113fd1d1909998c5bfe33b86a65ee03 diff --git a/tests/resources/merge-recursive/asparagus.txt b/tests/resources/merge-recursive/asparagus.txt index f51658077..ffb36e513 100644 --- a/tests/resources/merge-recursive/asparagus.txt +++ b/tests/resources/merge-recursive/asparagus.txt @@ -1,4 +1,4 @@ -ASPARAGUS SOUP! +ASPARAGUS SOUP. Take four large bunches of asparagus, scrape it nicely, cut off one inch of the tops, and lay them in water, chop the stalks and put them on the diff --git a/tests/resources/merge-recursive/oyster.txt b/tests/resources/merge-recursive/oyster.txt index 68af1fc74..7c7e08f95 100644 --- a/tests/resources/merge-recursive/oyster.txt +++ b/tests/resources/merge-recursive/oyster.txt @@ -1,4 +1,4 @@ -OYSTER SOUP. +OYSTER SOUP! Wash and drain two quarts of oysters, put them on with three quarts of water, three onions chopped up, two or three slices of lean ham, pepper diff --git a/tests/resources/merge-recursive/veal.txt b/tests/resources/merge-recursive/veal.txt index 94d2c0108..898d12687 100644 --- a/tests/resources/merge-recursive/veal.txt +++ b/tests/resources/merge-recursive/veal.txt @@ -1,10 +1,10 @@ -VEAL SOUP! +VEAL SOUP. -Put into a pot three quarts of water, three onions cut small, one +PUT INTO A POT THREE QUARTS OF WATER, 3 onions cut small, ONE spoonful of black pepper pounded, and two of salt, with two or three slices of lean ham; let it boil steadily two hours; skim it occasionally, then put into it a shin of veal, let it boil two hours -longer. take out the slices of ham, and skim off the grease if any +longer; take out the slices of ham, and skim off the grease if any should rise, take a gill of good cream, mix with it two table-spoonsful of flour very nicely, and the yelks of two eggs beaten well, strain this mixture, and add some chopped parsley; pour some soup on by degrees, @@ -16,3 +16,5 @@ in, first taking off their skins, by letting them stand a few minutes in hot water, when they may be easily peeled. When made in this way you must thicken it with the flour only. Any part of the veal may be used, but the shin or knuckle is the nicest. + +This is a mighty fine recipe! -- cgit v1.2.1 From 78859c63442bb367a4d426ec8ee31c82a28a93d7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 20 Nov 2015 17:33:49 -0500 Subject: merge: handle conflicts in recursive base building When building a recursive merge base, allow conflicts to occur. Use the file (with conflict markers) as the common ancestor. The user has already seen and dealt with this conflict by virtue of having a criss-cross merge. If they resolved this conflict identically in both branches, then there will be no conflict in the result. This is the best case scenario. If they did not resolve the conflict identically in the two branches, then we will generate a new conflict. If the user is simply using standard conflict output then the results will be fairly sensible. But if the user is using a mergetool or using diff3 output, then the common ancestor will be a conflict file (itself with diff3 output, haha!). This is quite terrible, but it matches git's behavior. --- src/merge.c | 67 ++++++++++++----- tests/merge/conflict_data.h | 31 ++++++++ tests/merge/trees/recursive.c | 80 +++++++++++++++++++++ tests/merge/workdir/recursive.c | 35 ++++++++- .../15/311229e70fa62653f73dde1d4deef1a8e47a11 | Bin 0 -> 710 bytes .../37/185b25a204309bf74817da1a607518f13ca3ed | Bin 0 -> 715 bytes .../37/a5054a9f9b4628e3924c5cb8f2147c6e2a3efc | Bin 0 -> 630 bytes .../42/44d13e2bbc38510320443bbb003f3967d12436 | Bin 0 -> 207 bytes .../4f/4e85a0ab8515e34302721fbcec06fa9d9c1a9a | Bin 0 -> 631 bytes .../56/07a8c4601a737daadd1f470bde3142aff57026 | 1 + .../63/e8773becdea9c3699c95a5740be5baa8be8d69 | Bin 0 -> 207 bytes .../6c/778edd0e4cf394f5a3df8b96db516024cc1bb8 | Bin 0 -> 636 bytes .../6e/f31d35a3f5abc1e24f4f9afa5cb2016f03fa2d | 1 + .../7a/9277e0c5ec75339f011c176d0c20e513c4de1c | 1 + .../88/8588a782ad433fbf0cc526e07cfe6f4a6b60b3 | Bin 0 -> 208 bytes .../98/1c79eb38518d3821e73bb159dc413bb42d6614 | Bin 0 -> 208 bytes .../a0/2d4fd126e0cc8fb46ee48cf38bad36d44f2dbc | Bin 0 -> 649 bytes .../aa/9e263294fd2f6f6fd9ceab23ca8ce3ea2ce707 | Bin 0 -> 175 bytes .../b9/1ef5ffa8612616c8e76051901caafd723f0e2c | Bin 0 -> 712 bytes .../ca/fa936d25f0b397432a27201f6b3284c47df8be | Bin 0 -> 712 bytes .../d6/04c75019c282144bdbbf3fd3462ba74b240efc | Bin 0 -> 620 bytes .../db/203155a789fb749aa3c14e93eea2c744a9c6c7 | 1 + .../e1/512550f09d980214e46e6d3f5a2b20c3d75755 | Bin 0 -> 208 bytes .../f7/929c5a67a4bdc98247fb4b5098675723932a64 | Bin 0 -> 207 bytes .../merge-recursive/.gitted/refs/heads/branchH-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchH-2 | 1 + .../merge-recursive/.gitted/refs/heads/branchI-1 | 1 + .../merge-recursive/.gitted/refs/heads/branchI-2 | 1 + 28 files changed, 201 insertions(+), 20 deletions(-) create mode 100644 tests/resources/merge-recursive/.gitted/objects/15/311229e70fa62653f73dde1d4deef1a8e47a11 create mode 100644 tests/resources/merge-recursive/.gitted/objects/37/185b25a204309bf74817da1a607518f13ca3ed create mode 100644 tests/resources/merge-recursive/.gitted/objects/37/a5054a9f9b4628e3924c5cb8f2147c6e2a3efc create mode 100644 tests/resources/merge-recursive/.gitted/objects/42/44d13e2bbc38510320443bbb003f3967d12436 create mode 100644 tests/resources/merge-recursive/.gitted/objects/4f/4e85a0ab8515e34302721fbcec06fa9d9c1a9a create mode 100644 tests/resources/merge-recursive/.gitted/objects/56/07a8c4601a737daadd1f470bde3142aff57026 create mode 100644 tests/resources/merge-recursive/.gitted/objects/63/e8773becdea9c3699c95a5740be5baa8be8d69 create mode 100644 tests/resources/merge-recursive/.gitted/objects/6c/778edd0e4cf394f5a3df8b96db516024cc1bb8 create mode 100644 tests/resources/merge-recursive/.gitted/objects/6e/f31d35a3f5abc1e24f4f9afa5cb2016f03fa2d create mode 100644 tests/resources/merge-recursive/.gitted/objects/7a/9277e0c5ec75339f011c176d0c20e513c4de1c create mode 100644 tests/resources/merge-recursive/.gitted/objects/88/8588a782ad433fbf0cc526e07cfe6f4a6b60b3 create mode 100644 tests/resources/merge-recursive/.gitted/objects/98/1c79eb38518d3821e73bb159dc413bb42d6614 create mode 100644 tests/resources/merge-recursive/.gitted/objects/a0/2d4fd126e0cc8fb46ee48cf38bad36d44f2dbc create mode 100644 tests/resources/merge-recursive/.gitted/objects/aa/9e263294fd2f6f6fd9ceab23ca8ce3ea2ce707 create mode 100644 tests/resources/merge-recursive/.gitted/objects/b9/1ef5ffa8612616c8e76051901caafd723f0e2c create mode 100644 tests/resources/merge-recursive/.gitted/objects/ca/fa936d25f0b397432a27201f6b3284c47df8be create mode 100644 tests/resources/merge-recursive/.gitted/objects/d6/04c75019c282144bdbbf3fd3462ba74b240efc create mode 100644 tests/resources/merge-recursive/.gitted/objects/db/203155a789fb749aa3c14e93eea2c744a9c6c7 create mode 100644 tests/resources/merge-recursive/.gitted/objects/e1/512550f09d980214e46e6d3f5a2b20c3d75755 create mode 100644 tests/resources/merge-recursive/.gitted/objects/f7/929c5a67a4bdc98247fb4b5098675723932a64 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchH-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchH-2 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchI-1 create mode 100644 tests/resources/merge-recursive/.gitted/refs/heads/branchI-2 diff --git a/src/merge.c b/src/merge.c index 64c8f1116..f05e45c9f 100644 --- a/src/merge.c +++ b/src/merge.c @@ -49,6 +49,19 @@ #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) #define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode) + +/** Internal merge flags. */ +enum { + /** The merge is for a virtual base in a recursive merge. */ + GIT_MERGE__VIRTUAL_BASE = (1 << 31), +}; + +enum { + /** Accept the conflict file, staging it as the merge result. */ + GIT_MERGE_FILE_FAVOR__CONFLICTED = 4, +}; + + typedef enum { TREE_IDX_ANCESTOR = 0, TREE_IDX_OURS = 1, @@ -801,11 +814,9 @@ static int merge_conflict_resolve_automerge( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict, - unsigned int merge_file_favor, - unsigned int file_flags) + const git_merge_file_options *file_opts) { const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL; - git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT; git_merge_file_result result = {0}; git_index_entry *index_entry; git_odb *odb = NULL; @@ -852,12 +863,9 @@ static int merge_conflict_resolve_automerge( theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? &conflict->their_entry : NULL; - opts.favor = merge_file_favor; - opts.flags = file_flags; - if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 || - (error = git_merge_file_from_index(&result, diff_list->repo, ancestor, ours, theirs, &opts)) < 0 || - !result.automergeable || + (error = git_merge_file_from_index(&result, diff_list->repo, ancestor, ours, theirs, file_opts)) < 0 || + (!result.automergeable && !(file_opts->flags & GIT_MERGE_FILE_FAVOR__CONFLICTED)) || (error = git_odb_write(&automerge_oid, odb, result.ptr, result.len, GIT_OBJ_BLOB)) < 0) goto done; @@ -887,8 +895,7 @@ static int merge_conflict_resolve( int *out, git_merge_diff_list *diff_list, const git_merge_diff *conflict, - unsigned int merge_file_favor, - unsigned int file_flags) + const git_merge_file_options *file_opts) { int resolved = 0; int error = 0; @@ -904,8 +911,7 @@ static int merge_conflict_resolve( if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0) goto done; - if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, - merge_file_favor, file_flags)) < 0) + if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, file_opts)) < 0) goto done; *out = resolved; @@ -1829,6 +1835,7 @@ int git_merge__iterators( *empty_theirs = NULL; git_merge_diff_list *diff_list; git_merge_options opts; + git_merge_file_options file_opts = GIT_MERGE_FILE_OPTIONS_INIT; git_merge_diff *conflict; git_vector changes; size_t i; @@ -1844,6 +1851,17 @@ int git_merge__iterators( if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0) return error; + file_opts.favor = opts.file_favor; + file_opts.flags = opts.file_flags; + + /* use the git-inspired labels when virtual base building */ + if (opts.flags & GIT_MERGE__VIRTUAL_BASE) { + file_opts.ancestor_label = "merged common ancestors"; + file_opts.our_label = "Temporary merge branch 1"; + file_opts.their_label = "Temporary merge branch 2"; + file_opts.flags |= GIT_MERGE_FILE_FAVOR__CONFLICTED; + } + diff_list = git_merge_diff_list__alloc(repo); GITERR_CHECK_ALLOC(diff_list); @@ -1862,7 +1880,8 @@ int git_merge__iterators( git_vector_foreach(&changes, i, conflict) { int resolved = 0; - if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor, opts.file_flags)) < 0) + if ((error = merge_conflict_resolve( + &resolved, diff_list, conflict, &file_opts)) < 0) goto done; if (!resolved) { @@ -1962,16 +1981,27 @@ static int create_virtual_base( git_repository *repo, git_annotated_commit *one, git_annotated_commit *two, + const git_merge_options *opts, size_t recursion_level) { git_annotated_commit *result = NULL; git_index *index = NULL; + git_merge_options virtual_opts = GIT_MERGE_OPTIONS_INIT; result = git__calloc(1, sizeof(git_annotated_commit)); GITERR_CHECK_ALLOC(result); + /* Conflicts in the merge base creation do not propagate to conflicts + * in the result; the conflicted base will act as the common ancestor. + */ + if (opts) + memcpy(&virtual_opts, opts, sizeof(git_merge_options)); + + virtual_opts.flags &= ~GIT_MERGE_FAIL_ON_CONFLICT; + virtual_opts.flags |= GIT_MERGE__VIRTUAL_BASE; + if ((merge_annotated_commits(&index, NULL, repo, one, two, - recursion_level + 1, NULL)) < 0) + recursion_level + 1, &virtual_opts)) < 0) return -1; result->type = GIT_ANNOTATED_COMMIT_VIRTUAL; @@ -1989,7 +2019,7 @@ static int compute_base( git_repository *repo, const git_annotated_commit *one, const git_annotated_commit *two, - bool recurse, + const git_merge_options *opts, size_t recursion_level) { git_array_oid_t head_ids = GIT_ARRAY_INIT; @@ -2007,7 +2037,7 @@ static int compute_base( if ((error = git_merge_bases_many(&bases, repo, head_ids.size, head_ids.ptr)) < 0 || (error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 || - !recurse) + (opts && (opts->flags & GIT_MERGE_NO_RECURSIVE))) goto done; for (i = 1; i < bases.count; i++) { @@ -2015,7 +2045,7 @@ static int compute_base( if ((error = git_annotated_commit_lookup(&other, repo, &bases.ids[i])) < 0 || - (error = create_virtual_base(&new_base, repo, base, other, + (error = create_virtual_base(&new_base, repo, base, other, opts, recursion_level)) < 0) goto done; @@ -2076,10 +2106,9 @@ static int merge_annotated_commits( { git_annotated_commit *base = NULL; git_iterator *base_iter = NULL, *our_iter = NULL, *their_iter = NULL; - bool recurse = !opts || !(opts->flags & GIT_MERGE_NO_RECURSIVE); int error; - if ((error = compute_base(&base, repo, ours, theirs, recurse, + if ((error = compute_base(&base, repo, ours, theirs, opts, recursion_level)) < 0) { if (error != GIT_ENOTFOUND) diff --git a/tests/merge/conflict_data.h b/tests/merge/conflict_data.h index b6c51332f..e6394a9e8 100644 --- a/tests/merge/conflict_data.h +++ b/tests/merge/conflict_data.h @@ -70,3 +70,34 @@ "This is a mighty fine recipe!\n" \ ">>>>>>> branchF-2\n" +#define CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3 \ + "VEAL SOUP.\n" \ + "\n" \ + "<<<<<<< HEAD\n" \ + "put into a pot three quarts of water, three onions cut small, one\n" \ + "||||||| merged common ancestors\n" \ + "<<<<<<< Temporary merge branch 1\n" \ + "Put into a pot three quarts of water, THREE ONIONS CUT SMALL, one\n" \ + "||||||| merged common ancestors\n" \ + "Put into a pot three quarts of water, three onions cut small, one\n" \ + "=======\n" \ + "PUT INTO A POT three quarts of water, three onions cut small, one\n" \ + ">>>>>>> Temporary merge branch 2\n" \ + "=======\n" \ + "Put Into A Pot Three Quarts of Water, Three Onions Cut Small, One\n" \ + ">>>>>>> branchH-2\n" \ + "spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "slices of lean ham; let it boil steadily two hours; skim it\n" \ + "occasionally, then put into it a shin of veal, let it boil two hours\n" \ + "longer; take out the slices of ham, and skim off the grease if any\n" \ + "should rise, take a gill of good cream, mix with it two table-spoonsful\n" \ + "of flour very nicely, and the yelks of two eggs beaten well, strain this\n" \ + "mixture, and add some chopped parsley; pour some soup on by degrees,\n" \ + "stir it well, and pour it into the pot, continuing to stir until it has\n" \ + "boiled two or three minutes to take off the raw taste of the eggs. If\n" \ + "the cream be not perfectly sweet, and the eggs quite new, the thickening\n" \ + "will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + "in, first taking off their skins, by letting them stand a few minutes in\n" \ + "hot water, when they may be easily peeled. When made in this way you\n" \ + "must thicken it with the flour only. Any part of the veal may be used,\n" \ + "but the shin or knuckle is the nicest.\n" diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index 1e5f61391..693c91065 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -297,3 +297,83 @@ void test_merge_trees_recursive__oh_so_many_levels_of_recursion(void) git_index_free(index); } + +/* Branch H-1 and H-2 have two common ancestors (aa9e263, 6ef31d3). The two + * ancestors themselves conflict. + */ +void test_merge_trees_recursive__conflicting_merge_base(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "3a66812fed1e03ea4a6a7ee28d8a57aec1ca6537", 1, "veal.txt" }, + { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, + { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-1", "branchH-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + +/* Branch H-1 and H-2 have two common ancestors (aa9e263, 6ef31d3). The two + * ancestors themselves conflict. The generated common ancestor file will + * have diff3 style conflicts inside it. + */ +void test_merge_trees_recursive__conflicting_merge_base_with_diff3(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" }, + { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, + { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, + }; + + opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-1", "branchH-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + +/* Branch I-1 and I-2 have two common ancestors (aa9e263, 6ef31d3). The two + * ancestors themselves conflict, but when each was merged, the conflicts were + * resolved identically, thus merging I-1 into I-2 does not conflict. + */ +void test_merge_trees_recursive__conflicting_merge_base_since_resolved(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a02d4fd126e0cc8fb46ee48cf38bad36d44f2dbc", 0, "veal.txt" }, + }; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchI-1", "branchI-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + + git_index_free(index); +} diff --git a/tests/merge/workdir/recursive.c b/tests/merge/workdir/recursive.c index a7326009a..795126255 100644 --- a/tests/merge/workdir/recursive.c +++ b/tests/merge/workdir/recursive.c @@ -36,7 +36,6 @@ void test_merge_workdir_recursive__writes_conflict_with_virtual_base(void) { 0100644, "3855170cef875708da06ab9ad7fc6a73b531cda1", 3, "veal.txt" }, }; - cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchF-1", GIT_REFS_HEADS_DIR "branchF-2", &opts, NULL)); cl_git_pass(git_repository_index(&index, repo)); @@ -49,3 +48,37 @@ void test_merge_workdir_recursive__writes_conflict_with_virtual_base(void) git_index_free(index); git_buf_free(&conflicting_buf); } + +void test_merge_workdir_recursive__conflicting_merge_base_with_diff3(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_buf conflicting_buf = GIT_BUF_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" }, + { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, + { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, + }; + + opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3; + checkout_opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3; + + cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchH-1", GIT_REFS_HEADS_DIR "branchH-2", &opts, &checkout_opts)); + + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + cl_git_pass(git_futils_readbuffer(&conflicting_buf, "merge-recursive/veal.txt")); + + cl_assert_equal_s(CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3, conflicting_buf.ptr); + + git_index_free(index); + git_buf_free(&conflicting_buf); +} diff --git a/tests/resources/merge-recursive/.gitted/objects/15/311229e70fa62653f73dde1d4deef1a8e47a11 b/tests/resources/merge-recursive/.gitted/objects/15/311229e70fa62653f73dde1d4deef1a8e47a11 new file mode 100644 index 000000000..8c21bb357 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/15/311229e70fa62653f73dde1d4deef1a8e47a11 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/37/185b25a204309bf74817da1a607518f13ca3ed b/tests/resources/merge-recursive/.gitted/objects/37/185b25a204309bf74817da1a607518f13ca3ed new file mode 100644 index 000000000..a8cf005bc Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/37/185b25a204309bf74817da1a607518f13ca3ed differ diff --git a/tests/resources/merge-recursive/.gitted/objects/37/a5054a9f9b4628e3924c5cb8f2147c6e2a3efc b/tests/resources/merge-recursive/.gitted/objects/37/a5054a9f9b4628e3924c5cb8f2147c6e2a3efc new file mode 100644 index 000000000..4591f0e04 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/37/a5054a9f9b4628e3924c5cb8f2147c6e2a3efc differ diff --git a/tests/resources/merge-recursive/.gitted/objects/42/44d13e2bbc38510320443bbb003f3967d12436 b/tests/resources/merge-recursive/.gitted/objects/42/44d13e2bbc38510320443bbb003f3967d12436 new file mode 100644 index 000000000..a19b19120 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/42/44d13e2bbc38510320443bbb003f3967d12436 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/4f/4e85a0ab8515e34302721fbcec06fa9d9c1a9a b/tests/resources/merge-recursive/.gitted/objects/4f/4e85a0ab8515e34302721fbcec06fa9d9c1a9a new file mode 100644 index 000000000..4752ea07a Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/4f/4e85a0ab8515e34302721fbcec06fa9d9c1a9a differ diff --git a/tests/resources/merge-recursive/.gitted/objects/56/07a8c4601a737daadd1f470bde3142aff57026 b/tests/resources/merge-recursive/.gitted/objects/56/07a8c4601a737daadd1f470bde3142aff57026 new file mode 100644 index 000000000..bf3639d05 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/56/07a8c4601a737daadd1f470bde3142aff57026 @@ -0,0 +1 @@ +xMJ1])#?<čp:3w=Ԧ((~`MxCrBYMSP-}tjzL`JRvR jBV8Ze&6zsTr͵̍2.9>~I~Gs1G!j1IcS1xW(܎u#rbV \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/63/e8773becdea9c3699c95a5740be5baa8be8d69 b/tests/resources/merge-recursive/.gitted/objects/63/e8773becdea9c3699c95a5740be5baa8be8d69 new file mode 100644 index 000000000..6d5c320fe Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/63/e8773becdea9c3699c95a5740be5baa8be8d69 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/6c/778edd0e4cf394f5a3df8b96db516024cc1bb8 b/tests/resources/merge-recursive/.gitted/objects/6c/778edd0e4cf394f5a3df8b96db516024cc1bb8 new file mode 100644 index 000000000..ec1db19e6 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/6c/778edd0e4cf394f5a3df8b96db516024cc1bb8 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/6e/f31d35a3f5abc1e24f4f9afa5cb2016f03fa2d b/tests/resources/merge-recursive/.gitted/objects/6e/f31d35a3f5abc1e24f4f9afa5cb2016f03fa2d new file mode 100644 index 000000000..e95a5e2db --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/6e/f31d35a3f5abc1e24f4f9afa5cb2016f03fa2d @@ -0,0 +1 @@ +xAN!]sahcx$2gpWE:z8‡5UA-YG zAl+&LLd>cW.-&͊)BI5o&p<gq/`n,<"!^C#anr]]Bɧ_*PV \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/7a/9277e0c5ec75339f011c176d0c20e513c4de1c b/tests/resources/merge-recursive/.gitted/objects/7a/9277e0c5ec75339f011c176d0c20e513c4de1c new file mode 100644 index 000000000..9fb34f7ee --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/7a/9277e0c5ec75339f011c176d0c20e513c4de1c @@ -0,0 +1 @@ +xOANE!sN>1nLܸ0ނc nڦiSӠwsP!gwaZB,CiB@HT ԰P(g@(*h7+,N*ĕd.5P6{|(mOaOo{8"Pbrױ^uɃO_.`s?o0Xa \ No newline at end of file diff --git a/tests/resources/merge-recursive/.gitted/objects/88/8588a782ad433fbf0cc526e07cfe6f4a6b60b3 b/tests/resources/merge-recursive/.gitted/objects/88/8588a782ad433fbf0cc526e07cfe6f4a6b60b3 new file mode 100644 index 000000000..44efd3315 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/88/8588a782ad433fbf0cc526e07cfe6f4a6b60b3 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/98/1c79eb38518d3821e73bb159dc413bb42d6614 b/tests/resources/merge-recursive/.gitted/objects/98/1c79eb38518d3821e73bb159dc413bb42d6614 new file mode 100644 index 000000000..d5787b44d Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/98/1c79eb38518d3821e73bb159dc413bb42d6614 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/a0/2d4fd126e0cc8fb46ee48cf38bad36d44f2dbc b/tests/resources/merge-recursive/.gitted/objects/a0/2d4fd126e0cc8fb46ee48cf38bad36d44f2dbc new file mode 100644 index 000000000..566976715 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/a0/2d4fd126e0cc8fb46ee48cf38bad36d44f2dbc differ diff --git a/tests/resources/merge-recursive/.gitted/objects/aa/9e263294fd2f6f6fd9ceab23ca8ce3ea2ce707 b/tests/resources/merge-recursive/.gitted/objects/aa/9e263294fd2f6f6fd9ceab23ca8ce3ea2ce707 new file mode 100644 index 000000000..0ec6cd891 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/aa/9e263294fd2f6f6fd9ceab23ca8ce3ea2ce707 differ diff --git a/tests/resources/merge-recursive/.gitted/objects/b9/1ef5ffa8612616c8e76051901caafd723f0e2c b/tests/resources/merge-recursive/.gitted/objects/b9/1ef5ffa8612616c8e76051901caafd723f0e2c new file mode 100644 index 000000000..e19652394 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/b9/1ef5ffa8612616c8e76051901caafd723f0e2c differ diff --git a/tests/resources/merge-recursive/.gitted/objects/ca/fa936d25f0b397432a27201f6b3284c47df8be b/tests/resources/merge-recursive/.gitted/objects/ca/fa936d25f0b397432a27201f6b3284c47df8be new file mode 100644 index 000000000..fb012eea3 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/ca/fa936d25f0b397432a27201f6b3284c47df8be differ diff --git a/tests/resources/merge-recursive/.gitted/objects/d6/04c75019c282144bdbbf3fd3462ba74b240efc b/tests/resources/merge-recursive/.gitted/objects/d6/04c75019c282144bdbbf3fd3462ba74b240efc new file mode 100644 index 000000000..059fcfe72 Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/d6/04c75019c282144bdbbf3fd3462ba74b240efc differ diff --git a/tests/resources/merge-recursive/.gitted/objects/db/203155a789fb749aa3c14e93eea2c744a9c6c7 b/tests/resources/merge-recursive/.gitted/objects/db/203155a789fb749aa3c14e93eea2c744a9c6c7 new file mode 100644 index 000000000..e9f7fd8fd --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/db/203155a789fb749aa3c14e93eea2c744a9c6c7 @@ -0,0 +1 @@ +xMJ1]$_q;/t;D Ԧ((K k2S A,J*b[,'KG dyRP0PuF1 o$jL 81}l}6'q/}9nC#$mQ'=-DŽzN Date: Fri, 20 Nov 2015 19:01:42 -0500 Subject: recursive merge: add a recursion limit --- include/git2/merge.h | 8 ++++++++ src/merge.c | 13 ++++++++++--- tests/merge/trees/recursive.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/include/git2/merge.h b/include/git2/merge.h index a272e8be4..af53ead22 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -265,6 +265,14 @@ typedef struct { /** Pluggable similarity metric; pass NULL to use internal metric */ git_diff_similarity_metric *metric; + /** + * Maximum number of times to merge common ancestors to build a + * virtual merge base when faced with criss-cross merges. When this + * limit is reached, the next ancestor will simply be used instead of + * attempting to merge it. The default is unlimited. + */ + unsigned int recursion_limit; + /** Flags for handling conflicting content. */ git_merge_file_favor_t file_favor; diff --git a/src/merge.c b/src/merge.c index f05e45c9f..9eb3b0904 100644 --- a/src/merge.c +++ b/src/merge.c @@ -2019,17 +2019,21 @@ static int compute_base( git_repository *repo, const git_annotated_commit *one, const git_annotated_commit *two, - const git_merge_options *opts, + const git_merge_options *given_opts, size_t recursion_level) { git_array_oid_t head_ids = GIT_ARRAY_INIT; git_oidarray bases = {0}; git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; size_t i; int error; *out = NULL; + if (given_opts) + memcpy(&opts, given_opts, sizeof(git_merge_options)); + if ((error = insert_head_ids(&head_ids, one)) < 0 || (error = insert_head_ids(&head_ids, two)) < 0) goto done; @@ -2037,15 +2041,18 @@ static int compute_base( if ((error = git_merge_bases_many(&bases, repo, head_ids.size, head_ids.ptr)) < 0 || (error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 || - (opts && (opts->flags & GIT_MERGE_NO_RECURSIVE))) + (opts.flags & GIT_MERGE_NO_RECURSIVE)) goto done; for (i = 1; i < bases.count; i++) { recursion_level++; + if (opts.recursion_limit && recursion_level > opts.recursion_limit) + break; + if ((error = git_annotated_commit_lookup(&other, repo, &bases.ids[i])) < 0 || - (error = create_virtual_base(&new_base, repo, base, other, opts, + (error = create_virtual_base(&new_base, repo, base, other, &opts, recursion_level)) < 0) goto done; diff --git a/tests/merge/trees/recursive.c b/tests/merge/trees/recursive.c index 693c91065..c5b129bf8 100644 --- a/tests/merge/trees/recursive.c +++ b/tests/merge/trees/recursive.c @@ -377,3 +377,34 @@ void test_merge_trees_recursive__conflicting_merge_base_since_resolved(void) git_index_free(index); } + +/* There are multiple levels of criss-cross merges, and multiple recursive + * merges would create a common ancestor that allows the merge to complete + * successfully. Test that we can build a single virtual base, then stop, + * which will produce a conflicting merge. + */ +void test_merge_trees_recursive__recursionlimit(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "ce7e553c6feb6e5f3bd67e3c3be04182fe3094b4", 1, "gravy.txt" }, + { 0100644, "d8dd349b78f19a4ebe3357bacb8138f00bf5ed41", 2, "gravy.txt" }, + { 0100644, "e50fbbd701458757bdfe9815f58ed717c588d1b5", 3, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + + opts.recursion_limit = 1; + + cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + + git_index_free(index); +} + -- cgit v1.2.1