Skip to content
blog.kenichikat.me
Go back

コンフリクトしたPRの解消方法:rebaseとmergeの比較

Updated:

Dependabotが同じタイミングで複数のPRを出してきて、package.jsonpnpm-lock.yamlを触るPRを先にマージしたら、残りのPRが軒並みコンフリクトする状態になった。これはDependabot特有の話ではなく、複数人が同じファイルを触るブランチを並行して作っていれば普通に起きる状況なので、rebaseとmergeそれぞれでの解消手順と違いを整理しておく。

状況

同じmainから分岐している、かつ、PR AとPR Bが同じファイルの同じ・あるいは近い行を書き換えている場合には、コンフリクトする。 今回は、両方のPRがpackage.jsonpnpm-lock.yamlを編集したためにコンフリクトが発生した。

この状態のPR Bを解消する方法が、大きく分けてrebaseとmergeの2通りある。

rebaseで解消する

PR Bのブランチのコミットを、最新のmainの上に積み直す方法。

git fetch origin
git switch pr-b-branch
git rebase origin/main

コンフリクトが起きると、そのコミットの適用が止まる。

# コンフリクトしたファイルを手動で編集して解消する
git add <解消したファイ>
git rebase --continue

PR Bに複数コミットが積まれている場合、コミットごとにこの作業を繰り返すことになる。全部解消したら、履歴を書き換えているのでリモートへは force push が必要。

git push --force-with-lease

--forceではなく--force-with-leaseを使うと、自分がfetchした時点から他人がリモートを更新していた場合はpushが止まる。共有ブランチで他人の変更を上書きしてしまう事故を防げる。

やめたくなったらgit rebase --abortで、rebase開始前の状態に戻せる。

mergeで解消する

PR Bのブランチに、最新のmainを取り込む方法。

git switch pr-b-branch
git merge origin/main

コンフリクトが起きたら同様に手動で解消する。

git add <解消したファイ>
git commit

マージコミットができるだけで、既存のコミットは書き換えられない。なのでpushも通常通りでよく、force pushは不要。

git push

こちらもgit merge --abortで開始前の状態に戻せる。

比較

rebasemerge
履歴の形直線的になる(PR Bのコミットがmainの先頭に積み直される)分岐がそのまま残り、マージコミットができる
既存コミットの扱い書き換わる(コミットハッシュが変わる)変わらない
push方法force push(--force-with-lease推奨)通常のpush
コンフリクト解消の回数コミットの数だけ発生しうる1回にまとめて解消
ブランチを他人と共有している場合危険(force pushで他人の履歴を壊しうる)安全

一番の判断基準は「そのブランチを自分以外も触っているか」だと思う。自分しかpushしていない作業ブランチなら、rebaseで履歴をきれいな直線に保てる。逆に他の人も同じブランチにpushしている、あるいはそのブランチから別のブランチを切っている人がいる場合は、force pushが履歴を壊す原因になるのでmergeの方が安全。

ちなみに、Dependabotが出すPRはbot側が自動でrebaseしてくれるため、待つだけで解消するので対応不要。


Share this post on:

Previous Post
GitHubのPRマージ戦略:Squash and merge・Merge commit・Rebase mergeの違い
Next Post
GTM経由でブログにGA4を導入した