小编典典

用 Git 寻找分支点?

all

我有一个带有分支 master 和 A 的存储库,并且两者之间有很多合并活动。当基于 master 创建分支 A 时,如何在我的存储库中找到提交?

我的存储库基本上是这样的:

-- X -- A -- B -- C -- D -- F  (master) 
          \     /   \     /
           \   /     \   /
             G -- H -- I -- J  (branch A)

我正在寻找修订版 A,这不是git merge-base (--all)找到的。


阅读 137

收藏
2022-03-09

共1个答案

小编典典

我一直在寻找同样的东西,我发现了这个问题。谢谢你的提问!

但是,我发现我在这里看到的答案似乎并没有完全给出您要求的(或我正在寻找的)答案——它们似乎给出了G提交,而不是A提交。

所以,我创建了以下树(按时间顺序分配的字母),所以我可以测试一下:

A - B - D - F - G   <- "master" branch (at G)
     \   \     /
      C - E --'     <- "topic" branch (still at E)

这看起来和你的有点不同,因为我想确保我得到(参考这张图,而不是你的)B,而不是 A(而不是 D 或 E)。以下是附加到 SHA 前缀和提交消息的字母(我的 repo 可以从这里克隆,如果这对任何人都感兴趣的话):

G: a9546a2 merge from topic back to master
F: e7c863d commit on master after master was merged to topic
E: 648ca35 merging master onto topic
D: 37ad159 post-branch commit on master
C: 132ee2a first commit on topic branch
B: 6aafd7f second commit on master before branching
A: 4112403 initial commit on master

所以,*目标:找到 B*。经过一番修改,我找到了以下三种方法:


1. 视觉上,使用 gitk:

您应该可以直观地看到这样的树(从主视图中查看):

来自 master 的 gitk 屏幕截图

或这里(从主题来看):

来自主题的 gitk 屏幕截图

在这两种情况下,我都选择了B图表中的提交。单击它后,其完整的 SHA 将显示在图形下方的文本输入字段中。


2. 视觉上,但从终端:

git log --graph --oneline --all

(编辑/旁注:添加--decorate也可能很有趣;它添加了分支名称、标签等的指示。不要将其添加到上面的命令行,因为下面的输出不反映它的用途。)

这表明(假设git config --global color.ui auto):

git log --graph --oneline --all 的输出

或者,直接文本:

* a9546a2 从主题合并回主
|\  
| * 648ca35 合并主到主题
| |\  
| * | 132ee2a 第一次提交主题分支
* | | 在 master 合并到 topic 后在 master 上提交 e7c863d
| |/  
|/|   
* | 37ad159 在 master 上的分支后提交
|/  
* 6aafd7f 分支前在 master 上的第二次提交
* 4112403 在 master 上的初始提交

在任何一种情况下,我们都将 6aafd7f 提交视为最低公共点,即B在我的图表中或A在您的图表中。


3.用贝壳魔法:

你没有在你的问题中指定你是否想要像上面这样的东西,或者一个只会让你得到一个修订版的命令,而不是别的。好吧,这是后者:

diff -u <(git rev-list --first-parent topic) \
             <(git rev-list --first-parent master) | \
     sed -ne 's/^ //p' | head -1
6aafd7ff98017c816033df18395c5c1e7829960d

您也可以将其放入您的 ~/.gitconfig 中(注意:尾随破折号很重要;感谢Brian引起了人们的注意)

[alias]
    oldest-ancestor = !zsh -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' -

这可以通过以下(与引号混淆)命令行来完成:

git config --global alias.oldest-ancestor '!zsh -c '\''diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne "s/^ //p" | head -1'\'' -'

注意:zsh可能很容易bash,但sh不会起作用 - vanilla 中<()存在语法sh。(再次感谢@conny,让我在对此页面上另一个答案的评论中意识到这一点!)

注意:上述的替代版本:

感谢liori指出,在比较相同的分支时,上述内容可能会下降,并提出了另一种差异形式,它从混合中删除了 sed 形式,并使其“更安全”(即它返回一个结果(即,最近的提交),即使您将 master 与 master 进行比较):

作为 .git-config 行:

[alias]
    oldest-ancestor = !zsh -c 'diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | head -1' -

从外壳:

git config --global alias.oldest-ancestor '!zsh -c '\''diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | head -1'\'' -'

因此,在我的测试树中(有一段时间不可用,抱歉;它又回来了),它现在适用于 master 和 topic(分别提供提交 G 和 B)。再次感谢 liori,提供替代形式。


所以,这就是我 [和 liori] 想出的。它似乎对我有用。它还允许另外几个可能很方便的别名:

git config --global alias.branchdiff '!sh -c "git diff `git oldest-ancestor`.."'
git config --global alias.branchlog '!sh -c "git log `git oldest-ancestor`.."'
2022-03-09