git merge — 枝分かれした歴史をつなぐ
2-3 では、Windows のノート PC と Mac で別々にコミットすると、push も git pull --ff-only も止まるのを見ました。枝分かれした2本の歴史を1本につなぐ方法の1つが git merge です。merge は「別のブランチの付箋が指すコミットを、今のブランチに取り込む」コマンドで、取り込み方は2通りあります。付箋を前へずらすだけの fast-forward(早送り)と、親が2つのマージコミットを作るやり方です。この回では、どちらになるかの決まりと --ff-only・--no-ff を見てから、同じ行を両方が変えたときのコンフリクトの直し方とやめ方を確かめます。最後に、2-3 で止まった枝分かれを merge で解きます。
- 上のターミナルは、実際に打ったときと同じ出力です(Git は英語で答えます)
- 下の中で起きていることは、コマンドの結果、Git の中の何が変わったかを図にしたものです。丸がコミット、黒い札がブランチ、ピンクの札が HEAD です。マージコミットには親が2つあるので、2本の線がその丸で合流します
- コンフリクトで止まっている間は、ターミナルのプロンプトに
|MERGING(マージの途中)が付きます - 6 の区間だけはリモートがあり、グラフが2つ並びます。上が GitHub 側、下が手元です。Mac での操作はターミナルには何も出ず、上の図だけが進みます
- 右の説明をスクロールして読み進めると、左のターミナルでコマンドが1つずつ打たれます。
→キーでも1つずつ進みます(←で1つ戻ります。スマホでは「次へ」ボタン)。最後まで進んでから→を押すと次の区間へ移ります。黄色く光っているのが、そのコマンドで変わった場所です
1. merge が取り込むもの — fast-forward
git merge memo は、付箋 memo が指すコミットと、そこから親を辿れるコミットを、今のブランチに取り込むコマンドです。「今のブランチ」は HEAD が乗っているブランチで、動くのはその付箋だけです。相手の memo は動きません。向きを取り違えやすいので、main に memo を取り込みたいなら、先に main に switch してから git merge memo を打つ、と覚えてください。
いちばん簡単なのは、今のブランチが相手の祖先(相手から親を辿っていくと行き着くコミット)になっている場面です。作業用のブランチ memo でコミットしてから main に戻り、memo を取り込みます。
付箋をずらすだけのマージ — fast-forward
作業用のブランチ
memoを作って乗り換えます。いまはmainとmemoの付箋が、同じ卵を追加に貼ってあります。$ git switch -c memo Switched to a new branch 'memo'memoの上で、新しいファイルnotes.txtを書きます。$ echo "牛乳は低脂肪" > notes.txtnotes.txtをステージに載せます。$ git add notes.txtmemoだけがメモを追加に進みました。mainは卵を追加に残っています。$ git commit -m "メモを追加" [memo b78e6bd] メモを追加 1 file changed, 1 insertion(+) create mode 100644 notes.txtmainに戻ります。作業ツリーからnotes.txtが消えたのは、mainのコミットにまだ入っていないからです。$ git switch main Switched to branch 'main'mainの卵を追加は、memoのメモを追加の親、つまり 祖先 です。だから Git は新しいコミットを作らず、付箋mainをメモを追加へずらすだけで済ませます(Fast-forward)。--ff-onlyは「早送りで済むときだけ進める」指定で、ここでは済むので通ります。$ git merge --ff-only memo Updating 8b41d07..b78e6bd Fast-forward notes.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 notes.txtもう一度 merge すると、
Already up to date.(もう取り込み済み)と答えて何もしません。memoのコミットは、すべてmainから辿れるからです。$ git merge memo Already up to date.取り込み済みなので、付箋
memoは-dで剥がせます。コミットメモを追加はmainから辿れるので消えません。$ git branch -d memo Deleted branch memo (was b78e6bd).歴史は1本のまっすぐな列のままです。fast-forward では、「ブランチで作業した」という跡はグラフに残りません。
$ git log --oneline b78e6bd (HEAD -> main) メモを追加 8b41d07 卵を追加 3f2a9c1 牛乳を追加
main の先頭は memo の祖先なので、付箋 main を memo の位置まで前へずらせば、memo のコミットはすべて main から辿れるようになります。これが fast-forward(早送り)で、新しいコミットは1つもできません。出力の読み方はこうです。
| 出力の行 | 意味 |
|---|---|
Updating 8b41d07..b78e6bd | 今のブランチの付箋を 8b41d07 から b78e6bd へ動かす |
Fast-forward | 早送りで済ませた(新しいコミットは作っていない) |
notes.txt | 1 + など | 動かす前と後で、作業ツリーのファイルがどう変わったか |
Already up to date. | 相手のコミットは、もう全部今のブランチから辿れる。何もしなかった |
2-3 の git pull --ff-only や、2-4 でプルリクエストのマージのあとに手元の main を追いつかせたときも、中でやっていたのはこの早送りです。相手が memo ではなく origin/main だった、というだけの違いです。
2. 両方が進んでいたら — マージコミット
今のブランチと相手が、同じ地点から別々に進んでいることもあります。2-3 で見た枝分かれ(diverged)です。このときは付箋をずらすだけでは済みません。main を memo の位置へずらすと、main にしかないコミットが辿れなくなるからです。
そこで Git は、両方の先頭を親に持つ新しいコミットを1つ作り、今のブランチの付箋をそこへ進めます。これがマージコミットです。中身は、分かれた地点・今のブランチの先頭・相手の先頭の3つを比べて決めます。分かれた地点から片方だけが変えたところは、その変更を採ります。両方の変更が1つのコミットに集まり、どちらのコミットも消えません。
早送りになるか、マージコミットになるかは、2本の位置の関係だけで決まります。
| 今のブランチと相手の関係 | git merge 相手 の結果 | 出力 |
|---|---|---|
| 相手が今のブランチの祖先(取り込み済み) | 何もしない | Already up to date. |
| 今のブランチが相手の祖先 | fast-forward(付箋をずらすだけ) | Updating a..b / Fast-forward |
| どちらも祖先ではない(枝分かれ) | マージコミットを作る | Merge made by the 'ort' strategy. |
次のシーンでは、main が todo.txt の1行目を、memo が notes.txt を足してから同じ todo.txt の4行目を変えています。
両方が進んでいたら — マージコミット
今度は
mainとmemoが、買い物リストを作るから別々に進んでいます。mainは1行目を牛乳を2本買うに、memoはnotes.txtを足してから4行目をバターを2箱買うに変えました。$ git log --oneline --all 7c3e915 (HEAD -> main) 牛乳を2本に d29f4b7 (memo) バターを2箱に a61c0e8 メモを追加 3f2a9c1 買い物リストを作るmainの先頭はmemoの祖先ではないので、付箋をずらすだけでは追いつけません。--ff-onlyはNot possible to fast-forward, aborting.(早送りできないので中止します)と止まり、何も変えません。$ git merge --ff-only memo hint: Diverging branches can't be fast-forwarded, you need to either: hint: hint: git merge --no-ff hint: hint: or: hint: hint: git rebase hint: hint: Disable this message with "git config set advice.diverging false" fatal: Not possible to fast-forward, aborting.オプションを付けない merge は、親が2つの マージコミット を作ります。同じ
todo.txtでも、変えた行が離れていればAuto-merging todo.txt(自動で混ぜた)で済みます。$ git merge memo Auto-merging todo.txt Merge made by the 'ort' strategy. notes.txt | 1 + todo.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 notes.txt1行目は
mainの変更、4行目はmemoの変更で、両方が入っています。$ cat todo.txt 牛乳を2本買う 卵を買う パンを買う バターを2箱買うmainから辿れるコミットに、memoの2つが加わりました。git logはマージコミットの親を両方辿るので、2本の枝のコミットが1列に並びます。$ git log --oneline 942c065 (HEAD -> main) Merge branch 'memo' 7c3e915 牛乳を2本に d29f4b7 (memo) バターを2箱に a61c0e8 メモを追加 3f2a9c1 買い物リストを作る取り込んだあとに同じ merge を打っても、
Already up to date.で何も起きません。$ git merge memo Already up to date.memoのコミットはすべてmainから辿れるので、-dで付箋を剥がせます。$ git branch -d memo Deleted branch memo (was d29f4b7).
ort は、Git がいま標準で使っているマージの方式の名前です。出力に出るだけで、気にしなくてかまいません。どこまで自動で混ざるかは、変えた場所で決まります。
| 両方が変えた場所 | merge の動き |
|---|---|
| 別々のファイル | 自動で混ざる |
| 同じファイルの、離れた行 | 自動で混ざる(Auto-merging todo.txt) |
| 同じ行、または隣り合う行 | コンフリクトで止まる(4 で扱う) |
気をつけたいのは、「自動で混ざった」は、行の位置がぶつからなかったという意味でしかないことです。Git は中身の意味を見ていません。たとえばプログラムで、片方が関数の名前を変え、もう片方が古い名前でその関数を呼ぶ行を足すと、行はぶつからないので静かに混ざり、できあがったコードは動きません。マージのあとは、テストを走らせるなどして中身を確かめる習慣が要ります。
もう1つ、人がターミナルで git merge を打ってマージコミットができるときは、メッセージを確かめるエディタが開くことがあります。何も変えずに保存して閉じれば、Merge branch 'memo' のまま確定します。Claude Code のようにプログラムから打つとエディタは開かず、そのまま確定します。
3. --ff-only と --no-ff — 合わせ方を指定する
オプションを付けない git merge は、早送りで済めば早送り、済まなければマージコミット、と Git に任せます。合わせ方を自分で決めたいときに付けるのが、次の2つです。
| 書き方 | 早送りできるとき | 枝分かれしているとき |
|---|---|---|
git merge 相手 | fast-forward | マージコミットを作る |
git merge --ff-only 相手 | fast-forward | 何も変えずに止まる |
git merge --no-ff 相手 | マージコミットを作る | マージコミットを作る |
--ff-only は、2-3 の git pull --ff-only と同じ約束です。歴史の形を変えずに済むときだけ進め、済まないときは止まって判断を返すので、1 と 2 のシーンで見たとおり、通っても止まっても何も壊しません。止まったら、その先をどうつなぐかを人が決めます。
--no-ff(no fast-forward)は逆に、早送りできる場面でもわざわざマージコミットを作ります。2-4 で、GitHub の Merge pull request は「GitHub 側の main が進んでいなくても、いつもマージコミットを作る」と書きました。手元で同じ形を作るのが --no-ff です。
早送りできてもマージコミットを作る — --no-ff
1 の merge の前と同じ形です。
memoがmainより1つ先にあり、ふつうに merge すれば早送りになります。$ git log --oneline --all 5d7e2b4 (memo) メモを追加 8b41d07 (HEAD -> main) 卵を追加 3f2a9c1 牛乳を追加--no-ffを付けると、早送りできる場面でも マージコミット を作ります。Merge made by the 'ort' strategy.(ort という方式でマージした)は、マージコミットを作ったときの出力です。グラフでは卵を追加からの線とメモを追加からの線が、新しいコミットで合流します。$ git merge --no-ff memo Merge made by the 'ort' strategy. notes.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 notes.txtメッセージには
Merge branch 'memo'が自動で付きます。マージコミットの親は2つで、1つ目が卵を追加(それまでのmain)、2つ目がメモを追加です。$ git log --oneline 361488b (HEAD -> main) Merge branch 'memo' 5d7e2b4 (memo) メモを追加 8b41d07 卵を追加 3f2a9c1 牛乳を追加付箋
memoを剥がしても、メモを追加はマージコミットの2つ目の親としてmainから辿れます。$ git branch -d memo Deleted branch memo (was 5d7e2b4).memoの札は消えましたが、「ここで memo を取り込んだ」というマージコミットが歴史に残りました。GitHub の Merge pull request がいつも作るのが、この形です。$ git log --oneline --all 361488b (HEAD -> main) Merge branch 'memo' 5d7e2b4 メモを追加 8b41d07 卵を追加 3f2a9c1 牛乳を追加
1 の fast-forward と見比べると違いがはっきりします。fast-forward のあとは、メモを追加 がもともと memo で作られたことは歴史から読み取れません。--no-ff なら、マージコミットの2つ目の親を辿れば「ここからここまでが memo の作業だった」と分かります。作業のまとまりを歴史に残したいチームが --no-ff を選び、まっすぐな歴史を好むなら早送り、という使い分けです。1人で2台を使うだけなら、どちらを選んでも困ることはありません。
4. 同じ行を両方が変えたとき — コンフリクト
同じ行を両方が別々に変えていると、Git にはどちらを採ればよいか決められません。この状態をコンフリクト(衝突)と呼びます。Git は自動で混ぜられるところまで済ませてから、ぶつかった箇所のファイルに印を書き込み、マージの途中で止まります。1-7 stash で「pop がぶつかるとき」として触れたのも、このコンフリクトです。
題材は、main で「卵を2つ買う」、feature で「卵を6つ買う」と、同じ2行目を別々に変えた場面です。
同じ行を両方が変えたとき — コンフリクト
mainは2行目を卵を2つ買うに、featureは同じ2行目を卵を6つ買うに変えています。どちらを採るか Git には決められないので、CONFLICT (content): Merge conflict in todo.txtと言って途中で止まります。ここから先のプロンプトには、(main|MERGING)(マージの途中)と付きます。$ git merge feature Auto-merging todo.txt CONFLICT (content): Merge conflict in todo.txt Automatic merge failed; fix conflicts and then commit the result.ぶつかった行に、Git が 印 を書き込みました。
<<<<<<< HEADから=======までが今のブランチ(main)の側、=======から>>>>>>> featureまでが取り込もうとした相手の側です。ぶつからなかった1行目と3行目は、そのまま残っています。$ cat todo.txt 牛乳を買う <<<<<<< HEAD 卵を2つ買う ======= 卵を6つ買う >>>>>>> feature パンを買うYou have unmerged paths.(まだ解決していないファイルがある)と、both modified:(両方が変えた)が出ます。直して commit するか、git merge --abortでやめるか、の案内も出ています。$ git status On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: todo.txt no changes added to commit (use "git add" and/or "git commit -a")印を消して、残したい中身にファイルを書き直します。ここでは
卵を6つ買うを採りました。両方を残しても、別の文に書き換えてもかまいません。$ printf '牛乳を買う\n卵を6つ買う\nパンを買う\n' > todo.txtマージの途中の
git addは、「このファイルは 解決した」という印を付ける意味になります。$ git add todo.txtAll conflicts fixed but you are still merging.(コンフリクトは全部直ったが、まだマージの途中)に変わりました。あとは commit でマージを締めくくります。$ git status On branch main All conflicts fixed but you are still merging. (use "git commit" to conclude merge) Changes to be committed: modified: todo.txt--no-editは、Git が用意したメッセージMerge branch 'feature'をそのまま使う指定です。親が2つのマージコミットができてマージの途中が終わり、プロンプトからMERGINGが外れます。$ git commit --no-edit [main dc55e06] Merge branch 'feature'卵を2つと卵を6つの両方が、mainの歴史に入りました。いまのファイルの中身は、手で直した卵を6つ買うです。$ git log --oneline dc55e06 (HEAD -> main) Merge branch 'feature' c3c3c3c (feature) 卵を6つ b4e81a2 卵を2つ 3f2a9c1 買い物リストを作る
印は3つで1組です。上から順に読みます。
| 印の行 | 意味 |
|---|---|
<<<<<<< HEAD | ここから下が、今のブランチ(HEAD。このシーンでは main)の側 |
======= | 区切り。ここから下が、取り込もうとした相手の側 |
>>>>>>> feature | 相手の側の終わり。feature は相手のブランチの名前 |
直し方は3手です。
- ファイルを書き直して、印を消す。どちらかの側を採る、両方を残す、新しい文に書き換える、のどれでもかまいません。シーンでは
printfでファイルを丸ごと書き直しましたが、エディタで印の行を消して直しても同じです git add ファイルで「解決した」と印を付ける。マージの途中のgit addは、ステージに載せると同時に、both modifiedの一覧から外す意味を持ちますgit commit --no-editでマージコミットを作る。--no-editは、Git が用意したメッセージ(Merge branch 'feature')をそのまま使う指定です。自分で書くならgit commit -m "…"
注意したいのは、Git は印が残っているかどうかを確かめずに add も commit も通すことです。印を消し忘れたまま add すると、<<<<<<< HEAD の行ごとコミットされてしまいます。add の前に、ファイルに <<<<<<< や ======= が残っていないかを見てください。
Claude Code にコンフリクトを任せると、ファイルを編集して印を消し、git add と git commit で締めくくる流れになります。許可画面で見るべきなのはコマンドではなく、どちらの側を採ったかです。「卵を2つ」と「卵を6つ」のように、どちらも正しそうに見える変更ほど、採った側が意図どおりかを差分で確かめてから許可します。
5. merge --abort — やめて元に戻す
コンフリクトで止まったマージは、解決して commit するか、やめるかしないと終わりません。その間は commit もブランチの乗り換えも止められます。「今はこのマージを片づけたくない」というときにやめるのが git merge --abort です。
やめて元に戻す — merge --abort
4 と同じ場面です。merge がコンフリクトで止まりました。
$ git merge feature Auto-merging todo.txt CONFLICT (content): Merge conflict in todo.txt Automatic merge failed; fix conflicts and then commit the result.解決していないファイルがあるうちは、commit できません(
Committing is not possible because you have unmerged files.)。最後の行のUは、Unmerged(未解決)の印です。$ git commit -m "とりあえず保存" error: Committing is not possible because you have unmerged files. hint: Fix them up in the work tree, and then use 'git add/rm <file>' hint: as appropriate to mark resolution and make a commit. fatal: Exiting because of an unresolved conflict. U todo.txtブランチの乗り換えも、
you need to resolve your current index first(先に解決して)と止められます。止まった merge は、片づけるまで付いて回ります。$ git switch feature error: you need to resolve your current index first todo.txt: needs merge直しかけて、
卵を4つ買うと書いてみました。でも、このマージは今はやめることにします。$ printf '牛乳を買う\n卵を4つ買う\nパンを買う\n' > todo.txtgit merge --abortは、merge を打つ前の状態に戻します。付箋もコミットも動かず、作業ツリーとステージが卵を2つのコミットの中身に戻ります。直しかけた卵を4つ買うも消えます。$ git merge --abortマージの途中ではなくなり、作業ツリーもきれいです。プロンプトからも
MERGINGが消えました。$ git status On branch main nothing to commit, working tree clean卵を2つ買うに戻っています。featureはそのまま残っているので、あとでいつでも merge し直せます。$ cat todo.txt 牛乳を買う 卵を2つ買う パンを買う
--abort が戻すのは、merge を打つ直前の状態です。コンフリクトで止まったマージは、まだ付箋もコミットも動かしていないので、そこは何も変わりません。変わるのは作業ツリーとステージで、印入りのファイルも、直しかけた中身も、HEAD のコミットの中身に戻ります。直しかけた作業はコミットしていないので、どこにも残りません。長いコンフリクトを半分まで直してから --abort すると、その半分は最初からやり直しです。
もう1つ、git merge は書きかけのあるファイルを上書きしそうなときは、始める前に Your local changes to the following files would be overwritten by merge(書きかけが merge で上書きされる)と止まります。checkout や pull と同じ守りです。merge は、作業ツリーをきれいにしてから打つのが基本で、書きかけがあるなら先にコミットするか、1-7 の stash で退避します。
6. 2台で枝分かれしたとき — fetch・merge・push
ここまでの道具で、2-3 で止まった場面を解けます。Windows のノート PC と Mac で別々にコミットして、手元の main と GitHub の main が枝分かれした場面です。手順は git fetch で GitHub の様子を取り込み、git merge origin/main で2本をつなぎ、git push で送る、の3手です。
2台で枝分かれしたら — fetch して merge して push
2-3 の続きです。Windows のノート PC で、GitHub の様子を確かめずに
todo.txtに1行書き足します。$ echo "バターを買う" >> todo.txt手元の
mainがバターを追加に進みました。$ git commit -am "バターを追加" [main 15e1410] バターを追加 1 file changed, 1 insertion(+)同じころ、Mac でも
メモを追加を作って push しました。GitHub 側のmainは、手元とは別の方向へ進みます。push は
(fetch first)で拒否されます。GitHub 側のメモを追加を消さないために、Git が止めています。$ git push To https://github.com/you/memo-app.git ! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/you/memo-app.git' hint: Updates were rejected because the remote contains work that you do not hint: have locally. This is usually caused by another repository pushing to hint: the same ref. If you want to integrate the remote changes, use hint: 'git pull' before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.fetch すると
メモを追加が手元に届き、origin/main がそこへ進みます。手元のグラフでも、卵を追加から2本に分かれたのが見えるようになりました。$ git fetch From https://github.com/you/memo-app c43e6a8..9ae3d51 main -> origin/mainhave diverged(枝分かれした)と出ます。2-3 では、ここでgit pull --ff-onlyが止まりました。今度は2本をつなぎます。$ git status On branch main Your branch and 'origin/main' have diverged, and have 1 and 1 different commits each, respectively. (use "git pull" if you want to integrate the remote branch with yours) nothing to commit, working tree clean取り込む相手は、追跡ブランチ
origin/mainでもかまいません。バターを追加とメモを追加を親に持つマージコミットができ、メッセージはMerge remote-tracking branch 'origin/main'になります。$ git merge origin/main Merge made by the 'ort' strategy. notes.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 notes.txtahead of 'origin/main' by 2 commitsに変わりました。バターを追加とマージコミットの2つが、まだ GitHub に無いコミットです。もう枝分かれではありません。$ git status On branch main Your branch is ahead of 'origin/main' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean今度は push が通ります。手元の
mainは GitHub 側のメモを追加を含んでいるので、GitHub の付箋は前に進むだけで、何も消えないからです。$ git push To https://github.com/you/memo-app.git 9ae3d51..530423b main -> mainWindows の
バターを追加も Mac のメモを追加も、GitHub のmainに残りました。git fetch→git merge origin/main→git pushが、枝分かれを解く手順の1つです。$ git log --oneline 530423b (HEAD -> main, origin/main, origin/HEAD) Merge remote-tracking branch 'origin/main' 9ae3d51 メモを追加 15e1410 バターを追加 c43e6a8 卵を追加 3f2a9c1 牛乳を追加
push が通ったのは、マージコミットが GitHub 側の メモを追加 を親として含んでいるからです。GitHub の main から見ると、手元の main は「自分の先にまっすぐ続いている」ので、付箋を前へ進めるだけで済みます。merge で2本をつなぐと、どちらのコミットも消さずに push できる形になるわけです。このあと Mac の側では、git pull --ff-only で早送りするだけで追いつけます。Mac の main(メモを追加)は、新しいマージコミットの祖先だからです。
2-3 で残しておいた、オプション無しの git pull の話もここでつながります。git pull は fetch と取り込みを続けて行うコマンドで、pull.rebase false と設定してあれば、取り込みは git merge origin/main です。つまりこのシーンの fetch と merge を、1回で打つのと同じです。設定が無いまま枝分かれした状態で git pull を打つと、You have divergent branches and need to specify how to reconcile them.(枝分かれしているので、どうつなぐか決めて)と止まります。
fetch と merge を分けて打つ利点は、間で git status や git log --oneline --all を打って、何が届いたかを確かめてから取り込めることです。コンフリクトしそうなら、そこで止まって考えられます。
ただ、2台で作業するたびに merge でつなぐと、そのたびにマージコミットが1つ増え、グラフは小さな輪がいくつも連なった形になっていきます。中身には問題がありませんが、あとで歴史を読むときに「Merge remote-tracking branch 'origin/main'」の行がたくさん挟まります。これを避けて、手元のコミットを origin/main の先へ並べ直すのが、次の回の rebase です。
7. Claude Code が打つ merge
Claude Code が打った Git のコマンド延べ約14,000回のうち、git merge は55回で、そのうち25回が git merge --ff-only でした。git pull も51回のうち24回が --ff-only です。半分近くが「早送りで済むときだけ」の指定になっているのは、済まない場面では止まって、つなぎ方の判断を人に返せるからです。
ですから、--ff-only が止まったあとに Claude Code が --ff-only を外した git merge を打とうとしたら、それは「マージコミットを作る」という判断です。中身が消えることはありませんが、歴史の形は変わります。rebase で並べ直すほうがよいか、そもそもつなぐ前に確かめることがないかを、許可の前に一度考えてみてください。
8. Claude Code の許可画面で見かけたら
この回で見たコマンドを、「何が消えうるか」で並べるとこうなります。
| コマンド | 何が起きるか | 消えうるもの |
|---|---|---|
git merge 相手(早送りになるとき) | 今のブランチの付箋を前へずらす。新しいコミットは作らない | なし(作業ツリーのファイルが新しい中身になる。書きかけが上書きされるなら止まる) |
git merge 相手(枝分かれしているとき) | 親が2つのマージコミットを足して、今のブランチを進める。ぶつかればコンフリクトで止まる | なし(歴史にマージコミットが残る) |
git merge --ff-only 相手 | 早送りで済むときだけ進める。済まないときは何も変えずに止まる | なし |
git merge --no-ff 相手 | 早送りできるときでも、マージコミットを作る | なし |
git add / git commit --no-edit(コンフリクトの途中) | 解決した印を付ける / マージコミットを作ってマージを終える | なし(印が残っていても、そのままコミットされる) |
git merge --abort | merge を打つ前の状態に戻す。付箋とコミットは動かない | 注意 コンフリクトを直しかけた作業 |
git pull(オプション無し) | fetch して、設定によってマージコミットを作る・rebase する・止まる | 注意 歴史の形が変わる(設定を確かめる) |
見分け方は、merge そのものは何も消さないということです。付箋を前へずらすか、コミットを1つ足すだけで、どちらのブランチのコミットも辿れるまま残ります。気をつけるのは、直しかけを捨てる --abort と、設定しだいで動きの変わる git pull の2つです。作ってしまったマージコミットを push の前に取り消したいときは、1-5 reset で付箋を1つ前に戻せます(--hard は書きかけも消すので、作業ツリーがきれいなときだけにします)。
まとめ
git merge 相手は、相手の付箋が指すコミットを今のブランチに取り込む。動くのは今のブランチの付箋だけ- 今のブランチが相手の祖先なら fast-forward(付箋をずらすだけで、新しいコミットはできない)。枝分かれしていれば、親が2つのマージコミットを作る。取り込み済みなら
Already up to date. --ff-onlyは早送りで済むときだけ進めて、済まなければ止まる。--no-ffは早送りできてもマージコミットを作る(GitHub の Merge pull request と同じ形)- 別々のファイル・離れた行の変更は自動で混ざる。同じ行を両方が変えるとコンフリクトになり、
<<<<<<< HEAD(今の側)/=======/>>>>>>> 相手(相手の側)の印が入る - 直し方は、ファイルを書き直して印を消す →
git add→git commit --no-edit。やめるならgit merge --abort(直しかけは消える)。止まっている間は commit も switch もできない - 2台で枝分かれしたら、
git fetch→git merge origin/main→git pushでつなげる
merge は、枝分かれした2本をそのままの形で残して、マージコミットで結ぶ方法でした。次の回では、もう1つの方法 git rebase を見ます。手元のコミットを相手の先頭の上に作り直して、歴史を1本にまっすぐ並べるやり方です。作り直したコミットは中身が同じでも ID が変わります。Claude Code がよく打つ git rebase --autostash と git rebase --continue が何をしているかも、そこで1コマンドずつ確かめます。