はじめに
Git の cherry-pick 機能を使用すると、あるブランチから別のブランチに特定のコミットを適用できます。強力な機能ですが、エラーや競合が原因で cherry-pick 操作を元に戻す必要がある場合があります。この実験(Lab)では、cherry-pick を実行し、必要に応じてそれを元に戻すためのさまざまな方法を学びます。最終的には、cherry-pick 操作に関する実践的な経験と、一般的な問題から回復するためのスキルを習得できます。
テストリポジトリの設定
このステップでは、cherry-pick 操作を練習するためのテスト Git リポジトリを作成します。これにより、さまざまな Git コマンドを試すための安全な環境が提供されます。
新しい Git リポジトリの作成
まず、テストリポジトリ用の新しいディレクトリを作成し、それを Git リポジトリとして初期化することから始めましょう。
mkdir -p ~/project/cherry-pick-lab
cd ~/project/cherry-pick-lab
git init
次のような出力が表示されるはずです。
Initialized empty Git repository in /home/labex/project/cherry-pick-lab/.git/
Git ユーザー設定のセットアップ
コミットを行う前に、Git のユーザー名とメールアドレスを設定する必要があります。
git config --local user.name "LabEx User"
git config --local user.email "labex@example.com"
メインブランチでの最初のコミットの作成
メインブランチで最初のコミットをいくつか作成しましょう。
## 最初のファイルを作成してコミットします
echo "## Cherry Pick Lab" > README.md
git add README.md
git commit -m "Initial commit with README"
## 2番目のファイルを作成してコミットします
echo "console.log('Hello, world!');" > app.js
git add app.js
git commit -m "Add main application file"
コミット履歴の表示
すべてが正しく設定されていることを確認するために、コミット履歴を確認しましょう。
git log --oneline
次のような出力が表示されるはずです。
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
実際のコミットハッシュは、システムによって異なります。「Add main application file」のコミットハッシュをメモしておいてください。後で使用します。
機能ブランチの作成
次に、いくつかの追加の変更を加える機能ブランチを作成しましょう。
git checkout -b feature-branch
次のような出力が表示されるはずです。
Switched to a new branch 'feature-branch'
次に、この機能ブランチにいくつかのコミットを追加しましょう。
## 新しい機能ファイルを作成してコミットします
echo "function newFeature() { return 'awesome'; }" > feature.js
git add feature.js
git commit -m "Add new feature function"
## README ファイルを変更します
echo -e "## Cherry Pick Lab\n\nThis repo demonstrates git cherry-pick operations." > README.md
git add README.md
git commit -m "Update README with project description"
これで、2 つのコミットを持つメインブランチと、2 つの追加コミットを持つ機能ブランチができました。次のステップでは、cherry-pick を使用して、機能ブランチのコミットの 1 つをメインブランチに適用します。
Cherry-pick 操作の実行
このステップでは、cherry-pick コマンドを使用して、あるブランチから別のブランチに特定のコミットを適用する方法を学びます。これは、あるブランチから別のブランチへの変更を、選択的に組み込みたい場合に役立ちます。
Cherry-pick の理解
Git の cherry-picking を使用すると、あるブランチから特定のコミットを選択し、それを別のブランチに適用できます。通常複数のコミットを適用するマージやリベースとは異なり、cherry-picking は一度に 1 つのコミットのみを適用します。
メインブランチへの切り替え
まず、機能ブランチからコミットを適用したいメインブランチに切り替えましょう。
git checkout main
切り替えを確認する出力が表示されるはずです。
Switched to branch 'main'
機能ブランチのコミットの表示
cherry-picking を行う前に、メインに適用したい機能ブランチのコミットを調べましょう。
git log feature-branch --oneline
これにより、メインブランチと共有されているものを含め、機能ブランチ内のすべてのコミットが表示されます。次のような出力が表示されます。
1234abc Update README with project description
5678def Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
「Add new feature function」のコミットハッシュ(この例では 5678def)をメモしておいてください。次のステップでこのハッシュを使用します。
コミットの Cherry-pick
次に、「Add new feature function」コミットを機能ブランチからメインブランチに cherry-pick しましょう。
git cherry-pick [COMMIT_HASH]
[COMMIT_HASH] を、先ほどメモした実際のハッシュに置き換えます。例:
git cherry-pick 5678def
cherry-pick が成功すると、次のような出力が表示されます。
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
Cherry-pick の検証
cherry-pick が期待どおりに機能したことを確認しましょう。
git log --oneline
これで、cherry-pick されたコミットがメインブランチの履歴に表示されるはずです。
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
また、ファイルが存在することも確認できます。
ls -la
出力に feature.js がリストされているはずです。
total 16
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 42 Jan 1 00:00 feature.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
cherry-pick 操作により、機能ブランチからのコミットがメインブランチに正常に適用されました。次のステップでは、必要に応じてこの cherry-pick を元に戻す方法を学びます。
Git Reset を使用した Cherry-pick の取り消し
cherry-pick を正常に実行したので、この操作を元に戻す方法を学びましょう。このステップでは、最近の cherry-pick を元に戻す最も簡単な方法である git reset コマンドを使用します。
Git Reset の理解
git reset コマンドは、現在のブランチポインタを指定されたコミットに移動し、その時点以降のすべてのコミットを効果的に「元に戻します」。git reset には、主に 3 つのモードがあります。
--soft: ブランチポインタを移動しますが、変更はステージングされたままになります--mixed(デフォルト): ブランチポインタを移動し、変更のステージングを解除します--hard: ブランチポインタを移動し、すべての変更を破棄します
cherry-pick を元に戻すために、cherry-pick されたコミットとその変更を完全に削除するために、--hard オプションを使用します。
現在のステータスの確認
まず、現在のステータスを確認して、cherry-pick されたコミットを含むメインブランチにいることを確認しましょう。
git log --oneline -n 3
次のような出力が表示されるはずです。
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Git Reset を使用した Cherry-pick の取り消し
cherry-pick 操作を元に戻すには、--hard オプションを指定して git reset を使用し、ブランチポインタを 1 つ前のコミットに戻します。
git reset --hard HEAD~1
このコマンドは、Git に対して、現在の HEAD (~1 の部分は「1 つ前のコミット」を意味します) の前のコミットにブランチをリセットするように指示します。
次のような出力が表示されるはずです。
HEAD is now at abcd123 Add main application file
リセットの検証
cherry-pick が元に戻されたことを確認しましょう。
git log --oneline
cherry-pick されたコミットが履歴に表示されなくなったはずです。
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
feature.js ファイルが削除されたかどうかも確認しましょう。
ls -la
出力には feature.js が含まれていないはずです。
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
おめでとうございます!git reset を使用して、cherry-pick 操作を正常に元に戻しました。この方法はクリーンでシンプルですが、履歴を書き換えるため、共有リポジトリにプッシュされていないローカルの変更にのみ使用する必要があります。
Git Revert を使用した Cherry-pick の取り消し
前のステップでは、git reset を使用して cherry-pick を元に戻しました。ただし、git reset は履歴を書き換えるため、変更を既に共有リポジトリにプッシュしている場合は問題が発生する可能性があります。このステップでは、履歴を書き換えることなく、git revert を使用して cherry-pick を安全に元に戻す方法を学びます。
Git Revert の理解
git revert コマンドは、以前のコミットによって導入された変更を元に戻す新しいコミットを作成します。履歴からコミットを削除する git reset とは異なり、git revert は変更に対抗する新しいコミットを追加し、コミット履歴を保持します。
Cherry-pick の再実行
まず、元に戻すものがあるように、コミットをもう一度 cherry-pick しましょう。
## Get the commit hash from the feature branch
FEATURE_HASH=$(git log feature-branch --oneline | grep "new feature" | cut -d ' ' -f 1)
## Cherry-pick the commit
git cherry-pick $FEATURE_HASH
次のような出力が表示されるはずです。
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
現在のステータスの確認
cherry-pick が成功したことを確認しましょう。
git log --oneline -n 3
ls -la
履歴に cherry-pick されたコミットと、ディレクトリリストに feature.js ファイルが表示されるはずです。
Cherry-pick の Revert
次に、履歴を保持しながら、git revert を使用して cherry-pick を元に戻しましょう。
git revert HEAD --no-edit
--no-edit フラグは、エディタを開かずにデフォルトのコミットメッセージを使用するように Git に指示します。
次のような出力が表示されるはずです。
[main abc9876] Revert "Add new feature function"
1 file changed, 1 deletion(-)
delete mode 100644 feature.js
Revert の検証
コミット履歴を確認しましょう。
git log --oneline -n 4
cherry-pick されたコミットと revert コミットの両方が表示されるはずです。
abc9876 (HEAD -> main) Revert "Add new feature function"
98765ab Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
次に、feature.js ファイルが削除されたかどうかを確認しましょう。
ls -la
出力には feature.js が含まれていないはずです。
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
git reset と git revert はどちらも同じ最終結果 (cherry-pick によって導入された変更の削除) を達成しますが、その方法は異なります。
git resetは履歴からコミットを削除します。これは、コミットが他のユーザーと共有されている場合に問題を引き起こす可能性があります。git revertは変更を元に戻す新しいコミットを追加し、コミット履歴を保持します。これは、共有リポジトリにとってより安全です。
これらの方法のどちらを選択するかは、特定の状況によって異なります。
- 共有されていないローカルの変更には
git resetを使用します - 共有リポジトリにプッシュされた変更には
git revertを使用します
Cherry-pick の競合の処理
コミットを cherry-pick すると、コミット内の変更が現在のブランチの変更と競合する場合、Git が競合に遭遇することがあります。このステップでは、cherry-pick の競合を処理する方法と、cherry-pick 操作を中止する方法を学びます。
潜在的な競合が発生するシナリオの作成
まず、cherry-pick の競合が発生するシナリオを作成しましょう。
## main ブランチに切り替えて README.md を変更します
git checkout main
echo -e "## Cherry Pick Lab\n\nThis is the main branch README." > README.md
git commit -am "Update README in main branch"
## feature ブランチに切り替えて、README.md に競合する変更を加えます
git checkout feature-branch
echo -e "## Cherry Pick Lab\n\nThis README has been updated in the feature branch." > README.md
git commit -am "Update README in feature branch"
競合を伴う Cherry-pick の試行
次に、main ブランチに戻り、feature ブランチからコミットを cherry-pick してみましょう。
git checkout main
CONFLICT_HASH=$(git log feature-branch --oneline | grep "Update README in feature" | cut -d ' ' -f 1)
git cherry-pick $CONFLICT_HASH
両方のブランチが README.md の同じ行を変更したため、競合が表示されるはずです。
error: could not apply a1b2c3d... Update README in feature branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
競合の表示
競合を調べてみましょう。
git status
README.md での競合を示す出力が表示されるはずです。
On branch main
You are currently cherry-picking commit a1b2c3d.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
競合したファイルの内容を見てみましょう。
cat README.md
次のようなものが表示されるはずです。
## Cherry Pick Lab
<<<<<<< HEAD
This is the main branch README.
=======
This README has been updated in the feature branch.
>>>>>>> a1b2c3d... Update README in feature branch
競合の解決
競合を解決するには、ファイルを編集し、どの変更を保持するかを決定する必要があります。README.md を変更して、両方の変更を含めましょう。
echo -e "## Cherry Pick Lab\n\nThis is the main branch README.\n\nThis README has also been updated with content from the feature branch." > README.md
次に、競合を解決済みとしてマークし、cherry-pick を続行しましょう。
git add README.md
git cherry-pick --continue
Git は、デフォルトのコミットメッセージでエディタを開きます。エディタを保存して閉じ、cherry-pick を完了します。
Cherry-pick の中止
場合によっては、競合を解決したくない場合があり、cherry-pick 操作をキャンセルしたい場合があります。別の競合を作成し、cherry-pick を中止しましょう。
## feature ブランチで別の競合するコミットを作成します
git checkout feature-branch
echo "// This will conflict with app.js in main" > app.js
git commit -am "Modify app.js in feature branch"
## このコミットを main に cherry-pick してみます
git checkout main
ANOTHER_CONFLICT=$(git log feature-branch --oneline | grep "Modify app.js" | cut -d ' ' -f 1)
git cherry-pick $ANOTHER_CONFLICT
別の競合が表示されるはずです。今回は、cherry-pick を中止しましょう。
git cherry-pick --abort
cherry-pick 操作がキャンセルされ、作業ディレクトリが以前の状態に復元されたことがわかるはずです。
git status
出力:
On branch main
nothing to commit, working tree clean
cherry-pick 操作中の競合の処理は、Git ユーザーにとって不可欠なスキルです。競合が発生した場合は、次の 3 つのオプションがあります。
- 競合を手動で解決し、
git addとgit cherry-pick --continueを使用します - 競合するコミットを
git cherry-pick --skipでスキップします git cherry-pick --abortで cherry-pick 操作全体を中止します
最適なアプローチは、特定の状況とプロジェクトの要件によって異なります。
まとめ
この実験では、Git の cherry-pick 機能に関する実践的な経験を積み、cherry-pick 操作を元に戻す複数の方法を学びました。
- 練習用に、複数のブランチとコミットを持つテストリポジトリを作成しました。
- あるブランチから別のブランチに特定のコミットを適用するために、cherry-pick 操作を実行しました。
- ローカルの変更に適した
git resetを使用して cherry-pick を元に戻す方法を学びました。 - 履歴を保持する
git revertを使用して、cherry-pick を安全に元に戻す方法を調べました。 - cherry-pick の競合を処理する練習をし、cherry-pick 操作を中止する方法を学びました。
これらのスキルは、実際のプロジェクトで Git を使用する際に非常に役立ちます。Cherry-picking を使用すると、ブランチ間で変更を選択的に適用できます。また、cherry-pick を元に戻す方法を知っておくことで、誤りから回復し、クリーンな Git 履歴を維持できます。
さまざまな元に戻す方法が異なる目的に役立つことを覚えておいてください。
- 共有されていないローカルの変更には
git resetを使用します - 共有リポジトリにプッシュされた変更には
git revertを使用します - 進行中の cherry-pick 操作をキャンセルするには、
git cherry-pick --abortを使用します
これらのオプションを理解することで、特定の状況に最適な方法を選択できます。



