Git

gitでrename&modifyしたファイルのログを追跡できるようにしたい場合

More than 2 years have passed since last update.

この記事のサマリ

gitでバージョン管理しているファイルをリネームしたい場合に、リネーム前のログもたどれるようにしておきたい場合は、
①「git mv」でリネームして「git commit」でコミットを発行
②その後、対象ファイルを修正してコミット
といった手順を取ると
③「git log --follow」でリネーム前のログも辿れるというお話です。
注意:①と②を同時にやってしまうと、どうもうまくログをたどれないらしいというお話も含みます。

シチュエーション

git管理して、すでにコミットログが溜まってそれなりに歴史のあるファイルがあったとします。
そのファイルをある時、ファイル名の変更と内容の修正が必要に迫られたようなシーンを想定しています。歴史のあるファイルなので、特に昔のログは追いかけるようにしておきたいですよね。

具体的な例では、
railsの勉強とgitの勉強のために、サンプルアプリを作っていて、ある程度作っていったのち、「あっ、erbじゃなくてhamlにも触れておこう
「おっ、erb2hamlというgemを使えば、一括置換してくれるらしい」
「あれっ、XX.html.erbは、それぞれXX.html.hamlにreplaceされたぞ!!」
「おーし、軽く動作確認&疎通するための修正が済んだからコミットじゃ~」
「およよ、hamlのファイルからログをたどるとうまくerbの時代のログが辿れん。。。orz」
といった状況の場合です。

renameとmodifyを一緒にコミットしてみる

「git mv」という、gitとしてのrenameコマンドがあるので、ちゃんと「git rename」にてrenameした上で、修正内容をコミット(renameとmodifyを一緒にコミット)してあげれば、たどれるのではなかろうか?

→検証してみましょう
まずは元となるファイルのログが以下の状態だとします(2つのコミット履歴がある状態)

git log --oneline app/views/dogs/index.html.erb
9736e4a show&edit nick_name
3295c02 rails generate dog scaffold

次に、git mvでファイルをリネームしてみます。

git mv app/views/dogs/index.html.erb app/views/dogs/index.html.haml

すると、git statusでは、以下のようにリネームされた情報が検知されています。

git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    app/views/dogs/index.html.erb -> app/views/dogs/index.html.haml

では、さらにapp/views/dogs/index.html.hamlに修正を加えた後、git statusを確認してみましょう。

git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    app/views/dogs/index.html.erb -> app/views/dogs/index.html.haml
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   app/views/dogs/index.html.haml

リネームの情報と修正の情報が検知されています。

ではコミットしてみましょう。

git add app/views/dogs/index.html.erb
fatal: pathspec 'app/views/dogs/index.html.erb' did not match any files

なるほど、リネーム前のファイルはaddできないようです。というわけで、リネーム後のファイルをaddしてstatusを確認します。

git add app/views/dogs/index.html.haml
git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    app/views/dogs/index.html.erb
#       new file:   app/views/dogs/index.html.haml
#

うーむ、renameの情報がなくなっているのでちょっと嫌な予感。。。

とりあえずコミットしましょう。

git commit -m "rename&modify"

はてさてログは?

git log --oneline app/views/dogs/index.html.haml
ccfb91c rename&modify

おぅ、無い。。。orzと思って調べてみると、リネームした情報も含めてログをたどるには、「--follow」というオプションが必要らしいので、も一度確認。

git log --follow --oneline app/views/dogs/index.html.haml
ccfb91c rename&modify

おぅ、無い。。。orz
という感じで、リネームと修正は、一緒にするとうまく追えなくなってしまうようです。(もし、一緒にやる方法をご存じでしたら教えていただけると幸いです。)

renameとmodifyを別々にコミットしてみる

前述の結果を踏まえて、renameとmodifyを別々にコミットしてみることにします。

→検証してみましょう
まずは元となるファイルのログが以下の状態だとします(2つのコミット履歴がある状態)

git log --oneline app/views/dogs/_form.html.erb
9736e4a show&edit nick_name
3295c02 rails generate dog scaffold

次に、git mvでファイルをリネームしてみます。

git mv app/views/dogs/_form.html.erb app/views/dogs/_form.html.haml

すると、git statusでは、以下のようにリネームされた情報が検知されています。

git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    app/views/dogs/_form.html.erb -> app/views/dogs/_form.html.haml

今回は、ここで一回コミットします。

git add app/views/dogs/_form.html.haml
git commit -m "rename app/views/dogs/_form.html.erb -> app/views/dogs/_form.html.haml"

この時ログはどうなっているかというと

git log --follow --oneline app/views/dogs/_form.html.haml
8396fe3 rename app/views/dogs/_form.html.erb -> app/views/dogs/_form.html.haml
9736e4a show&edit nick_name
3295c02 rails generate dog scaffold

期待通りですね。

では、さらにapp/views/dogs/_form.html.hamlに修正を加えた後、git commitしておきましょう。

# _form.html.hamlを修正後
git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   app/views/dogs/_form.html.haml
git add app/views/dogs/_form.html.haml
git commit -m "modify app/views/dogs/_form.html.haml"

はてさてログは?

git log --follow --oneline app/views/dogs/_form.html.haml
5d03226 modify app/views/dogs/_form.html.haml
8396fe3 rename app/views/dogs/_form.html.erb -> app/views/dogs/_form.html.haml
9736e4a show&edit nick_name
3295c02 rails generate dog scaffold

おぉ、無事の辿ることができました。
とはいえ、今回のようにerbをhamlに変換する際、中身はerbのまま、hamlにリネームしてコミットした版は、動作しない怪しいコミットなので、個人的にはちょっと嫌な感じがします。。。何かうまい方法はあると思うんですけど、まだ見つけられておりません。。。(ニーズはあると思うので、ありそうだとは感じていますが)
まぁ、今回の具体的なシチュエーションでは、基の.erbファイルも残しておくことで、動作しない怪しいコミットは回避できるのですが、まだまだほかにもユースケースがあると思うので、やはり本質的な解がほしいところです。

ではでは~