[英]git - Find commit from which was branch created
Is it possible to find commit (ideally only the commit hash) from which was branch created, even if the branch was already merged ?即使分支已经合并,是否有可能找到创建分支的提交(理想情况下只有提交哈希)?
For example:例如:
master A-B-C-D-E
\ /
feature F-G
feature
branch is already merged in master
, but it still exists and can be checkout to. feature
分支已经合并到master
中,但它仍然存在并且可以被 checkout 到。 I would like to find, that feature
branch started from A
.我想找到,该
feature
分支从A
开始。
( Disclaimer : off-topic answer - not adressing already merged branches) (免责声明:题外话 - 不涉及已经合并的分支)
If feature
and master
are not yet merged , you can just get their "merge-base" ( doc ):如果
feature
和master
还没有合并,你可以得到他们的“merge-base”( doc ):
git merge-base master feature
It will output your commit A
's long-form hash.它将 output 您的提交
A
的长格式 hash。
Branches don't really have parent branches.分支实际上没有父分支。 (Related: How to find the nearest parent of a Git branch? ) You can find the hash of
A
pretty easily, but consider this diagram: (相关:如何找到 Git 分支的最近父级? )您可以很容易地找到
A
的 hash,但请考虑下图:
H--I--L--N--O--R---T--U <-- master
\ \ \ /
J--K--M--P--Q--S <-- feature
Which commit(s) would you like to find here?您想在这里找到哪些提交?
O
, L
, and H
are all viable candidates for "where feature
started from". O
、 L
和H
都是“ feature
从哪里开始”的可行候选者。 But maybe feature
didn't start from any of those;但也许
feature
不是从其中任何一个开始的; maybe it started from P
, which used to have a label main-feature
.也许它是从
P
开始的,它曾经有一个 label main-feature
。 See the related question for details.有关详细信息,请参阅相关问题。
To find commit A
from your diagram, which I'll reproduce here a form I consider more accurate (the name master
merely points directly to commit E
for instance—commits F
and G
are on branch master
too:):要从您的图表中找到提交
A
,我将在这里复制一个我认为更准确的形式(例如,名称master
仅直接指向提交E
- 提交F
和G
也在分支master
上:):
A--B--C--D--E <-- master
\ /
F----G <-- feature
we can start from commit E
(tip of master) and step back to commit D
(the merge).我们可以从提交
E
(master 的提示)开始,然后退回到提交D
(合并)。 We know we have hit D
when one of its parents is the tip of feature
, ie, is commit G
.我们知道我们已经击中
D
当它的父母之一是feature
的尖端,即提交G
。 We then get both parent hash IDs from commit D
:然后我们从提交
D
中获取父 hash ID:
git rev-parse <hash-of-D>^@
and make sure there are exactly two of them (a three-parent merge makes this hard), and then invoke git merge-base --all
on those two parent hash IDs.并确保其中恰好有两个(三父合并使这变得困难),然后在这两个父 hash ID 上调用
git merge-base --all
。 This immediately produces the hash ID of commit A
.这会立即产生提交
A
的 hash ID。
When we use this same procedure on my sample graph, we step back from U
to T
, discover that it has two parents and the second is S
which is the tip of feature
, and ask Git to find the merge base of R
and S
.当我们在我的示例图上使用相同的过程时,我们从
U
退回到T
,发现它有两个父级,第二个是S
,它是feature
的尖端,并要求 Git 找到R
和S
的合并基。 The output of this git merge-base --all
is the hash of commit O
.这个
git merge-base --all
是提交O
的 hash。
To do this relatively quickly in shell script, start with:要在 shell 脚本中相对快速地执行此操作,请从以下开始:
git rev-list --merges --first-parent master
which produces a list of all merge commit hash IDs reachable by walking first-parent descendants of master
.这会生成一个列表,其中列出了所有合并提交 hash ID 可通过步行
master
的第一父后代到达。 (You may or may not want --first-parent
; if you've been using git pull
heavily, the first parent linkages of master
may be somewhat damaged by "foxtrot merges" .) That is, this gives us commit hashes T
and D
in the two diagrams here (and probably more). (你可能想要也可能不想要
--first-parent
;如果你一直在使用git pull
, master
的第一个父链接可能会被“foxtrot 合并”损坏。)也就是说,这给了我们提交哈希T
和此处的两个图中的D
(可能更多)。 If you omit --first-parent
, think about what you want from cases where other branches have merged into master
, bringing with them commits from the feature
branch in question, and decide whether you might want --topo-order
in your git rev-list
.如果您省略
--first-parent
,请考虑从其他分支合并到master
的情况下您想要什么,并从相关feature
分支中进行提交,并决定您是否可能需要--topo-order
在您的git rev-list
中git rev-list
。
Next, walk through these commits, getting their parent hashes:接下来,遍历这些提交,获取它们的父哈希:
looking_for=$(git rev-parse feature) # this is the hash ID we're looking for
found=false
for hash in (output of above git rev-list); do
set -- $(git rev-parse ${hash}^@)
case $# in
2) # two parents, good
if [ $2 == $looking_for ]; then found=true; break; fi;;
*) # more than two parents, we might go wrong
echo "commit $hash has $# parents, help"; exit 1;;
esac
done
if ! $found; then
echo "unable to find the commit hash you were looking for"
exit 1
fi
At this point, you have the desired commit pair in $1
and $2
due to the way set
parses arguments, so:此时,由于
set
解析 arguments 的方式,您在$1
和$2
中有所需的提交对,因此:
# found the desired commit pair, so now just invoke git merge-base
set -- $(git merge-base --all $1 $2)
case $# in
1) echo "the commit you are looking for is $1"; exit 0;;
*) echo "I found $# candidate commits $@"; exit 1;;
esac
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.