目次
はじめに
ソースコードを編集しているときに変更した行をステージングさせたくないけど、変更前に戻したいときってありますよね?(ない場合はこの記事は参考になりません。。)
その時、vscodeのGit History という拡張機能は便利でワンクリックで戻せるので普段はそれを使っています。
ですが、サーバなどのリモート環境での操作時など、ほかの人に迷惑をかけたくない状況の時、クライアントとサーバ間で情報をやり取りするエディタまたはサーバ上のメモリをたくさん食うエディタ(例えばvscode)を使いたくないときがあります。
その時に、gitコマンドだけでvscodeの便利な機能を使えたらいいなと考え検索した結果、思いのほか情報が少ないように感じたので、自分なりにまとめました。
本来ならvimやneovimでできるといいのですが、見つからなかったのでgitコマンドで頑張りました。(もし知っている方、いらっしゃれば教えてほしいです。。)
やりたいこと
方法
完全に同じようにはできませんが、似たようなことはできます。
git checkout -p <file>
を使います。
今回の例で使うファイル
-
URL
-
今回の例の再現の為の準備
再現したい場合は、少し面倒ですが、以下の順に行ってください。 -
コード
変更前のコード(test.py)
test.pyfrom matplotlib import pyplot as plt import numpy as np for i in range(10): colums_name, table_name = "similarity{}".format(i), "table{}".format(i) similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) imfile = "{}.png".format(colums_name) plt.savefig(imfile) # im = plt.imread(imfile) # Log the image # clear figure plt.clf()
変更後のコード(test.py)
test.pyfrom matplotlib import pyplot as plt import numpy as np for i in range(10): colums_name, table_name = "similarity{}".format(i), "table{}".format(i) similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) test = "test" test2 = "test2" test3 = "test3" imfile = "{}.png".format(colums_name) plt.savefig(imfile) # clear figure yyy = "yyy" plt.cla()
変更状況
変更状況は以下のようになっている(上記のgif画像の最初の画像と同じ)と仮定し、このファイルの変更を例にして、その変更の順番通りに使い方を説明します。
$ ls -a .git test.py $ git diff diff --git a/test.py b/test.py index 20adb80..788eb57 100644 --- a/test.py +++ b/test.py @@ -6,9 +6,11 @@ for i in range(10): similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) + test = "test" + test2 = "test2" + test3 = "test3" imfile = "{}.png".format(colums_name) plt.savefig(imfile) - # im = plt.imread(imfile) - # Log the image # clear figure - plt.clf() + yyy = "yyy" + plt.cla()
使い方の基本
hunkと呼ばれるgitが勝手につくってくれるgit diffの塊ごとに編集
具体的には、$ git checkout -p test.py diff --git a/test.py b/test.py index 20adb80..788eb57 100644 --- a/test.py +++ b/test.py @@ -6,9 +6,11 @@ for i in range(10): similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) + test = "test" + test2 = "test2" + test3 = "test3" imfile = "{}.png".format(colums_name) plt.savefig(imfile) - # im = plt.imread(imfile) - # Log the image # clear figure - plt.clf() + yyy = "yyy" + plt.cla() (1/1) Discard this hunk from worktree [y,n,q,a,d,s,e,?]?
となるので、
?
の横にy
と打てば、ここで表示されている変更部分は全て破棄されます。上記コマンド実行後のコード
test.pyfrom matplotlib import pyplot as plt import numpy as np for i in range(10): colums_name, table_name = "similarity{}".format(i), "table{}".format(i) similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) imfile = "{}.png".format(colums_name) plt.savefig(imfile) # im = plt.imread(imfile) # Log the image # clear figure plt.clf()
少し応用(hunkの分割)
上記と同じような状況で
?
の横にs
と打つと以下のようになります。(1/1) Discard this hunk from worktree [y,n,q,a,d,s,e,?]? s Split into 3 hunks. @@ -6,5 +6,8 @@ similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) + test = "test" + test2 = "test2" + test3 = "test3" imfile = "{}.png".format(colums_name) plt.savefig(imfile) (1/3) Discard this hunk from worktree [y,n,q,a,d,j,J,g,/,e,?]?
今回の場合はhunkが3つに分割されます。
これで分割されたhunkごとに変更の破棄ができるようになります。s
を入力した後すぐに、最初のhunkに対してどうしますか?と再度聞かれるようになるので、分割前と同様にy
と入力すれば、分割された最初のhunkで表示されている変更は全て破棄されます。1行ずつ変更(さらに応用)
本来なら1行ずつ変更したいので、もっと分割してほしいところですが、ここでもう一度
s
を入力しても分割してくれません。。
なので、その場合は?
の横にe
を入力して、直接編集します。
すると以下のようなvim/neovimが立ち上がります。
これ以降は分割されたhunckに対して、編集画面を立ち上げたうえでの編集方法を順番に見ていきます。
編集と保存にはvimを使っているので、わからない場合はvimの操作方法を調べてください。(例えば、よく使う Vim のコマンドまとめ)1つ目のhunck(追加分の取り消し)
1つ目は元ファイルからの追加分だけが差分として表示されています。
この時の編集の仕方を示していきます。
ここで例として、test2 = "test2"
の行だけ変更を元に戻したい(その行を削除したいとした)時を考えます。
この場合の編集方法は以下です。test2 = "test2"
の行以外の+
を(空白)に変えて保存後、閉じます。
画像で示すと、以下のように編集・保存して、閉じます。
閉じると、以下のような画面に戻って次のhunkについてどうするか聞かれます。(1/3) Discard this hunk from worktree [y,n,q,a,d,j,J,g,/,e,?]? e @@ -9,5 +12,3 @@ imfile = "{}.png".format(colums_name) plt.savefig(imfile) - # im = plt.imread(imfile) - # Log the image # clear figure (2/3) Discard this hunk from worktree [y,n,q,a,d,K,j,J,g,/,e,?]?
2つ目のhunck(削除分の取り消し)
2つ目は元ファイルからの削除分だけが差分として表示されています。
この時の編集の仕方を記載していきます。
例によって、1行ずつ編集したいので、?
の横にe
と入力して編集画面を立ち上げます。
今回の例の場合は、以下のようになります。
ここで例として、
# Log the image
の行だけを復活したいとした場合を考えます。この時の編集方法は、以下です。
その行だけ残してほかの変更部分は行ごと削除して保存後、閉じます。
画像で示すと、以下のように編集・保存して閉じます。
閉じると、以下のような画面に戻って次のhunkについてどうするか聞かれます。(2/3) Discard this hunk from worktree [y,n,q,a,d,K,j,J,g,/,e,?]? e @@ -13,2 +14,3 @@ # clear figure - plt.clf() + yyy = "yyy" + plt.cla() (3/3) Discard this hunk from worktree [y,n,q,a,d,K,g,/,e,?]?
3つ目のhunck(削除分と追加分が混在している場合)
3つ目は元ファイルからの削除分も追加分も差分として表示されています。
つまり、vscodeでいうところの青い部分のことを指します。
今回の例では、以下のような変更部分です。変更前 変更後 plt.clf()
yyy = "yyy"
plt.cla()
この時の編集の仕方を示していきます。
編集方法は特に何も変わりません。今までの方法を組み合わせるだけでできます。ここで例として、
plt.clf()
を編集して、書き換えたかった文字は、yyy = "yyy"
というものに戻したい場合(plt.cla()
はいらないし、plt.clf()
も復活しなくていい場合)を考えます。この時の編集方法は、以下です。
yyy = "yyy"
の前の+
をに変え、
plt.clf()
の行を削除して保存後、閉じます。
画像で示すと、以下のように編集・保存後、閉じます。
閉じると、全てのhunckについての編集が終わったので、以下のような画面に戻って編集作業が終了します。(3/3) Discard this hunk from worktree [y,n,q,a,d,K,g,/,e,?]? e $
余談
もう一つの例として、ただ単に
plt.clf()
を復活して本当に今の変更をなかったことにしたいだけの場合(plt.cla()
とyyy = "yyy"
の追加分がいらない場合)を考えます。この時は、何も編集せずに保存して閉じれば実現できます。
画像で示すと、以下のような編集です。
(この場合は、編集ではなく、初めからy
を入力しても同じですし、そのほうが楽かもしれません。)
この場合も閉じると、全てのhunckについての編集が終わったので以下のような画面に戻って編集作業が終了します。(3/3) Discard this hunk from worktree [y,n,q,a,d,K,g,/,e,?]? e $
総括
なるべく分かり易いようにまとめたつもりですが、あくまで自分のメモ要素が強いので冗長だったり、分かりにくかったりするかもしれません。。
ですが、もし自分だけでなく誰かの役に立っていることがあったとしたら、うれしいです。使い方のまとめ
- 大きな塊で処理したいだけなら、
git checkout -p <file>
の後にy
でOK - もう少し小さい塊でやりたいなら、
git checkout -p <file>
の後にs
を入力してから、y
を入力 - 1行ずつ細かく見たいなら、
git checkout -p <file>
の後にe
を入力して、直接編集 - 編集の思想としては基本的に何も編集しない場合は全ての変更を破棄するという思想です。(残したければ、あるいは復活させたくなければ編集する。)
参考文献
付録
今回の例で行ったコマンドの全体像のスクショ:
今回取り上げた1行ずつ編集する例の通りに変更を元に戻した時のコード:
(ただし、最後の行は余談ではないほうを選んだ場合のコード)
test.py
test.pyfrom matplotlib import pyplot as plt import numpy as np for i in range(10): colums_name, table_name = "similarity{}".format(i), "table{}".format(i) similarityes = np.random.randn(1000) hist, bins, _ = plt.hist(similarityes, bins=10) test = "test" test3 = "test3" imfile = "{}.png".format(colums_name) plt.savefig(imfile) # Log the image # clear figure yyy = "yyy"
- 大きな塊で処理したいだけなら、