プルリクエストを行うすべての深刻なGithubリポジトリが、コミットを1つのコミットにまとめるように要求するのはなぜですか?
gitログがあると思ったので、すべての履歴を調べて、どこでどのような変更が発生したかを正確に確認できますが、それを潰すと履歴から引き出され、すべてが1つのコミットにまとめられます。ポイントは?
これは「早期にコミットし、頻繁にコミットする」というマントラにも反するようです。
プルリクエストを行うすべての深刻なGithubリポジトリが、コミットを1つのコミットにまとめるように要求するのはなぜですか?
gitログがあると思ったので、すべての履歴を調べて、どこでどのような変更が発生したかを正確に確認できますが、それを潰すと履歴から引き出され、すべてが1つのコミットにまとめられます。ポイントは?
これは「早期にコミットし、頻繁にコミットする」というマントラにも反するようです。
回答:
これにより、行われた変更とその理由を明確かつ容易に文書化する、明確で簡潔な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つの異なる段階があります
開発中に、「早期かつ頻繁に」コミットし、迅速な「使い捨て」メッセージを送信します。ここでは、wipやtodoメッセージのコミットを潰すなど、時々つぶします。ブランチ内では、開発で行った明確なステップを表す複数のコミットを保持してもかまいません。あなたが選択するほとんどのスカッシュは、これらの機能ブランチ内に存在する必要があります。それらは開発されており、マスターにマージする前です。
メインラインブランチに追加する場合、コミットを簡潔にし、既存のメインラインの履歴に従って正しくフォーマットする必要があります。これには、例に示すJIRAなどのチケットトラッカーシステムIDが含まれる場合があります。マスターでいくつかの異なるコミットを「ロールアップ」したい場合を除き、ここでは実際にスカッシュは適用されません。通常はそうしません。
--no-ff
マスターへのマージ時に使用すると、マージに1つのコミットが使用され、(ブランチ内の)履歴も保持されます。一部の組織では、これをベストプラクティスと見なしています。でより多くを参照してくださいhttps://stackoverflow.com/q/9069061/631619あなたはまた、中に実用的な効果が表示されますgit log
場所--no-ff
(ちょうど行われたとき)のない一方で、頭の上で、最新のコミットとなりますコミットし--no-ff
、それはかもしれ日付やその他のコミットに応じて、履歴のさらに下に移動します。
多くの場合、PRを引く人は、「ベーステンプレート、バグ修正関数X、関数Yの追加、コメントのタイプミスの修正、データスケーリングパラメーターの調整」ではなく、「追加機能X」のコミットの最終的な効果を重視するため、ハッシュマップはリスト」...詳細レベル
16個のコミットが1個ではなく2個のコミットで最もよく表されると考える場合、「Xを使用するために機能Xを追加し、Zをリファクタリングします」と考えられます。その場合、2つの別個のpr(レポジトリがまだ単一コミットprを主張する場合)
これは、リポジトリのように「早期にコミットし、頻繁にコミットする」というマントラに反するものではありません。開発中はまだ詳細な情報があるため、作業を失う可能性は最小限に抑えられ、他の人がレビュー/プル/提案することができます新しいprが開発されている間、prはあなたの仕事に反対します。
私が見ることができる主な理由は次のとおりです。
Merge pull request #123 from joebloggs/fix-snafoo
--first-parent
観点--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 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 ...
--first-parent
コミットを;-)退治に対する引数を勝つために自分自身を
追加された機能と修正されたバグの明確で簡潔な履歴を表示することについて、このスレッドの他の回答で表明された感情に同意します。しかし、私はあなたの質問が逃げたが明示的に述べていない別の側面に取り組みたいと思いました。gitのいくつかの作業方法についてのハングアップの一部は、gitを使用すると、そのようなアクションが不可能な他の形式のソース管理を使用した後、gitに導入されたときに奇妙に思える履歴を書き換えることができることです。さらに、これはソース管理の一般に受け入れられている原則にも反します。ソース管理に何かがコミット/チェックインされると、そのコミット後にどのような変更を加えてもその状態に戻ることができるはずです。あなたが質問で暗示しているように、これはそのような状況の1つです。gitは優れたバージョン管理システムだと思います。ただし、それを理解するには、実装の詳細とその背後にある設計上の決定を理解する必要があり、その結果、学習曲線が急勾配になります。gitは分散バージョン管理システムであることを意図しており、デザイナーがgit履歴の書き換えを許可する理由を説明するのに役立つことを忘れないでください。スカッシュコミットはこの一例です。
git gc
参照されていないオブジェクトを破棄するために実行されていない限り、reflogを使用していつでも以前の状態に戻すことができます。
観点から...ベストプラクティスは<<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