Merge branch 'en/merge-recursive-fixes'
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 22:55:40 +0000 (14:55 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 22:55:40 +0000 (14:55 -0800)
* en/merge-recursive-fixes:
  merge-recursive: add explanation for src_entry and dst_entry
  merge-recursive: fix logic ordering issue
  Tighten and correct a few testcases for merging and cherry-picking

merge-recursive.c
t/t3501-revert-cherry-pick.sh
t/t7607-merge-overwrite.sh

index cc5fa0a..9d53f30 100644 (file)
@@ -513,6 +513,25 @@ static void record_df_conflict_files(struct merge_options *o,
 
 struct rename {
        struct diff_filepair *pair;
+       /*
+        * Purpose of src_entry and dst_entry:
+        *
+        * If 'before' is renamed to 'after' then src_entry will contain
+        * the versions of 'before' from the merge_base, HEAD, and MERGE in
+        * stages 1, 2, and 3; dst_entry will contain the respective
+        * versions of 'after' in corresponding locations.  Thus, we have a
+        * total of six modes and oids, though some will be null.  (Stage 0
+        * is ignored; we're interested in handling conflicts.)
+        *
+        * Since we don't turn on break-rewrites by default, neither
+        * src_entry nor dst_entry can have all three of their stages have
+        * non-null oids, meaning at most four of the six will be non-null.
+        * Also, since this is a rename, both src_entry and dst_entry will
+        * have at least one non-null oid, meaning at least two will be
+        * non-null.  Of the six oids, a typical rename will have three be
+        * non-null.  Only two implies a rename/delete, and four implies a
+        * rename/add.
+        */
        struct stage_data *src_entry;
        struct stage_data *dst_entry;
        unsigned processed:1;
@@ -1998,10 +2017,10 @@ int merge_trees(struct merge_options *o,
                get_files_dirs(o, merge);
 
                entries = get_unmerged();
-               record_df_conflict_files(o, entries);
                re_head  = get_renames(o, head, common, head, merge, entries);
                re_merge = get_renames(o, merge, common, head, merge, entries);
                clean = process_renames(o, re_head, re_merge);
+               record_df_conflict_files(o, entries);
                if (clean < 0)
                        goto cleanup;
                for (i = entries->nr-1; 0 <= i; i--) {
index 4f2a263..783bdbf 100755 (executable)
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
        test_cmp expect actual
 '
 
-test_expect_success 'cherry-pick works with dirty renamed file' '
+test_expect_failure 'cherry-pick works with dirty renamed file' '
        test_commit to-rename &&
        git checkout -b unrelated &&
        test_commit unrelated &&
@@ -150,7 +150,10 @@ test_expect_success 'cherry-pick works with dirty renamed file' '
        test_tick &&
        git commit -m renamed &&
        echo modified >renamed &&
-       git cherry-pick refs/heads/unrelated
+       test_must_fail git cherry-pick refs/heads/unrelated >out &&
+       test_i18ngrep "Refusing to lose dirty file at renamed" out &&
+       test $(git rev-parse :0:renamed) = $(git rev-parse HEAD^:to-rename.t) &&
+       grep -q "^modified$" renamed
 '
 
 test_done
index 9444d6a..9c422bc 100755 (executable)
@@ -97,7 +97,10 @@ test_expect_failure 'will not overwrite unstaged changes in renamed file' '
        git mv c1.c other.c &&
        git commit -m rename &&
        cp important other.c &&
-       git merge c1a &&
+       test_must_fail git merge c1a >out &&
+       test_i18ngrep "Refusing to lose dirty file at other.c" out &&
+       test_path_is_file other.c~HEAD &&
+       test $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&
        test_cmp important other.c
 '