はじめに
機能毎の仕様書を読みつつ、「変更点」を忠実にコーディングしてcommitした後、push前に再度仕様書を確認したときのことです。
「...ん?Aパラメータの追加とB検索条件の追加って、別リリースじゃね?汗」
ということで、別ブランチにpushすべき内容を一つのブランチにまとめてcommitしてしまったときの対処を記録しておこうと思います。
対処としてやったこと一つ一つは大したことありませんが、実際やったときは結構焦りましたね...。
前提となる状況
- とあるプロジェクトの中のとある機能の仕様変更
- A変更とB変更は同一機能かつ同一ファイルに対する変更
- A変更は実際に作業したブランチ(以下、branch_a)にcommitするべき(ここであってた)
- B変更は別のブランチ(以下、branch_b)にcommitするべき(ここじゃダメ)
この状況で、A変更・B変更共にbranch_aにて作業し、いっぺんにcommitしてしまいました(pushはまだしていない)
対処の流れ
とりあえず当該commitを作業ツリーに戻す
↓
add -p でこのブランチに対応する変更のみステージングしてcommit
↓
残りをstashで退避して別ブランチに移動
↓
退避していた分を作業ツリーに戻しcommit
とりあえず当該commitを作業ツリーに戻す
$ git reset HEAD~1
HEADから1つめのcommit、つまり直近のcommitについて、commitとaddをresetするコマンドです。
これによってadd前、すなわち全変更が作業ツリー上にあり、ステージングされていない状態に戻ります。
add -p でこのブランチに対応する変更のみステージングしてcommit
$ git add -p
git add -pは、ステージングするときにファイルの一部分だけ選んだりできる便利なコマンドです。
このコマンドを叩くと下記のように、各変更をステージングするか聞かれるので、こちらの記事などを参考に編集してステージングしていきます。
diff --git a/sample.txt b/sample.txt
index 51827b4..68e24a3 100644
--- a/sample.txt
+++ b/sample.txt
@@ -1,6 +1,8 @@
サンプル
サンプル
+A変更
サンプル
+B変更
サンプル
サンプル
サンプル
Stage this hunk [y,n,q,a,d,s,e,?]?
バラバラにステージングしたいので「s」(split)と入力します。
すると以下のように表示されます。(eだと手動でeditできるみたいですね)
Split into 2 hunks.
@@ -1,3 +1,4 @@
サンプル
サンプル
+A変更
サンプル
Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?
A変更はbranch_a(当該ブランチ)にコミットするので「y」を入力してステージングします。
同様にB変更についても聞かれますが、branch_aではステージングしないため、「n」を入力して作業ツリーに残したままにします。
statusはこんな感じ。
$ git status
On branch branch_a
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: sample.txt
希望通りにステージングされたので、commitします。
$ git commit -m "A変更を実装"
残りをstashで退避して別ブランチに移動
$ git stash save
$ git checkout branch_b
stashで一時的に作業(ここではB変更)を退避したあと、本来B変更をcommitするはずだったbranch_bに移動します。
退避していた分を作業ツリーに戻しcommit
$ git stash pop
$ git add .
$ git commit -m "B変更を実装"
めでたしめでたし!
おわりに
今回はpush前だったのでセーフ(?)ですが、pushしてしまった場合もバレないうちに周りの人に許可を取ってrebaseすればいいかと思います。
commitが大きい点に関しては、チケット毎にcommitするというプロジェクト規約に則っていたので一チケットだと勘違いしてcommitするに至りました。push時に規約に合わせるのはともかくとして、localでは細かくcommitして、push前にまとめればよかったのかもしれません。
あと、一番の解決策は最初からちゃんと仕様書を確認して作業を始めることです。反省します。