rebaseとcherry-pick
変更内容の同一性とコミットの同一性を分け、再適用後の親・ファイル構成・履歴を確認します。
説明
Gitでは、同じ変更を別の履歴の上へ適用できます。rebaseは一連のコミットを別の基点へ載せ直し、cherry-pickは指定したコミットの変更を現在のブランチへ適用します。変更内容が同じでも、親が変わればコミットIDは変わります。
共通の初期コミットから、mainは説明書、featureは機能ファイル、releaseは設定ファイルを追加した状態で始めます。featureをmainの上へrebaseし、元の機能変更をreleaseへcherry-pickします。元のコミットはbefore-rebaseタグで参照できるようにしてあります。
変更内容の同一性とコミットの同一性を分け、再適用後の親・ファイル構成・履歴を確認します。
1三つに分かれた開始状態
各ブランチとタグを含む履歴を表示します。現在はfeatureです。
git log --graph --all全参照からたどれる履歴を表示する --oneline --decorateブランチとタグの名前を付けるinitialから3方向へ履歴が分かれています。before-rebaseは現在のfeatureのコミットを指し、後で載せ直す前後を比較する目印になります。
2featureが追加した変更
共通祖先からfeatureの差分を表示します。
git diff main...feature共通祖先以降のfeatureの変更を読むfeature.txtにbetaを1行追加した変更です。mainの説明書とは別ファイルなので、この例では同じ箇所の競合なしで再適用できます。
3mainの上へ載せ直す
featureの変更をmainの先へrebaseします。コマンド後に、新しい親と件名を表示します。
git rebase -q main現在のfeatureをmainの上へ再適用する
git log feature --format="%h parent=%p各コミットの親IDを表示する %s"featureの親がmainの説明書追加コミットになりました。初期コミットを親に持っていた元のfeatureとは、別のコミットです。
4親が違っても機能ファイルは同じ
機能ファイルの内容差と、新旧の親IDを確認します。
git diff before-rebase feature -- feature.txt機能ファイルの新旧を比較する
git rev-parse before-rebase^ feature^ main元の親・新しい親・mainを順に解決するfeature.txtの差分は出ません。最初の親IDはinitial、次の二つはmainのIDで一致します。変更対象の内容は保ちつつ、基点が変わっています。
5全ファイルが同一とは限らない
今度はファイルを限定せずに、載せ直す前後を比較します。
git diff --stat全体の変更ファイルと行数を表示する before-rebase feature
git show feature:README.md新しい基点から継承した内容を読む新しいfeatureにはmainから継承したREADME.mdが加わっています。機能パッチが同じことと、コミット全体のファイル構成が同じことは別です。
6パッチ列の対応を確認
range-diffで、旧基点から旧feature、新基点から新featureという二つの変更列を比較します。
git range-diff二つのコミット列のパッチを比較する initial..before-rebase main..feature旧系列と新系列の範囲対応するコミットに=が付きます。この例ではパッチが等しくても、コミットIDは異なります。rebase後はIDだけでなく変更の内容も確認します。
7一つの変更をreleaseへ適用
releaseへ切り替え、元のfeatureの変更だけを適用します。
git switch release適用先へ切り替える
git cherry-pick before-rebase指定コミットの変更を適用する
git log -2 --format="%h parent=%p %s"release設定のコミットを親に持つ、新しい機能追加コミットができます。mainの説明書追加を一緒に取り込む操作ではありません。
8適用先ごとのファイル構成
releaseとfeatureにあるファイルを列挙します。
git ls-tree --name-only releasereleaseのファイル構成
git ls-tree --name-only featurefeatureのファイル構成
git diff release feature -- feature.txt機能ファイルだけの内容差releaseにはrelease.txt、featureにはREADME.mdがあります。feature.txtの差分はありません。同じ機能変更が、異なる基点に載っている状態です。
9元のコミットも参照できる
最後に元のタグと、新しいfeature・releaseのIDを確認します。
git rev-parse before-rebase feature release三つのコミットIDを表示する
git log --graph --all再適用後の全体の関係を読む --oneline --decorate同じ機能追加でも3個のコミットIDがあります。元のコミットはタグから参照できるため、この例では履歴に残っています。共有済みの履歴を載せ直すと他者の参照と分かれるため、共同作業では更新方針の合意が必要です。
まとめ
rebaseとcherry-pickは、変更を別の基点へ適用して新しいコミットを作ります。
親や基点が異なるため、パッチが同じでもIDと全体のファイル構成は変わります。
元の参照と再適用後を比較し、意図した変更だけが含まれているか確認します。
操作履歴と解説を振り返れます。
Git / シェル
git log --graph --all --oneline --decorate* b5f7c0f (HEAD -> feature, tag: before-rebase) Add feature file | * e98026c (main) Add main documentation |/ | * dd02e64 (release) Add release configuration |/ * dfaf585 (tag: initial) Initial files
git diff main...featurediff --git a/feature.txt b/feature.txt new file mode 100644 index 0000000..65b2df8 --- /dev/null +++ b/feature.txt @@ -0,0 +1 @@ +beta
git rebase -q main
git log feature --format="%h parent=%p %s"69a412b parent=e98026c Add feature file e98026c parent=dfaf585 Add main documentation dfaf585 parent= Initial files
git diff before-rebase feature -- feature.txt
git rev-parse before-rebase^ feature^ maindfaf585ee68990808a5f4c486d0007de53bee54d e98026c7506c02518bd2ebc1e9b3b5db6191d55a e98026c7506c02518bd2ebc1e9b3b5db6191d55a
git diff --stat before-rebase feature
git show feature:README.mdREADME.md | 1 + 1 file changed, 1 insertion(+) main documentation
git range-diff initial..before-rebase main..feature1: b5f7c0f = 1: 69a412b Add feature file
git switch release
git cherry-pick before-rebase
git log -2 --format="%h parent=%p %s"Switched to branch 'release' [release 3f483d9] Add feature file Date: Sun Nov 1 09:00:00 2026 +0900 1 file changed, 1 insertion(+) create mode 100644 feature.txt 3f483d9 parent=dd02e64 Add feature file dd02e64 parent=dfaf585 Add release configuration
git ls-tree --name-only release
git ls-tree --name-only feature
git diff release feature -- feature.txtfeature.txt note.txt release.txt README.md feature.txt note.txt
git rev-parse before-rebase feature release
git log --graph --all --oneline --decorateb5f7c0fd934a53b9eccdcf8b8d5ab8a9dcd0b040 69a412b6599e1cffec5d123677c81defbc8ce744 3f483d9a860dc02e008e01b015545260d0f4c13d * 69a412b (feature) Add feature file * e98026c (main) Add main documentation | * 3f483d9 (HEAD -> release) Add feature file | * dd02e64 Add release configuration |/ | * b5f7c0f (tag: before-rebase) Add feature file |/ * dfaf585 (tag: initial) Initial files
演習完了