am --skip: revert changes introduced by failed 3way merge
authorPaul Tan <pyokagan@gmail.com>
Sat, 6 Jun 2015 11:46:07 +0000 (19:46 +0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 8 Jun 2015 20:05:43 +0000 (13:05 -0700)
Even when a merge conflict occurs with am --3way, the index will be
modified with the results of any succesfully merged files (such as a new
file). These changes to the index will not be reverted with a
"git read-tree --reset -u HEAD HEAD", as git read-tree will not be aware
of how the current index differs from HEAD.

To fix this, we first reset any conflicting entries from the index. The
resulting index will contain the results of successfully merged files.
We write the index to a tree, then use git read-tree -m to fast-forward
the "index tree" back to HEAD, thus undoing all the changes from the
failed merge.

Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-am.sh
t/t4151-am-abort.sh
index ee61a77d717a7210a1cf614914ab62788fd5e4fc..80a7fdbd24244ca78d228a49fcfc59c1fcf5fdab 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -68,6 +68,8 @@ then
        cmdline="$cmdline -3"
 fi
 
+empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
 sq () {
        git rev-parse --sq-quote "$@"
 }
@@ -492,7 +494,10 @@ then
                ;;
        t,)
                git rerere clear
-               git read-tree --reset -u HEAD HEAD
+               head_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) &&
+               git read-tree --reset -u $head_tree $head_tree &&
+               index_tree=$(git write-tree) &&
+               git read-tree -m -u $index_tree $head_tree
                orig_head=$(cat "$GIT_DIR/ORIG_HEAD")
                git reset HEAD
                git update-ref ORIG_HEAD $orig_head
index 1176bcccf3b3f3708df04f49bfd084190cd27600..5ac741a1ac398cebade95137fec9ef0e61ff8493 100755 (executable)
@@ -63,6 +63,17 @@ do
 
 done
 
+test_expect_success 'am -3 --skip removes otherfile-4' '
+       git reset --hard initial &&
+       test_must_fail git am -3 0003-*.patch &&
+       test 3 -eq $(git ls-files -u | wc -l) &&
+       test 4 = "$(cat otherfile-4)" &&
+       git am --skip &&
+       test_cmp_rev initial HEAD &&
+       test -z $(git ls-files -u) &&
+       test_path_is_missing otherfile-4
+'
+
 test_expect_success 'am --abort will keep the local commits intact' '
        test_must_fail git am 0004-*.patch &&
        test_commit unrelated &&