開発Divの藤原です。
レビュー待ちの間に、次の修正をしたい。だけど、次の修正も同じファイルだからレビュー中のコミットに修正が入ったらマージが面倒。。。という場面、開発していると出くわすことはあるかと思います。
こういったケースに使うGitコマンドを実例を交え、Step by Step(ステップ・バイ・ステップ)でご紹介します。
1つ目の修正
以下のような内容のREADME.mdを修正する例を元に説明していきます。
aaaaaaaaaa bbbbbbbbbb cccccccccc
まずは、featureブランチ作成。
/git-test (develop) $ ls README.md /git-test (develop) $ git checkout -b features_001 /git-test (features_001) $
最終行に一行追加します。
/git-test (features_001) $ vim README.md
aaaaaaaaaa
bbbbbbbbbb
cccccccccc
+dddddddddd
修正をコミットし、サーバーにプッシュ。
/git-test (features_001) $ git add . /git-test (features_001) $ git commit -m '001' /git-test (features_001) $ git push origin features_001
コミットログの確認。
/git-test (features_001) $ git log --oneline b457454 (HEAD -> features_001, origin/features_001) 001
ここまでは通常の手順です。続いてこの修正に重ねて修正する方法について説明していきます。
2つ目の修正
features_001のから派生させたブランチを作ります。
/git-test (features_001) $ git checkout -b features_002 /git-test (features_002) $
こうすることで、features_001の修正が入った状態のファイルに修正を加えることが可能です。
先頭行を変更します。
/git-test (features_002) $ vim README.md
-aaaaaaaaaa +1111111111 bbbbbbbbbb cccccccccc dddddddddd
あとは、1つ目と同じように修正をコミットし、サーバーにプッシュ。
/git-test (features_002) $ git add . /git-test (features_002) $ git commit -m '002' /git-test (features_002) $ git push origin features_002
コミットログの確認。
/git-test (features_002) $ git log --oneline 71525b4 (HEAD -> features_002, origin/features_002) 002 b457454 (origin/features_001, features_001) 001
ここまでで、1つ目の修正を取り込んだ2つ目の修正ができました。
1つ目の修正を変更
例えば、1つ目でレビュー指摘を受けた場合などにより修正が必要になった場合の対応方法です。
まずは、1つ目の修正のブランチへ切り替え。
/git-test (features_002) $ git checkout features_001 /git-test (features_001) $
最終行に入れた修正を変更します。
/git-test (features_001) $ vim README.md
aaaaaaaaaa bbbbbbbbbb cccccccccc -dddddddddd +dddddeeeee
コミットを上書きします。
/git-test (features_001) $ git add . /git-test (features_001) $ git commit --amend コミットのviが立ち上がるので、そのまま保存。
変更を確認。
/git-test (features_001) $ git show
aaaaaaaaaa
bbbbbbbbbb
cccccccccc
+dddddeeeee
コミットが上書きされていることを確認。
サーバーにプッシュ。
/git-test (features_001) $ git push -f origin features_001
サーバーに一度プッシュしている場合、-f
オプション強制
オプションを付ける必要があります。
これは文字通り強制的にローカルの内容をサーバーへ反映するものですので、利用の際には注意が必要です。他の人のコミットを消したりしないように気を付けてください。
ちなみに、このケースで-f
オプションが必要なのは、一度サーバーに反映したコミットを書き換える(履歴を書き換える)ためだと思います。コミットの上書きではなく追加の別コミットをプッシュする場合は-f
オプションは不要です。
コミットログの確認。
/git-test (features_001) $ git log --oneline a762606 (HEAD -> features_001) 001
1つ目の修正の変更を2つ目の修正へ取り込む
この段階で2つ目の修正には、上記の1つ目の修正の変更は取り込まれていません。 しかし、あるコマンドを使うことで簡単に取り込むことができます。
まずは、2つ目の修正のブランチへ切り替え。
/git-test (features_001) $ git checkout features_002 /git-test (features_002) $
1つ目の修正の変更をマージ。※この記事はココが一番ポイントです。
/git-test (features_002) $ git pull --rebase origin features_001 From localhost:fuji/git-test * branch features_001 -> FETCH_HEAD First, rewinding head to replay your work on top of it... Applying: 002 Using index info to reconstruct a base tree... M README.md Falling back to patching base and 3-way merge... Auto-merging README.md
自動でマージされました。
変更を確認。
/git-test (features_002) $ git show
-aaaaaaaaaa +1111111111 bbbbbbbbbb cccccccccc dddddeeeee
1つ目の修正の変更が反映されています。最後の行。
コミットログの確認。
/git-test (features_002) $ git log --oneline cb1e694 (HEAD -> features_002) 002 a762606 (origin/features_001, features_001) 001
マージコミットも作られておらず、履歴も保たれています。
サーバーにプッシュ。
/git-test (features_002) $ git push -f origin features_002
ここでも-f
オプション強制
オプションが必要です。
これで、1つ目の修正の変更を2つ目の修正へ取り込むことができました。
developブランチに入れられた他の人のコミットを取り込む場合なども手順は同じです。その場合は、サーバーの情報を一度pullコマンドで取得する必要があります。
/git-test (features_002) $ git checkout develop /git-test (develop) $ git pull origin develop /git-test (develop) $ git checkout features_002 /git-test (features_002) $ git pull --rebase origin develop
1つ目の修正を変更を2つ目の修正へ取り込んでコンフリクト(衝突)したとき
1つ目の修正の変更を取り込む以下のコマンドで、修正内容によってはコンフリクトが発生することがあります。
/git-test (features_002) $ git pull --rebase origin features_001 From localhost:fuji/git-test * branch features_001 -> FETCH_HEAD First, rewinding head to replay your work on top of it... Applying: 002 error: Failed to merge in the changes. Using index info to reconstruct a base tree... M README.md Falling back to patching base and 3-way merge... Auto-merging README.md CONFLICT (content): Merge conflict in README.md Patch failed at 0001 002 The copy of the patch that failed is found in: .git/rebase-apply/patch Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". /git-test (features_002|REBASE 1/1) $
このようなメッセージが表示された場合はコンフリクトが発生していますので、手動でマージする必要があります。
コンフリクトを発生させるため、1つ目の修正の先頭行に以下のような行を追加しています。
+xxxxxxxxxx
aaaaaaaaaa
手動マージをします。
/git-test (features_002|REBASE 1/1) $ vim README.md
ファイルはこんな感じになっています。
<<<<<<< HEAD xxxxxxxxxx aaaaaaaaaa ======= 1111111111 >>>>>>> 002 bbbbbbbbbb cccccccccc dddddeeeee
不要な行を削除し、以下のように変更し保存します。
xxxxxxxxxx 1111111111 bbbbbbbbbb cccccccccc dddddeeeee
修正したファイルをaddします。
/git-test (features_002|REBASE 1/1) $ git add README.md
手動マージを完了します。
/git-test (features_002|REBASE 1/1) $ git rebase --continue
変更を確認。
/git-test (features_002) $ git show
xxxxxxxxxx -aaaaaaaaaa +1111111111 bbbbbbbbbb cccccccccc dddddeeeee
期待通りの差分が表示されます。
コミットログの確認。
/git-test (features_002) $ git log --oneline 6d2bd26 (HEAD -> features_002) 002 b1ebd43 (origin/features_001, features_001) 001
マージコミットも作られておらず、履歴も保たれています。
後は、サーバーにプッシュするだけ。
/git-test (features_002) $ git push -f origin features_002
これでコンフリクトも解消できました。