web-dev-qa-db-ja.com

git、履歴を保持しながらファイルを移動/名前変更する確実な方法

似ている既存の質問が「たくさん」あることを知っているので、私の質問をする前にそれらを要約しましょう。

最初の質問に対する答えは、同意していません。以前に行ったことがあるからです。 2つ目の答えは、この質問をする理由です。つまり、

いつもgit mvを実行していることがわかりましたが、移動/名前変更として扱われることもあれば、削除+追加として扱われることもあります。したがって、常に移動/名前を変更する方法を知りたいですか?

例として これ を例に取ると、下部に、easygenapi/tf-varcaser.go → tf-varcaser.goのようないくつかの移動/名前変更のケースがあります。このような移動は、フォルダ間/フォルダ間です!つまり、私はdidそれです!

ただし、git mvが削除+追加として扱われ、まったく同じ変更ログに表示される他の多くのケースがあります。繰り返しますが、私は常にgit mvを行っています。 gitの動作が異なるのはなぜですか?

履歴を保持しながらgitファイルを移動/名前変更するsure-fire方法はありますか?

16
xpt

tl; dr;番号

長いバージョン:私の経験では、ファイルが変更されていない限り、gitは移動/名前変更の検出に非常に優れています。 Gitはヒューリスティックを使用して、移動を試みて特定します。似ているファイルがいくつかある場合や、移動中にファイルが変更されている場合、元のファイルとの違いが大きすぎるためにだまされる可能性があります。

私がこれを実行するために見つけた最良の方法は、マルチステージコミットを実行して、すべての移動を1つのコミットに分離し、次に別のコミットで変更を行うことです。例えば...

git mv foo.txt bar.txt
git commit

... modify bar.txt ...

git add bar.txt
git commit

複数の候補者がいる場合でも混乱する可能性があるため、移動が正しく検出されるとは限りません。しかし、それは私にとって非常にうまく機能し、ほとんどの場合をキャッチします。

24
Kevin Burdett

Gitは名前の変更を追跡しません。限目。また、追加は追跡されません。または削除します。または差分。またはパッチ。または移動します。または、実際には何らかの変化。

Gitはスナップショットベースです。コミットごとにプロジェクト全体のスナップショットが記録されます。それでおしまい。 方法スナップショットが作成されるようになりましたが、Gitは知りませんし、気にしません。

差分、パッチ、追加、削除、移動、名前変更などは、さまざまな視覚化ツールによって表示され、ヒューリスティックを使用して事実を推測します(これは「推測」の別の言い方です)。時々、彼らはあなたがしたことを正しく推測するかもしれませんし、時にはそうではないかもしれません。しかし、それは視覚化にすぎないので、問題ではありません。それは、いかなる形、形、形でも歴史の一部ではありません。

ほとんどのツールは何らかの形の類似性メトリックを使用しており、2つのファイルの類似性があるしきい値よりも大きい場合に名前変更が発生したと推測します。一部のツールでは、このしきい値は構成可能です。一部のツールでは、アルゴリズムでさえ構成可能です。 (少し関連する例:git diffを使用すると、異なるアルゴリズムを選択して、違いを推測できますwithinファイル。)

Gitは変更を記録しないため、新しいバージョンの視覚化ツールに新しい変更を追加して、新しい種類の変更を理解する新しいツールが作成される前に記録された古いコミットからの変更を推測できます。たとえば、使用しているプログラミング言語の構文とセマンティクスを理解するツールを想像してみてください。特定のコミットを、それぞれが数行が変更された一連のファイル全体としてではなく、サブルーチンの名前を変更して各コールサイトを更新する単一の変更として視覚化できます(つまり、Rename Method Refactoring)。

名前の変更は、実際にはこの良い例です。たとえば、git log --followで使用される名前変更検出ヒューリスティックと類似性メトリックは、複数回改善されました。 IIRCは当初、名前の変更はまったく推論されていませんでした。その機能は後で追加されました。 Gitがスナップショットの代わりに変更を記録した場合、これは単に不可能でした。

13
Jörg W Mittag