mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
In e6c06e87a2 (last-modified: fix bug when some paths remain unhandled,
2025-09-18), we have fixed a bug where under certain circumstances,
git-last-modified(1) would BUG because there's still some unhandled
paths. The fix claims that the root cause here is criss-cross merges,
and it adds a test case that seemingly exercises this.
Curiously, this test case fails on some systems because the actual
output does not match our expectations:
diff --git a/expect b/actual
index 5271607..bdc620e 100644
--- a/expect
--- b/actual
@@ -1,3 +1,3 @@
km3 a
-k2 k
+km2 k
1 file
error: last command exited with $?=1
not ok 15 - last-modified with subdir and criss-cross merge
The output we see is git-name-rev(1) with `--annotate-stdin`. What it
does is to take the output of git-last-modified(1), which contains
object IDs of the blamed commits, and convert those object IDs into the
names of the corresponding tags. Interestingly, we indeed have both "k2"
and "km2" as tags, and even more interestingly both of these tags point
to the same commit. So the output we get isn't _wrong_, as the tags are
ambiguous.
But why do both of these tags point to the same commit? "km2" really is
supposed to be a merge, but due to the way the test is constructed the
merge turns into a fast-forward merge. Which means that the resulting
commit-graph does not even contain a criss-cross merge in the first place!
A quick test though shows that the test indeed triggers the bug, so
the initial analysis that the behaviour is triggered by such merges
must be wrong.
And it is: seemingly, the issue isn't with criss-cross merges, but
rather with a graph where different files in the same directory were
modified on both sides of a merge.
Refactor the test so that we explicitly test for this specific situation
instead of mentioning the "criss-cross merge" red herring. As the test
is very specific to the actual layout of the repository we also adapt it
to use its own standalone repository.
Note that this requires us to drop the `test_when_finished` call in
`check_last_modified` because it's not supported to execute that
function in a subshell.
This refactoring also fixes the original tag ambiguity that caused us to
fail on some platforms.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
231 lines
4.3 KiB
Bash
Executable File
231 lines
4.3 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
test_description='last-modified tests'
|
|
|
|
. ./test-lib.sh
|
|
|
|
test_expect_success 'setup' '
|
|
test_commit 1 file &&
|
|
mkdir a &&
|
|
test_commit 2 a/file &&
|
|
mkdir a/b &&
|
|
test_commit 3 a/b/file
|
|
'
|
|
|
|
test_expect_success 'cannot run last-modified on two trees' '
|
|
test_must_fail git last-modified HEAD HEAD~1
|
|
'
|
|
|
|
check_last_modified() {
|
|
local indir= &&
|
|
while test $# != 0
|
|
do
|
|
case "$1" in
|
|
-C)
|
|
indir="$2"
|
|
shift
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac &&
|
|
shift
|
|
done &&
|
|
|
|
cat >expect &&
|
|
git ${indir:+-C "$indir"} last-modified "$@" >tmp.1 &&
|
|
git name-rev --annotate-stdin --name-only --tags \
|
|
<tmp.1 >tmp.2 &&
|
|
tr '\t' ' ' <tmp.2 >actual &&
|
|
test_cmp expect actual
|
|
}
|
|
|
|
test_expect_success 'last-modified non-recursive' '
|
|
check_last_modified <<-\EOF
|
|
3 a
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified recursive' '
|
|
check_last_modified -r <<-\EOF
|
|
3 a/b/file
|
|
2 a/file
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified recursive with show-trees' '
|
|
check_last_modified -r -t <<-\EOF
|
|
3 a
|
|
3 a/b
|
|
3 a/b/file
|
|
2 a/file
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified non-recursive with show-trees' '
|
|
check_last_modified -t <<-\EOF
|
|
3 a
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified subdir' '
|
|
check_last_modified a <<-\EOF
|
|
3 a
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified subdir recursive' '
|
|
check_last_modified -r a <<-\EOF
|
|
3 a/b/file
|
|
2 a/file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified from non-HEAD commit' '
|
|
check_last_modified HEAD^ <<-\EOF
|
|
2 a
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified from subdir defaults to root' '
|
|
check_last_modified -C a <<-\EOF
|
|
3 a
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified from subdir uses relative pathspecs' '
|
|
check_last_modified -C a -r b <<-\EOF
|
|
3 a/b/file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'limit last-modified traversal by count' '
|
|
check_last_modified -1 <<-\EOF
|
|
3 a
|
|
^2 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'limit last-modified traversal by commit' '
|
|
check_last_modified HEAD~2..HEAD <<-\EOF
|
|
3 a
|
|
^1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'only last-modified files in the current tree' '
|
|
git rm -rf a &&
|
|
git commit -m "remove a" &&
|
|
check_last_modified <<-\EOF
|
|
1 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'subdirectory modified via merge' '
|
|
test_when_finished rm -rf repo &&
|
|
git init repo &&
|
|
(
|
|
cd repo &&
|
|
test_commit base &&
|
|
git switch --create left &&
|
|
mkdir subdir &&
|
|
test_commit left subdir/left &&
|
|
git switch --create right base &&
|
|
mkdir subdir &&
|
|
test_commit right subdir/right &&
|
|
git switch - &&
|
|
test_merge merge right &&
|
|
check_last_modified <<-\EOF
|
|
merge subdir
|
|
base base.t
|
|
EOF
|
|
)
|
|
'
|
|
|
|
test_expect_success 'cross merge boundaries in blaming' '
|
|
git checkout HEAD^0 &&
|
|
git rm -rf . &&
|
|
test_commit m1 &&
|
|
git checkout HEAD^ &&
|
|
git rm -rf . &&
|
|
test_commit m2 &&
|
|
git merge m1 &&
|
|
check_last_modified <<-\EOF
|
|
m2 m2.t
|
|
m1 m1.t
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified merge for resolved conflicts' '
|
|
git checkout HEAD^0 &&
|
|
git rm -rf . &&
|
|
test_commit c1 conflict &&
|
|
git checkout HEAD^ &&
|
|
git rm -rf . &&
|
|
test_commit c2 conflict &&
|
|
test_must_fail git merge c1 &&
|
|
test_commit resolved conflict &&
|
|
check_last_modified conflict <<-\EOF
|
|
resolved conflict
|
|
EOF
|
|
'
|
|
|
|
|
|
# Consider `file` with this content through history:
|
|
#
|
|
# A---B---B-------B---B
|
|
# \ /
|
|
# C---D
|
|
test_expect_success 'last-modified merge ignores content from branch' '
|
|
git checkout HEAD^0 &&
|
|
git rm -rf . &&
|
|
test_commit a1 file A &&
|
|
test_commit a2 file B &&
|
|
test_commit a3 file C &&
|
|
test_commit a4 file D &&
|
|
git checkout a2 &&
|
|
git merge --no-commit --no-ff a4 &&
|
|
git checkout a2 -- file &&
|
|
git merge --continue &&
|
|
check_last_modified <<-\EOF
|
|
a2 file
|
|
EOF
|
|
'
|
|
|
|
# Consider `file` with this content through history:
|
|
#
|
|
# A---B---B---C---D---B---B
|
|
# \ /
|
|
# B-------B
|
|
test_expect_success 'last-modified merge undoes changes' '
|
|
git checkout HEAD^0 &&
|
|
git rm -rf . &&
|
|
test_commit b1 file A &&
|
|
test_commit b2 file B &&
|
|
test_commit b3 file C &&
|
|
test_commit b4 file D &&
|
|
git checkout b2 &&
|
|
test_commit b5 file2 2 &&
|
|
git checkout b4 &&
|
|
git merge --no-commit --no-ff b5 &&
|
|
git checkout b2 -- file &&
|
|
git merge --continue &&
|
|
check_last_modified <<-\EOF
|
|
b5 file2
|
|
b2 file
|
|
EOF
|
|
'
|
|
|
|
test_expect_success 'last-modified complains about unknown arguments' '
|
|
test_must_fail git last-modified --foo 2>err &&
|
|
grep "unknown last-modified argument: --foo" err
|
|
'
|
|
|
|
test_done
|