Skip to content

Instantly share code, notes, and snippets.

@hankei6km
Last active February 8, 2024 09:01
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hankei6km/4301ebc7e320b987de1f7a5b0acb994a to your computer and use it in GitHub Desktop.
Save hankei6km/4301ebc7e320b987de1f7a5b0acb994a to your computer and use it in GitHub Desktop.
git のブランチを別のブランチへ付け替える (git rebase --onto)

git のブランチを別のブランチへ付け替える (git rebase --onto)

たまに --onto を使おうと思うと忘れているのでメモ.

基本(普通に rebase)

これを

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch1
  checkout branch1
  commit id: "D"
  commit id: "E"
  commit id: "F"
  checkout develop
  commit id: "a"
  commit id: "b"

こうするには

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-1"

以下のように rebase を使う。

$ git rebase develop branch1

現在のブランチが branch1 だった場合はこうでも大丈夫。

$ git rebase develop

なお、実行するとコミット「D E F」のハッシュ値などは変更されます(このメモでは変更されたコミットに枝番を付けます)。

例1

これを

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch1
  checkout branch1
  commit id: "D"
  commit id: "E"
  commit id: "F"
  branch branch2
  checkout branch2
  commit id: "G"
  commit id: "H"
  commit id: "I"
  checkout develop
  commit id: "a"
  commit id: "b"

こうするには

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch1
  checkout branch1
  commit id: "D"
  commit id: "E"
  commit id: "F"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch2
  checkout branch2
  commit id: "G-1"
  commit id: "H-1"
  commit id: "I-1"

以下のように --onto を使う。

$ git rebase --onto develop branch1 branch2

意味としては、

  • develop へ付け替える
  • 付け替えるのは branch2
  • branch2 の上流(branch2 の分岐元)は branch1

となります。

例2

これの branch1rebase したら

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch1
  checkout branch1
  commit id: "D"
  commit id: "E"
  commit id: "F"
  branch branch2
  checkout branch2
  commit id: "G"
  commit id: "H"
  commit id: "I"
  checkout develop
  commit id: "a"
  commit id: "b"

こうなってしまった

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch2 order:2
  checkout branch2
  commit id: "D"
  commit id: "E"
  commit id: "F"
  commit id: "G"
  commit id: "H"
  commit id: "I"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-1"

そのまま branch2rebase する

branch2 を新しい branch1rebase すると

$ git rebase branch1 branch2
warning: skipped previously applied commit <HASH値>
warning: skipped previously applied commit <HASH値>
warning: skipped previously applied commit <HASH値>
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config advice.skippedCherryPicks false"

こうなる。

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-1"
  branch branch2
  checkout branch2
  commit id: "G-1"
  commit id: "H-1"
  commit id: "I-1"

rebase のデフォルトの挙動では対象になるコミットの内容を読みとって比較します(詳細はこちら)。よって、branch2 に含まれている「D E F」は「D-1 E-1 F-1」と同一として扱われるのでスキップされます。 (コメントで教えてもらいました、ありがとうございます)

また、上記のスキップは branch1 にコミットを追加していても機能します。

branch2 の存在を忘れていて branch1 を更新してしまった(コミット c ができている)

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch2 order:2
  checkout branch2
  commit id: "D"
  commit id: "E"
  commit id: "F"
  commit id: "G"
  commit id: "H"
  commit id: "I"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-1"
  commit id: "c"

branch2 の存在を思い出して rebase すると

$ git rebase branch1 branch2
warning: skipped previously applied commit <HASH値>
warning: skipped previously applied commit <HASH値>
warning: skipped previously applied commit <HASH値>
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config advice.skippedCherryPicks false"
Successfully rebased and updated refs/heads/branch2.

コンフリクトがなければこうなる。

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-1"
  commit id: "c"
  branch branch2
  checkout branch2
  commit id: "G-1"
  commit id: "H-1"
  commit id: "I-1"

-onto が必要な場合

F-1--amend して F-2 がで出来てしまった

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  branch branch2 order:2
  checkout branch2
  commit id: "D"
  commit id: "E"
  commit id: "F"
  commit id: "G"
  commit id: "H"
  commit id: "I"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-2"

この後に rebase すると F がスキップされないのでコンフリクトしやすい。

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px', 'git2': '#ff0000', 'gitBranchLabel2': '#ffffff' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-2"
  branch branch2 order:2
  checkout branch2
  commit id: "F" type: REVERSE
  commit id: "G"
  commit id: "H"
  commit id: "I"

以下のように、branch2 の分岐元としてコミット F(元の branch1)のハッシュ値(今回の例では 53c6b6 とする)を指定

$ git rebase --onto branch1 53c6b6 branch2

コンフリクトがなければこうなる。

%%{init: { 
 'gitGraph': { 'rotateCommitLabel': false, 'mainBranchName': 'develop' },
 'themeVariables': { 'commitLabelFontSize': '18px' }
} }%%
gitGraph
  commit id: "A"
  commit id: "B"
  commit id: "C"
  checkout develop
  commit id: "a"
  commit id: "b"
  branch branch1
  checkout branch1
  commit id: "D-1"
  commit id: "E-1"
  commit id: "F-2"
  branch branch2
  checkout branch2
  commit id: "G-1"
  commit id: "H-1"
  commit id: "I-1"
@hkuno9000
Copy link

例2のシナリオでは --onto を使わなくても

git rebase branch1 branch2

にて、無事にリベース出来るようです。
gitが、自動的にD,E,Fのコミット適用をスキップしてくれました。

@hankei6km
Copy link
Author

hankei6km commented Oct 14, 2022

@hkuno9000 こちらでもスキップされたのでテキストの方に反映させました。
コメントありがとうございました!

@hankei6km
Copy link
Author

MermaidGitgraph Diagrams を使って書き直して、Zenn にも転載しました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment