如何在git中获得更多有用的分支图?

时间:2013-05-09 16:54:11

标签: git

我有时很难尝试查看git存储库历史中发生的事情,即使使用像SourceTree这样的优秀工具,分支图也会令人困惑。对我来说,主要的问题是我无法分辨哪些分支是在哪些分支上进行的,并且单个分支上的提交字符串通常显示在不同的视觉行上,因为并发分支和在分支上工作的人数增加和减少

我最初的想法是“如果git存储了提交的分支名称怎么办?那么图表生成器可以将这些提交分组到同一行”。这个问题:Why does Git not store the branch name as part of the commit?问同样的事情(但由于不同的原因),在阅读它和其他一些链接之后,我意识到简单地存储分支名称无论如何也无法解决我的问题。例如,当多个人在其本地分支上使用相同的分支名进行交替提交时,尝试在同一行上显示这些提交在技术上是错误的。

无论如何,等我的问题......

  1. 目前是否有办法推断出正确的历史分支结构并生成一个漂亮的图表 - 也许正在寻找“merge master into branchX”样式提交消息?
  2. git中的某个功能是否有一个有效的案例,有助于保留一些工作流信息(即完成该工作的上下文),或者这已经是可能的,我只是做错了吗?

  3. 关于问题2:我想的可能是一个名为“工作流”的东西。创建分支时,您可以选择提供工作流名称(或从当前分支的工作流名称“继承”),并且在切换分支时,当前工作流也会发生变化。因此,每个提交都将在工作流的上下文中进行,并且该信息可以存储在提交中,也可以作为单独的元数据存储在git仓库中。我真的不知道git的内部工作方式,所以可能有其他/更好的方法来实现这一点。然后,分支图可以做一些视觉上明显的事情(例如不同的背景颜色),以帮助查看提交链如何在不同的工作流之间流动。

1 个答案:

答案 0 :(得分:8)

请记住,git是自称为"愚蠢的内容跟踪器。"它不希望变得比它需要的更聪明,因为这使它保持高度灵活性,因此非常强大。提交自己只是文本文件,仅此而已。它们看起来像这样:

tree 68cd5b298858425fd8b5c2c0adfa62249b4eb650
parent c9ac0bb0d74d59b1ccb5aa8c498c33314b16948e
author aperson <aperson@somecompany.com> 1368010332 -0700
committer aperson <aperson@somecompany.com> 1368010332 -0700

Add test module for widget.py

tree指向列出项目文件夹内容的散列文本文件,此列表可以包含递归的其他树和blob s,它们是文件的散列内容。 parent只是另一个提交的哈希 - 这也是另一个像这样的文本文件。作者和提交者行也有Unix时间戳和GMT偏移量。文件的其余部分是提交消息。提交 - 文本文件 - 回答关于自身的5个元问题:谁(作者/提交者),什么(指向树的指针),何时(时间戳),何处(父提交)以及为什么(提交消息) 。 treeparent(父级可以有多行父级来表示合并提交)是指针。他们说&#34;那棵树描述了这个提交的快照,&#34;和#34;提交/提交是它来自的地方。&#34;

可以理论上保留分支名称,但分支也只是指针。如果您在主分支上,那么master中有一个名为.git/refs/heads的文本文件,其中包含用于命名您的提交的哈希值(即40位数字)。目前重新开始。您在该分支上的事实(也称为&#34; head&#34;)只是.git/HEAD文本文件中的一行 - 也是指针 - 读取ref: refs/heads/master,它只指向masterheads文件夹中的refs文件名。它只是指针,但更重要的是,它都非常流畅。

Git希望对于分支来说太愚蠢了。最初创建的一个提交分支是非常有用的 - 或者更好的放置,是一个太不稳定的东西,试图使其有用 - 因为你可以随意移动提交。我经常这样做是为了得到我想要的东西。

我意识到我在项目分支上来回进行一般性和特定于项目的提交 - 让我们称之为mixedbranch - 项目的东西应该是它自己的分支,所以我交互式地重新定位以解压缩它们。即我做了git branch projectname添加第二个分支头,指向mixedbranch指向的同一个提交(但没有切换到它),然后git rebase -i <commit before I started mixing things>。然后在弹出的文本编辑器中,我删除了所有项目特定的提交行,保存并退出。这在当前名称下重建了分支,但是没有基于项目的提交(保持提交的细节足以容易地实现这一点,出于以下几个原因)。

然后我做git checkout projectname切换到新的分支头,它仍然在所有混合提交的尖端保持位置,我反过来做了同样的事情 - git rebase -i <that same old commit before the mixing occurred>,但删除了这次是非项目特定行。这使用原始分支提交重建了新分支,没有进行非项目提交,并将projectname指向新重定位的头部。既然两个分支都没有指向原始的交错提交集,它们都从视图中消失了,看起来a-a-b-b-a-b-b-a-b-a<--mixed只是a-a-a-a<--nonmixedb-b-b-b-b<--project。存储最初创建的分支内容现在将变得一团糟。它也是&#34;聪明&#34;一个值得信赖的东西,所以git - &#34;愚蠢的内容跟踪器&#34; - 甚至不尝试。

在跟踪分支上的提交跟踪方面,所有这些都是向后完成的,因为提交 - 那些文本文件 - 只是存储对其父级的引用。你只能弄清楚过去的血统。合并时,您将创建一个新提交,它只是整个合并树的快照。您当前处于(或以其他方式合并)的分支被视为第一个父分支,而合并分支是第二个分支。如果还有其他分支被合并,那么它们就是第三个,第四个等等。通过这种方式,git可以轻松地跟踪主要提交,以便跟踪 - 并在视觉上指示 - 提交的是哪些提交,比如说,主分公司。切换到分支并进行提交时,然后执行git log --oneline --graph --decorate --all,你会看到类似这样的内容(来自Vim easymotion插件):

* 4fb1af8 (origin/develop, develop) Update jumplist when moving cursor
*   fe9f404 Merge branch 'master' into develop
|\  
| *   667a668 (HEAD, tag: 1.3, origin/master, origin/HEAD, master) Merge pull request #34 from Layzie/master
| |\  
| | * 06826d7 fix EasyMotion#InitHL arguments
| |/  
| *   afd0e42 Merge branch 'release/1.3'
| |\  
* | \   44c6bfd Merge branch 'release/1.3' into develop
|\ \ \  
| | |/  
| |/|   
| * | c4863f8 Update vim docs
| * | 8dc93e6 Update README
|/ /  
* | c1f1926 Update default leader key to <Leader><Leader>
* | 6f0c9b9 Move most of the code to autoload/

即使没有颜色的好处,也很容易看出发生了什么。开发分支是最近承诺的,所以它在顶部显示。如果您按照图表左侧的行,则这些是developorigin/develop分支的主要提交。所有&#39;合并&#39;分支从右边进来。 develop分支具有合并提交,其中合并了master。您可以将该合并的右侧跟随到主分支(667a668),这也是合并提交,其中拉入Layzie/master06826d7),这显然是在afd0e42之上开发的(显然位于master分支上(按照直线向上看第一个 - master的父提交包括它) - 所有必要的上下文都在图中)。合并提交(667a668)告诉你哪个分支 - 它是Lazie / master,所以06826d7是来自master远程仓库的Layzie分支。

这是我建议工作流习惯的地方 - 在合并时留下有关合并内容的提交消息。 那是你怎么可以 - 而且应该,IMO - 知道哪些提交哪些分支(当前的头是告诉哪些提交当前的机制在哪个分支上)。合并说&#34;在我的左边是我合并的分支的目标分支。右边是我合并的分支。在我的提交消息中是分支I&的名称#39; m合并在我将其合并到&#34; (这里暗示的重要一点是:你可以在工作时随意替换分支名称,我经常这样做。)

通过不将分支名称作为提交的一部分,您可以cherry-pickrebase周围的事情,而无需尝试推断不断变化的提交位置,这太难了,而且没有帮助。提交只是一个完整的树快照,包含一些关于谁创建它的元数据,何时以及它在何处适合互连提交的dag。这使您可以从其他分支,甚至其他人的回购中提取提交。我已经使用这个功能将完全不同的repos合并在一起,将提交交错在一起(与我在第一个例子中提到的相反)。我已经使用这种能力将特定文件的历史记录从另一个仓库中提取到一个新的分支上,然后将其合并,这样我就可以在一个更合理的地方跟踪它的发展。然后我扔出了原本的,垃圾填充的回购,我不再想要了。你可以在这里看到一些例子,说明git的提交是如何提交的,以及你可以用它做多少。

如果我cherry-pick来自同事的承诺,那就是{&#39;}分支,我不在乎它在coworker/dev上。我只想在我目前的分支中工作。提交元数据将显示我将其提交到现在的位置,并且我的同事创作了它,当我们每个人都做了这些事情。现在它只是我的分支上的变化,它们并没有试图弄清楚它们是在我的分支上,而是曾经在他们的分支上。在这样一个灵活的系统中试图跟踪它会很麻烦,而且你可能最终得到的信息不正确,系统试图变得那么聪明(可能不是,但这似乎是一个难题)。我说让合并告诉你想要分支被调用,让git为你排序第一父历史。我可以说,我一次跟几十个分支机构的历史记录没有任何问题(我们在工作时有很多并行分支,它们不适合宽屏显示器)。