開発していて「この差分だけ早めにpr出しておきたいな」って時の便利術


# 概要

開発中に差分が大きくなってきて、一部分を先にプルリクエスト出したかったり、先に本番化してしまいたい事があるときに使える方法です。以下のコマンドを教えてもらって便利だったので、備忘録として投稿します。

**今回使うコマンド**

 - `git diff master > /tmp/diff`
 - `patch -p1 < /tmp/diff`
 - `git add -p`

## 流れ

 - masterブランチにてファイルを作成
 - masterから切ったdevブランチで、そのファイルを修正
 - 上記devブランチのファイル修正の一部だけをfugaブランチに反映させる

## 準備

masterブランチで`hoge.txt`ファイルを作成し、`hogehoge`の文字列を適当に追加しcommitします。

```:hoge.txt
hogehoge


hogehoge
hogehoge



hogehoge
hogehoge
hogehoge

hogehoge


hogehoge
```

## 開発ブランチで文字列の追加

`hoge.txt`ファイルを別ブランチで手を加えていきます。
手を加えていくブランチは`master`からチェックアウトした`dev`ブランチで行います。

```console
git checkout -b dev
```

`fugafuga`, `fugapiyo`, `piyopiyo`の文字列を追加し、commitします。
以下はその差分です。

```:hoge.txt
diff --git a/hoge.txt b/hoge.txt
index e25f5b6..1782e25 100644
--- a/hoge.txt
+++ b/hoge.txt
@@ -1,16 +1,21 @@
 hogehoge
 
+fugafuga
 
+piyopiyo
 hogehoge
 hogehoge
+fugafuga
 
 
 
-hogehoge
-hogehoge
+hogehoge fugafuga
+hogehoge piyopiyo
 hogehoge
 
 hogehoge
+fugapiyo
 
 
 hogehoge
+fugafuga
```

## 差分をピックアップする

いくつか文字列を追加しましたが、`fuga`の部分だけを先にmasterブランチににマージすることになりました。devブランチはそのままにし、別のブランチにて`fuga`だけ差分を反映させたブランチを作成したいと思います。

`master`との差分を`/tmp`以下に一時保存。
そして`dev`ブランチはそのままに`fuga`ブランチで手直しをしましょう。

```terminal
$ git diff master > /tmp/diff
$ git co -b fuga master
```

`fuga`ブランチで一時保存していた差分を当てます。

```
$ patch -p1 < /tmp/diff
```

`git diff`でワークツリー上で保存していた差分が反映されていることが確認できます。
差分が適用されていることが確認できたら以下のコマンドでステージにあげていきます。

```
$ git add -p
```

コマンドで`?`を入力すると利用方法が表示されます。

```
Stage this hunk [y,n,q,a,d,s,e,?]? ?
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
```


```
$ git add -p
diff --git a/hoge.txt b/hoge.txt
index e25f5b6..1782e25 100644
--- a/hoge.txt
+++ b/hoge.txt
@@ -1,16 +1,21 @@
 hogehoge
 
+fugafuga
 
+piyopiyo
 hogehoge
 hogehoge
+fugafuga
 
 
 
-hogehoge
-hogehoge
+hogehoge fugafuga
+hogehoge piyopiyo
 hogehoge
 
 hogehoge
+fugapiyo
 
 
 hogehoge
+fugafuga
Stage this hunk [y,n,q,a,d,s,e,?]? 
```

「この塊(hunk)をステージに上げるか？」と聞かれ、コマンド`[y,n,q,a,d,s,e,?]`を催促されます。
この塊だと`piyopiyo`, `fugapiyo`も含まれてしまうので分割します。
`s`を入力すると塊(hunk)を分割してくれます。

```
Stage this hunk [y,n,q,a,d,s,e,?]? s
Split into 6 hunks.
@@ -1,3 +1,4 @@
 hogehoge
 
+fugafuga
 
Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? y
```

6つに分割してくれたようです。
`fugafuga`はステージに上げるたいので`y`を入力します。
続けて差分が出てきます。

```
@@ -3,3 +4,4 @@
 
+piyopiyo
 hogehoge
 hogehoge
Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? n
```

`piyopiyo`は今回ステージは挙げないので`s`を入力し、スキップします。

```
@@ -6,8 +9,8 @@
 
 
 
-hogehoge
-hogehoge
+hogehoge fugafuga
+hogehoge piyopiyo
 hogehoge
 
 hogehoge
Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? 
```

こちらの差分は2行で一つの差分とされてしまっているので分割は出来ません。
`e`を使って直接編集します。編集は`vi`になります。

```
# Manual hunk edit mode -- see bottom for a quick guide.
@@ -6,8 +9,8 @@
 
 
 
-hogehoge
-hogehoge          # -を半角スペースに置き換える
+hogehoge fugafuga
+hogehoge piyopiyo # 削除
 hogehoge
 
 hogehoge
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
# 
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging.
# If it does not apply cleanly, you will be given an opportunity to
# edit again.  If all lines of the hunk are removed, then the edit is
# aborted and the hunk is left unchanged.
```

`fugafuga`だと思っていたら`fugapiyo`だった！って時も
`K`コマンドで一つ前に戻り、改めて編集することが出来ます。

```
@@ -11,6 +14,7 @@
 hogehoge
 
 hogehoge
+fugapiyo
 
 
 hogehoge
Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? y # ←間違えてステージ追加してしまった
@@ -14,3 +18,4 @@
 
 
 hogehoge
+fugafuga
Stage this hunk [y,n,q,a,d,K,g,/,e,?]? K     # Kコマンドでやり直し
@@ -11,6 +14,7 @@
 hogehoge
 
 hogehoge
+fugapiyo
 
 
 hogehoge
Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? 
```

すべての塊(hunk)の分別が完了したらステージに上っているか確認しましょう。

```
$ git diff --cached
diff --git a/hoge.txt b/hoge.txt
index e25f5b6..3420bb5 100644
--- a/hoge.txt
+++ b/hoge.txt
@@ -1,16 +1,20 @@
 hogehoge
 
+fugafuga
 
 hogehoge
 hogehoge
+fugafuga
 
 
 
 hogehoge
-hogehoge
+hogehoge fugafuga
 hogehoge
 
 hogehoge
+fuga
 
 
 hogehoge
+fugafuga
```

`fuga`だけがステージに上がっていることが確認できました。


## 参考

- [横着で神経質な私とあなたに贈るgit add -p
](https://qiita.com/crifff/items/1abf08bca4ce51db4775)