关于 Git 提交,我知道的 89 件事

This is an article that's been swimming around in my head for ~5 weeks now, and may become a "living post" that I keep updated over time.

In no particular order, some things I've learned about Git commits and commit history, over the last 12 years. This is a mix of experience in companies with teams of 2-12 people, as well as in Open Source codebases with a vast range of contributors.

  1. Git has different uses - a collaboration tool, a backup tool, a documentation tool

  2. Git commit messages are excellent

  3. I've never met anyone who likes reading commit messages as much as me

  4. Finding out why a change was made is easier sorting through commits than it is through an issue/bug tracker

  5. It's better to have a commit that says "Various fixes. DEV-123" than it is to have "Various fixes"

  6. It's worse to have a commit that says "Various fixes. DEV-123" when the issue itself has no useful information

  7. Rebase-merging is my preference. Then squash-merge, then merge

  8. If you don't learn how to rebase, you're missing out on a good skill

  9. People who say "just delete the repo" when things go wrong really frustrate me

  10. Learn how to use git reflog, and it'll save you deleting a repo and work that was recoverable

  11. Learn how to use git reflog, and you'll be able to save yourself from mistakes that aren't that bad

  12. No amount of learning fancy tools and commands saves you from fucking up every once in a while

  13. My most recent botched rebase was last week, and I needed git reflog to help un-fuck it

  14. Learn how to undo a force push and then how to more safely force push (remember the =ref!!)

  15. Squashing is a waste of well-written atomic commits

  16. Squashing is better than 100 crap commits

  17. Squashing, and writing a good commit message at the time of merge is good

  18. Squashing, and then not re-editing the message is the worst

  19. Squashing, when you have 100 crap commits, and then not re-editing the message is a crime

  20. Squashing, and then not re-editing the message is worse than a merge commit from a branch with 100 crap commits

  21. Writing a well documented PR/MR description but not using that to inform the squash-merge message is a waste of time

  22. Writing commit messages have helped me pick up on missing test cases, missing documentation, or invalid thought processes, as it helps me rewrite why the changes are being made

  23. Using your git log as an indication for standup updates is valid

  24. I can't be bothered to sign my commits (unless I'm forced to)

  25. If I have to sign my commits, SSH key signing makes it almost not awful

  26. If you're moving files between repos, you need to keep the history intact, using git subtree

  27. Commits should be atomic - all the code and tests, and configuration changes should all be in there

  28. I spend a good chunk of time ensuring that each commit passes CI checks atomically

  29. Some people do horrific things, like split their implementation and test code from each other

  30. It's OK to put documentation in a separate commit - we don't have to have a whole end-to-end feature delivery in a single commit

  31. Repos that use squash-merges suck

  32. As a maintainer of Open Source projects, I like squash-merge, so I can rewrite contributors' commit messages

  33. Sometimes it's not worth coaching how to write a given commit message

  34. The people around you shape the way you write commits

  35. Do the work up front to make your history atomic

  36. It's much more painful to split a mega-commit into atomic commits after the fact

  37. Splitting work atomically can be good for improving your reward drive - you can get many more things done

  38. Atomic commits work really well with prefactoring

  39. Sometimes prefactor commits can go into separate PRs (especially if squash-merge is used)

  40. Writing commit messages can take longer than the implementation

  41. The commit message can be an order of magnitude larger than the number of lines changed in a commit

  42. If you end up writing a lot of "and"s or "also" in a commit message, you may be trying to do too many things

  43. Trawling through Git commit history in the past has helped unlock a number of cases where I could then understand the why without the original authors there to answer my questions

  44. Commit messages are a great point to reflect on not just what you've done, but why

  45. Why is more important than what - anyone can look at the diff and generally work out what changes were made, but the intent behind it is the special sauce

  46. If you only write what changed, you're annoying, and I dislike you

  47. A commit that explains what is better than a commit that just has "fixes"

  48. Chris Beams' article, How to Write a Git Commit Message is still an excellent post and a great place to start, just under 10 years later!

  49. Commits are a point-in-time explanation of the assumptions and the state of the world for the committer. Don't be too hard on them

  50. I don't want to read AI/LLM rewrites of your changes - either write it yourself, or call it Various fixes

  51. There needs to be a way to add an annotation (maybe using git notes) to a previous message to correct assumptions

  52. I won't write perfect commit messages up front - they'll sometimes be as much as rew! add support for SBOMs or sq, or use git commit --fixup

  53. I will, generally, break off very good atomic chunks of work into commits

  54. I will split atomic commits into multiple commits, sometimes

  55. Make sure you review your own code changes before you send it out for review to your collaborators

  56. Reviewing your commit messages should be as important as reviewing the code changes

  57. Getting all your contributors to invest the same amount of care into the commit history is a losing battle

  58. Trying to police commit history is going to be painful

  59. Trying to mandate reviews of commit messages as part of code review is going to be painful

  60. Trying to police commit history does lead to a greater level of documentation and consideration around changes int he codebase

  61. Making implicit assumptions explicit is really useful

  62. Introducing commitlint can be useful, but also frustrating

  63. It's nicer to have your collaborators want to write good commit messages than you having to force them

  64. Some people don't write, and that's alright

  65. Writing is a skill

  66. I'm not perfect at writing (commit messages)

  67. Sometimes I can't be arsed to write the perfect message

  68. Sometimes I write some really great commit messages, and impress myself

  69. Using a template for your Git commit messages is a good nudge to doing it right

  70. fixup commits and git rebase --autosquash has been one of the best Git tips I've learned

  71. I value working on a team with a diverse set of perspectives, skills and approaches to work

  72. But I also really value having a team who writes atomic commits with well-written commit messages

  73. Commit message writing is as useful as writing well-refined user stories/tickets

  74. git commit -m sq is probably my most-run command

  75. Using git add -p and git commit -p are hugely important for atomic commits

  76. Never use git add -u or git add .

  77. Learn when you can use git add -u or git add .

  78. I really need to look into tools like Graphite, git-branchless and other means to provide a stacked PR setup

  79. Using conventional commits with semantic-release or go-semantic-release can make a huge difference when wanting to release automagically and often

  80. Using conventional commits as a framework for your commits can be really useful

  81. Using conventional commits, as someone with ADHD, reduces the need for thinking at times and can allow you to focus more on what the changes are

  82. Using conventional commits helps you work out when you're trying to do too much in a commit

  83. I think through writing so commit messages help understand why I did the thing

  84. It can be better to write a good commit message than a piece of documentation, stored elsewhere

  85. It can be better to write a good commit message than a code comment

  86. Give people space to learn

  87. Give people space to fail

  88. Remember you weren't so great at one point in time

  89. Documentation is rad. Do more of it


这篇文章已经在我脑海中盘旋了大约 5 周,也许会成为我的 "活文章",随着时间的推移不断更新。

在过去的 12 年里,我学到了一些关于 Git 提交和提交历史的东西,排名不分先后。这其中既有在拥有 2-12 人团队的公司工作的经验,也有在拥有众多贡献者的开源代码库工作的经验。


Git 有多种用途--协作工具、备份工具、文档工具

Git 提交信息非常棒

我从未见过像我这样喜欢阅读提交信息的人

比起问题/错误跟踪器,通过提交信息更容易找出修改的原因

写着 "Various fixes. DEV-123" 而不是 "各种修正"。

更糟糕的是,如果提交的内容是 "各种修复。DEV-123",而问题本身却没有任何有用的信息

我更倾向于重置合并。然后粉碎-合并,然后合并

如果你不学习如何重置,你就错过了一项很好的技能

出了问题就说 "删除仓库就好了 "的人真让我沮丧

学习如何使用 git reflog,你就不会再删除 repo 和原本可以恢复的工作了。

学会使用 git reflog,你就能从一些并不严重的错误中解脱出来

学习再多花哨的工具和命令,也免不了偶尔犯错

我最近一次失败的重置是在上周,我需要 git reflog 来帮我解除错误。

学习如何撤销强制推送,然后更安全地强制推送(记住 =ref!!)。

压制是对精心编写的原子提交的浪费

挤压提交胜过 100 次垃圾提交

挤压,并在合并时写好提交信息是件好事

挤压,然后不重新编辑提交信息是最糟糕的

挤压,当你有 100 次垃圾提交时,不重新编辑提交信息就是犯罪

挤压,然后不重新编辑信息,比从有 100 条垃圾提交的分支合并提交更糟糕

写一份文档齐全的 PR/MR 说明,但不用来为压扁合并信息提供信息,这简直是浪费时间

撰写提交信息能帮助我发现遗漏的测试用例、遗漏的文档或无效的思维过程,因为它能帮助我重写更改的原因。

使用 git 日志作为站立更新的指示是有效的

我懒得签署我的提交(除非被迫签署)

如果我不得不签署提交,SSH 密钥签名几乎就不可怕了

如果要在版本库之间移动文件,需要使用 git subtree 保持历史记录的完整性

提交应该是原子性的--所有代码、测试和配置变更都应该在里面

我花了很多时间确保每个提交都以原子方式通过 CI 检查

有些人会做一些可怕的事情,比如把实现代码和测试代码拆分开来

将文档放在单独的提交中也没关系--我们不必在一次提交中完成整个端到端的功能交付

使用压扁合并的版本库很糟糕

作为开源项目的维护者,我喜欢压扁合并(squash-merge),这样我就可以重写贡献者的提交信息了。

有时不值得指导如何编写特定的提交信息

你周围的人塑造了你撰写提交的方式

事先做好工作,使你的历史记录具有原子性

事后再将巨型提交拆分成原子提交会痛苦得多

以原子方式拆分工作有利于提高你的奖励驱动力--你可以完成更多事情

原子提交与预编译配合得天衣无缝

有时,前置因子提交可能会进入不同的 PR 中(尤其是在使用 squash-merge 的情况下)

编写提交信息的时间可能比执行时间更长

提交信息可能比提交中更改的行数大一个数量级

如果在提交信息中写了很多 "and "或 "also",可能是想做的事情太多了

在过去,通过翻阅 Git 的提交历史,我发现了很多情况,在没有原作者回答问题的情况下,我也能理解其中的原因。

提交信息是一个很好的反思点,不仅能让你反思做了什么,还能反思为什么要这么做

为什么比做了什么更重要--任何人都能通过查看差异大致了解做了哪些改动,但背后的意图才是关键所在

如果你只写 "修改了什么",你就很烦人,我也不喜欢你。

一个能解释 "改了什么 "的提交比一个只有 "修正了什么 "的提交要好得多。

Chris Beams 的文章《如何撰写 Git 提交信息》(How to Write a Git Commit Message)在不到 10 年后的今天仍然是一篇优秀的文章,也是一个很好的开始!

提交是对提交者的假设和世界现状的时间点解释。不要对它们太苛刻

我不想看人工智能/LLM 对你的改动进行的重写--要么自己写,要么称之为各种修正

需要有一种方法在之前的信息中添加注释(也许可以使用 git 注释)以纠正假设

我不会在前面写出完美的提交信息--它们有时就像 rew!添加对 SBOM 或 sq 的支持,或者使用 git commit --fixup

一般来说,我会把非常好的原子块工作分解成多个提交

我有时会将原子提交拆分成多个提交。

确保在发送给协作者审核之前,先审核自己的代码变更

审核提交信息与审核代码修改同样重要

让所有贡献者对提交历史投入同样的关注是一场失败的战斗

管理提交历史会很痛苦

将审查提交信息作为代码审查的一部分会很痛苦

尝试对提交历史进行监管确实会提高文档记录的水平,并对代码库中的变更进行更多的考虑

明确隐含假设非常有用

引入 commitlint 可能有用,但也可能令人沮丧

让你的合作者愿意写出好的提交信息比你强迫他们写更好

有些人不会写,没关系

写作是一种技能

我并不擅长写作(提交信息)

有时我懒得写出完美的信息

有时我会写一些非常棒的提交信息,给自己留下深刻印象

使用模板来写 Git 提交信息,对写好提交信息很有帮助

fixup commitits 和 git rebase --autosquash 是我学到的最好的 Git 技巧之一。

我很重视在一个拥有不同观点、技能和工作方法的团队中工作

不过,我也非常看重拥有一支能编写原子提交和精心撰写提交信息的团队

撰写提交信息和撰写精炼的用户故事/项目一样有用

git commit -m sq 可能是我用得最多的命令

使用 git add -p 和 git commit -p 对原子提交非常重要

永远不要使用 git add -u 或 git add .

了解何时可以使用 git add -u 或 git add 。

我真的需要研究一下 Graphite、git-branchless 等工具,以及其他提供堆栈式 PR 设置的方法。

使用常规提交和语义发布或 go-semantic-release 可以在自动发布和频繁发布时带来巨大的不同。

将常规提交作为提交框架非常有用

作为多动症患者,使用常规提交可以减少思考的时间,让你更专注于修改的内容

使用常规提交可以帮助你找出在提交中试图做得太多的地方

我通过写作来思考,因此提交信息有助于理解我为什么要这么做

写一条好的提交信息可能比保存在别处的文档更好

写一条好的提交信息可能比写一条代码注释更好

给人们学习的空间

给人们失败的空间

记住你曾经不那么伟大

文档很重要。多做文档


相关文章