2009-12-25 18:08:04 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='undoing resolution'
|
|
|
|
|
2020-11-18 23:44:22 +00:00
|
|
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
tests: mark tests relying on the current default for `init.defaultBranch`
In addition to the manual adjustment to let the `linux-gcc` CI job run
the test suite with `master` and then with `main`, this patch makes sure
that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts
that currently rely on the initial branch name being `master by default.
To determine which test scripts to mark up, the first step was to
force-set the default branch name to `master` in
- all test scripts that contain the keyword `master`,
- t4211, which expects `t/t4211/history.export` with a hard-coded ref to
initialize the default branch,
- t5560 because it sources `t/t556x_common` which uses `master`,
- t8002 and t8012 because both source `t/annotate-tests.sh` which also
uses `master`)
This trick was performed by this command:
$ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' $(git grep -l master t/t[0-9]*.sh) \
t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh
After that, careful, manual inspection revealed that some of the test
scripts containing the needle `master` do not actually rely on a
specific default branch name: either they mention `master` only in a
comment, or they initialize that branch specificially, or they do not
actually refer to the current default branch. Therefore, the
aforementioned modification was undone in those test scripts thusly:
$ git checkout HEAD -- \
t/t0027-auto-crlf.sh t/t0060-path-utils.sh \
t/t1011-read-tree-sparse-checkout.sh \
t/t1305-config-include.sh t/t1309-early-config.sh \
t/t1402-check-ref-format.sh t/t1450-fsck.sh \
t/t2024-checkout-dwim.sh \
t/t2106-update-index-assume-unchanged.sh \
t/t3040-subprojects-basic.sh t/t3301-notes.sh \
t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \
t/t3436-rebase-more-options.sh \
t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \
t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \
t/t5511-refspec.sh t/t5526-fetch-submodules.sh \
t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \
t/t5548-push-porcelain.sh \
t/t5552-skipping-fetch-negotiator.sh \
t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \
t/t5614-clone-submodules-shallow.sh \
t/t7508-status.sh t/t7606-merge-custom.sh \
t/t9302-fast-import-unpack-limit.sh
We excluded one set of test scripts in these commands, though: the range
of `git p4` tests. The reason? `git p4` stores the (foreign) remote
branch in the branch called `p4/master`, which is obviously not the
default branch. Manual analysis revealed that only five of these tests
actually require a specific default branch name to pass; They were
modified thusly:
$ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' t/t980[0167]*.sh t/t9811*.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-18 23:44:19 +00:00
|
|
|
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
|
|
|
|
2009-12-25 18:08:04 +00:00
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
check_resolve_undo () {
|
|
|
|
msg=$1
|
|
|
|
shift
|
|
|
|
while case $# in
|
|
|
|
0) break ;;
|
|
|
|
1|2|3) die "Bug in check-resolve-undo test" ;;
|
|
|
|
esac
|
|
|
|
do
|
|
|
|
path=$1
|
|
|
|
shift
|
|
|
|
for stage in 1 2 3
|
|
|
|
do
|
|
|
|
sha1=$1
|
|
|
|
shift
|
|
|
|
case "$sha1" in
|
|
|
|
'') continue ;;
|
|
|
|
esac
|
|
|
|
sha1=$(git rev-parse --verify "$sha1")
|
|
|
|
printf "100644 %s %s\t%s\n" $sha1 $stage $path
|
|
|
|
done
|
|
|
|
done >"$msg.expect" &&
|
|
|
|
git ls-files --resolve-undo >"$msg.actual" &&
|
|
|
|
test_cmp "$msg.expect" "$msg.actual"
|
|
|
|
}
|
|
|
|
|
|
|
|
prime_resolve_undo () {
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout second^0 &&
|
|
|
|
test_tick &&
|
|
|
|
test_must_fail git merge third^0 &&
|
|
|
|
check_resolve_undo empty &&
|
2023-07-31 22:44:05 +00:00
|
|
|
|
|
|
|
# how should the conflict be resolved?
|
|
|
|
case "$1" in
|
|
|
|
remove)
|
|
|
|
rm -f file/le && git rm fi/le
|
|
|
|
;;
|
|
|
|
*) # modify
|
|
|
|
echo different >fi/le && git add fi/le
|
|
|
|
;;
|
|
|
|
esac
|
2010-01-21 08:23:48 +00:00
|
|
|
check_resolve_undo recorded fi/le initial:fi/le second:fi/le third:fi/le
|
2009-12-25 18:08:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success setup '
|
2010-01-21 08:23:48 +00:00
|
|
|
mkdir fi &&
|
2013-04-01 21:36:36 +00:00
|
|
|
printf "a\0a" >binary &&
|
|
|
|
git add binary &&
|
2010-01-21 08:23:48 +00:00
|
|
|
test_commit initial fi/le first &&
|
2009-12-25 18:08:04 +00:00
|
|
|
git branch side &&
|
|
|
|
git branch another &&
|
2013-04-01 21:36:36 +00:00
|
|
|
printf "a\0b" >binary &&
|
|
|
|
git add binary &&
|
2010-01-21 08:23:48 +00:00
|
|
|
test_commit second fi/le second &&
|
2009-12-25 18:08:04 +00:00
|
|
|
git checkout side &&
|
2010-01-21 08:23:48 +00:00
|
|
|
test_commit third fi/le third &&
|
2013-04-04 18:41:43 +00:00
|
|
|
git branch add-add &&
|
2009-12-25 18:08:04 +00:00
|
|
|
git checkout another &&
|
2010-01-21 08:23:48 +00:00
|
|
|
test_commit fourth fi/le fourth &&
|
2013-04-04 18:41:43 +00:00
|
|
|
git checkout add-add &&
|
|
|
|
test_commit fifth add-differently &&
|
2020-11-18 23:44:22 +00:00
|
|
|
git checkout main
|
2009-12-25 18:08:04 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'add records switch clears' '
|
|
|
|
prime_resolve_undo &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m merged &&
|
|
|
|
echo committing keeps &&
|
2010-01-21 08:23:48 +00:00
|
|
|
check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le &&
|
2009-12-25 18:08:04 +00:00
|
|
|
git checkout second^0 &&
|
|
|
|
echo switching clears &&
|
|
|
|
check_resolve_undo cleared
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'rm records reset clears' '
|
|
|
|
prime_resolve_undo &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m merged &&
|
|
|
|
echo committing keeps &&
|
2010-01-21 08:23:48 +00:00
|
|
|
check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le &&
|
2009-12-25 18:08:04 +00:00
|
|
|
|
|
|
|
echo merge clears upfront &&
|
|
|
|
test_must_fail git merge fourth^0 &&
|
|
|
|
check_resolve_undo nuked &&
|
|
|
|
|
2010-01-21 08:23:48 +00:00
|
|
|
git rm -f fi/le &&
|
2009-12-25 18:08:04 +00:00
|
|
|
echo resolving records &&
|
2010-01-21 08:23:48 +00:00
|
|
|
check_resolve_undo recorded fi/le initial:fi/le HEAD:fi/le fourth:fi/le &&
|
2009-12-25 18:08:04 +00:00
|
|
|
|
|
|
|
git reset --hard &&
|
|
|
|
echo resetting discards &&
|
|
|
|
check_resolve_undo discarded
|
|
|
|
'
|
|
|
|
|
2009-12-25 18:31:26 +00:00
|
|
|
test_expect_success 'plumbing clears' '
|
|
|
|
prime_resolve_undo &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m merged &&
|
|
|
|
echo committing keeps &&
|
2010-01-21 08:23:48 +00:00
|
|
|
check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le &&
|
2009-12-25 18:31:26 +00:00
|
|
|
|
|
|
|
echo plumbing clear &&
|
|
|
|
git update-index --clear-resolve-undo &&
|
|
|
|
check_resolve_undo cleared
|
|
|
|
'
|
|
|
|
|
2009-12-25 19:57:11 +00:00
|
|
|
test_expect_success 'add records checkout -m undoes' '
|
|
|
|
prime_resolve_undo &&
|
|
|
|
git diff HEAD &&
|
2010-01-21 08:23:48 +00:00
|
|
|
git checkout --conflict=merge fi/le &&
|
2009-12-25 19:57:11 +00:00
|
|
|
echo checkout used the record and removed it &&
|
|
|
|
check_resolve_undo removed &&
|
|
|
|
echo the index and the work tree is unmerged again &&
|
|
|
|
git diff >actual &&
|
|
|
|
grep "^++<<<<<<<" actual
|
|
|
|
'
|
|
|
|
|
2009-12-25 21:40:02 +00:00
|
|
|
test_expect_success 'unmerge with plumbing' '
|
|
|
|
prime_resolve_undo &&
|
2010-01-21 08:23:48 +00:00
|
|
|
git update-index --unresolve fi/le &&
|
2023-07-31 22:44:05 +00:00
|
|
|
git ls-files --resolve-undo fi/le >actual &&
|
|
|
|
test_must_be_empty actual &&
|
2009-12-25 21:40:02 +00:00
|
|
|
git ls-files -u >actual &&
|
2012-04-11 11:24:01 +00:00
|
|
|
test_line_count = 3 actual
|
2009-12-25 21:40:02 +00:00
|
|
|
'
|
|
|
|
|
update-index: do not read HEAD and MERGE_HEAD unconditionally
When "update-index --unresolve $path" cannot find the resolve-undo
record for the path the user requested to unresolve, it stuffs the
blobs from HEAD and MERGE_HEAD to stage #2 and stage #3 as a
fallback. For this reason, the operation does not even start unless
both "HEAD" and "MERGE_HEAD" exist.
This is suboptimal in a few ways:
* It does not recreate stage #1. Even though it is a correct
design decision not to do so (because it is impossible to
recreate in general cases, without knowing how we got there,
including what merge strategy was used), it is much less useful
not to have that information in the index.
* It limits the "unresolve" operation only during a conflicted "git
merge" and nothing else. Other operations like "rebase",
"cherry-pick", and "switch -m" may result in conflicts, and the
user may want to unresolve the conflict that they incorrectly
resolved in order to redo the resolution, but the fallback would
not kick in.
* Most importantly, the entire "unresolve" operation is disabled
after a conflicted merge is committed and MERGE_HEAD is removed,
even though the index has perfectly usable resolve-undo records.
By lazily reading the HEAD and MERGE_HEAD only when we need to go to
the fallback codepath, we will allow cases where resolve-undo
records are available (which is 100% of the time, unless the user is
reading from an index file created by Git more than 10 years ago) to
proceed even after a conflicted merge was committed, during other
mergy operations that do not use MERGE_HEAD, or after the result of
such mergy operations has been committed.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-07-31 22:44:03 +00:00
|
|
|
test_expect_success 'unmerge can be done even after committing' '
|
|
|
|
prime_resolve_undo &&
|
|
|
|
git commit -m "record to nuke MERGE_HEAD" &&
|
|
|
|
git update-index --unresolve fi/le &&
|
2023-07-31 22:44:05 +00:00
|
|
|
git ls-files --resolve-undo fi/le >actual &&
|
|
|
|
test_must_be_empty actual &&
|
|
|
|
git ls-files -u >actual &&
|
|
|
|
test_line_count = 3 actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'unmerge removal' '
|
|
|
|
prime_resolve_undo remove &&
|
|
|
|
git update-index --unresolve fi/le &&
|
|
|
|
git ls-files --resolve-undo fi/le >actual &&
|
|
|
|
test_must_be_empty actual &&
|
|
|
|
git ls-files -u >actual &&
|
|
|
|
test_line_count = 3 actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'unmerge removal after committing' '
|
|
|
|
prime_resolve_undo remove &&
|
|
|
|
git commit -m "record to nuke MERGE_HEAD" &&
|
|
|
|
git update-index --unresolve fi/le &&
|
|
|
|
git ls-files --resolve-undo fi/le >actual &&
|
|
|
|
test_must_be_empty actual &&
|
update-index: do not read HEAD and MERGE_HEAD unconditionally
When "update-index --unresolve $path" cannot find the resolve-undo
record for the path the user requested to unresolve, it stuffs the
blobs from HEAD and MERGE_HEAD to stage #2 and stage #3 as a
fallback. For this reason, the operation does not even start unless
both "HEAD" and "MERGE_HEAD" exist.
This is suboptimal in a few ways:
* It does not recreate stage #1. Even though it is a correct
design decision not to do so (because it is impossible to
recreate in general cases, without knowing how we got there,
including what merge strategy was used), it is much less useful
not to have that information in the index.
* It limits the "unresolve" operation only during a conflicted "git
merge" and nothing else. Other operations like "rebase",
"cherry-pick", and "switch -m" may result in conflicts, and the
user may want to unresolve the conflict that they incorrectly
resolved in order to redo the resolution, but the fallback would
not kick in.
* Most importantly, the entire "unresolve" operation is disabled
after a conflicted merge is committed and MERGE_HEAD is removed,
even though the index has perfectly usable resolve-undo records.
By lazily reading the HEAD and MERGE_HEAD only when we need to go to
the fallback codepath, we will allow cases where resolve-undo
records are available (which is 100% of the time, unless the user is
reading from an index file created by Git more than 10 years ago) to
proceed even after a conflicted merge was committed, during other
mergy operations that do not use MERGE_HEAD, or after the result of
such mergy operations has been committed.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-07-31 22:44:03 +00:00
|
|
|
git ls-files -u >actual &&
|
|
|
|
test_line_count = 3 actual
|
|
|
|
'
|
|
|
|
|
2010-01-21 08:23:48 +00:00
|
|
|
test_expect_success 'rerere and rerere forget' '
|
2009-12-25 23:51:32 +00:00
|
|
|
mkdir .git/rr-cache &&
|
|
|
|
prime_resolve_undo &&
|
|
|
|
echo record the resolution &&
|
|
|
|
git rerere &&
|
|
|
|
rerere_id=$(cd .git/rr-cache && echo */postimage) &&
|
|
|
|
rerere_id=${rerere_id%/postimage} &&
|
|
|
|
test -f .git/rr-cache/$rerere_id/postimage &&
|
2010-01-21 08:23:48 +00:00
|
|
|
git checkout -m fi/le &&
|
2009-12-25 23:51:32 +00:00
|
|
|
echo resurrect the conflict &&
|
2010-01-21 08:23:48 +00:00
|
|
|
grep "^=======" fi/le &&
|
2009-12-25 23:51:32 +00:00
|
|
|
echo reresolve the conflict &&
|
|
|
|
git rerere &&
|
2010-01-21 08:23:48 +00:00
|
|
|
test "z$(cat fi/le)" = zdifferent &&
|
2009-12-25 23:51:32 +00:00
|
|
|
echo register the resolution again &&
|
2010-01-21 08:23:48 +00:00
|
|
|
git add fi/le &&
|
|
|
|
check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le &&
|
2009-12-25 23:51:32 +00:00
|
|
|
test -z "$(git ls-files -u)" &&
|
2010-01-21 08:23:48 +00:00
|
|
|
git rerere forget fi/le &&
|
2009-12-25 23:51:32 +00:00
|
|
|
! test -f .git/rr-cache/$rerere_id/postimage &&
|
|
|
|
tr "\0" "\n" <.git/MERGE_RR >actual &&
|
2010-01-21 08:23:48 +00:00
|
|
|
echo "$rerere_id fi/le" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'rerere and rerere forget (subdirectory)' '
|
|
|
|
rm -fr .git/rr-cache &&
|
|
|
|
mkdir .git/rr-cache &&
|
|
|
|
prime_resolve_undo &&
|
|
|
|
echo record the resolution &&
|
|
|
|
(cd fi && git rerere) &&
|
|
|
|
rerere_id=$(cd .git/rr-cache && echo */postimage) &&
|
|
|
|
rerere_id=${rerere_id%/postimage} &&
|
|
|
|
test -f .git/rr-cache/$rerere_id/postimage &&
|
|
|
|
(cd fi && git checkout -m le) &&
|
|
|
|
echo resurrect the conflict &&
|
|
|
|
grep "^=======" fi/le &&
|
|
|
|
echo reresolve the conflict &&
|
|
|
|
(cd fi && git rerere) &&
|
|
|
|
test "z$(cat fi/le)" = zdifferent &&
|
|
|
|
echo register the resolution again &&
|
|
|
|
(cd fi && git add le) &&
|
|
|
|
check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le &&
|
|
|
|
test -z "$(git ls-files -u)" &&
|
|
|
|
(cd fi && git rerere forget le) &&
|
|
|
|
! test -f .git/rr-cache/$rerere_id/postimage &&
|
|
|
|
tr "\0" "\n" <.git/MERGE_RR >actual &&
|
|
|
|
echo "$rerere_id fi/le" >expect &&
|
2009-12-25 23:51:32 +00:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2013-04-01 21:36:36 +00:00
|
|
|
test_expect_success 'rerere forget (binary)' '
|
|
|
|
git checkout -f side &&
|
2021-05-10 14:19:06 +00:00
|
|
|
test_commit --printf binary binary "a\0c" &&
|
2013-04-01 21:36:36 +00:00
|
|
|
test_must_fail git merge second &&
|
|
|
|
git rerere forget binary
|
|
|
|
'
|
|
|
|
|
2013-04-04 18:41:43 +00:00
|
|
|
test_expect_success 'rerere forget (add-add conflict)' '
|
2020-11-18 23:44:22 +00:00
|
|
|
git checkout -f main &&
|
|
|
|
echo main >add-differently &&
|
2013-04-04 18:41:43 +00:00
|
|
|
git add add-differently &&
|
|
|
|
git commit -m "add differently" &&
|
|
|
|
test_must_fail git merge fifth &&
|
|
|
|
git rerere forget add-differently 2>actual &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "no remembered" actual
|
2013-04-04 18:41:43 +00:00
|
|
|
'
|
|
|
|
|
2022-06-09 23:44:20 +00:00
|
|
|
test_expect_success 'resolve-undo keeps blobs from gc' '
|
|
|
|
git checkout -f main &&
|
|
|
|
|
|
|
|
# First make sure we do not have any cruft left in the object store
|
|
|
|
git repack -a -d &&
|
|
|
|
git prune --expire=now &&
|
|
|
|
git prune-packed &&
|
|
|
|
git gc --prune=now &&
|
|
|
|
git fsck --unreachable >cruft &&
|
|
|
|
test_must_be_empty cruft &&
|
|
|
|
|
|
|
|
# Now add three otherwise unreferenced blob objects to the index
|
|
|
|
git reset --hard &&
|
|
|
|
B1=$(echo "resolve undo test data 1" | git hash-object -w --stdin) &&
|
|
|
|
B2=$(echo "resolve undo test data 2" | git hash-object -w --stdin) &&
|
|
|
|
B3=$(echo "resolve undo test data 3" | git hash-object -w --stdin) &&
|
|
|
|
git update-index --add --index-info <<-EOF &&
|
|
|
|
100644 $B1 1 frotz
|
|
|
|
100644 $B2 2 frotz
|
|
|
|
100644 $B3 3 frotz
|
|
|
|
EOF
|
|
|
|
|
|
|
|
# These three blob objects are reachable (only) from the index
|
|
|
|
git fsck --unreachable >cruft &&
|
|
|
|
test_must_be_empty cruft &&
|
|
|
|
# and they should be protected from GC
|
|
|
|
git gc --prune=now &&
|
|
|
|
git cat-file -e $B1 &&
|
|
|
|
git cat-file -e $B2 &&
|
|
|
|
git cat-file -e $B3 &&
|
|
|
|
|
|
|
|
# Now resolve the conflicted path
|
|
|
|
B0=$(echo "resolve undo test data 0" | git hash-object -w --stdin) &&
|
|
|
|
git update-index --add --cacheinfo 100644,$B0,frotz &&
|
|
|
|
|
|
|
|
# These three blob objects are now reachable only from the resolve-undo
|
|
|
|
git fsck --unreachable >cruft &&
|
|
|
|
test_must_be_empty cruft &&
|
|
|
|
|
|
|
|
# and they should survive GC
|
|
|
|
git gc --prune=now &&
|
|
|
|
git cat-file -e $B0 &&
|
|
|
|
git cat-file -e $B1 &&
|
|
|
|
git cat-file -e $B2 &&
|
|
|
|
git cat-file -e $B3 &&
|
|
|
|
|
|
|
|
# Now we switch away, which nukes resolve-undo, and
|
|
|
|
# blobs B0..B3 would become dangling. fsck should
|
|
|
|
# notice that they are now unreachable.
|
|
|
|
git checkout -f side &&
|
|
|
|
git fsck --unreachable >cruft &&
|
|
|
|
sort cruft >actual &&
|
|
|
|
sort <<-EOF >expect &&
|
|
|
|
unreachable blob $B0
|
|
|
|
unreachable blob $B1
|
|
|
|
unreachable blob $B2
|
|
|
|
unreachable blob $B3
|
|
|
|
EOF
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
# And they should go away when gc runs.
|
|
|
|
git gc --prune=now &&
|
|
|
|
git fsck --unreachable >cruft &&
|
|
|
|
test_must_be_empty cruft &&
|
|
|
|
|
|
|
|
test_must_fail git cat-file -e $B0 &&
|
|
|
|
test_must_fail git cat-file -e $B1 &&
|
|
|
|
test_must_fail git cat-file -e $B2 &&
|
|
|
|
test_must_fail git cat-file -e $B3
|
|
|
|
'
|
|
|
|
|
2009-12-25 18:08:04 +00:00
|
|
|
test_done
|