git/t/t7110-reset-merge.sh
Junio C Hamano e11d7b5969 "reset --merge": fix unmerged case
Commit 9e8ecea (Add 'merge' mode to 'git reset', 2008-12-01) disallowed
"git reset --merge" when there was unmerged entries.  But it wished if
unmerged entries were reset as if --hard (instead of --merge) has been
used.  This makes sense because all "mergy" operations makes sure that
any path involved in the merge does not have local modifications before
starting, so resetting such a path away won't lose any information.

The previous commit changed the behavior of --merge to accept resetting
unmerged entries if they are reset to a different state than HEAD, but it
did not reset the changes in the work tree, leaving the conflict markers
in the resulting file in the work tree.

Fix it by doing three things:

 - Update the documentation to match the wish of original "reset --merge"
   better, namely, "An unmerged entry is a sign that the path didn't have
   any local modification and can be safely resetted to whatever the new
   HEAD records";

 - Update read_index_unmerged(), which reads the index file into the cache
   while dropping any higher-stage entries down to stage #0, not to copy
   the object name from the higher stage entry.  The code used to take the
   object name from the a stage entry ("base" if you happened to have
   stage #1, or "ours" if both sides added, etc.), which essentially meant
   that you are getting random results depending on what the merge did.

   The _only_ reason we want to keep a previously unmerged entry in the
   index at stage #0 is so that we don't forget the fact that we have
   corresponding file in the work tree in order to be able to remove it
   when the tree we are resetting to does not have the path.  In order to
   differentiate such an entry from ordinary cache entry, the cache entry
   added by read_index_unmerged() is marked as CE_CONFLICTED.

 - Update merged_entry() and deleted_entry() so that they pay attention to
   cache entries marked as CE_CONFLICTED.  They are previously unmerged
   entries, and the files in the work tree that correspond to them are
   resetted away by oneway_merge() to the version from the tree we are
   resetting to.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-03 16:01:05 -08:00

184 lines
5.7 KiB
Bash
Executable File

#!/bin/sh
#
# Copyright (c) 2009 Christian Couder
#
test_description='Tests for "git reset --merge"'
. ./test-lib.sh
test_expect_success setup '
for i in 1 2 3; do echo line $i; done >file1 &&
cat file1 >file2 &&
git add file1 file2 &&
test_tick &&
git commit -m "Initial commit" &&
git tag initial &&
echo line 4 >>file1 &&
cat file1 >file2 &&
test_tick &&
git commit -m "add line 4 to file1" file1 &&
git tag second
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: C C C D --merge D D D
# file2: C D D D --merge C D D
test_expect_success 'reset --merge is ok with changes in file it does not touch' '
git reset --merge HEAD^ &&
! grep 4 file1 &&
grep 4 file2 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
test -z "$(git diff --cached)"
'
test_expect_success 'reset --merge is ok when switching back' '
git reset --merge second &&
grep 4 file1 &&
grep 4 file2 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
test -z "$(git diff --cached)"
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: B B C D --merge D D D
# file2: C D D D --merge C D D
test_expect_success 'reset --merge discards changes added to index (1)' '
git reset --hard second &&
cat file1 >file2 &&
echo "line 5" >> file1 &&
git add file1 &&
git reset --merge HEAD^ &&
! grep 4 file1 &&
! grep 5 file1 &&
grep 4 file2 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
test -z "$(git diff --cached)"
'
test_expect_success 'reset --merge is ok again when switching back (1)' '
git reset --hard initial &&
echo "line 5" >> file2 &&
git add file2 &&
git reset --merge second &&
! grep 4 file2 &&
! grep 5 file1 &&
grep 4 file1 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
test -z "$(git diff --cached)"
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: C C C D --merge D D D
# file2: C C D D --merge D D D
test_expect_success 'reset --merge discards changes added to index (2)' '
git reset --hard second &&
echo "line 4" >> file2 &&
git add file2 &&
git reset --merge HEAD^ &&
! grep 4 file2 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
test -z "$(git diff)" &&
test -z "$(git diff --cached)"
'
test_expect_success 'reset --merge is ok again when switching back (2)' '
git reset --hard initial &&
git reset --merge second &&
! grep 4 file2 &&
grep 4 file1 &&
test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
test -z "$(git diff --cached)"
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: A B B C --merge (disallowed)
test_expect_success 'reset --merge fails with changes in file it touches' '
git reset --hard second &&
echo "line 5" >> file1 &&
test_tick &&
git commit -m "add line 5" file1 &&
sed -e "s/line 1/changed line 1/" <file1 >file3 &&
mv file3 file1 &&
test_must_fail git reset --merge HEAD^ 2>err.log &&
grep file1 err.log | grep "not uptodate"
'
test_expect_success 'setup 3 different branches' '
git reset --hard second &&
git branch branch1 &&
git branch branch2 &&
git branch branch3 &&
git checkout branch1 &&
echo "line 5 in branch1" >> file1 &&
test_tick &&
git commit -a -m "change in branch1" &&
git checkout branch2 &&
echo "line 5 in branch2" >> file1 &&
test_tick &&
git commit -a -m "change in branch2" &&
git tag third &&
git checkout branch3 &&
echo a new file >file3 &&
rm -f file1 &&
git add file3 &&
test_tick &&
git commit -a -m "change in branch3"
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: X U B C --merge C C C
test_expect_success '"reset --merge HEAD^" is ok with pending merge' '
git checkout third &&
test_must_fail git merge branch1 &&
git reset --merge HEAD^ &&
test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
test -z "$(git diff --cached)" &&
test -z "$(git diff)"
'
# The next test will test the following:
#
# working index HEAD target working index HEAD
# ----------------------------------------------------
# file1: X U B B --merge B B B
test_expect_success '"reset --merge HEAD" is ok with pending merge' '
git reset --hard third &&
test_must_fail git merge branch1 &&
git reset --merge HEAD &&
test "$(git rev-parse HEAD)" = "$(git rev-parse third)" &&
test -z "$(git diff --cached)" &&
test -z "$(git diff)"
'
test_expect_success '--merge with added/deleted' '
git reset --hard third &&
rm -f file2 &&
test_must_fail git merge branch3 &&
! test -f file2 &&
test -f file3 &&
git diff --exit-code file3 &&
git diff --exit-code branch3 file3 &&
git reset --merge HEAD &&
! test -f file3 &&
! test -f file2 &&
git diff --exit-code --cached
'
test_done