目的:这个答案测试了在这个线程中给出的各种答案。
测试库
-- X -- A -- B -- C -- D -- F (master)
\ / \ /
\ / \ /
G -- H -- I -- J (branch A)
$ git --no-pager log --graph --oneline --all --decorate
* b80b645 (HEAD, branch_A) J - Work in branch_A branch
| * 3bd4054 (master) F - Merge branch_A into branch master
| |\
| |/
|/|
* | a06711b I - Merge master into branch_A
|\ \
* | | bcad6a3 H - Work in branch_A
| | * b46632a D - Work in branch master
| |/
| * 413851d C - Merge branch_A into branch master
| |\
| |/
|/|
* | 6e343aa G - Work in branch_A
| * 89655bb B - Work in branch master
|/
* 74c6405 (tag: branch_A_tag) A - Work in branch master
* 7a1c939 X - Work in branch master
正确的解决方案
唯一可行的解决方案是由lindes提供的正确返回A:
$ diff -u <(git rev-list --first-parent branch_A) \
<(git rev-list --first-parent master) | \
sed -ne 's/^ //p' | head -1
74c6405d17e319bd0c07c690ed876d65d89618d5
正如查尔斯·贝利指出的那样,这种解决方案非常脆弱。
如果你将branch_A合并为master,然后将master合并为branch_A,而不干预提交,那么lindes的解决方案只给你最近的第一次分歧。
这意味着对于我的工作流,我认为我将不得不坚持标记长时间运行的分支的分支点,因为我不能保证以后可以可靠地找到它们。
这实际上都归结为gits缺乏hg所谓的命名分支。博主jhw在他的文章《为什么我更喜欢Mercurial而不是Git》和他的后续文章《More On Mercurial vs. Git (with Graphs!)》中称这些为谱系vs.家族。我建议人们阅读它们,看看为什么一些mercurial转换错过了在git中没有命名分支。
不正确的解决方案
mipadi提供的解决方案返回两个答案I和C:
$ git rev-list --boundary branch_A...master | grep ^- | cut -c2-
a06711b55cf7275e8c3c843748daaa0aa75aef54
413851dfecab2718a3692a4bba13b50b81e36afc
由Greg Hewgill提供的解返回I
$ git merge-base master branch_A
a06711b55cf7275e8c3c843748daaa0aa75aef54
$ git merge-base --all master branch_A
a06711b55cf7275e8c3c843748daaa0aa75aef54
Karl提供的解返回X:
$ diff -u <(git log --pretty=oneline branch_A) \
<(git log --pretty=oneline master) | \
tail -1 | cut -c 2-42
7a1c939ec325515acfccb79040b2e4e1c3e7bbe5
测试存储库复制
创建一个测试存储库:
mkdir $1
cd $1
git init
git commit --allow-empty -m "X - Work in branch master"
git commit --allow-empty -m "A - Work in branch master"
git branch branch_A
git tag branch_A_tag -m "Tag branch point of branch_A"
git commit --allow-empty -m "B - Work in branch master"
git checkout branch_A
git commit --allow-empty -m "G - Work in branch_A"
git checkout master
git merge branch_A -m "C - Merge branch_A into branch master"
git checkout branch_A
git commit --allow-empty -m "H - Work in branch_A"
git merge master -m "I - Merge master into branch_A"
git checkout master
git commit --allow-empty -m "D - Work in branch master"
git merge branch_A -m "F - Merge branch_A into branch master"
git checkout branch_A
git commit --allow-empty -m "J - Work in branch_A branch"
我唯一添加的是标记,它明确了我们创建分支的点,从而明确了我们希望找到的提交。
我怀疑git版本对此有很大的不同,但是:
$ git --version
git version 1.7.1
感谢Charles Bailey向我展示了一种更紧凑的编写示例存储库脚本的方法。