かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Git 変更のあるファイルの一部だけをコミットしたい。

ファイルを色々変更しちゃったけど、コミットは分けたい時

git add -p を使う

-p オプションで変更のブロック = Hunk(ハンク)ごとにステージにaddするかどうか対話式で選択することができます。

$ git add -p <変更のあるファイル名>

コマンドを実行すると、ファイル内の変更のHunkごと、どうするかが聞きかれます。

  • ステージに追加する場合は y
  • ステージに追加しない場合は n でスキップ
  • 残りのハンクはチェックせずに終了する場合は q

基本的によく使うのはこの3つかなと思います。

変更箇所が7行以上空くと別のハンクとして扱われるそうですが、別にしたい箇所が同じハンクとして表示された場合は

  • s でハンクを分割
  • 上手くハンクを分割できない時は、e で手動でハンクを編集

とすればOK。

サンプル

次のようなステキなリストを作成しました。

// aikatsu.txt
スターライト学園
0. 神崎 美月
1. 星宮 いちご
2. 霧矢 あおい
3. 紫吹 蘭
4. 有栖川 おとめ
5. 藤堂 ユリカ
6. 北大路 さくら
7. 一ノ瀬 かえで
8. 神谷 しおん
9. 三ノ輪 ヒカリ
ドリームアカデミー
1. 音城 セイラ
2. 冴草 きい
3. 風沢 そら
4. 姫里 マリア

↓ 次のように変更してみました

@@ -5,10 +5,10 @@
 3. 紫吹 蘭
 4. 有栖川 おとめ
 5. 藤堂 ユリカ
-6. 北大路 さくら
-7. 一ノ瀬 かえで
-8. 神谷 しおん
-9. 三ノ輪 ヒカリ
+6. 一ノ瀬 かえで
+7. 神谷 しおん
+8. 三ノ輪 ヒカリ
+9. 北大路 さくら
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
+その他
+夏樹 みくる

Hunk(ハンク)を分割してステージにaddする

みくるちゃん(推し)の追加と北大路劇場の並び替えは別々にコミットしたいと思います。
ターミナルに git add -p <ファイル名> を入力します。

$ git add -p aikatsu.txt
diff --git a/aikatsu.txt b/aikatsu.txt
index 3a2c5fe..d17369b 100644
--- a/aikatsu.txt
+++ b/aikatsu.txt
@@ -5,12 +5,14 @@
 3. 紫吹 蘭
 4. 有栖川 おとめ
 5. 藤堂 ユリカ
-6. 北大路 さくら
-7. 一ノ瀬 かえで
-8. 神谷 しおん
-9. 三ノ輪 ヒカリ
+6. 一ノ瀬 かえで
+7. 神谷 しおん
+8. 三ノ輪 ヒカリ
+9. 北大路 さくら
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
+その他
+夏樹 みくる
Stage this hunk [y,n,q,a,d,/,s,e,?]?

Hunkが1つで表示されました。これを分割したいのでsを入力すると…

Split into 2 hunks.
@@ -5,12 +5,12 @@
 3. 紫吹 蘭
 4. 有栖川 おとめ
 5. 藤堂 ユリカ
-6. 北大路 さくら
-7. 一ノ瀬 かえで
-8. 神谷 しおん
-9. 三ノ輪 ヒカリ
+6. 一ノ瀬 かえで
+7. 神谷 しおん
+8. 三ノ輪 ヒカリ
+9. 北大路 さくら
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

いい感じに分かるされました。y でステージにaddします。
残りの変更は今回コミットしたくないのでnでスキップするかqで終了します。
f:id:kikiki-kiki:20170627221439p:plain
👆 SourceTreeでステージの状態
Hunkをスキップした部分がワークス―ペース内に残った状態になっています。
これで、さくらちゃんの並び順の変更とみくるちゃんの追加を別々にコミットすることができます!

さらに、美月さんが卒業して、あかりジェネレーションが入学したのでリストを編集しました。

@@ -1,5 +1,4 @@
 スターライト学園
-0. 神崎 美月
 1. 星宮 いちご
 2. 霧矢 あおい
 3. 紫吹 蘭
@@ -9,10 +8,20 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
+17. 大地のの
+18. 白樺リサ
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
 その他
+神崎 美月
 夏樹 みくる

Hunkが分かれていますが、 美月さんの卒業と、あかりジェネレーションの入学のコミットがいい感じに分かれていません。
美月さんの卒業をコミットした後で、あかりジェネレーションを追加、17, 18の ののりさは編入なので、これもコミットを分けたいと思います。

ターミナルに git add -p <ファイル名> を入力します。

$ git add -p aikatsu.txt
diff --git a/aikatsu.txt b/aikatsu.txt
index d17369b..2b59a87 100644
--- a/aikatsu.txt
+++ b/aikatsu.txt
@@ -1,5 +1,4 @@
 スターライト学園
-0. 神崎 美月
 1. 星宮 いちご
 2. 霧矢 あおい
 3. 紫吹 蘭
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

最初のHunkが表示されます。この部分はコミットしたいのでyを入力。
次のHunkに進みます。

@@ -9,10 +8,20 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
+17. 大地のの
+18. 白樺リサ
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
 その他
+神崎 美月
 夏樹 みくる
Stage this hunk [y,n,q,a,d,/,k,K,g,s,e,?]?

この部分は分割したいのでsで分割します。

Split into 2 hunks.
@@ -9,9 +8,18 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
+17. 大地のの
+18. 白樺リサ
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
 その他
Stage this hunk [y,n,q,a,d,/,k,K,j,J,g,e,?]?

分割され最初のHunkが表示されました。
この部分はコミットしたくないので n でスキップします。
( j で未確定にして次のHunkに進んでもOK。)

@@ -12,7 +20,8 @@
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
 3. 風沢 そら
 4. 姫里 マリア
 その他
+神崎 美月
 夏樹 みくる
Stage this hunk [y,n,q,a,d,/,K,g,e,?]?

この箇所はコミットしたい部分なので y を入力。
ステージは次のような感じになっています。
f:id:kikiki-kiki:20170627224136p:plain
神崎先輩の位置を移動させたものだけがステージに上がっているので、コミットします。

連続した変更箇所を手動で別のコミットにする

次にあかりジェネレーションのリストから、17,18 ののりさ を別にしてステージにaddしたいと思います。

$ git add -p aikatsu.txt
diff --git a/aikatsu.txt b/aikatsu.txt
index eef8b0c..2b59a87 100644
--- a/aikatsu.txt
+++ b/aikatsu.txt
@@ -8,6 +8,15 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
+17. 大地のの
+18. 白樺リサ
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
Stage this hunk [y,n,q,a,d,/,e,?]?

変更箇所が連続していて s でHunkを分割することができないので、e で手動で編集を行う必要があります。
e を入力すると下記のようなdiffを編集するエディタが立ち上がります。
そこから、差分を作成することで、Hunkを分割することができます。

Manual hunk edit mode -- see bottom for a quick guide.
@@ -8,6 +8,15 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
+17. 大地のの
+18. 白樺リサ
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい
# ---
# 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.

今回は17. 18. の追加を無しにしたいので下記のように、その行を削除してファイルを保存しました。

Manual hunk edit mode -- see bottom for a quick guide.
@@ -8,6 +8,15 @@
 7. 神谷 しおん
 8. 三ノ輪 ヒカリ
 9. 北大路 さくら
+10. 大空 あかり
+11. 氷上 スミレ
+12. 新条 ひなき
+13. 服部 ユウ
+14. 紅林 珠璃
+15. 天羽 まどか
+16. 黒沢 凛
 ドリームアカデミー
 1. 音城 セイラ
 2. 冴草 きい

ファイルの編集が完了すると、先程のdiffファイルの内容だけがそのままステージに反映されています。
f:id:kikiki-kiki:20170627225454p:plain
diffファイル内で削除した内容も元ファイルは変更箇所としてワークスペースに残っているので失われることはありませんでした!!
 

対話式コマンドのオプション
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

? でヘルプを表示することができます。

option mean
y stage this hunk
ハンクをステージにaddする
n do not stage this hunk
ハンクをaddしないでスキップ
q quit; do not stage this hunk or any of the remaining ones
このハンクをaddせず、残りの未確定なハンクもaddしないで終了
a stage this hunk and all later hunks in the file
これ以降のハンクを全てaddする
d do not stage this hunk or any of the later hunks in the file
これ以降のハンクはaddしない
g select a hunk to go to
指定したハンクへ移動
/ search for a hunk matching the given regex
正規表現でハンクを探す
j leave this hunk undecided, see next undecided hunk
このハンクは未確定のまま、次の未確定のハンクに移動
J leave this hunk undecided, see next hunk
このハンクは未確定なまま、次のハンクに移動
k leave this hunk undecided, see previous undecided hunk
このハンクは未確定のまま、前の未確定のハンクに移動
K leave this hunk undecided, see previous hunk
このハンクは未確定なまま、前のハンクに移動
s split the current hunk into smaller hunks
ハンクを分割
e manually edit the current hunk
手動でハンクを編集
? print help
ヘルプを表示

※ 当方、英語力に全く自信がありません!

まとめ・感想

git add -p を利用すると、興が乗ってしまい色々編集しちゃったファイルも後からコミットすべき単位に比較的簡単に分ける事ができそうです。
まぁ最初から計画的にファイル編集してこまめにコミットすれば済む話ではありますが。覚えておいて損はなさそうです!特にWEBさいととかのCSSとかではやってしまいがち…

また、GUIのSourceTreeは変更箇所はHunk毎に表示されているので、ボタンからハンク毎にステージにaddすることができます。
f:id:kikiki-kiki:20170627230332p:plain
ただ、ハンクを分けたり手動での変更はGUIだけでは難しいみたいです。

 
某会社でGitを本格的に導入するということで使い方のワークショップをさせてもらいました。
僕自身、現場で使いながら覚えたゆるふわ理解だったので、ワークショップをするにあたって改めて入門gitを読んだのですが、対話形式でステージにaddしたり、変更の1部 Hunk別にaddするの方法が書かれていたり、ログを検索する git blam の便利なオプションや、運用に当たってのブランチの作り方など、改めて勉強になることがたくさんありました!

入門git

入門git


[参考]

アイカツ!1stシーズン Blu-ray BOX1

アイカツ!1stシーズン Blu-ray BOX1