【问题标题】:What git commit practice is better?什么 git commit 实践更好?
【发布时间】:2013-03-11 07:06:25
【问题描述】:

我真的相信对一个问题进行一次提交是一种很好的做法。我确定我在“最佳实践”之类的文章中某处读过它。

因此,我的工作流程如下:

  • 对于一个新问题,我使用git checkout -b new-issue 创建一个新的本地分支。
  • 提交所有更改。有时这涉及到 很多 次提交。
  • 完成后,我将squash 提交和rebase 提交到当前主题分支。
  • 如果出现问题,我可以git revert 提交,找到错误,修复它,然后将新补丁提交到主题分支。我不会更改远程存储库的历史记录。

但今天,我很惊讶听到以下工作流程:

  • 为新问题创建新分支。
  • 提交所有内容。
  • 使用merge --no-ff 将问题分支与主题分支合并(这样我们就可以使用revert 的“合并提交”)。
  • 如果出现问题,我们可以使用git bisect 查找错误。

根据第一种方法,我们将拥有一个干净的 git 历史记录,并且不知道开发期间使用的开销分支。

根据第二种方法,我们将有一个非常混乱的历史记录,其中包含许多丑陋的、不必要的合并和提交,仅针对一个问题。但是,我们可以使用git bisect 来查找错误。 (也许这更适合重构?)


  • 您认为这两种方法的优缺点是什么?

  • 您使用哪种方法,为什么?

  • 在实践中,你真的使用git bisect 来查找错误吗? (我没有……)

【问题讨论】:

  • 您可以使用git log--first-parent 选项来隐藏合并分支上的单个提交。一点也不乱。

标签: git merge commit rebase bisect


【解决方案1】:

第二种方法不必有很多丑陋和不必要的合并和提交。这是我更喜欢做的:

  1. 新建主题分支
  2. 进行一堆提交
  3. 就在合并回父分支之前,清理提交:
    • 重新定位到最新版本的父分支
    • 壁球错字修复提交
    • 将同时执行多项操作的提交拆分为单独的提交
    • 对提交重新排序,以便审阅者更容易理解更改顺序
  4. --no-ff合并到父分支中

上述步骤会产生如下所示的历史记录:

*   354b644 Merge branch 'topic3'
|\
| * 54527e0 remove foo now that it is no longer used
| * 1ef3dad stop linking against foo
| * 7dfc7e5 wrap lines longer than 80 characters, no other changes
| * b45fbcf delete end-of-line whitespace, fix indendataion
|/
*   db13612 Merge branch 'topic2'
|\
| * 961eebf unbreak build by adding a missing semicolon
|/
*   a5b6b16 Merge branch 'topic1'
|\
... (more history not shown)

上图具有方法#1的所有相同优点:

  • 您可以使用git log--first-parent 参数来获得类似于方法#1 的简洁摘要:

    * 354b644 Merge branch 'topic3'
    * db13612 Merge branch 'topic2'
    * a5b6b16 Merge branch 'topic1'
    ... (more history not shown)
    
  • 您仍然可以轻松检查在主题分支中所做的全部更改。例如,git diff 354b644^..354b644 将显示主题 #3 的更改内容。

但是您可以获得方法#1 无法给您的好处:

  • 历史记录非常更容易查看:提交b45fbcf7dfc7e5(对于topic3 分支)引入了很多噪音,但没有实际的逻辑更改。有人试图回答这个问题,“对主题 #3 进行了哪些逻辑更改?”如果所有这些提交都被压缩成一个,那么可能很难从噪音中挖掘出来。
  • 合并提交很好地识别了合并分支上一系列提交的上下文(例如,这组提交是为了解决主题 #3)。
  • 更精细的提交粒度可以更轻松地找出进行特定更改的原因,这有助于区分意外更改和有意但微妙的更改。
  • 如果多个人在分支机构中进行协作,您可以看到他们都是谁以及每个人贡献了多少。
  • 合并主题分支上的提交次数让您大致了解更改了多少。
  • 提交的时间范围可以提供有用的上下文。
  • 您可以轻松地挑选对不同分支进行的特定更改(例如,挑选将错误修复到发布分支所需的最小更改)。

我能想到一个缺点:可能很难将您的软件开发工具配置为仅遵循第一父路径并忽略所有这些中间提交。例如,there is no --first-parent argument to git bisect。另外,我对 Jenkins 不够熟悉,不知道配置它以优先构建和测试第一父路径而不是所有其他提交是多么容易。

【讨论】:

    【解决方案2】:

    归根结底,这很大程度上是个人品味问题……只能解释我的品味(并给出一点理由)。

    我倾向于保留单个提交,即使它们只是“修复愚蠢的错别字”。任何“历史重写”都会创建以前从未存在过的提交,因此保证从未经过测试。此外,最小的提交使git bisect 在稍后出现错误时非常有用。最好能够将其缩小到几行更改,而不是把一周的工作挤在一起。

    如果一个开发分支的历史记录一团糟,我会清理它(最低限度,即从未发生过恢复的提交,诸如空格或变量重命名之类的一般修复可能会更早地应用,一些重新排序将相关更改放在一起)。提交仍然很小,很少被压扁。这种清理我主要是逐步进行的。然后我将清理后的分支与“官方”分支合并(或变基)。

    【讨论】:

    • 你用过git bisect吗?另外,假设我正在为其中一个项目开发新模块,我做了很多提交并将它们保存在历史记录中。当我在其他项目中需要这个模块时,我会复制它并只创建一个提交。
    • @viakondratiuk,不经常。但是当我需要找出是什么破坏了一个完美的构建时,它让我能够在几次尝试中找到罪魁祸首。我从未尝试过手动查看。
    猜你喜欢
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 2011-07-07
    • 2011-02-14
    • 2011-12-04
    • 2011-02-05
    • 2022-10-20
    相关资源
    最近更新 更多