Git Cherry-Pick:特定のコミットを選択して適用する方法

コラボレーティブソフトウェア開発環境でブランチを使用することは、機能、バグ修正、または実験を分離するために不可欠です。ただし、ブランチ全体をマージせずに特定の変更を別のブランチに適用する必要がある場合があります。これがgit cherry-pickが貴重な存在になる場面です。

このチュートリアルの目標は、git cherry-pickの効果的な使用方法について包括的なガイドを提供することです。コマンドの構文を学び、競合の処理方法を理解し、避けるべきベストプラクティスや一般的な落とし穴を探求します。さあ始めましょう!

Git Cherry-Pickとは何ですか?

git cherry-pickコマンドは、開発者にソースコードを細かく制御する機能を提供する基本的なGitコマンドです。

他のGit操作とは異なり、マージリベースなど、ブランチ全体を対象とする操作に対して、cherry-pickは特定のコミットを1つのブランチから取り出して別のブランチに適用することができます。これにより、特定の変更のみを統合する必要がある場合など、特に精度が高まります。

git cherry-pickコマンドは、選択したコミットの内容をコピーし、新しいコミットをターゲットブランチに作成することで動作し、コミット履歴の整合性を維持します。

git cherry-pickの使用方法

git cherry-pickの使用例には次のものがあります: 

  • バックポーティングのバグ修正: 開発ブランチでバグを解決し、安定したリリースブランチに同じ修正を必要とする場合。チェリーピックを使用すると、関連のない変更を取り込まずにバグ修正を移動できます。
  • ホットフィックスの適用: 本番環境で重要な修正が必要な場合、開発ブランチが進化を続ける中で、チェリーピックを使用して修正を本番ブランチに抽出および適用できます。
  • テスト用の機能分離: テスト中に機能に関連する特定のコミットのみをテストする必要がある場合。必要なコミットをチェリーピックして、テストブランチを清潔で効率的に保ちます。
  • 間違ったコミットの修正:コミットが間違って別のブランチにプッシュされた場合、プロジェクトの履歴を崩さずに、そのコミットを適切なブランチにチェリーピックすることができます。
  • 複数のブランチ間で変更を再利用:複数のブランチで同じ更新が必要な場合、チェリーピックを使用すると、作業をやり直したりブランチの複雑さを導入することなく、異なるブランチで変更を複製することができます。

Git Cherry-Pickの構文

git cherry-pickの構文を理解することは、このコマンドを効果的に使用するための鍵です。単にコミットを選択するだけでなく、それを正確に適用して目的の結果を達成することが重要です。

単一のコミットを cherry-pick するための基本的な構文は次の通りです:

git cherry-pick <commit-hash>
  • git cherry-pick:操作を開始するコマンド。
  • <commit-hash>:cherry-pick したいコミットの一意の識別子(SHA-1 ハッシュ)。このハッシュは、コミット履歴を表示するために git log を実行して見つけることができます。

上記のコマンドを実行すると、Git は指定されたコミットからの変更を現在のブランチに適用し、同じ変更を持つが異なるハッシュを持つ新しいコミットを作成します。

重要な点として、このコマンドはコミットそのもののみを移動し、元のブランチからのコンテキストや親の履歴は移動しません。

GitとGitHubに初めて触れる方?この初心者向けGitHubとGitチュートリアルでバージョン管理を始めましょう。

Git Cherry-Pickの使い方:ステップバイステップの例

git cherry-pickの基本構文を理解したら、コマンドを実行してみましょう。

このセクションでは、チェリーピックが役立つ一般的な基本的なシナリオとより複雑なシナリオを実践的な例で説明します。各例は、1つ以上のコミットから他のブランチに変更を適用する方法を示します。

例1:1つのコミットをチェリーピックする

たとえば、機能ブランチで修正を行い、その修正を機能ブランチ全体をマージせずにメインブランチに適用したいとします。

  • 最初に、次のコマンドを実行して、cherry-pickしたいコミットのハッシュを見つけます:
git log
  • コミットのハッシュを見つけます。
  • メインブランチに切り替えます:
git checkout main
  • cherry-pickコマンドを実行します(ハッシュがabc1234と仮定):
git cherry-pick abc1234

このコマンドを実行すると、Gitは現在のブランチ(この場合はmain)にコミットabc1234で識別される変更を適用します。 Gitは、元のコミットと同じ変更を含む新しいコミットをメインブランチに作成しますが、新しいコミットハッシュが付けられます。

Example 2: 複数のコミットをチェリーピックする

いくつかの状況では、1つのブランチから別のブランチに複数の異なるコミットを適用する必要があるかもしれません。たとえば、フィーチャーブランチに3つの別々のコミットがあるが、これをメインブランチに取り込む必要があるとします。

  • git logを使用して、チェリーピックしたい各コミットのコミットハッシュを見つけます:
git log
  • メインブランチに切り替えます:
git checkout main
  • cherry-pickコマンドを実行し、コミットをリストアップします:
git cherry-pick abc1234 def5678 ghi7890

例3: コミット範囲を指定してチェリーピックする

フィーチャーブランチで一連のコミットを行い、それらを個々に指定せずに本ブランチに一括適用したいとします。どのように行いますか?

  • git logを使用して、チェリーピックしたい開始コミットと終了コミットを特定します(例:abc1234からghi7890まで)。
  • メインブランチに切り替えます:
git checkout main
  • コミット範囲を指定してcherry-pickコマンドを実行します:
git cherry-pick abc1234...ghi7890

例4: リモートブランチからコミットをチェリーピック

時には、リモートブランチに重要な修正が存在し、ブランチ全体をマージせずにその修正をローカルブランチに適用したい場合があります。以下がその方法です:

  • リモートリポジトリから最新の変更をフェッチします
git fetch origin
  • リモートブランチのコミットをリストアップして必要なハッシュを見つけます:
git log origin/feature_branch --oneline
  • 必要なコミットのハッシュをabc1234と仮定します。
  • ローカルのメインブランチに切り替えます:
git checkout main
  • リモートブランチからコミットをチェリーピックします:
git cherry-pick abc1234

これにより、リモートブランチからコミットを適用することができ、ブランチ全体をマージする必要はありません。

リモートブランチをチェックアウトする必要がありますか?Gitのリモートブランチ用のチェックアウトのステップバイステップガイドに従ってください。

例5:コミットをチェリーピックして変更する

コミットをチェリーピックしたが、コミットする前にわずかな修正を加える必要がある場合、Gitのインタラクティブモードを使用できます。次の方法をご覧ください:

  • ターゲットブランチに切り替える:
git checkout main
  • コミットをチェリーピックしますが、コミットする前に停止します:
git cherry-pick -n abc1234

-n(または--no-commit)フラグは変更を適用しますが、コミットを作成しません。

  • 必要に応じてファイルを変更します。
  • 変更をステージングして手動でコミットします:
git add . git commit -m "Modified cherry-picked commit from feature_branch"

これは、チェリーピックされたコミットを最終化する前に微調整が必要な場合に役立ちます。

GitのCherry-Pick中の競合の処理

ブランチ間でコミットをチェリーピックする際には、特にコードベースが大幅に分岐している場合には競合が避けられません。

cherry-pickは変更をきれいに適用するよう設計されていますが、常に違いを自動的に調整できるわけではありません。このような場合、衝突を手動で解決する必要があります。衝突がどのように発生し、それを処理する方法を理解することは、cherry-pick操作を完了するために重要です。

衝突が発生する原因

通常、衝突は、cherry-pickされたコミットの変更が対象ブランチに既に存在する変更と重複したり矛盾したりする場合に発生します。たとえば:

  • 両方のブランチで同じ行が変更された場合:ソースと対象の両方のブランチで同じコード行が変更された場合、Gitはどちらのバージョンを適用すべきかわかりません。
  • 1つのブランチでファイルが削除されましたが、別のブランチで修正されました:ファイルが1つのブランチで削除されたが、cherry-pickされたコミットで修正された場合、Gitはそれを保持するか変更を適用するかわからなくなります。
  • 関連のない変更があるが、同じファイルです:変更が関連していないように見えても、同じファイル内で発生する場合、Gitは潜在的な競合としてフラグを立てるかもしれません。

競合が発生すると、Gitはcherry-pick操作を停止し、作業ディレクトリを解決する必要がある競合状態に置いておきます。

競合の解決

一度競合が発生すると、Gitは競合しているファイルの指標を提供し、不一致を手動で解決する必要があります。競合を解決する方法は次のとおりです:

1. 競合しているファイルを確認します: 以下のコマンドを実行して、競合しているファイルを確認します:

git status

コマンドを実行すると、競合しているファイルの一覧が表示されます。

2. 競合を解決します: 問題を解決するために、競合しているファイルを手動で編集できます。競合マーカー(<<<<<<<, =======, >>>>>>>)を削除し、どの変更を残すか、またはどのように組み合わせるかを決定します。

3. Git Mergetoolを使用する(オプション):手動での競合解決が煩雑な場合、マージツールを使用して競合の可視化および解決を支援できます:

git mergetool

設定に応じて、上記のツールがビジュアルマージツールを開くことがあり、競合の確認および解決が容易になります。

4. 競合を解決済みとしてマークする: 競合を解決した後は、ファイルを解決済みとしてマークします:

git add <conflicted-file>

5. チェリーピックを完了します:すべての競合が解決され、ファイルがステージングされたら、次のコマンドを実行してチェリーピックを完了させます:

git cherry-pick --continue

多くの現代のIDEやツール、例えばVisual Studio CodeやGitHubなどが組み込みのマージ競合解決機能を提供しています。GitHubのWebインターフェースを使用すると、プルリクエスト内で競合を直接解決でき、ローカル環境に切り替えることなく共有リポジトリでの共同作業が容易になります。

競合後のコミットをスキップする

場合によっては、競合の解決が複雑すぎることがあるか、コミットが実際に必要ないことに気付くかもしれません。そのような場合には、コミットをスキップすることができます。

1. 現在のチェリーピックプロセスを中止します:もし競合が複雑すぎて、コミットを適用したくない場合は、次のコマンドを実行してスキップすることができます:

git cherry-pick --skip

これにより、競合しているコミットが放棄され、次のコミットに移行します(複数のコミットをチェリーピックしている場合)。

2. チェリーピック全体を中止します:もしcherry-pick操作を完全に中止したい場合は、次のコマンドを実行します:

git cherry-pick --abort

このコマンドにより、作業ディレクトリがチェリーピックを開始する前の状態に戻ります。

コミット履歴を整理したいですか?複数のコミットを1つにまとめる方法を学びましょうこの Git squash チュートリアルを使用して。

Git Cherry-Pick の使用に関するベストプラクティス

cherry-pick を誤用すると、プロジェクトのバージョン管理で複雑な履歴や混乱が発生する可能性があります。これらの落とし穴を避けるために、最善の方法を守ることで、不必要な複雑さをコードベースに導入せずにcherry-pick を効果的に使用できます。

小さくて具体的に保つ

Cherry-pick を使用する際は、バグ修正や小規模な機能の向上など、明確に定義されたタスクに対処する小さな具体的なコミットに最も効果的です。

大規模で複雑なコミットを選別することは避け、複数の変更をまとめたものは衝突を発生させ、コードベースの管理を難しくします。コミットがターゲットを絞れば、予期せぬ副作用なく適用しやすくなります。

チェリーピックを文書化する

明確な履歴を維持するためには、チェリーピック時には常に適切な文脈を提供してください。詳細なコミットメッセージやドキュメントの注釈を通じて行うことができます。

要点は、なぜチェリーピックが必要だったのかを説明する必要があるということです。長期間存続するブランチ間や協力環境を超えてチェリーピックする場合に特に重要です。これにより、将来の貢献者がなぜ変更が選択的に適用されたのかを理解するのに役立ちます。

コミット履歴を確認

チェリーピックをする前に、ソースとターゲットのブランチのコミット履歴を確認してください。このステップは、チェリーピックしようとしているコミットが他の変更に依存していないかを特定するのに役立ちます。依存関係が欠落していると、機能が不完全であったりバグが発生する可能性があるため、チェリーピックが半端な機能や更新を導入しないようにしてください。

チェリーピックの過度な使用を避ける

チェリーピックは特定の変更を適用するのに便利ですが、過度に使用するとブランチ間で重複したコミットが生じ、断片化した履歴が生まれる可能性があります。これにより、特定の変更の元をたどることや、より広範な開発の文脈を理解することが難しくなる場合があります。

チェリーピックの前に、マージやリベースがより適切な戦略かどうかを常に評価してください。コミット履歴を混乱させないように、cherry-pickを慎重かつ目的を持って使用してください。

Gitで不要なファイルに苦戦していますか?.gitignoreを効果的に使用する方法を学び、this Git ignore チュートリアルを参照してください。

Git Cherry-Pickの一般的な問題の解決方法

cherry-pickを使用する際に発生する問題のトラブルシューティングには、Gitの基本的なメカニズムを明確に理解する必要があります。このセクションでは、cherry-pick中に遭遇する可能性のある一般的な問題とその解決方法について説明します。

存在しないコミットをcherry-pickする

現在のブランチからアクセスできないか、すでにマージ済みのコミットをcherry-pickしようとすることがあります。これにより、コミットが見つからないか適用できないというエラーメッセージが表示されることが一般的です。

1. コミットが見つかりません: これは、チェリーピックしようとしているコミットハッシュが現在のリポジトリやブランチのコンテキストに存在しない場合に発生します。コミットが存在するブランチで git log を使用してコミット履歴を確認し、正しいコミットを参照していることを確認してください。解決策:

  • コミットハッシュが正しいことを再確認してください。
  • アクセス権限を持っているブランチにコミットが存在することを確認してください。
  • コミットがリモートブランチにある場合は、git fetch でブランチが取得されているか確認してください。

2. すでに適用されたコミット:コミットがすでにマージまたはチェリーピックされている場合、Gitは重複を防ぎます。この保護機能により、履歴が整理され、冗長な変更が回避されます。解決策:

  • git logを使用して、コミットがすでにターゲットブランチにあるかどうかを確認します。
  • 必要な場合は、変更がすでに適用されているため、cherry-pick操作をスキップしてください。

リベースまたはマージ後のチェリーピック

リベースまたはマージ後のチェリーピックは、ブランチの変更された履歴によって複雑さを導入する可能性があります。リベースはコミット履歴を書き換え、マージはブランチを結合しますが、どちらもチェリーピックの適用可能性に影響を与えるかもしれません。

1. Rebased commitsに起因する競合: リベース後、コミット履歴が書き換えられるため、リベースプロセス中に変更されたコミットをcherry-pickしようとすると問題が発生する可能性があります。cherry-pickが書き換えられた履歴に合わない変更を適用しようとするため、競合が発生することがあります。解決策:

  • cherry-pickするコミットがすでに変更されていないかを確認するために、リベース後のコミット履歴を注意深く確認するには、git logを使用します。
  • 標準のcherry-pickプロセスと同様に、git statusと手動での編集を使用して競合を解決します。

2. マージ後の重複コミット: ブランチをマージすると、チェリーピックしたいコミットが既にマージされた履歴に含まれている場合があります。もう一度チェリーピックすると、重複したコミットが発生し、履歴がごちゃごちゃして変更を追跡しにくくなります。解決策:

  • チェリーピックする前に、両方のブランチのコミット履歴を確認して、コミットが既にマージされているかどうかを確認します。
  • ターゲットブランチにすでに同じコミットがある場合は、チェリーピックを避けます。

Gitで変更を元に戻す必要がありますか?この Git reset と revert の違いについて学ぶ:git resetgit revertこの Git reset と revert の違いのチュートリアル

Conclusion

git cherry-pickは、特定のコミットを1つのブランチから別のブランチにマージせずに適用する強力な方法です。バグ修正、機能の更新、または変更を選択的に適用する場合、Gitの履歴をきれいで焦点を絞った状態に保つのに役立ちます。

このガイドでは、単一のコミットや複数のコミットをcherry-pickする方法、競合の解決、一般的な落とし穴を避けるためのベストプラクティスについて説明しました。賢くcherry-pickを使用することで、リポジトリを整理し、作業フローを改善できます。

Gitスキルを向上させたい場合は、強力な出発点としてGitの基礎をチェックしてみてください。また、GitHubコンセプト入門を探求したり、GitHub基礎スキルトラックで構造化されたアプローチを取ることもできます。

これでプロのようにcherry-pickする方法を知ったので、次のプロジェクトで試してみましょう!

Source:
https://www.datacamp.com/tutorial/git-cherry-pick