可视化git分支依赖性

时间:2019-06-04 23:46:11

标签: git branch git-log

是否有工具可以显示特定分支已合并到的分支?例如,如果“ A”已合并为“ B”和“ C”,但未合并为“ D”,那么我如何输出“ B”和“ C”?我只需要分支名称。

2 个答案:

答案 0 :(得分:4)

重要的是要在这里意识到分支名称实际上并没有任何意义。

分支名称只是指向提交的标签或指针。可以将它们视为黄色粘滞便笺之一,甚至sticky arrows,您可以将其粘贴到提交上。重要的是 commit 。提交的身份是其哈希ID。提交是永久性的 1 且不可更改,并且每个提交都记录其直接父级(大多数提交)或父级(对于合并提交,大于或等于2)的哈希ID。这就是产生 commit图的原因,除了您始终可以对其进行 add 之外,它与提交本身一样永久且不可更改。

由图本身确定存储库的实际“分支”:

(older commits towards the left, newer ones towards the right)

          o--A
         /
...--o--o
         \
          o--o--B

该图的特定部分显示了两个分支,以两个 tip提交 AB结尾。在A之后添加新的提交将使我们C记住A作为其父节点:

          o--A--C
         /
...--o--o
         \
          o--o--B

如果我们现在添加合并提交-我们将其M称为“合并”-父母都是 C B,我们得到:

          o--A--C
         /       \
...--o--o         M
         \       /
          o--o--B

要记住AB或同时记住CB都需要两个标签(两个粘滞箭头),但是现在我们有了{{ 1}},我们可以处理其中一个标签,而只需留一个指向M本身的粘滞便笺箭头即可:

M

这就是分支名称的作用和作用:它是一个指向一个提交的指针,Git将其视为向后的 tip 提交的提交链。当Git向后工作时,从该技巧提交开始,Git将遍历合并的所有分支,以查找可以通过向后工作而到达的所有提交。由于 o--A--C / \ ...--o--o M <-- branch \ / o--o--B 有两个父母MC,因此Git将访问提交B,然后访问C,依此类推,依次访问A和全部提交到B的左侧。

我们当然可以使标签指向B和/或A和/或B

C

如此图中所示,标签不必是分支名称。分支名称的特殊功能是,通过使用 .... <-- tag: v1.0 . . o--A--C / \ ...--o--o M <-- branch \ / o--o--B <-- feature “进入”分支,我们所做的任何 new 提交都会自动更新名称以指向新的提交。新的提交将指向先前的提交。

这也是git checkout name背后的概念。由于提交git branch --contains与提交{{1}相比是可访问的,因此从B开始并向后退一步,M将打印名称{{1 }}。该名称指向Mgit branch --contains specifier-for-B到达B。更一般而言,Git反复询问并回答问题:

  • 提交branch是提交M的祖先吗?

使用M,Git询问有关每个分支名称的每个分支提示提交的问题:

B

如果X是类似于Y的分支名称,则将其转换为哈希ID的操作将选择提交git branch --contains anything that finds some commit的哈希ID。然后,将target=$(git rev-parse $argument) || exit 1 git for-each-ref --format='%(refname)' refs/heads | while read fullbranchname; do branchtip=$(git rev-parse $fullbranchname) if git merge-base --is-ancestor $branchtip $target; then echo "branch ${fullbranchname#refs/heads/} contains $argument" fi done 转换为哈希ID的操作将选择$argument的哈希ID,然后branch回答问题是commit M的提交者{{ 1}} (确实如此)。 2

您要问的问题稍微复杂一点:您想要为每个分支名称不仅确定该分支的尖端提交是否在某些选定分支的尖端提交之前(就像refs/heads/feature一样),对于每个这样的分支名称,还,哪个是较高祖先的,哪个是较小祖先的。这个问题 可以回答,但仅在某些情况下

例如,考虑以下图表:

B

我认为您希望将git merge-base --is-ancestor称为“ B之后”,因为引入M提示的合并提交位于引入提示的合并提交之后git branch --contains中的一个。 3 但是合并并不总是将两个 提交放在一起。 4 考虑:

...--o--o--o--o---M1--M2-o   <-- master
      \     \    /   /
       \     o--o   /  <-- feature1
        \          /
         o--o--o--o   <-- feature2

现在没有明显的顺序:feature2feature1都是通过一次提交同时引入的。

(当然,如果我们删除两个feature2名称中的一个,就可以解决问题。如果我们删除两个 名称,则可以解决更多问题!?)


1 可以通过删除对提交的所有访问 来删除提交。 Git从已知的名称(分支和标签名称,以及所有其他形式的引用)开始,并向后遍历图形。如果向后工作到达提交,则必须保留该提交。如果不是,则提交可以删除。除了显而易见的名称以外,还有其他名称通常可以使提交至少存活30天。

2 我们可以消除feature1调用,因为 o--o--o <-- feature1 / \ ...--o--o--o--o---M1--o <-- master \ / o--o--o <-- feature2 接受分支名称代替哈希ID。给定名称后,它仅以feature1相同的方式查找提交哈希。我把它们主要用于说明。

3 您必须编写自己的代码才能产生这种排序。请注意,它不像比较各个分支的尖端提交那样简单。我们需要知道哪些合并(如果有的话)引入这些技巧,并比较合并。我们还必须考虑通过将其尖端嵌入非合并y子图中而形成的分支:

feature2

在这里,我想我们要声明feature

4 即使在一对一对的合并情况下,您也可以将某些提交与某些主线重复合并,这使问题产生麻烦( are < / em>可能的排序,但是您必须选择某种图形遍历算法才能在此处选择总订单)。本质上,请记住,当您使用DAG时,您正在处理poset

答案 1 :(得分:3)

如果您是指图形工具,那么gitk似乎是一个不错的起点。

或者,您可能更喜欢对于某些需求非常有用的CLI,请尝试一下:

git log --oneline --decorate --simplify-by-decoration --graph --all

要更具体地解决问题“如何知道哪些分支合并到分支A中?”

git branch --contains A