给定SHA-1哈希值,是否有方法确定提交来自哪个分支?

如果你能告诉我如何使用Ruby Grit实现这一点,那就加分。


当前回答

一个穷人的选择是在HEAD上使用工具tig1,搜索提交,然后直观地从提交开始一直到看到合并提交。默认合并消息应指定要合并到的分支位置:)

1Tig是一个基于ncurses的Git文本模式界面。它的功能主要作为Git存储库浏览器,但它也可以帮助更改块级别的提交,并充当各种Git命令。

其他回答

作为一个实验,我制作了一个提交后挂钩,它在提交元数据中存储关于当前签出的分支的信息。我还略微修改了gitk以显示该信息。

你可以在这里查看:https://github.com/pajp/branch-info-commits

如果OP试图确定在创建特定提交时分支所遍历的历史(“在给定SHA-1哈希值的情况下,找出提交来自哪个分支”),那么如果没有reflog,Git对象数据库中就没有任何记录显示哪个命名的分支绑定到了什么提交历史。

(我将此作为回复评论的回复发布。)

希望这个脚本能说明我的观点:

rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;

输出表明,没有任何方法知道使用“Add f1”的提交是来自远程克隆/tmp/r2的分支b1还是b2。

(此处为输出的最后一行)

+ cd /tmp/r1
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head

除了在所有树中搜索直到找到匹配的哈希值之外,没有。

虽然Dav认为信息没有直接存储是正确的,但这并不意味着你永远都找不到。这里有一些你可以做的事情。

查找提交所在的分支

git branch -a --contains <commit>

这将告诉您其历史中具有给定承诺的所有分支。显然,如果提交已经被合并,这就不太有用了。

搜索回流

如果您正在进行提交的存储库中工作,可以在reflog中搜索该提交的行。gitgc会删除90天以上的反射,因此如果提交时间太长,您将找不到它。也就是说,您可以这样做:

git reflog show --all | grep a871742

找到提交a871742。请注意,您必须使用提交的缩写7个第一位数字。输出应该是这样的:

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite

表明提交是在分支“完成”时进行的。默认输出显示缩写的提交哈希值,因此请确保不要搜索完整的哈希值,否则将找不到任何内容。

git reflog show实际上只是git log-g--abbrev commit--prett=oneline的别名,因此如果您想修改输出格式以使grep可以使用不同的内容,这就是您的出发点!

如果您不是在进行提交的存储库中工作,那么在这种情况下,您所能做的最好的工作就是检查reflog并查找提交首次引入存储库的时间;幸运的是,您获取了它提交到的分支。这有点复杂,因为您不能同时遍历提交树和reflog。您可能需要解析reflog输出,检查每个哈希,看看它是否包含所需的提交。

查找后续合并提交

这取决于工作流,但对于良好的工作流,在开发分支上进行提交,然后将其合并到中。您可以这样做:

git log --merges <commit>..

以查看将给定提交作为祖先的合并提交。(如果提交只合并了一次,那么第一次应该是您要进行的合并;否则,我想您必须检查一些。)合并提交消息应该包含合并的分支名称。

如果您希望能够做到这一点,您可能需要使用--noff选项来gitmerge,以强制创建合并提交,即使在快进情况下也是如此。(不过,不要过于急切。如果过度使用,这可能会让人困惑。)VonC对相关问题的回答有助于阐述这一主题。

这个简单的命令就像一个符咒:

git名称rev<SHA>

例如(其中测试分支是分支名称):

git name-rev 651ad3a
251ad3a remotes/origin/test-branch

即使这样也适用于复杂的场景,例如:

origin/branchA/
              /branchB
                      /commit<SHA1>
                                   /commit<SHA2>

这里git-namerev-commit<SHA2>返回branchB。