From c1d648c5c6361edfb1aa85a31656b628672c7616 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 8 Jan 2014 18:29:42 -0800 Subject: [PATCH] merge_file should use more aggressive levels The default merge_file level was XDL_MERGE_MINIMAL, which will produce conflicts where there should not be in the case where both sides were changed identically. Change the defaults to be more aggressive (XDL_MERGE_ZEALOUS) which will more aggressively compress non-conflicts. This matches git.git's defaults. Increase testing around reverting a previously reverted commit to illustrate this problem. --- include/git2/merge.h | 21 +- src/checkout.c | 3 +- src/merge.c | 17 +- src/merge_file.c | 11 +- src/merge_file.h | 14 +- tests/merge/trees/automerge.c | 4 +- tests/merge/trees/trivial.c | 2 +- tests/merge/workdir/simple.c | 14 +- tests/merge/workdir/trivial.c | 2 +- tests/resources/revert/.gitted/index | Bin 320 -> 464 bytes .../0a/d19525be6d8cae5e5deb2770fc244b65255057 | Bin 0 -> 133 bytes .../13/a6fdfd10bd74b1f258fb58801215985dd2e797 | Bin 0 -> 121 bytes .../1b/c915c5cb7185a9438de28a7b1a7dfe8c01ee7f | Bin 0 -> 1169 bytes .../1f/f0c423042b46cb1d617b81efb715defbe8054d | Bin 0 -> 751 bytes .../21/a96a98ed84d45866e1de6e266fd3a61a4ae9dc | Bin 0 -> 19 bytes .../39/9fb3aba3d9d13f7d40a9254ce4402067ef3149 | Bin 0 -> 165 bytes .../46/ff0854663aeb2182b9838c8da68e33ac23bc1e | Bin 0 -> 20 bytes .../5c/f1d643f100d8112834e540264546ba2c159976 | Bin 0 -> 86 bytes .../6b/ccd0dc58cea5ccff86014f3d64b31bd8c02a37 | Bin 0 -> 171 bytes .../71/eb9c2b53dbbf3c45fb28b27c850db4b7fb8011 | Bin 0 -> 148 bytes .../87/59ad453cf01cf7daf14e2a668f8218f9a678eb | Bin 0 -> 122 bytes .../9a/95fd974e03c5b93828ceedd28755965b5d5c60 | Bin 0 -> 122 bytes .../a8/c86221b400b836010567cc3593db6e96c1a83a | Bin 0 -> 24 bytes .../ac/c4d33902092efeb3b714aa0b1007c329e2f2e6 | Bin 0 -> 116 bytes .../b6/9d88e177455579896e2be495046e2a51456a9a | Bin 0 -> 197 bytes .../ca/f99de3a49827117bb66721010eac461b06a80c | Bin 0 -> 33 bytes .../de/03538407ed18914ff05657eeff70425c0f304d | Bin 0 -> 212 bytes .../e3/4ef1afe54eb526fd92eec66084125f340f1d65 | Bin 0 -> 150 bytes .../ea/392a157085bc32daccd59aa1998fe2f5fb9fc0 | Bin 0 -> 134 bytes .../ee/c6adcb2f3ceca0cadeccfe01b19382252ece9b | Bin 0 -> 66 bytes .../revert/.gitted/refs/heads/master | Bin 42 -> 41 bytes tests/resources/revert/.gitted/refs/heads/two | Bin 0 -> 41 bytes tests/revert/workdir.c | 199 +++++++++++++++++- 33 files changed, 255 insertions(+), 32 deletions(-) create mode 100644 tests/resources/revert/.gitted/objects/0a/d19525be6d8cae5e5deb2770fc244b65255057 create mode 100644 tests/resources/revert/.gitted/objects/13/a6fdfd10bd74b1f258fb58801215985dd2e797 create mode 100644 tests/resources/revert/.gitted/objects/1b/c915c5cb7185a9438de28a7b1a7dfe8c01ee7f create mode 100644 tests/resources/revert/.gitted/objects/1f/f0c423042b46cb1d617b81efb715defbe8054d create mode 100644 tests/resources/revert/.gitted/objects/21/a96a98ed84d45866e1de6e266fd3a61a4ae9dc create mode 100644 tests/resources/revert/.gitted/objects/39/9fb3aba3d9d13f7d40a9254ce4402067ef3149 create mode 100644 tests/resources/revert/.gitted/objects/46/ff0854663aeb2182b9838c8da68e33ac23bc1e create mode 100644 tests/resources/revert/.gitted/objects/5c/f1d643f100d8112834e540264546ba2c159976 create mode 100644 tests/resources/revert/.gitted/objects/6b/ccd0dc58cea5ccff86014f3d64b31bd8c02a37 create mode 100644 tests/resources/revert/.gitted/objects/71/eb9c2b53dbbf3c45fb28b27c850db4b7fb8011 create mode 100644 tests/resources/revert/.gitted/objects/87/59ad453cf01cf7daf14e2a668f8218f9a678eb create mode 100644 tests/resources/revert/.gitted/objects/9a/95fd974e03c5b93828ceedd28755965b5d5c60 create mode 100644 tests/resources/revert/.gitted/objects/a8/c86221b400b836010567cc3593db6e96c1a83a create mode 100644 tests/resources/revert/.gitted/objects/ac/c4d33902092efeb3b714aa0b1007c329e2f2e6 create mode 100644 tests/resources/revert/.gitted/objects/b6/9d88e177455579896e2be495046e2a51456a9a create mode 100644 tests/resources/revert/.gitted/objects/ca/f99de3a49827117bb66721010eac461b06a80c create mode 100644 tests/resources/revert/.gitted/objects/de/03538407ed18914ff05657eeff70425c0f304d create mode 100644 tests/resources/revert/.gitted/objects/e3/4ef1afe54eb526fd92eec66084125f340f1d65 create mode 100644 tests/resources/revert/.gitted/objects/ea/392a157085bc32daccd59aa1998fe2f5fb9fc0 create mode 100644 tests/resources/revert/.gitted/objects/ee/c6adcb2f3ceca0cadeccfe01b19382252ece9b create mode 100644 tests/resources/revert/.gitted/refs/heads/two diff --git a/include/git2/merge.h b/include/git2/merge.h index 8a1dfec2e..1888babd1 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -32,14 +32,21 @@ typedef enum { } git_merge_tree_flag_t; /** - * Automerge options for `git_merge_trees_opts`. + * Merge file options for `git_merge_trees_opts`. */ typedef enum { - GIT_MERGE_AUTOMERGE_NORMAL = 0, - GIT_MERGE_AUTOMERGE_NONE = 1, - GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2, - GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3, -} git_merge_automerge_flags; + /* Produce a conflict in a file when two similar regions are changed. */ + GIT_MERGE_FILE_FAVOR_NORMAL = 0, + + /* Do not attempt to produce an automerged file during tree merge. */ + GIT_MERGE_FILE_FAVOR_NO_MERGE = 1, + + /* Produce a file containing the "ours" side of conflicting regions. */ + GIT_MERGE_FILE_FAVOR_OURS = 2, + + /* Produce a file containing the "theirs" side of conflicting regions. */ + GIT_MERGE_FILE_FAVOR_THEIRS = 3, +} git_merge_file_favor_t; typedef struct { @@ -58,7 +65,7 @@ typedef struct { git_diff_similarity_metric *metric; /** Flags for automerging content. */ - git_merge_automerge_flags automerge_flags; + git_merge_file_favor_t file_favor; } git_merge_tree_opts; #define GIT_MERGE_TREE_OPTS_VERSION 1 diff --git a/src/checkout.c b/src/checkout.c index e642c975e..cc49800a2 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1626,6 +1626,7 @@ static int checkout_write_merge( { git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT, path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT; + git_merge_file_options merge_file_opts = GIT_MERGE_FILE_OPTIONS_INIT; git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, ours = GIT_MERGE_FILE_INPUT_INIT, theirs = GIT_MERGE_FILE_INPUT_INIT; @@ -1662,7 +1663,7 @@ static int checkout_write_merge( theirs.label = git_buf_cstr(&their_label); } - if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, 0)) < 0) + if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0) goto done; if (result.path == NULL || result.mode == 0) { diff --git a/src/merge.c b/src/merge.c index c0be37dd8..3ac9167e3 100644 --- a/src/merge.c +++ b/src/merge.c @@ -511,8 +511,9 @@ static int merge_conflict_resolve_automerge( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict, - unsigned int automerge_flags) + unsigned int merge_file_favor) { + git_merge_file_options merge_file_opts = GIT_MERGE_FILE_OPTIONS_INIT; git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, ours = GIT_MERGE_FILE_INPUT_INIT, theirs = GIT_MERGE_FILE_INPUT_INIT; @@ -526,9 +527,11 @@ static int merge_conflict_resolve_automerge( *resolved = 0; - if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE) + if (merge_file_favor == GIT_MERGE_FILE_FAVOR_NO_MERGE) return 0; + merge_file_opts.favor = merge_file_favor; + /* Reject D/F conflicts */ if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) return 0; @@ -552,7 +555,7 @@ static int merge_conflict_resolve_automerge( (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 || (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 || (error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 || - (error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 || + (error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0 || !result.automergeable || (error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0) goto done; @@ -586,7 +589,7 @@ static int merge_conflict_resolve( int *out, git_merge_diff_list *diff_list, const git_merge_diff *conflict, - unsigned int automerge_flags) + unsigned int merge_file_favor) { int resolved = 0; int error = 0; @@ -596,14 +599,14 @@ static int merge_conflict_resolve( if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0) goto done; - if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) { + if (merge_file_favor != GIT_MERGE_FILE_FAVOR_NO_MERGE) { if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0) goto done; 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, automerge_flags)) < 0) + if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, merge_file_favor)) < 0) goto done; } @@ -1589,7 +1592,7 @@ int git_merge_trees( git_vector_foreach(&changes, i, conflict) { int resolved = 0; - if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0) + if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor)) < 0) goto done; if (!resolved) diff --git a/src/merge_file.c b/src/merge_file.c index 48fc46e57..d13190276 100644 --- a/src/merge_file.c +++ b/src/merge_file.c @@ -130,7 +130,7 @@ int git_merge_files( git_merge_file_input *ancestor, git_merge_file_input *ours, git_merge_file_input *theirs, - git_merge_automerge_flags flags) + git_merge_file_options *opts) { xmparam_t xmparam; mmbuffer_t mmbuffer; @@ -152,12 +152,15 @@ int git_merge_files( out->path = merge_file_best_path(ancestor, ours, theirs); out->mode = merge_file_best_mode(ancestor, ours, theirs); - if (flags == GIT_MERGE_AUTOMERGE_FAVOR_OURS) + if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_OURS) xmparam.favor = XDL_MERGE_FAVOR_OURS; - - if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS) + else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_THEIRS) xmparam.favor = XDL_MERGE_FAVOR_THEIRS; + xmparam.level = + (opts && (opts->flags & GIT_MERGE_FILE_SIMPLIFY_ALNUM)) ? + XDL_MERGE_ZEALOUS_ALNUM : XDL_MERGE_ZEALOUS; + if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile, &theirs->mmfile, &xmparam, &mmbuffer)) < 0) { giterr_set(GITERR_MERGE, "Failed to merge files."); diff --git a/src/merge_file.h b/src/merge_file.h index 0af2f0a57..5d7ea9752 100644 --- a/src/merge_file.h +++ b/src/merge_file.h @@ -34,6 +34,18 @@ typedef struct { #define GIT_MERGE_FILE_RESULT_INIT {0} +typedef enum { + /* Condense non-alphanumeric regions for simplified diff file */ + GIT_MERGE_FILE_SIMPLIFY_ALNUM = (1 << 0), +} git_merge_file_flags_t; + +typedef struct { + git_merge_file_favor_t favor; + git_merge_file_flags_t flags; +} git_merge_file_options; + +#define GIT_MERGE_FILE_OPTIONS_INIT {0} + int git_merge_file_input_from_index_entry( git_merge_file_input *input, git_repository *repo, @@ -49,7 +61,7 @@ int git_merge_files( git_merge_file_input *ancestor, git_merge_file_input *ours, git_merge_file_input *theirs, - git_merge_automerge_flags flags); + git_merge_file_options *opts); GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input) { diff --git a/tests/merge/trees/automerge.c b/tests/merge/trees/automerge.c index 746ce5068..ebc6e271d 100644 --- a/tests/merge/trees/automerge.c +++ b/tests/merge/trees/automerge.c @@ -149,7 +149,7 @@ void test_merge_trees_automerge__favor_ours(void) REMOVED_IN_MASTER_REUC_ENTRY, }; - opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_OURS; + opts.file_favor = GIT_MERGE_FILE_FAVOR_OURS; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); @@ -180,7 +180,7 @@ void test_merge_trees_automerge__favor_theirs(void) REMOVED_IN_MASTER_REUC_ENTRY, }; - opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_THEIRS; + opts.file_favor = GIT_MERGE_FILE_FAVOR_THEIRS; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); diff --git a/tests/merge/trees/trivial.c b/tests/merge/trees/trivial.c index bfd5dfed3..244cd3223 100644 --- a/tests/merge/trees/trivial.c +++ b/tests/merge/trees/trivial.c @@ -33,7 +33,7 @@ static int merge_trivial(git_index **index, const char *ours, const char *theirs git_buf branch_buf = GIT_BUF_INIT; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; - opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE; + opts.file_favor |= automerge ? 0 : GIT_MERGE_FILE_FAVOR_NO_MERGE; git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours); cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c index 98dca53ef..2142fc4f9 100644 --- a/tests/merge/workdir/simple.c +++ b/tests/merge/workdir/simple.c @@ -113,7 +113,7 @@ void test_merge_workdir_simple__cleanup(void) cl_git_sandbox_cleanup(); } -static git_merge_result *merge_simple_branch(int automerge_flags, int checkout_strategy) +static git_merge_result *merge_simple_branch(int merge_file_favor, int checkout_strategy) { git_oid their_oids[1]; git_merge_head *their_heads[1]; @@ -123,7 +123,7 @@ static git_merge_result *merge_simple_branch(int automerge_flags, int checkout_s cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_SIMPLE_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); - opts.merge_tree_opts.automerge_flags = automerge_flags; + opts.merge_tree_opts.file_favor = merge_file_favor; opts.checkout_opts.checkout_strategy = checkout_strategy; cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); @@ -336,7 +336,7 @@ void test_merge_workdir_simple__favor_ours(void) REMOVED_IN_MASTER_REUC_ENTRY, }; - cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_OURS, 0)); + cl_assert(result = merge_simple_branch(GIT_MERGE_FILE_FAVOR_OURS, 0)); cl_assert(!git_merge_result_is_fastforward(result)); cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); @@ -365,7 +365,7 @@ void test_merge_workdir_simple__favor_theirs(void) REMOVED_IN_MASTER_REUC_ENTRY, }; - cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_THEIRS, 0)); + cl_assert(result = merge_simple_branch(GIT_MERGE_FILE_FAVOR_THEIRS, 0)); cl_assert(!git_merge_result_is_fastforward(result)); cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); @@ -414,7 +414,7 @@ void test_merge_workdir_simple__directory_file(void) cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); - opts.merge_tree_opts.automerge_flags = 0; + opts.merge_tree_opts.file_favor = 0; cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); cl_assert(merge_test_index(repo_index, merge_index_entries, 20)); @@ -447,7 +447,7 @@ void test_merge_workdir_simple__unrelated(void) cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); - opts.merge_tree_opts.automerge_flags = 0; + opts.merge_tree_opts.file_favor = 0; cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); cl_assert(merge_test_index(repo_index, merge_index_entries, 9)); @@ -480,7 +480,7 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void) cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); - opts.merge_tree_opts.automerge_flags = 0; + opts.merge_tree_opts.file_favor = 0; cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); cl_assert(merge_test_index(repo_index, merge_index_entries, 11)); diff --git a/tests/merge/workdir/trivial.c b/tests/merge/workdir/trivial.c index df18b0e0b..ebf09095c 100644 --- a/tests/merge/workdir/trivial.c +++ b/tests/merge/workdir/trivial.c @@ -39,7 +39,7 @@ static int merge_trivial(const char *ours, const char *theirs, bool automerge) checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; - opts.merge_tree_opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE; + opts.merge_tree_opts.file_favor |= automerge ? 0 : GIT_MERGE_FILE_FAVOR_NO_MERGE; git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours); cl_git_pass(git_reference_symbolic_create(&our_ref, repo, "HEAD", branch_buf.ptr, 1, NULL, NULL)); diff --git a/tests/resources/revert/.gitted/index b/tests/resources/revert/.gitted/index index 87419ff5772da4296fc517dd9f14f7ab7971d87d..3513c04a6ca3c9fb199446f6aa8b44c7ae17e0b6 100644 GIT binary patch delta 233 zcmX@Wbb(pI#WTp6fq{Vuh}nP`4kji@>oQo`eNKP%`CsMx-@m!SHf0|0(T@Blz?qhr zlWM3}Qc(g|3}S#aoccNU@sb(pg4Ns76&d-~xJk3E;8DP*p`={xf#RNcmmRs!_zaBx z=FgXIZZ<&D5Oj0Zd64NrbKhT?m|)9|!j+zQSP4bsgN?}b6&K!{{<&W^|A$#{N;}hy Ij6ZH-0O$Ws>i_@% delta 137 zcmcb>e1J*9#WTp6fq{Vuh*^UA+ZO|AhM@lLQxg-Ub!T|@pZ}U-{)|83<+44=yqBC_ ze|x3Fz?qhrlWM3}Qc(g_*r5y8@WGZFs1MFfke(dOsDvyuxq;C}WYgz9ANEx<`P!Qb O`{r=uX06-hXbb?&mNFjz diff --git a/tests/resources/revert/.gitted/objects/0a/d19525be6d8cae5e5deb2770fc244b65255057 b/tests/resources/revert/.gitted/objects/0a/d19525be6d8cae5e5deb2770fc244b65255057 new file mode 100644 index 0000000000000000000000000000000000000000..4aa0459d8e4e04250a6f4031535762fa33683dfe GIT binary patch literal 133 zcmV;00DAv;0V^p=O;s>7v0yMXFfcPQQAo?oNj20fsVHGM^>gmyB{S3otGA^qGV-l) zlV)4NgQUm^tcYvFyk%DoCwt$|Q4&+TvF-caPWE&pMaE!7Ummg_GPux{@Y`{&WZQgs n4Q+MZIY^4kz>4^z|9tHU?QM%)wvVatdS&F~l$>_}D9<}b%t=9? literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/13/a6fdfd10bd74b1f258fb58801215985dd2e797 b/tests/resources/revert/.gitted/objects/13/a6fdfd10bd74b1f258fb58801215985dd2e797 new file mode 100644 index 0000000000000000000000000000000000000000..3c54aab0c503fe12ffaa55c89b2c898adb88fe93 GIT binary patch literal 121 zcmV-<0EYi~0V^p=O;s>7G-EI{FfcPQQP4}zEJ-XWDauSLElDkAkpFN*nMK>}v}|H^ z b&k>Sl^;)rMXLC>QvOeQA%6sGhF_17*Gb%i$ literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/1b/c915c5cb7185a9438de28a7b1a7dfe8c01ee7f b/tests/resources/revert/.gitted/objects/1b/c915c5cb7185a9438de28a7b1a7dfe8c01ee7f new file mode 100644 index 0000000000000000000000000000000000000000..0a6955b5da107cb8a76e7fd8fb637a7257a0b708 GIT binary patch literal 1169 zcmV;C1aA9y0d-bQZyPrd?U}!Vje`PJ;uVk-J+#QdmYl?ZzbYwB3qcULTxypwmt>Y) zTk0Xdy>G~sswR#PqvddBIDGSF=+d~7zk2oh^$#Z}{Ia&LQ~XaIdSUoH_LX)#s@A(s zbUVJ$MunHW?6s+Qr$TQcmcmvHzG;)!%BoI8Rq=Aiz4N^h-BE;3dTcvclu;t6G28z7%b2A^ zp+7HI+T!=tt;$bhig95@X%v5!EuQg>GnMMNwmde9-}LWPh0GL3-JctV)tK8Tq<`?1G03C4m_Y?M9=MB>ULXF67#G zj=~sMLp}r_B*l0Lfj)|Kg8+rs>4a=XTe#Ffn8}M5TnY&U6B(FBN@KVPPmWg7+0H8) zstvxfO!j1c6lWkF5~2;t+XodW2GYuMOXlx-T?s16Ssz_1qIQ-qoHO@2!m9Rj;tUzi z)VvX$rwRuycyV*F;L=sv)|}X=En6Q<0RE^*rC83xD!WmPg%a&V$6XGQ;5az%_fV!2 zK6P>89`pZ4FsoS~P(%q0tKc z=lbY-VjeM(P@T@q6mz9m=U>%;}htL#5XRZ!c6$38zufSh>vrZvPIfsR2?&&M`B4&ws+p zf%gQ=rPqXSI@h8XEkaOKye1rs-UmuXJUTS3Rgd8LVb%;Y0&W46F8B~V2Nl59x(FXt zDb%J^QqZJ+RJoKjM)vQgKeP1*Uw5KXvy{>LEoC%jITYr=uzTg|QSsOH)&JHYBGqU9 z#}%Kej@msP%}|W>R78PpX))%GmIh0>ToF+7M;&FeZ$!M7+4+Fl8Nk>G06AvsyN9^G z*hY*^Toj6H0BWv<)f-T7Pvtk?`#a)XrDCUJAE5f4^_yeP>6S(oWtOLUV2h@2%K)A* z)x^U$;=Rr9C+fJ-b#h@-749SWrLCr*GbMKtkw8I?Qeb}B96Dgc;$eS2yO{hvxwmQqQMn|=Kr z<;+Rj_?83)0-GX5KE6j5))(~g(}&M*=I8y*=5!~CDyg}%i3(|WYkZ*OiM!-mPNrmQ zcjSC%*_yvX);J+?m2vC1n4LGB`RqLlzsi=xdlLDJj{Z4(t0XGLG)=5KV0g+jy;pccPUU7bPIX zy9F(ePqd7NGFm(2=Pd$id5EUT5~wdO0)kva&Bkgi)^j!7x}dL)*d_@M$^^f9-&xQE z@lbLQPD5U}U?`rEwQ(GF8Q|1(kp{?Y&$~E+k*z@p3J~bT6!~;LF+5AIf<9K#mC|M>q`5cPt|k&MjRG~YT2|5aUaBc z^q!@c2?|{uNQwEjAB*STB;dlsW(^)3xUqrMj^Edq4deR-(8<$b+^Ko+LnIh*l`p$2 z7JS2wjgT9j8}FbnY~ew%FArsnV?qFQxDB&MhX>|R3q9(dsxbk&JnHb0*9dPhM7Y3g zc{M_Hqrk5VZd_9b8SevYTF=CMkv^eP^dYYxj=KLhmW@+2FK=%qEbw`n^!a_-QenEE hwk&T~6P8V-966QS&*irXOGr~bzg8!G{sA+ixECtgav=Z! literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/21/a96a98ed84d45866e1de6e266fd3a61a4ae9dc b/tests/resources/revert/.gitted/objects/21/a96a98ed84d45866e1de6e266fd3a61a4ae9dc new file mode 100644 index 0000000000000000000000000000000000000000..95842dbf87aa03a265eefc00cc0fd0a73563ac5c GIT binary patch literal 19 acmbP(0z~o&K&KQ-HpQ1U6;$E{J#SMa=TtGP)h>`F3_yCSQCk-x zEfkkT9vlgHkIG%%=mVYPy>i=mljl6?Z(Z9HJMUb^3AtUQwlP_q{1W9+MWw`~^XSNb TBm`_c>MUS|?UBV7VMk8IjbBO3 literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/46/ff0854663aeb2182b9838c8da68e33ac23bc1e b/tests/resources/revert/.gitted/objects/46/ff0854663aeb2182b9838c8da68e33ac23bc1e new file mode 100644 index 0000000000000000000000000000000000000000..7064dab5271999c6a353f3782a18c05a6f0a7adf GIT binary patch literal 20 bcmbT}WVHF1RP?o;{QtJod literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/5c/f1d643f100d8112834e540264546ba2c159976 b/tests/resources/revert/.gitted/objects/5c/f1d643f100d8112834e540264546ba2c159976 new file mode 100644 index 0000000000000000000000000000000000000000..dbbf711b5b1bad52430f7c5f7fea334ffd0fcf65 GIT binary patch literal 86 zcmV-c0IC0Y0ZYosPf{>4vS6@*00j?MM;9(z2;g$d%t=+q&r8L}u!8`Fg2bZKyb^`{ sG=&ty6cYpE6g@pXh2qTI0-zD8DVZhs%pk@dBGf3t?ZD0g0M(;Nc2L$P#Q*>R literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/6b/ccd0dc58cea5ccff86014f3d64b31bd8c02a37 b/tests/resources/revert/.gitted/objects/6b/ccd0dc58cea5ccff86014f3d64b31bd8c02a37 new file mode 100644 index 0000000000000000000000000000000000000000..2664da4804fdf5d59ef1acbf33bfe1a7288f9030 GIT binary patch literal 171 zcmV;c095~Y0gaAb3c@fDg#A}?ily&Lnsl24#6yS|$R=A_Fjms&`4xKspJo_7hA)gM z4Fyzd7bP=;^A5Y{Ov6$KB&V&ifjLHH4Wet2Fk)z>c>2tb0;XniK@sXm)alS*N6L~i z!J>@Rkm<Q@Ne0Z_y7@yO8|HeQu+V@ literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/71/eb9c2b53dbbf3c45fb28b27c850db4b7fb8011 b/tests/resources/revert/.gitted/objects/71/eb9c2b53dbbf3c45fb28b27c850db4b7fb8011 new file mode 100644 index 0000000000000000000000000000000000000000..995a1e6260d813d0d5e6cc7ec523637507d3e3ed GIT binary patch literal 148 zcmV;F0Biqv0gcW{3IZ_@Kv8EUr>F}EmC6j_T`K7cHW*t%^!$n^aQ7E)@ypWMJU}PE z8eIfpaET}DOsS|#4HH*wh1mO8Bk5QZ`w%6oCwF-a;8N^lOhUp$QYD)lv}MMu5koPQ zger+w{2I5V!+Nvb?GMM(H{c?T=ld13i76O|k>HFDQI+4+kUzQV@|HfJiTVK1tu(=h CxJ66= literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/87/59ad453cf01cf7daf14e2a668f8218f9a678eb b/tests/resources/revert/.gitted/objects/87/59ad453cf01cf7daf14e2a668f8218f9a678eb new file mode 100644 index 0000000000000000000000000000000000000000..ab19acf83f1bc5095891a748f6bbe86e6a5202a2 GIT binary patch literal 122 zcmV-=0EPc}0V^p=O;s>7G-EI{FfcPQQP4}zEJ-XWDauSLElDkAkpFN*nMK>}v}|H^ z*7P%`lW*ruJGjCM04!TDH#oXE?EnA( literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/9a/95fd974e03c5b93828ceedd28755965b5d5c60 b/tests/resources/revert/.gitted/objects/9a/95fd974e03c5b93828ceedd28755965b5d5c60 new file mode 100644 index 0000000000000000000000000000000000000000..bb93a34bb0a18500e7093940c302613af24aa7d0 GIT binary patch literal 122 zcmV-=0EPc}0V^p=O;s>7G-EI{FfcPQQP4}zEJ-XWDauSLElDkAkpFN*nMK>}v}|H^ zWKa&m$%w1r7#_oh*L=Zp;Xg literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/ac/c4d33902092efeb3b714aa0b1007c329e2f2e6 b/tests/resources/revert/.gitted/objects/ac/c4d33902092efeb3b714aa0b1007c329e2f2e6 new file mode 100644 index 0000000000000000000000000000000000000000..91bb68b4194a23a861ff45a510d4e137c2f54206 GIT binary patch literal 116 zcmV-)0E_>40gcUD3IZ_2%UIAnv7;Ml4Jn7~=jFSK#0MIB;d@y&3p1 zY;08pE=-TgX;chC6NfxxQLS~ziHIXjR7oPb^0w!)!gjYm98c%VH{hndwD}G`WKMxF WdblDXI{8gZ|KzT{nz;}44kXTh!8MTp literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/b6/9d88e177455579896e2be495046e2a51456a9a b/tests/resources/revert/.gitted/objects/b6/9d88e177455579896e2be495046e2a51456a9a new file mode 100644 index 0000000000000000000000000000000000000000..a5f69f2c887a615ff710006d0087efec01fe47d3 GIT binary patch literal 197 zcmV;$06PD80i};!Y6Bq@h5PI(E_rXz(V2UNQu5Lbgls^)PDZF&)U@00B-ucrZ-*TdE$eIH> zR+45?+92`5v{;^XcJxwbykVL(T7?G+ApGiwLih zq!c^dhmQD<2yu?zu?;wcTGr1LMk-ebn=9AY4?JpWm%ndS$&C;)Tt|)Z3tM!GG~7g*B32yeF)c z@*&ECHE9+hVQ13Ey!HXFmuqi(zrm9p>5qG9n~c8qI?vMEGb|L>bqz=k9x)=C zBR!5z{YQm)(@z}}PW#sG?+RMBc{1j5-F6tiXotTUC`)0aVy$Gg>{eTXb(Psha#Gn> O^(ZmP*?a?E5Mw4WNnknv literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/e3/4ef1afe54eb526fd92eec66084125f340f1d65 b/tests/resources/revert/.gitted/objects/e3/4ef1afe54eb526fd92eec66084125f340f1d65 new file mode 100644 index 0000000000000000000000000000000000000000..fc19ebd3de1ba3fad2c8060266f61144ce68c5a0 GIT binary patch literal 150 zcmV;H0BQet0gaAZ3IZ_<0DUVxMK2&E?Y7N=c$YRwalv(^RPgwUC-84R24;Af=c!v9 z)2cUBi$2FHRS=4#p7v0yMXFfcPQQAo?oNj20fsVHH1cWmuxeVaE6PTf26k8$JV zCRM$2vyl`TffaFWn78c8;biaoIZ9$`H@1Dh+sU4eq{tYo=*vU)Lk1VR5`H_*m28_Y ouc583I|oUT8CVg2^q;Rip}lRf%l0ufUayRtoRaen0PJ}`8M`Jw5&!@I literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/objects/ee/c6adcb2f3ceca0cadeccfe01b19382252ece9b b/tests/resources/revert/.gitted/objects/ee/c6adcb2f3ceca0cadeccfe01b19382252ece9b new file mode 100644 index 0000000000000000000000000000000000000000..f59f3d48de922dd711cc58d42a63afb030a740eb GIT binary patch literal 66 zcmV-I0KNZs0ZYosPf{>6vtUqk%gjkt$j?hvg~Yu4l8n?Mh18VH Y61YlS;&26U28!KC&Ol-U04Q}g8{1YKZU6uP literal 0 HcmV?d00001 diff --git a/tests/resources/revert/.gitted/refs/heads/master b/tests/resources/revert/.gitted/refs/heads/master index d3850daa6960c9b959bd19a3c0161a8017f62dbf..180f407e3cd114c133a17741c4877afbd0b9a1c5 100644 GIT binary patch delta 6 NcmdPWoS?zT1pow-0T%!O delta 7 OcmdPYnxMhN%LM=hya6Qu diff --git a/tests/resources/revert/.gitted/refs/heads/two b/tests/resources/revert/.gitted/refs/heads/two new file mode 100644 index 0000000000000000000000000000000000000000..f31ec00e546b2e81a3de8d0cd234efbca114d29f GIT binary patch literal 41 ucmV~$#}NP^38o-KLQdHly9-XQ_*@W$lGlb9;JlIU)T8ivkNf* literal 0 HcmV?d00001 diff --git a/tests/revert/workdir.c b/tests/revert/workdir.c index 9dc72a9a8..bca1ff926 100644 --- a/tests/revert/workdir.c +++ b/tests/revert/workdir.c @@ -137,6 +137,203 @@ void test_revert_workdir__orphan(void) git_commit_free(head); } +/* + * revert the same commit twice (when the first reverts cleanly): + * + * git revert 2d440f2 + * git revert 2d440f2 + */ +void test_revert_workdir__again(void) +{ + git_reference *head_ref; + git_commit *orig_head; + git_tree *reverted_tree; + git_oid reverted_tree_oid, reverted_commit_oid; + git_signature *signature; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 0, "file1.txt" }, + { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, + { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, + { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, + }; + + cl_git_pass(git_repository_head(&head_ref, repo)); + cl_git_pass(git_reference_peel((git_object **)&orig_head, head_ref, GIT_OBJ_COMMIT)); + cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD)); + + cl_git_pass(git_revert(repo, orig_head, NULL)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); + + cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index)); + cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); + + cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); + + cl_git_pass(git_revert(repo, orig_head, NULL)); + cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); + + git_signature_free(signature); + git_tree_free(reverted_tree); + git_commit_free(orig_head); + git_reference_free(head_ref); +} + +/* git reset --hard 72333f47d4e83616630ff3b0ffe4c0faebcc3c45 + * git revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */ +void test_revert_workdir__again_after_automerge(void) +{ + git_commit *head, *commit; + git_tree *reverted_tree; + git_oid head_oid, revert_oid, reverted_tree_oid, reverted_commit_oid; + git_signature *signature; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 0, "file1.txt" }, + { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, + { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, + { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, + }; + + struct merge_index_entry second_revert_entries[] = { + { 0100644, "3a3ef367eaf3fe79effbfb0a56b269c04c2b59fe", 1, "file1.txt" }, + { 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 2, "file1.txt" }, + { 0100644, "747726e021bc5f44b86de60e3032fd6f9f1b8383", 3, "file1.txt" }, + { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, + { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, + { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, + }; + + git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); + cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD)); + + git_oid_fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac"); + cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); + cl_git_pass(git_revert(repo, commit, NULL)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); + + cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index)); + cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); + + cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&head)); + + cl_git_pass(git_revert(repo, commit, NULL)); + cl_assert(merge_test_index(repo_index, second_revert_entries, 6)); + + git_signature_free(signature); + git_tree_free(reverted_tree); + git_commit_free(commit); + git_commit_free(head); +} + +/* + * revert the same commit twice (when the first reverts cleanly): + * + * git revert 2d440f2 + * git revert 2d440f2 + */ +void test_revert_workdir__again_after_edit(void) +{ + git_reference *head_ref; + git_commit *orig_head, *commit; + git_tree *reverted_tree; + git_oid orig_head_oid, revert_oid, reverted_tree_oid, reverted_commit_oid; + git_signature *signature; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "3721552e06c4bdc7d478e0674e6304888545d5fd", 0, "file1.txt" }, + { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, + { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, + { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, + }; + + cl_git_pass(git_repository_head(&head_ref, repo)); + + cl_git_pass(git_oid_fromstr(&orig_head_oid, "399fb3aba3d9d13f7d40a9254ce4402067ef3149")); + cl_git_pass(git_commit_lookup(&orig_head, repo, &orig_head_oid)); + cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD)); + + cl_git_pass(git_oid_fromstr(&revert_oid, "2d440f2b3147d3dc7ad1085813478d6d869d5a4d")); + cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); + + cl_git_pass(git_revert(repo, commit, NULL)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); + + cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index)); + cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); + + cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); + + cl_git_pass(git_revert(repo, commit, NULL)); + cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); + + git_signature_free(signature); + git_tree_free(reverted_tree); + git_commit_free(commit); + git_commit_free(orig_head); + git_reference_free(head_ref); +} + +/* + * revert the same commit twice (when the first reverts cleanly): + * + * git reset --hard e34ef1a + * git revert 71eb9c2 + */ +void test_revert_workdir__again_after_edit_two(void) +{ + git_buf diff_buf = GIT_BUF_INIT; + git_config *config; + git_oid head_commit_oid, revert_commit_oid; + git_commit *head_commit, *revert_commit; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "1ff0c423042b46cb1d617b81efb715defbe8054d", 0, ".gitattributes" }, + { 0100644, "1bc915c5cb7185a9438de28a7b1a7dfe8c01ee7f", 0, ".gitignore" }, + { 0100644, "a8c86221b400b836010567cc3593db6e96c1a83a", 1, "file.txt" }, + { 0100644, "46ff0854663aeb2182b9838c8da68e33ac23bc1e", 2, "file.txt" }, + { 0100644, "21a96a98ed84d45866e1de6e266fd3a61a4ae9dc", 3, "file.txt" }, + }; + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "core.autocrlf", 0)); + + cl_git_pass(git_oid_fromstr(&head_commit_oid, "e34ef1afe54eb526fd92eec66084125f340f1d65")); + cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_oid)); + cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD)); + + cl_git_pass(git_oid_fromstr(&revert_commit_oid, "71eb9c2b53dbbf3c45fb28b27c850db4b7fb8011")); + cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_commit_oid)); + + cl_git_pass(git_revert(repo, revert_commit, NULL)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 5)); + + cl_git_pass(git_futils_readbuffer(&diff_buf, "revert/file.txt")); + cl_assert(strcmp(diff_buf.ptr, "a\n" \ + "<<<<<<< HEAD\n" \ + "=======\n" \ + "a\n" \ + ">>>>>>> parent of 71eb9c2... revert me\n" \ + "a\n" \ + "a\n" \ + "a\n" \ + "a\n" \ + "ab\n") == 0); + + git_commit_free(revert_commit); + git_commit_free(head_commit); + git_config_free(config); + git_buf_free(&diff_buf); +} + /* git reset --hard 72333f47d4e83616630ff3b0ffe4c0faebcc3c45 * git revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */ void test_revert_workdir__conflict_use_ours(void) @@ -161,7 +358,7 @@ void test_revert_workdir__conflict_use_ours(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - opts.merge_tree_opts.automerge_flags = GIT_MERGE_AUTOMERGE_NONE; + opts.merge_tree_opts.file_favor = GIT_MERGE_FILE_FAVOR_NO_MERGE; opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45");