diff options
-rw-r--r-- | Documentation/git-reset.txt | 4 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | read-cache.c | 3 | ||||
-rwxr-xr-x | t/t7110-reset-merge.sh | 40 | ||||
-rw-r--r-- | unpack-trees.c | 21 |
5 files changed, 49 insertions, 20 deletions
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index cf2433d52c..dc73dca736 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -122,14 +122,14 @@ entries: X U A B --soft (disallowed) --mixed X B B --hard B B B - --merge X B B + --merge B B B working index HEAD target working index HEAD ---------------------------------------------------- X U A A --soft (disallowed) --mixed X A A --hard A A A - --merge (disallowed) + --merge A A A X means any state and U means an unmerged index. @@ -177,6 +177,7 @@ struct cache_entry { #define CE_HASHED (0x100000) #define CE_UNHASHED (0x200000) +#define CE_CONFLICTED (0x400000) /* * Extended on-disk flags diff --git a/read-cache.c b/read-cache.c index 1bbaf1cffb..16c4548a74 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1606,9 +1606,8 @@ int read_index_unmerged(struct index_state *istate) len = strlen(ce->name); size = cache_entry_size(len); new_ce = xcalloc(1, size); - hashcpy(new_ce->sha1, ce->sha1); memcpy(new_ce->name, ce->name, len); - new_ce->ce_flags = create_ce_flags(len, 0); + new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED; new_ce->ce_mode = ce->ce_mode; if (add_index_entry(istate, new_ce, 0)) return error("%s: cannot drop to stage #0", diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh index ff2875c00b..8704d00196 100755 --- a/t/t7110-reset-merge.sh +++ b/t/t7110-reset-merge.sh @@ -116,10 +116,11 @@ test_expect_success 'reset --merge fails with changes in file it touches' ' grep file1 err.log | grep "not uptodate" ' -test_expect_success 'setup 2 different branches' ' +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 && @@ -128,34 +129,55 @@ test_expect_success 'setup 2 different branches' ' echo "line 5 in branch2" >> file1 && test_tick && git commit -a -m "change in branch2" && - git tag third + 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 X C C +# 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 && - cat file1 >orig_file1 && git reset --merge HEAD^ && test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && test -z "$(git diff --cached)" && - test_cmp file1 orig_file1 + test -z "$(git diff)" ' # The next test will test the following: # # working index HEAD target working index HEAD # ---------------------------------------------------- -# file1: X U B B --merge (disallowed) -test_expect_success '"reset --merge HEAD" fails with pending merge' ' +# 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 && - test_must_fail git reset --merge HEAD && + git reset --merge HEAD && test "$(git rev-parse HEAD)" = "$(git rev-parse third)" && - test -n "$(git diff --cached)" + 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 diff --git a/unpack-trees.c b/unpack-trees.c index dd5999c356..3df0de6005 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -436,6 +436,8 @@ static int same(struct cache_entry *a, struct cache_entry *b) return 0; if (!a && !b) return 1; + if ((a->ce_flags | b->ce_flags) & CE_CONFLICTED) + return 0; return a->ce_mode == b->ce_mode && !hashcmp(a->sha1, b->sha1); } @@ -666,7 +668,11 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, { int update = CE_UPDATE; - if (old) { + if (!old) { + if (verify_absent(merge, "overwritten", o)) + return -1; + invalidate_ce_path(merge, o); + } else if (!(old->ce_flags & CE_CONFLICTED)) { /* * See if we can re-use the old CE directly? * That way we get the uptodate stat info. @@ -682,11 +688,12 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, return -1; invalidate_ce_path(old, o); } - } - else { - if (verify_absent(merge, "overwritten", o)) - return -1; - invalidate_ce_path(merge, o); + } else { + /* + * Previously unmerged entry left as an existence + * marker by read_index_unmerged(); + */ + invalidate_ce_path(old, o); } add_entry(o, merge, update, CE_STAGEMASK); @@ -702,7 +709,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, return -1; return 0; } - if (verify_uptodate(old, o)) + if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o)) return -1; add_entry(o, ce, CE_REMOVE, 0); invalidate_ce_path(ce, o); |