git-查找从中创建分支的提交

git-查找从中创建分支的提交,git,branch,Git,Branch,即使分支已经合并,也能找到创建分支的提交(理想情况下仅是提交哈希)吗 例如: master A-B-C-D-E \ / feature F-G 功能分支已合并到主中,但它仍然存在,可以签出到。我想发现,功能分支从A开始(免责声明:主题外答案-不处理已合并的分支) 如果feature和master尚未合并,您只需获取它们的“合并基础”(): 它将输出提交的长格式散列。分支实际上没有父分支。(相关:)您可以很容易地找到 A < /COD>的散列,但请考虑此图:

即使分支已经合并,也能找到创建分支的提交(理想情况下仅是提交哈希)吗

例如:

master   A-B-C-D-E
          \   /
feature    F-G
功能
分支已合并到
中,但它仍然存在,可以签出到。我想发现,
功能
分支从
A

开始(免责声明:主题外答案-不处理已合并的分支)


如果
feature
master
尚未合并,您只需获取它们的“合并基础”():


它将输出提交
的长格式散列。

分支实际上没有父分支。(相关:)您可以很容易地找到<代码> A < /COD>的散列,但请考虑此图:

H--I--L--N--O--R---T--U   <-- master
 \     \     \    /
  J--K--M--P--Q--S   <-- feature
我们可以从提交
E
(主机提示)开始,然后返回提交
D
(合并)。我们知道,当它的一个父项是
功能
的提示时,我们已经点击了
D
,即,是commit
G
。然后,我们从commit
D
获取两个父哈希ID:

git rev-parse <hash-of-D>^@
它生成所有合并提交哈希ID的列表,这些ID可通过遍历
master
的第一个父后代访问。(您可能想要也可能不想要
——第一个父级
;如果您一直在大量使用
git pull
,那么
master
的第一个父级链接可能会受到某种程度的损坏。)也就是说,这给了我们在这里的两个图中提交哈希
T
D
(可能更多)。如果省略了
--第一个父级
,请考虑其他分支已合并到
主级
,并从有问题的
功能
分支提交的情况,然后决定是否需要
--拓扑顺序

接下来,遍历这些提交,获取其父哈希:

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
此时,由于
set
解析参数的方式,您在
$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

当分支尚未合并时,此操作有效。但是对于已经合并的分支,它显示了分支中最后一次提交的哈希(
G
hash)。你说得对,这不是针对合并的分支,我必须进一步搜索,因为你想要的确实更难获得。同时,我也进行了编辑,以避免误导人们。
git rev-list --merges --first-parent master
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
# 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