mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
![Junio C Hamano](/assets/img/avatar_default.png)
In a topic branch workflow, you often want to find the latest commit that merged a side branch that touched a particular area of the system, so that a new topic branch to work on that area can be forked from that commit. For example, I wanted to find an appropriate fork-point to queue Luke's changes related to git-p4 in contrib/fast-import/. "git log --first-parent" traverses the first-parent chain, and "-m --stat" shows the list of paths touched by commits including merge commits. We could ask the question this way: # What is the latest commit that touched that path? $ git log --first-parent --oneline -m --stat master | sed -e '/^ contrib\/fast-import\/git-p4 /q' | tail The above finds that8cbfc11
(Merge branch 'pw/p4-view-updates', 2012-01-06) was such a commit. But a more natural way to spell this question is this: $ git log --first-parent --oneline -m --stat -1 master -- \ contrib/fast-import/git-p4 Unfortunately, this does not work. It findsecb7cf9
(git-p4: rewrite view handling, 2012-01-02). This commit is a part of the merged topic branch and is _not_ on the first-parent path from the 'master': $ git show-branch8cbfc11
ecb7cf9
! [8cbfc11
] Merge branch 'pw/p4-view-updates' ! [ecb7cf9
] git-p4: rewrite view handling -- - [8cbfc11
] Merge branch 'pw/p4-view-updates' + [8cbfc11^2] git-p4: view spec documentation ++ [ecb7cf9
] git-p4: rewrite view handling The problem is caused by the merge simplification logic when it inspects the merge commit8cbfc11
. In this case, the history leading to the tip of 'master' did not touch git-p4 since 'pw/p4-view-updates' topic forked, and the result of the merge is simply a copy from the tip of the topic branch in the view limited by the given pathspec. The merge simplification logic discards the history on the mainline side of the merge, and pretends as if the sole parent of the merge is its second parent, i.e. the tip of the topic. While this simplification is correct in the general case, it is at least surprising if not outright wrong when the user explicitly asked to show the first-parent history. Here is an attempt to fix this issue, by not allowing us to compare the merge result with anything but the first parent when --first-parent is in effect, to avoid the history traversal veering off to the side branch. Signed-off-by: Junio C Hamano <gitster@pobox.com>
92 lines
1.9 KiB
Bash
Executable file
92 lines
1.9 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
test_description='merge simplification'
|
|
|
|
. ./test-lib.sh
|
|
|
|
note () {
|
|
git tag "$1"
|
|
}
|
|
|
|
unnote () {
|
|
git name-rev --tags --stdin | sed -e "s|$_x40 (tags/\([^)]*\)) |\1 |g"
|
|
}
|
|
|
|
test_expect_success setup '
|
|
echo "Hi there" >file &&
|
|
git add file &&
|
|
test_tick && git commit -m "Initial file" &&
|
|
note A &&
|
|
|
|
git branch other-branch &&
|
|
|
|
echo "Hello" >file &&
|
|
git add file &&
|
|
test_tick && git commit -m "Modified file" &&
|
|
note B &&
|
|
|
|
git checkout other-branch &&
|
|
|
|
echo "Hello" >file &&
|
|
git add file &&
|
|
test_tick && git commit -m "Modified the file identically" &&
|
|
note C &&
|
|
|
|
echo "This is a stupid example" >another-file &&
|
|
git add another-file &&
|
|
test_tick && git commit -m "Add another file" &&
|
|
note D &&
|
|
|
|
test_tick && git merge -m "merge" master &&
|
|
note E &&
|
|
|
|
echo "Yet another" >elif &&
|
|
git add elif &&
|
|
test_tick && git commit -m "Irrelevant change" &&
|
|
note F &&
|
|
|
|
git checkout master &&
|
|
echo "Yet another" >elif &&
|
|
git add elif &&
|
|
test_tick && git commit -m "Another irrelevant change" &&
|
|
note G &&
|
|
|
|
test_tick && git merge -m "merge" other-branch &&
|
|
note H &&
|
|
|
|
echo "Final change" >file &&
|
|
test_tick && git commit -a -m "Final change" &&
|
|
note I
|
|
'
|
|
|
|
FMT='tformat:%P %H | %s'
|
|
|
|
check_result () {
|
|
for c in $1
|
|
do
|
|
echo "$c"
|
|
done >expect &&
|
|
shift &&
|
|
param="$*" &&
|
|
test_expect_success "log $param" '
|
|
git log --pretty="$FMT" --parents $param |
|
|
unnote >actual &&
|
|
sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual &&
|
|
test_cmp expect check || {
|
|
cat actual
|
|
false
|
|
}
|
|
'
|
|
}
|
|
|
|
check_result 'I H G F E D C B A' --full-history
|
|
check_result 'I H E C B A' --full-history -- file
|
|
check_result 'I H E C B A' --full-history --topo-order -- file
|
|
check_result 'I H E C B A' --full-history --date-order -- file
|
|
check_result 'I E C B A' --simplify-merges -- file
|
|
check_result 'I B A' -- file
|
|
check_result 'I B A' --topo-order -- file
|
|
check_result 'H' --first-parent -- another-file
|
|
|
|
test_done
|