为什么我执行的每个严肃的Github回购请求都要求我将提交压缩为单个提交?
我以为git日志在那里,所以您可以检查所有历史记录,并确切查看发生了什么更改,但是挤压它会将其从历史记录中拉出来,然后将其全部合并为一个提交。有什么意义?
这似乎也违反了“尽早提交并经常提交”的口头禅。
为什么我执行的每个严肃的Github回购请求都要求我将提交压缩为单个提交?
我以为git日志在那里,所以您可以检查所有历史记录,并确切查看发生了什么更改,但是挤压它会将其从历史记录中拉出来,然后将其全部合并为一个提交。有什么意义?
这似乎也违反了“尽早提交并经常提交”的口头禅。
Answers:
这样您便拥有了清晰明了的git历史记录,可以清晰,轻松地记录所做的更改及其原因。
例如,对于我来说,典型的“未压缩” git日志可能如下所示:
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
787g8fgf78... hotfix for #5849564648
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
真是一团糟!
而更仔细地管理和合并的git日志,以及针对此消息的其他一些关注,可能看起来像:
7hgf8978g9... 8483948393 Added new slideshow feature
787g8fgf78... 5849564648 Hotfix for android display issue
9080gf6567... 6589685988 Implemented pop-up to select language
我认为您通常可以看到压缩提交的要点,并且相同的原则也适用于拉取请求- 历史记录的可读性。 您可能还会向已经有数百甚至数千次提交的提交日志中添加内容,这将有助于使不断增长的历史变得简明扼要。
您想尽早且经常做出承诺。出于多种原因,这是最佳做法。我发现这导致我经常使用“ wip”(进行中的工作)或“ A部分完成”或“ typo,次要修复”的提交,这些提交是我使用git来帮助我工作并提供工作要点的我可以回到下面的代码无法正常工作的过程中。但是,我不需要或不希望将该历史记录作为最终git历史记录的一部分,因此可以压缩自己的提交-但请参阅以下注释,以了解这对开发分支vs. master意味着什么。
如果有代表不同工作阶段的主要里程碑,则每个功能/任务/错误提交不只一次即可。但是,这通常可以凸显以下事实:正在开发的票证“太大”,需要分解成可以独立的小块,例如:
8754390gf87... Implement feature switches
好像是“一件工作”。它们要么存在,要么不存在!打破它似乎没有任何意义。但是经验表明,(取决于组织的规模和复杂性)更细粒度的路径可能是:
fgfd7897899... Add field to database, add indexes and a trigger for the dw group
9458947548g... Add 'backend' code in controller for when id is passed in url.
6256ac24426... Add 'backend' code to make field available for views.
402c476edf6... Add feature to UI
小块意味着更容易的代码审查,更容易的单元测试,更好的质量保证机会,更好地与单一职责原则保持一致,等等。
对于何时实际进行这种南瓜的实用性,基本上有两个不同的阶段,它们都有自己的工作流程
在开发过程中,您“尽早且经常”地提交信息,并带有快速的“一次性”信息。有时您可能希望在这里进行挤压,例如挤压wip和todo消息提交。可以在分支内保留代表您在开发中所采取的不同步骤的多个提交。您选择要做的大多数南瓜都应该在这些要素分支内,而这些要素正在开发中,并且在合并到母版之前。
当添加到主线分支时,您希望简明扼要的提交和根据现有主线历史记录的正确格式。这可能包括票务跟踪器系统ID,例如JIRA,如示例所示。除非您要在主数据库上“汇总”几个不同的提交,否则在这里并不是真正适用于压缩。通常你不会。
使用--no-ff
合并掌握将使用一个提交了合并,并保存历史(分支)时。一些组织认为这是最佳做法。多见于https://stackoverflow.com/q/9069061/631619您也将看到实际效果git log
,其中一个--no-ff
承诺将以最新的承诺,在头顶(刚完成时),而没有--no-ff
可能根据日期和其他提交在历史中进一步深入。
因为拉动PR的人通常关心提交“添加的功能X”的最终效果,而不是“基本模板,错误修复功能X,添加功能Y,注释中的固定错别字,调整的数据缩放参数,散列图性能优于列表” ...详细程度
如果您认为最好用2次提交而不是1次“添加功能X,重构Z以使用X”来最好地表示16次提交,那么建议用2次提交建议pr可能是不错的选择,但是最好提出在这种情况下,需要2个独立的公关(如果回购协议仍然坚持单次提交公关)
这与在回购中一样,没有违背“尽早提交并经常提交”的口头禅,而在开发过程中,您仍然具有详细的细节,因此您失去工作的机会很小,其他人可以进行审核/拉动/提议开发新的公关时,公关不利于您的工作。
从我看到的主要原因如下:
Merge pull request #123 from joebloggs/fix-snafoo
--first-parent
角度查看分支的历史记录--first-parent
性功能(请注意,这仅在Git 2.6.2中已修复,因此我们可以原谅GitHub没有该功能)可用)因此,当您结合以上所有这三种情况时,就会出现一种情况,即从GitHub UI中合并未压缩的提交看起来很丑陋。
您的历史记录被压缩后看起来像
1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... Hotfix for android display issue
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... Implemented pop-up to select language
而如果不压缩提交,历史将看起来像
1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... hotfix for #5849564648
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
如果您限制自己使用GitHub UI,那么在PR跟踪中有很多提交会导致更改的噩梦就变成了噩梦。
例如,您发现在文件中某处取消引用了空指针...,所以您说“这是谁执行的,何时执行的?哪些发行版本受到影响?”。然后,您转到GitHub UI中的blame视图,然后看到该行在789fdfffdf
...“哦,等等,那一行只是更改了缩进以适合其余代码”,所以现在您需要在父提交中导航到该文件的树状状态并重新访问责备页面...最终您找到了提交...这是6个月前的提交...“哦,这可能会影响6个月的用户”您说...啊,但是等等,那个提交实际上是在“拉取请求”中,只是在昨天才合并,还没有人发布任何版本……“该死的人们在不压缩历史的情况下合并提交”是在经过大约2或3次代码考古探险之后通常可以听到的哭声GitHub用户界面
现在,让我们考虑一下如果您使用Git命令行(以及具有修复功能的超酷2.6.2 git blame --first-parent
)的工作原理,
所以我们的提交历史看起来像
$ git log
1256556316... #423 Added new slideshow feature
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... #324 Hotfix for android display issue
787g8fgf78... hotfix for #5849564648
f56556316e... #28 Implemented pop-up to select language
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
但是我们也可以
$ git log --first-parent
1256556316... #423 Added new slideshow feature
56556316ad... #324 Hotfix for android display issue
f56556316e... #28 Implemented pop-up to select language
(换句话说:Git CLI让您也可以吃蛋糕)
现在,当我们遇到空指针问题时...好了,我们就使用它git blame --first-parent -w dodgy-file.c
,我们会得到确切的提交,其中空指针取消引用被引入到master分支,而忽略了简单的空格更改。
当然,如果您正在使用GitHub UI进行合并,则git log --first-parent
由于GitHub强制执行了合并提交消息的第一行,因此确实很糟糕:
1256556316... Merge pull request #423 from jrandom/add-slideshows
56556316ad... Merge pull request #324 from ahacker/fix-android-display
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
因此,简而言之:
GitHub UI(2015年10月)在合并合并请求,如何呈现提交历史记录以及如何归咎于责任信息方面存在许多缺陷。解决GitHub UI中这些缺陷的当前最佳方法是要求人们在合并之前先压缩提交内容。
Git CLI没有这些问题,您可以轻松选择要查看的视图,以便既可以找到以这种方式进行特定更改的原因(通过查看未压缩的提交的历史记录),也可以看到有效压缩的提交。
压缩提交经常被引用的最终原因是使向后移植更加容易...如果您只有一个向后移植的提交(即压缩的提交),那么很容易就可以选择...
好吧,如果您正在查看git历史记录,git log --first-parent
那么您可以选择合并提交。大多数人会感到困惑,因为您必须指定-m N
选项,但是如果您从中获得提交,git log --first-parent
那么您就会知道它是您要遵循的第一个父级,因此git cherry-pick -m 1 ...
--first-parent
为了赢得反对挤压提交的争论而推动了自我修复;-)
我同意在此主题的其他答案中表达的关于显示清晰简洁的已添加功能和已修复错误的历史的观点。但是,我确实想解决您的问题未曾提及但未明确陈述的另一个方面。与git的某些工作方法有关的部分挂断是git允许您重写历史记录,当使用其他形式的源代码控制(无法执行此类操作)后,将其引入git时似乎很奇怪。此外,这还违反了源代码管理的普遍接受原则,即一旦将某些内容提交/签入到源代码管理中,无论您在提交之后进行了什么更改,您都应该能够恢复到该状态。正如您在问题中暗示的那样,这是其中一种情况。我认为git是一个很棒的版本控制系统;但是,要理解它,您必须了解一些实现细节和背后的设计决策,因此它的学习曲线更加陡峭。请记住,git旨在成为一个分布式版本控制系统,这将有助于解释为什么设计人员允许使用南瓜提交重写git历史,这是一个例子。
git gc
已运行以丢弃未引用的对象,否则您始终可以使用reflog返回以前的状态。
由于观点...最佳实践是在可能的情况下对每个<<issue-management-system>>
问题进行一次提交。
您可以在自己的功能分支/存储库中进行任意数量的提交,但是从您的角度来看,这与您现在正在做的事情有关的历史记录...与整个团队/项目或应用程序中的应用程序的历史记录无关从现在开始要保留几个月的观点...
因此,每当您想将错误修复或功能提交到通用存储库(此示例与develop分支一起使用)时,都可以执行以下操作:
# set your current branch , make a backup of it , caveat minute precision
curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr
# squash all your changes at once
git reset $(git merge-base develop $curr_branch)
# check the modified files to add
git status
# add the modified files dir by dir, or file by file or all as shown
git add --all
# check once again
git log --format='%h %ai %an %m%m %s' | less
# add the single message of your commit for the stuff you did
git commit -m "<<MY-ISSUE-ID>>: add my very important feature"
# check once again
git log --format='%h %ai %an %m%m %s' | less
# make a backup once again , use seconds precision if you were too fast ...
curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr
# compare the old backup with the new backup , should not have any differences
git diff <<old-backup>>..<<new-backup-branch>>
# you would have to git push force to your feature branch
git push --force