プルリクエストに対してgitコミットをスカッシュするのはなぜですか?


200

プルリクエストを行うすべての深刻なGithubリポジトリが、コミットを1つのコミットにまとめるように要求するのはなぜですか?

gitログがあると思ったので、すべての履歴を調べて、どこでどのような変更が発生したかを正確に確認できますが、それを潰すと履歴から引き出され、すべてが1つのコミットにまとめられます。ポイントは?

これは「早期にコミットし、頻繁にコミットする」というマントラにも反するようです。


1
大きなレポの場合、人々がレポで何かをしたいときに多くの時間とスペースを節約します。
raptortech97 14年

8
これは「早期にコミットし、頻繁にコミットする」というマントラにも反するようです。」-いいえ、早期/頻繁にコミットしますが、小さな変更ごとにPRする必要はありません。そして、レビュアーはそれらに目を通したくありません、それは確かです。
JensG 14年

7
知覚された答えが何であるかを要約するために、質問に編集を加える必要はありません。それは受け入れられた答えと賛成の場所です。人々は答えを読んで自分の結論を引き出すことができます。

5
私はまだコミットをつぶしたいという欲求がある理由を理解していません。プロをほとんど持たずに潰すにはあまりにも多くの短所があると思います。これは、データの問題を装ったプレゼンテーションの問題です。
mkobit

3
ログに関する有用な分析はすべてスカッシュで失われます。したがって、開発者は1回のコミットで機能を作成したようです。また、奇妙なコードが存在する理由を確認することも困難です。機能の履歴は重要な場合があり、コードがそうである理由を説明するのに大いに役立ちます。ログの簡潔なビューは便利ですが、別の方法では実現できませんか?
Tjaart

回答:


158

これにより、行われた変更とその理由を明確かつ容易に文書化する、明確で簡潔なgit履歴が得られます。

たとえば、私にとっての典型的な 'unsquashed' 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」(作業中)または「part A done」または「typo、minor fix」であるコミットが頻繁に発生することがわかりました。作業を進めるために次のコードがうまくいかない場合に戻ることができます。ただし、コミットを破棄するために、最終的なgit履歴の一部としてその履歴を必要としないか、または必要としません。

明確な作業段階を表す主要なマイルストーンがある場合、機能/タスク/バグごとに複数のコミットを行ってもかまいません。ただし、これは、開発中のチケットが「大きすぎる」という事実を強調することがよくあります。たとえば、次のように、スタンドアロンの小さな断片に分割する必要があります。

8754390gf87... Implement feature switches

「1作品」のようです。存在するかしないかのどちらかです!それを突破する意味がないようです。ただし、経験から、組織の規模と複雑さに応じて、より詳細なパスが次のようになることがわかりました。

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

小さな断片は、コードレビューの容易化、ユニットテストの容易化、品質保証の機会の向上、単一責任原則への整合性の向上などを意味します。

実際にそのようなスカッシュを行うタイミングの実用性のために、独自のワークフローを持つ基本的に2つの異なる段階があります

  • プルリクエストなどの開発
  • メインラインブランチに追加した作業、たとえばmaster

開発中に、「早期かつ頻繁に」コミットし、迅速な「使い捨て」メッセージを送信します。ここでは、wipやtodoメッセージのコミットを潰すなど、時々つぶします。ブランチ内では、開発で行った明確なステップを表す複数のコミットを保持してもかまいません。あなたが選択するほとんどのスカッシュは、これらの機能ブランチ内に存在する必要があります。それらは開発されており、マスターにマージする前です。
メインラインブランチに追加する場合、コミットを簡潔にし、既存のメインラインの履歴に従って正しくフォーマットする必要があります。これには、例に示すJIRAなどのチケットトラッカーシステムIDが含まれる場合があります。マスターでいくつかの異なるコミットを「ロールアップ」したい場合を除き、ここでは実際にスカッシュは適用されません。通常はそうしません。

--no-ffマスターへのマージ時に使用すると、マージに1つのコミットが使用され、(ブランチ内の)履歴も保持されます。一部の組織では、これをベストプラクティスと見なしています。でより多くを参照してくださいhttps://stackoverflow.com/q/9069061/631619あなたはまた、中に実用的な効果が表示されますgit log場所--no-ff(ちょうど行われたとき)のない一方で、頭の上で、最新のコミットとなりますコミットし--no-ff、それはかもしれ日付やその他のコミットに応じて、履歴のさらに下に移動します。


30
私はこの哲学に完全に同意しません。小さな定期的なコミットは、タスクを小さなタスクに分割し、多くの場合、行が変更されたときに何が処理されていたかに関する正確な情報を提供します。小規模な「WIP」コミットがある場合は、プッシュする前にインタラクティブなリベースを使用してクリーンアップする必要があります。PRをつぶすことは、私見での定期的な小さなコミットのポイントを完全に打ち負かすようです。特定のコミット情報を含むログメッセージを提供する努力をしてきた著者にとっては、ほとんど失礼であり、あなたはそれをすべて捨ててしまいます。
ジェズ

6
面白い。一日の終わりに、私は自分の作品を見たことに基づいて「哲学」を作ります。明確にするために-作業を小さな部分に分割し、それぞれをコミットすることは、変更に取り組んでいる間素晴らしいです。私の経験では、ということであった後に、この作業はマスターにマージされ、メイン検討を取得する傾向があること「はその中にどのような、完全にこのマージは、(通常は)問題xを引き起こしているコミットされているもの...
マイケル・デュラント

6
私も反スカッシュです。そもそも愚かなコミットメッセージを書くべきではありません。そして、例では(85493g2458 ... IEのスライドショー表示の問題を修正しました)それに関連するコードをデバッグする場合、それははるかに役立ちます。
トーマスデイビス

5
このような不注意で見当違いの教義がSCMの実践に現れたことは残念です。フィルタリングツールを使用して、コミット動作ではなく履歴の可読性を管理する必要があります。
ctpenrose

4
不穏な傾向と教義。よ もっと事実に基づいた議論を、より快適な方法で提示したいと思います。別の意見を投稿/投票してください。それは、コミュニティ投票のポイントだ
マイケル・デュラント

26

多くの場合、PRを引く人は、「ベーステンプレート、バグ修正関数X、関数Yの追加、コメントのタイプミスの修正、データスケーリングパラメーターの調整」ではなく、「追加機能X」のコミットの最終的な効果を重視するため、ハッシュマップはリスト」...詳細レベル

16個のコミットが1個ではなく2個のコミットで最もよく表されると考える場合、「Xを使用するために機能Xを追加し、Zをリファクタリングします」と考えられます。その場合、2つの別個のpr(レポジトリがまだ単一コミットprを主張する場合)

これは、リポジトリのように「早期にコミットし、頻繁にコミットする」というマントラに反するものではありません。開発中はまだ詳細な情報があるため、作業を失う可能性は最小限に抑えられ、他の人がレビュー/プル/提案することができます新しいprが開発されている間、prはあなたの仕事に反対します。


4
しかし、コミットをスカッシュすると、フォークでもその履歴が失われますか?なぜその歴史を捨てたいのですか?
ハムスター14年

4
a)ブランチの履歴を保持したい場合は、「マージ」ブランチと「dev」ブランチ(メインdevに新しいコミットを追加する可能性があるため、とにかく必要になるかもしれません)を持つのに十分簡単です。 PR)を提案した後の分岐)b)これらのコミットの正味の効果を維持している場合、個々のコミットが必要になるのは、prのサブコンポーネントを元に戻す、またはチェリーピックする場合のみです。その場合、おそらく単一のPRで複数のこと(例えば、バグ修正X、機能Yの追加)を行っており、複数のPRが再び必要になる可能性があります。
アンドリューヒル14年

@AndrewHillなんて素晴らしいコンセプト!このワークフローをチームに導入したいのですが、どのように機能しましたか?私はそれについてのブログ投稿を書き調査中にこのコメントに出会いました。
Droogans

19

私が見ることができる主な理由は次のとおりです。

  • 現在(2015年10月)プルリクエストをマージするためのGitHub UIでは、コミットメッセージの最初の行を編集することはできません。 Merge pull request #123 from joebloggs/fix-snafoo
  • 現在、コミットの歴史を閲覧するためのGitHubのUIは、あなたからのブランチの履歴を表示することはできません--first-parent観点
  • 現在、ファイルの非表示を確認するためのGitHub UIでは、ファイルの非表示を視点で表示することはできません--first-parent(これはGit 2.6.2でのみ修正されているため、GitHubがそれを持たないことを許すことができます。利用可能)

そのため、上記の3つの状況すべてを組み合わせると、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の非表示ビューに移動すると、行が変更されたことがわかります789fdfffdf...「ちょっと待ってください、その行はインデントが残りのコードに合わせて変更されただけです」ので、今度は親のコミットでそのファイルのツリー状態に移動し、再訪問する必要があります責任のページ...最終的にはコミットが見つかります...それは6か月前のコミットです... "ああ****これは6か月間ユーザーに影響を与える可能性があります"と言います...ああ、しかし、そのコミット実際にはプルリクエストであり、昨日マージされただけで、まだ誰もリリースをカットしていません... GitHub UI

ここで、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を使用すると、ケーキを食べて食べることもできます)

これで、nullポインターの問題が発生したとき...使用するだけでgit blame --first-parent -w dodgy-file.c、マスターブランチに単純な空白の変更を無視してnullポインター逆参照が導入された正確なコミットがすぐに与えられます。

もちろん、GitHub UIを使用してマージを実行している場合、GitHub git log --first-parentがマージコミットメッセージの最初の行を強制するため、本当にくだらないことになります。

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にはこれらの問題はなく、どのビューを表示するかを簡単に選択できるため、特定の変更がそのように行われた理由を発見することができます(押しつぶされていないコミットの履歴を見る)効果的に押しつぶされたコミットを参照してください。

ポストスクリプト

コミットのスカッシュでよく引用される最後の理由は、バックポートを簡単にすることです...バックポートへのコミットが1つしかない場合(つまり、スカッシュコミット)、簡単に選択できます...

gitの履歴を見ているのであればgit log --first-parent、マージコミットを選択するだけです。ほとんどの人は、-m Nオプションを指定する必要があるため、チェリーピックマージコミットを混乱させますが、コミットを取得し場合git log --first-parent、それが最初の親であることを知っているので、git cherry-pick -m 1 ...


1
素敵な答え!しかし、範囲をチェリーピッキングするのは簡単です。理由として購入するかどうかはわかりません。
スティグラー

1
@stiggler私は個人的にそれを理由として購入していませんが、他の人がそれを理由として引用しているのを見てきました。gitのツーリング悪で何がしたいと潰しコミットです...しかし、私はの固定駆動したと言うでしょう私見--first-parentコミットを;-)退治に対する引数を勝つために自分自身を
スティーブン・コノリー

1
これは受け入れられた答えであるべきです。教義ははるかに少なく、履歴フィルタリングを使用して「ケーキを食べて食べる」ことができることを示しています。Gitの履歴探索を明確にするために、履歴を消滅させる必要はありません。
ctpenrose

コミットをつぶすことで、異なるファイルへの多くの変更を1つのコミットにグループ化することになる場合、簡単に選ぶことはできません。これは、コードベース、どのような変更が行われたか、何人の人々が共同作業しているかなどによって大きく異なると思います。すべての場合に有効な単一の一般的なルールを考え出すことはできないと思います。
エイミーペレグリーニ

2

追加された機能と修正されたバグの明確で簡潔な履歴を表示することについて、このスレッドの他の回答で表明された感情に同意します。しかし、私はあなたの質問が逃げたが明示的に述べていない別の側面に取り組みたいと思いました。gitのいくつかの作業方法についてのハングアップの一部は、gitを使用すると、そのようなアクションが不可能な他の形式のソース管理を使用した後、gitに導入されたときに奇妙に思える履歴を書き換えることができることです。さらに、これはソース管理の一般に受け入れられている原則にも反します。ソース管理に何かがコミット/チェックインされると、そのコミット後にどのような変更を加えてもその状態に戻ることができるはずです。あなたが質問で暗示しているように、これはそのような状況の1つです。gitは優れたバージョン管理システムだと思います。ただし、それを理解するには、実装の詳細とその背後にある設計上の決定を理解する必要があり、その結果、学習曲線が急勾配になります。gitは分散バージョン管理システムであることを意図しており、デザイナーがgit履歴の書き換えを許可する理由を説明するのに役立つことを忘れないでください。スカッシュコミットはこの一例です。


厳密に言えば、Gitでは履歴を変更することはできません。コミットオブジェクトは不変です。可変であるのはブランチポインターのみであり、その場合にのみ、「強制更新」が行われます。これは一般に、マスターブランチ上ではなく、開発目的でのみ行うことと見なされます。git gc参照されていないオブジェクトを破棄するために実行されていない限り、reflogを使用していつでも以前の状態に戻すことができます。
ジョンパーディ14年

あなたは正しいです、そして、私はおそらくこれを上で述べたはずです。しかし、コミットの順序と配置はコミット自体と同じくらい重要であるため、リモートリポジトリに既にプッシュされている強制プッシュやコミットのリベースなどが、履歴の書き換えとして適格であると主張します。
フレッドトムセン14年

これは、特定のコミットに当てはまります。全体像を見ると、インタラクティブなリベースとフィルターブランチは、その構成を変更することで効果的に履歴を書き換えていると思います。
マイケルデュラント

1
公平を期すために、SVNは「すべてのコミットは神聖な」アプローチを維持しますが、マージすると、そのマージで単一のコミットが作成され、それに貢献したリビジョンが非表示になり、すべてのSVNマージが「リベース」されるように見えます そうではなく、マージされたコンポーネントを表示するためにhistoryコマンドに指示するだけです。このアプローチが一番好きです。
gbjbaanb

1

観点から...ベストプラクティスは<<issue-management-system>>、可能であれば、単一の問題ごとに単一のコミットを行うことです。

自分の機能ブランチ/レポで好きなだけコミットすることができますが、それはあなたの視点であなたが今していることに関連するあなたの歴史です...それは彼がチーム/プロジェクト全体または彼らのアプリケーションの履歴ではありません今から数ヶ月保持される見通し...

したがって、バグ修正または機能を共通のレポジトリにコミットする場合(この例は開発ブランチにあります)は、次のようにします。

機能ブランチをリベースして迅速に開発する方法

    # 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の

私は何とか(ただし評価されて最初のリビジョンを向上させることを努力)数年前に投稿された答えを投票し追加説明がなさポイントを超える大幅な何かを提供していますかを確認するために失敗し、トップで説明
ブヨを

キーワードは「パースペクティブ」です。パースペクティブコンセプトにより、ITにおけるこの種の問題の説明がはるかに簡単になります。たとえば、この質問の答えに対するあなたのパースペクティブはすでに提供されているものです。そして、異なる視点から説明されたまったく同じベストプラクティスを実装する方法の実用的な例を提供します...
ヨルダンゲオルギエフ

1

コードが公開されるかどうかを確認します。

プロジェクトが非公開の場合:

つぶさないで、ソーセージを作ることをお勧めします。良いコミットと小さなコミットを使用する場合、git bisectのようなツールは非常に便利であり、人々はリグレッションコミットをすばやく特定し、なぜコミットしたかを確認できます(コミットメッセージのため)。

プロジェクトが公開されるとき:

一部のコミットにはセキュリティリークが含まれている可能性があるため、すべてをつぶしてください。たとえば、コミットされて再び削除されたパスワード。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.