git checkout -pのユースケース

特にプロトタイプ的なコードを書いている時、将来的にはオプションなどで変更できるようにする予定のモノをコードに直書きで埋め込んだりするよね。簡単なものでは1行だったり、複雑なものだったらモックのクラスだったり。

今回のユースケースは「もうこのモックは必要ないな」と思って削除して、しばらくしてからまだ消しちゃダメだったと気づいたケース。

下記のコードのCODEってところを削除する。

sIDENTIFIER = "[^-+#: ]+"
IDENTIFIER = re.compile(sIDENTIFIER)
ENHANCER = re.compile("\+\s*(%s)" % sIDENTIFIER)
SUPPRESSOR = re.compile("-\s*(%s)" % sIDENTIFIER)
BODY = re.compile(":\s*(%s)" % sIDENTIFIER)
CODE = """
+START :OUT_H
+OUT_H :OUT_E
+OUT_E :OUT_L
-SUP_L +OUT_L :OUT_L
+OUT_L :SUP_L
-SUP_O +SUP_L :OUT_O :SUP_O
"""
NONE = "NONE" # it always be in environment

ハイ消した、保存した。でもまだ消しちゃダメだった!そして消しちゃダメだと気付くまでに他の部分もいろいろ書き換えてしまったのでundoで手軽に戻すわけにはいかない。さあどうする!?

sIDENTIFIER = "[^-+#: ]+"
IDENTIFIER = re.compile(sIDENTIFIER)
ENHANCER = re.compile("\+\s*(%s)" % sIDENTIFIER)
SUPPRESSOR = re.compile("-\s*(%s)" % sIDENTIFIER)
BODY = re.compile(":\s*(%s)" % sIDENTIFIER)
NONE = "NONE" # it always be in environment

もう一度書くとか、古いバージョンを表示してそこからコピペするとか、を解決策として考える人も多いかと思うけど、ここで説明したいのはタイトルにも書かれているgit checkout -p。さっそくやってみよう。

--- a/main.py
+++ b/main.py
@@ -7,12 +7,4 @@ IDENTIFIER = re.compile(sIDENTIFIER)
 ENHANCER = re.compile("\+\s*(%s)" % sIDENTIFIER)
 SUPPRESSOR = re.compile("-\s*(%s)" % sIDENTIFIER)
 BODY = re.compile(":\s*(%s)" % sIDENTIFIER)
-CODE = """
-+START :OUT_H
-+OUT_H :OUT_E
-+OUT_E :OUT_L
--SUP_L +OUT_L :OUT_L
-+OUT_L :SUP_L
--SUP_O +SUP_L :OUT_O :SUP_O
-"""
 NONE = "NONE" # it always be in environment
Discard this hunk from worktree [y,n,q,a,d,/,e,?]?

このようにhunk(かたまり)ごとに、変更を破棄して前回コミットした状態に戻すかどうかを聞いてくる。戻したいところでyを押して、それ以外ではnを押し、もう戻したいものがなければqを押せばOK。
かたまりが自分の戻したい単位より大きくくっついてて、もっと分割したいなと思ったらsでもっと細かく分割。それでも期待したような分割のされ方をしないならeで行単位でどれを戻してどれを戻さないか指定できる。このあたりのコマンドの説明は?を押せば表示される。

というユースケースにちょうど今コードを書いていて遭遇したので、記録も兼ねてブログに書いておいた。