为什么壁挂git提交拉取请求?


199

为什么我执行的每个严肃的Github回购请求都要求我将提交压缩为单个提交?

我以为git日志在那里,所以您可以检查所有历史记录,并确切查看发生了什么更改,但是挤压它会将其从历史记录中拉出来,然后将其全部合并为一个提交。有什么意义?

这似乎也违反了“尽早提交并经常提交”的口头禅。


1
对于大型仓库,当人们想对仓库进行任何操作时,它可以节省大量的时间和空间。
raptortech97 2014年

8
这似乎也违背了“提早提交并经常提交”的口头禅。 ”-不,您确实早/经常提交,但您不一定要对每个微小的更改进行公关。当然,审稿人也不想浏览它们。
JensG 2014年

7
无需在问题中进行编辑即可总结出感知到的答案是什么。那是公认的答案和赞誉的地方。人们可以通过阅读答案得出自己的结论。

5
我仍然不明白为什么要压缩提交。我认为有太多弊端要压倒几乎没有利弊。这是一个伪装成数据问题的演示问题。
mkobit

3
日志上所有有用的分析都会丢失。因此,似乎开发人员只需一次提交即可完成一项功能。很难理解为什么存在一段奇怪的代码。功能的历史可能很重要,并且可以在很大程度上解释代码为何如此。日志的简洁视图很有用,但是不能以其他方式实现吗?
Tjaart

Answers:


158

这样您便拥有了清晰明了的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

小块意味着更容易的代码审查,更容易的单元测试,更好的质量保证机会,更好地与单一职责原则保持一致,等等。

对于何时实际进行这种南瓜的实用性,基本上有两个不同的阶段,它们都有自己的工作流程

  • 您的开发,例如请求请求
  • 您的工作已添加到主线分支,例如master

在开发过程中,您“尽早且经常”地提交信息,并带有快速的“一次性”信息。有时您可能希望在这里进行挤压,例如挤压wip和todo消息提交。可以在分支内保留代表您在开发中所采取的不同步骤的多个提交。您选择要做的大多数南瓜都应该在这些要素分支内,而这些要素正在开发中,并且在合并到母版之前。
当添加到主线分支时,您希望简明扼要的提交和根据现有主线历史记录的正确格式。这可能包括票务跟踪器系统ID,例如JIRA,如示例所示。除非您要在主数据库上“汇总”几个不同的提交,否则在这里并不是真正适用于压缩。通常你不会。

使用--no-ff合并掌握将使用一个提交了合并,并保存历史(分支)时。一些组织认为这是最佳做法。多见于https://stackoverflow.com/q/9069061/631619您也将看到实际效果git log,其中一个--no-ff承诺将以最新的承诺,在头顶(刚完成时),而没有--no-ff可能根据日期和其他提交在历史中进一步深入。


30
我完全不同意这种哲学。小型常规提交将任务分解为较小的任务,并且经常提供有关更改线路时正在处理的内容的有用信息。如果您有小的“ WIP”提交,则应在推送之前使用交互式的基准库来清理它。压缩PR似乎完全击败了常规的小型提交恕我直言。对于努力提供带有特定提交信息的日志消息的作者来说,这几乎是不敬的,您只需将其全部丢弃即可。
耶斯

6
有趣。归根结底,我的“哲学”基于我所看到的作品。需要明确的是,在进行变更时,将工作分解成小部分并投入每一部分是很棒的。我的经验是,一旦将这项工作合并到母版中,往往要检查的主要内容是“什么,通常是(通常)引起问题的合并提交什么……
Michael Durrant

6
我也是防南瓜。首先,您不应该编写愚蠢的提交消息。在示例中(85493g2458 ...修复了ie中的幻灯片显示问题),如果我要调试与其相关的代码,这将大有帮助。
托马斯·戴维斯

5
不幸的是,在SCM实践中出现了这种粗心和错位的教条。应当使用过滤工具来管理历史记录的可读性而不是提交行为。
ctpenrose

4
令人不安的趋势和教条。佑。我希望以更合意的方式提出基于事实的论点。欢迎您发表/投票提出不同的意见。这就是社区投票的重点
Michael Durrant

26

因为拉动PR的人通常关心提交“添加的功能X”的最终效果,而不是“基本模板,错误修复功能X,添加功能Y,注释中的固定错别字,调整的数据缩放参数,散列图性能优于列表” ...详细程度

如果您认为最好用2次提交而不是1次“添加功能X,重构Z以使用X”来最好地表示16次提交,那么建议用2次提交建议pr可能是不错的选择,但是最好提出在这种情况下,需要2个独立的公关(如果回购协议仍然坚持单次提交公关)

这与在回购中一样,没有违背“尽早提交并经常提交”的口头禅,而在开发过程中,您仍然具有详细的细节,因此您失去工作的机会很小,其他人可以进行审核/拉动/提议开发新的公关时,公关不利于您的工作。


4
但是,当您壁球犯错时,您也会在叉中丢失该历史记录,对吗?您为什么要放弃那个历史?
hamstar

4
a)如果您想保留分支中的历史记录,可以轻松地创建一个“ for merge”分支和一个“ dev”分支(无论如何,这都是您所需要的,因为您可以向主开发中添加新的提交)提出PR后分支)b)您仍然保留这些提交的最终结果,只有在您希望撤消或选择PR的子组件的情况下,才需要单个提交。在这种情况下,您可能在单个PR中执行多项操作(例如:错误修正X,添加功能Y),并且可能再次需要多个PR。
2014年

@AndrewHill多么伟大的概念!我想将这个工作流程介绍给我的团队,它对您有什么帮助?我写了一篇有关它的博客文章,并在研究它时遇到了此评论。
Droogans 2015年

19

从我看到的主要原因如下:

  • 当前用于合并拉取请求的GitHub UI(2015年10月)不允许您编辑提交消息的第一行,强制将其设置为 Merge pull request #123 from joebloggs/fix-snafoo
  • 当前用于浏览提交历史记录的GitHub UI不允许您从--first-parent角度查看分支的历史记录
  • GitHub UI用于查看文件的非功能性内容目前不允许您以角度查看文件的非--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命令行,则可以完全控制合并提交消息,因此合并提交可以有一个不错的摘要行。

所以我们的提交历史看起来像

$ 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 ...


1
好答案!但是挑选一个范围很容易,不确定我是否会买它。
斯蒂格勒'16

1
@stiggler我个人不购买它是有原因的,但我认为它被其他人引用是有原因的。恕我直言,git工具是您想要的,并且挤压提交是邪恶的……但是我要说的是,--first-parent为了赢得反对挤压提交的争论而推动了自我修复;-)
Stephen Connolly

1
这应该是公认的答案。教条要少得多,它表明历史过滤可以用来“吃蛋糕也吃”。您无需消灭历史就可以使git历史探索变得清晰。
ctpenrose

如果通过挤压提交最终导致将对不同文件的许多更改分组到单个提交中,那么选择樱桃并不是那么容易。我猜这会根据代码库,进行了哪些更改,正在协作的人数等等而有很大不同。我认为我们无法提出一条通用规则在所有情况下均有效。
艾米·佩莱格里尼

2

我同意在此主题的其他答案中表达的关于显示清晰简洁的已添加功能和已修复错误的历史的观点。但是,我确实想解决您的问题未曾提及但未明确陈述的另一个方面。与git的某些工作方法有关的部分挂断是git允许您重写历史记录,当使用其他形式的源代码控制(无法执行此类操作)后,将其引入git时似乎很奇怪。此外,这还违反了源代码管理的普遍接受原则,即一旦将某些内容提交/签入到源代码管理中,无论您在提交之后进行了什么更改,您都应该能够恢复到该状态。正如您在问题中暗示的那样,这是其中一种情况。我认为git是一个很棒的版本控制系统;但是,要理解它,您必须了解一些实现细节和背后的设计决策,因此它的学习曲线更加陡峭。请记住,git旨在成为一个分布式版本控制系统,这将有助于解释为什么设计人员允许使用南瓜提交重写git历史,这是一个例子。


严格来说,Git不允许您更改历史记录。提交对象是不可变的。只有可变的分支指针,然后才具有“强制更新”,这通常被认为是您仅出于开发目的而不是在master分支上执行的操作。除非git gc已运行以丢弃未引用的对象,否则您始终可以使用reflog返回以前的状态。
乔恩·普迪

您是正确的,也许我应该在上面提到这一点。但是,我会主张强制推送或重新部署已提交到远程仓库的提交等东西,可以视为重写历史,因为提交的顺序和排列与提交本身一样重要。
Fred Thomsen 2014年

对于给定的提交,这是正确的。在较大的图中,我认为交互式重新基准化和筛选器分支通过更改其组成有效地重写了历史。
Michael Durrant 2014年

1
公平地说,SVN保持“每次提交都是神圣的”方法,但是在合并时,使用该合并创建单个提交,并隐藏促成此合并的修订,因此看起来所有SVN合并都是“重新设置”的。它们不是,您只需要告诉history命令向您显示合并的组件即可。我最喜欢这种方法。
gbjbaanb 2015年

1

由于观点...最佳实践是在可能的情况下对每个<<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 

这甚至都没有尝试解决所问的问题,为什么壁球git提交拉取请求?请参阅如何回答
蚊蚋

经过解释尝试后,它应该做...
Yordan Georgiev '18

我不知为何看不到添加的解释如何提供超过几年前发表的最高投票答案中提出和解释的要点的实质内容(尽管对改进
第一版的

关键字是“ perspective”,透视图的概念使解释IT中的这类问题更加容易,例如-您对这个问题的回答的透视图已经提供,我的观点是使用“ perspective”关键词并提供了如何实施通过不同观点解释的相同最佳实践的实际示例……
Yordan Georgiev

1

我会看看代码是否公开。

当项目不公开时:

我建议不要压榨,看看香肠的制作方法。如果使用好的提交和小的提交,则git bisect之类的工具非常方便,人们可以快速查明回归提交,并查看您为什么这样做(由于提交消息)。

当项目公开时:

压缩所有内容,因为某些提交可能包含安全漏洞。例如,已提交并再次删除的密码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.