From: Elijah Newren <newren@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>
Subject: [RFC/WIP PATCH 1/1] merge-recursive: make file/directory conflicts easier to resolve
Date: Mon, 6 Aug 2018 15:45:47 -0700 [thread overview]
Message-ID: <20180806224547.8619-2-newren@gmail.com> (raw)
In-Reply-To: <20180806224547.8619-1-newren@gmail.com>
File/directory conflicts are somewhat difficult to resolve; by way of
contrast, renames are much easier to handle. For file/directory
conflicts, we already have to record the file under a different name in
the working copy due to the directory being in the way; if we also record
the file under a different name in the index then it simplifies matters
for the user, and ensures that 'git reset --hard' and 'git merge --abort'
will clean up files created by the merge operation.
Note that there are multiple ways to get a file/directory conflict:
* add/add (one side adds a file, the other a directory)
* modify/delete (the side that deletes puts a directory in the way)
* rename vs add-directory (directory added on one side in way of rename)
As such, there are multiple code paths that need updating.
FIXME: Several testcases were updated to show how this affected the
testsuite in general, but there are still 11 more tests across five
testfiles that need fixing. As I said, this is just WIP/RFC.
Signed-off-by: Elijah Newren <newren@gmail.com>
---
merge-recursive.c | 38 ++++++++++++++++++++++------
t/t3030-merge-recursive.sh | 16 ++++++------
t/t6020-merge-df.sh | 4 +--
t/t6022-merge-rename.sh | 4 +--
t/t6036-recursive-corner-cases.sh | 5 ++--
t/t6042-merge-rename-corner-cases.sh | 4 +--
t/t6043-merge-rename-directories.sh | 4 +--
7 files changed, 49 insertions(+), 26 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 1446e92bea..34906b0f90 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1527,6 +1527,20 @@ static int handle_change_delete(struct merge_options *o,
* path. We could call update_file_flags() with update_cache=0
* and update_wd=0, but that's a no-op.
*/
+ if (!o->call_depth && alt_path) {
+ struct diff_filespec orig, new;
+ int stage = (change_branch == o->branch1) ? 2 : 3;
+
+ remove_file_from_cache(path);
+ orig.mode = o_mode;
+ oidcpy(&orig.oid, o_oid);
+ new.mode = changed_mode;
+ oidcpy(&new.oid, changed_oid);
+ if (update_stages(o, alt_path, &orig,
+ stage == 2 ? &new : NULL,
+ stage == 3 ? &new : NULL))
+ ret = -1;
+ }
if (change_branch != o->branch1 || alt_path)
ret = update_file(o, 0, changed_oid, changed_mode, update_path);
}
@@ -3089,11 +3103,11 @@ static int merge_content(struct merge_options *o,
if (df_conflict_remains || is_dirty) {
char *new_path;
- if (o->call_depth) {
- remove_file_from_cache(path);
- } else {
+ new_path = unique_path(o, path, rename_conflict_info->branch1);
+ remove_file_from_cache(path);
+ if (!o->call_depth) {
if (!mfi.clean) {
- if (update_stages(o, path, &one, &a, &b))
+ if (update_stages(o, new_path, &one, &a, &b))
return -1;
} else {
int file_from_stage2 = was_tracked(o, path);
@@ -3101,14 +3115,13 @@ static int merge_content(struct merge_options *o,
oidcpy(&merged.oid, &mfi.oid);
merged.mode = mfi.mode;
- if (update_stages(o, path, NULL,
+ if (update_stages(o, new_path, NULL,
file_from_stage2 ? &merged : NULL,
file_from_stage2 ? NULL : &merged))
return -1;
}
}
- new_path = unique_path(o, path, rename_conflict_info->branch1);
if (is_dirty) {
output(o, 1, _("Refusing to lose dirty file at %s"),
path);
@@ -3244,10 +3257,19 @@ static int process_entry(struct merge_options *o,
output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
"Adding %s as %s"),
conf, path, other_branch, path, new_path);
+ remove_file_from_cache(path);
+ if (!o->call_depth) {
+ struct diff_filespec dfs;
+
+ dfs.mode = mode;
+ oidcpy(&dfs.oid, oid);
+ if (update_stages(o, new_path, NULL,
+ a_oid ? &dfs : NULL,
+ a_oid ? NULL : &dfs))
+ clean_merge = -1;
+ }
if (update_file(o, 0, oid, mode, new_path))
clean_merge = -1;
- else if (o->call_depth)
- remove_file_from_cache(path);
free(new_path);
} else {
output(o, 2, _("Adding %s"), path);
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index ff641b348a..6d456da001 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -369,9 +369,9 @@ test_expect_success 'merge-recursive d/f conflict result' '
git ls-files -s >actual &&
(
- echo "100644 $o0 1 a" &&
- echo "100644 $o1 2 a" &&
echo "100644 $o4 0 a/c" &&
+ echo "100644 $o0 1 a~$c1" &&
+ echo "100644 $o1 2 a~$c1" &&
echo "100644 $o0 0 b" &&
echo "100644 $o0 0 c" &&
echo "100644 $o1 0 d/e"
@@ -393,9 +393,9 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '
git ls-files -s >actual &&
(
- echo "100644 $o0 1 a" &&
- echo "100644 $o1 3 a" &&
echo "100644 $o4 0 a/c" &&
+ echo "100644 $o0 1 a~$c1" &&
+ echo "100644 $o1 3 a~$c1" &&
echo "100644 $o0 0 b" &&
echo "100644 $o0 0 c" &&
echo "100644 $o1 0 d/e"
@@ -420,9 +420,9 @@ test_expect_success 'merge-recursive d/f conflict result' '
echo "100644 $o1 0 a" &&
echo "100644 $o0 0 b" &&
echo "100644 $o0 0 c" &&
- echo "100644 $o6 3 d" &&
echo "100644 $o0 1 d/e" &&
- echo "100644 $o1 2 d/e"
+ echo "100644 $o1 2 d/e" &&
+ echo "100644 $o6 3 d~$c6"
) >expected &&
test_cmp expected actual
@@ -444,9 +444,9 @@ test_expect_success 'merge-recursive d/f conflict result' '
echo "100644 $o1 0 a" &&
echo "100644 $o0 0 b" &&
echo "100644 $o0 0 c" &&
- echo "100644 $o6 2 d" &&
echo "100644 $o0 1 d/e" &&
- echo "100644 $o1 3 d/e"
+ echo "100644 $o1 3 d/e" &&
+ echo "100644 $o6 2 d~$c6"
) >expected &&
test_cmp expected actual
diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh
index 2af1beec5f..f4ea318ec8 100755
--- a/t/t6020-merge-df.sh
+++ b/t/t6020-merge-df.sh
@@ -81,7 +81,7 @@ test_expect_success 'modify/delete + directory/file conflict' '
test 5 -eq $(git ls-files -s | wc -l) &&
test 4 -eq $(git ls-files -u | wc -l) &&
- test 1 -eq $(git ls-files -o | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
test -f letters.txt &&
@@ -100,7 +100,7 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '
test 5 -eq $(git ls-files -s | wc -l) &&
test 4 -eq $(git ls-files -u | wc -l) &&
- test 1 -eq $(git ls-files -o | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
test -f letters.txt &&
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index b760c223c6..0ea3760265 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -385,7 +385,7 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t
test_must_fail git merge --strategy=recursive dir-in-way &&
test 5 -eq "$(git ls-files -u | wc -l)" &&
- test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
+ test 3 -eq "$(git ls-files -u dir~HEAD | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
test_must_fail git diff --quiet &&
@@ -421,7 +421,7 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
test 5 -eq "$(git ls-files -u | wc -l)" &&
- test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
+ test 3 -eq "$(git ls-files -u dir~renamed-file-has-conflicts | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
test_must_fail git diff --quiet &&
diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 59e52c5a09..f8790e6975 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -471,7 +471,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict
test_must_fail git merge C^0 &&
git clean -fd &&
git rm -rf a/ &&
- git rm a &&
+ git rm a~HEAD &&
git cat-file -p B:a >a2 &&
git add a2 &&
git commit -m D2 &&
@@ -492,6 +492,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict
test_must_fail git merge B^0 &&
git clean -fd &&
git rm -rf a/ &&
+ git rm a~B^0 &&
test_write_lines 1 2 3 4 5 6 7 8 >a &&
git add a &&
git commit -m E3 &&
@@ -501,7 +502,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict
test_must_fail git merge B^0 &&
git clean -fd &&
git rm -rf a/ &&
- git rm a &&
+ git rm a~B^0 &&
test_write_lines 1 2 3 4 5 6 7 8 >a2 &&
git add a2 &&
git commit -m E4 &&
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 07dd09d985..25cb50478c 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -305,14 +305,14 @@ test_expect_success 'rename/directory conflict + clean content merge' '
git ls-files -u >out &&
test_line_count = 1 out &&
git ls-files -o >out &&
- test_line_count = 2 out &&
+ test_line_count = 1 out &&
echo 0 >expect &&
git cat-file -p base:file >>expect &&
echo 7 >>expect &&
test_cmp expect newfile~HEAD &&
- test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
+ test $(git rev-parse :2:newfile~HEAD) = $(git hash-object expect) &&
test_path_is_file newfile/realfile &&
test_path_is_file newfile~HEAD
diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh
index 4a71f17edd..12047a3309 100755
--- a/t/t6043-merge-rename-directories.sh
+++ b/t/t6043-merge-rename-directories.sh
@@ -1160,10 +1160,10 @@ test_expect_success '5d-check: Directory/file/file conflict due to directory ren
git ls-files -u >out &&
test_line_count = 1 out &&
git ls-files -o >out &&
- test_line_count = 2 out &&
+ test_line_count = 1 out &&
git rev-parse >actual \
- :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&
+ :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e &&
git rev-parse >expect \
O:z/b O:z/c B:z/d B:z/f A:y/d B:y/d/e &&
test_cmp expect actual &&
--
2.18.0.550.g44d6daf40a.dirty
next prev parent reply other threads:[~2018-08-06 22:45 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-06 22:44 Two RFC/WIP series for facilitating merge conflict resolution Elijah Newren
2018-08-06 22:45 ` [RFC/WIP PATCH 0/1] Simplify handling of directory/file conflicts Elijah Newren
2018-08-06 22:45 ` Elijah Newren [this message]
2018-08-09 17:36 ` [RFC/WIP PATCH 1/1] merge-recursive: make file/directory conflicts easier to resolve Junio C Hamano
2018-08-09 19:26 ` Elijah Newren
2018-08-09 20:54 ` Junio C Hamano
2018-08-09 21:27 ` Elijah Newren
2018-08-06 22:47 ` [RFC/WIP PATCH 0/3] Modifications to handling of non-textual file merge conflicts Elijah Newren
2018-08-06 22:47 ` [RFC/WIP PATCH 1/3] rerere: avoid buffer overrun Elijah Newren
2018-08-06 22:47 ` [RFC/WIP PATCH 2/3] merge-recursive: fix handling of submodules in modify/delete conflicts Elijah Newren
2018-08-06 22:47 ` [RFC/WIP PATCH 3/3] merge-recursive: provide more conflict hints for non-textual conflicts Elijah Newren
2018-08-09 17:52 ` [RFC/WIP PATCH 0/3] Modifications to handling of non-textual file merge conflicts Junio C Hamano
2018-08-09 18:51 ` Elijah Newren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180806224547.8619-2-newren@gmail.com \
--to=newren@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).