git - 什么 git commit 实践更好?

标签 git merge commit rebase bisect

我坚信在一个问题上做出一次 promise 是一种很好的做法。我确信我在“最佳实践”之类的文章中的某个地方读到了它。

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

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

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

  • 为新问题创建新分支。
  • 全力以赴。
  • 使用 merge --no-ff 将问题分支与主题分支 merge (这样我们就有了可以还原的“merge-commit”)。
  • 如果出现问题,我们可以使用 git bisect 来查找错误。

根据第一种方法,我们将拥有干净的 git 历史记录,并且对开发过程中使用的开销分支一无所知。

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


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

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

  • 在实践中,你真的用过git bisect来找bug吗? (我没有……)

最佳答案

第二种方法不必进行大量丑陋和不必要的 merge 和提交。这是我喜欢做的:

  1. 创建一个新的主题分支
  2. 做一堆提交
  3. 在 merge 回父分支之前,清理提交:
    • rebase 到父分支的最新版本
    • 挤压错字修复提交
    • 将一次做多件事的提交拆分成单独的提交
    • 重新排序提交,使审阅者更容易理解更改的顺序
    • 等等
  4. --no-ff merge 到父分支

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

*   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 的所有相同优点:

  • 您可以使用 --first-parent 参数到 git log 来获得类似于方法 #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 做了哪些逻辑更改?”如果将所有这些提交都压缩成一个,可能很难从噪音中挖掘出来。
  • merge 提交很好地标识了 merge 分支上一系列提交的上下文(例如,这组提交是为了解决主题 #3)。
  • 提交的粒度越细,就越容易找出进行特定更改的原因,这有助于区分意外更改和有意但微妙的更改。
  • 如果分支机构有多人协作,您可以看到他们都是谁以及每个人贡献了多少。
  • merge 主题分支上的提交数量让您大致了解更改了多少。
  • 提交的时间范围可以提供有用的上下文。
  • 您可以轻松地挑选对不同分支所做的特定更改(例如,挑选将错误修复到发布分支所需的最小更改)。

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

关于git - 什么 git commit 实践更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15553172/

相关文章:

r - 合并和删除*文件之间的冗余行

python - pd.merge 时处理空值

repository - Bitbucket 获取有关存储库所有提交的信息

svn - 如何防止 Subversion 在没有注释的情况下提交?

git-p4 克隆单个文件

c++ - 从 github 编译 c++ boost 库时出错

javascript - 合并具有相似值的数组,保持内部值的顺序

git clone git hooks 中的不同存储库造成麻烦

Git:忽略跟踪文件

git - 在多个分支中处理对 Jenkinsfile 的常见更新