10

1 つの課題に対して 1 つのコミットを行うことは、良い習慣であると心から信じています。「ベスト プラクティス」などの記事のどこかで読んだはずです。

そのため、私のワークフローは次のとおりです。

  • 新しい問題については、新しいローカル ブランチを作成しgit checkout -b new-issueます。
  • すべての変更をそれにコミットします。これには、多くのコミットが含まれることがあります。
  • 完了したらsquash、コミットし、rebaseそれらを現在のテーマ別ブランチに入れます。
  • 何か問題が発生した場合はgit revert、コミットしてバグを見つけて修正し、新しいパッチをテーマ ブランチにコミットできます。リモート リポジトリの履歴は変更しません。

しかし、今日、次のワークフローを聞いて驚きました。

  • 新しい問題の新しいブランチを作成します。
  • それにすべてをコミットします。
  • 課題ブランチをテーマ ブランチとマージするために使用merge --no-ffします (そのため、「マージ コミット」が可能になりますrevert)。
  • 何か問題が発生した場合はgit bisect、バグを見つけるために使用できます。

最初のアプローチによると、クリーンな git 履歴があり、開発中に使用されるオーバーヘッド ブランチについてはわかりません。

2 番目のアプローチによれば、非常に厄介な履歴が残り、たった 1 つの課題に対して多くの醜く不必要なマージとコミットが行われます。ただし、git bisectバグを見つけるために使用できます。(おそらく、これはリファクタリングに適していますか?)


  • 両方のアプローチについて、どのような長所と短所がありますか?

  • どのアプローチを使用し、その理由は何ですか?

  • 実際に、実際にgit bisectバグを見つけることに慣れていますか? (私はそうではありません…)

4

2 に答える 2

9

2 番目のアプローチでは、見苦しくて不必要なマージやコミットをたくさん行う必要はありません。これは私がやりたいことです:

  1. 新しいトピック ブランチを作成する
  2. たくさんのコミットをする
  3. 親ブランチにマージする直前に、コミットをクリーンアップします。
    • 親ブランチの最新バージョンにリベースします
    • スカッシュタイプミス修正コミット
    • 一度に複数のことを行うコミットを別々のコミットに分割する
    • コミットを並べ替えて、レビュアーが変更の順序を理解しやすくする
  4. --no-ff親ブランチにマージする

上記の手順により、履歴は次のようになります。

*   354b644 Merge branch 'topic3'
|\
| * 54527e0 remove foo now that it is no longer used
| * 1ef3dad stop linking against foo
| * 7dfc7e5 wrap lines longer than 80 characters, no other changes
| * b45fbcf delete end-of-line whitespace, fix indendataion
|/
*   db13612 Merge branch 'topic2'
|\
| * 961eebf unbreak build by adding a missing semicolon
|/
*   a5b6b16 Merge branch 'topic1'
|\
... (more history not shown)

上記のグラフには、アプローチ 1 と同じ利点があります。

  • --first-parent引数 toを使用してgit log、アプローチ #1 で得られるものに似た簡潔な要約を得ることができます。

    * 354b644 Merge branch 'topic3'
    * db13612 Merge branch 'topic2'
    * a5b6b16 Merge branch 'topic1'
    ... (more history not shown)
    
  • トピック ブランチで行われた変更全体を簡単に調べることができます。たとえば、git diff 354b644^..354b644トピック #3 の変更点が表示されます。

しかし、アプローチ 1 では得られない利点があります。

  • 履歴を確認するのははるかに簡単です。コミットb45fbcf7dfc7e5(topic3ブランチの場合) 多くのノイズが発生しますが、実際のロジックの変更はありません。「トピック 3 では、どのようなロジックの変更が行われたか?」という質問に答えようとしている人がいます。これらのコミットがすべて 1 つにまとめられた場合、ノイズを掘り下げるのに苦労する可能性があります。
  • マージ コミットは、マージされたブランチでの一連のコミットのコンテキストを適切に識別します (たとえば、このコミット グループはトピック #3 に対処するために作成されました)。
  • コミットの粒度が細かいほど、特定の変更が行われた理由を把握しやすくなり、意図的だが微妙な変更と偶発的な変更を区別するのに役立ちます。
  • 複数の人がブランチで共同作業を行った場合、全員が誰で、各人がどれだけ貢献したかを確認できます。
  • マージされたトピック ブランチのコミット数から、どの程度変更されたかを大まかに把握できます。
  • コミットの時間範囲は、有用なコンテキストを提供できます。
  • 別のブランチに加えられた特定の変更を簡単にチェリー ピックできます (たとえば、リリース ブランチでバグを修正するために必要な最小限の変更をチェリー ピックします)。

私が考えることができる欠点が 1 つあります。最初の親パスのみをたどり、それらの中間コミットをすべて無視するようにソフトウェア開発ツールを構成するのは難しいかもしれません。たとえば、には引数がありません--first-parentgit bisect。また、他のすべてのコミットよりも最初の親パスの構築とテストを優先するように Jenkins を構成するのがどれほど簡単かを知るほど、私は Jenkins に精通していません。

于 2013-03-30T17:36:39.450 に答える
5

結局のところ、それは主に個人的な好みの問題です...私の好みを説明することしかできません(そしてそれを少し正当化することができます)。

私は、たとえ「ダムのタイプミスを修正する」だけであっても、個々のコミットを維持する傾向があります。「履歴の書き換え」は、これまで存在しなかったコミットを作成するため、テストされていないことが保証されます。さらに、最小限のコミットにより、git bisect後でバグが発生したときに非常に役立ちます。一緒に押しつぶされた1週間の作業よりも、いくつかの変更された行に絞り込むことができる方がよいでしょう。

開発ブランチが履歴の混乱を取得した場合、私はそれをクリーンアップします(つまり、コミットの取り消しはまったく発生しませんでした。空白や変数の​​名前変更などの一般的な修正が以前に適用される可能性があり、関連する変更をまとめるためにいくつかの並べ替えが行われます)。コミットはまだ小さいままで、潰されることはめったにありません。このクリーンアップは、主に段階的に行います。次に、クリーンアップされたブランチを「公式」ブランチとマージ(またはリベース)します。

于 2013-03-21T19:10:36.853 に答える