名前を変更したファイルのログをgitで本当に表示するにはどうすればよいですか?


132

私はgitに比較的慣れていません。以前にSubversionを使用しました。

ほとんどのグラフィカルgitフロントエンドとIDEプラグインは、ファイルの名前が変更されている場合、ファイルの履歴を表示できないようです。私が使うとき

git log --follow

コマンドラインでは、名前を変更してもログ全体を確認できます。

Linus Torvalds氏によると、-followスイッチは「SVN noob」を喜ばせるものであり、深刻なgitユーザーはそれを使用しません。

--followは完全なハックであり、親子関係や素敵なリビジョングラフなどについて何も知らなかった元SVNユーザーを満足させるだけのものです。

これは完全に基本的なものではありませんが、「-follow」の現在の実装は、実際に不可欠なものではなく、リビジョンウォーキングロジックにボルトで固定された迅速な前処理です。

それは文字通り、「実際のgit機能」としてではなく、「SVN noob」を満足させるものとして設計されました。アイデアは、全体像で問題の名前を変更するという(壊れた)思考の考え方から逃れることでした。

私の質問:名前が変更されたときに、ハードコアのgitユーザーがファイルの履歴をどのように取得しますか?これを行う「本当の」方法は何ですか?


17
@David Hall:git mv oldfile newfile名前の変更がまったく記録さない-1 つのファイルを削除して別のファイルを追加するのと同じです。gitは、事後のコミットごとに、ツリーの状態から名前の変更とコピーのみを実行します。
Mark Longair、2011

20
@David Hall:git外の別のツール(例:)を使用してファイルの名前を変更してからを/bin/mv oldfile newfile実行するgit add newfile; git rm oldfileと、結果はの結果と区別がつきませんgit mv oldfile newfile
Mark Longair、2011

1
このイデオロギーは、ファイルを新しいリポジトリに移動した場合に崩れます。その場合、履歴全体を移動できないことが大きな問題になる可能性があります。もちろん、複雑なプロジェクトでファイルを使用して実際の履歴をどの程度作成できるかには制限があります。
Roman Starkov 14年

1
注:git log --followgit 2.9(2016年6月)で少し改善しました。以下の私の回答を
VonC '14

1
v2.15以降、を試して--color-movedみることができますdiff
マイケル-どこですかクレイシャーキー

回答:


71

Linusのポイントの背後にある一般的な動機は、ハードコアのgitユーザーが「ファイル」の履歴を気にしないということです。コンテンツは全体として意味のある履歴を持っているため、コンテンツをgitリポジトリに配置します。

ファイルの名前変更は、パス間を移動する「コンテンツ」の小さな特殊なケースです。gitユーザーが機能的に "pickaxe"を使用して追跡できるファイル間を移動する機能がある場合があります(例:)log -S

その他の「パス」の変更には、ファイルの結合と分割が含まれます。gitは、名前の変更を検討しているファイルや、コピー(または名前の変更と削除)を検討しているファイルを実際には気にしません。ツリーのコンテンツ全体を追跡するだけです。

gitは、多くのバージョン管理システムが非常にファイル中心である「ツリー全体」の考え方を奨励しています。これが、gitが「ファイル名」を参照するよりも「パス」を参照することが多い理由です。


こんにちはチャールズ、あなたの答えをありがとう。SVNと同じようにgitを使用しているようです。gitは他のバージョン管理システムとは非常に異なることは理解していますが、gitの多くの概念はまだ奇妙に見えます...おそらく、最近購入したgitブックを完成させる必要があります。
マイク

24
Linusのポイントは、「適切な」guiがファイル間でコードのチャンクを追跡できることであり、彼は今までにそのようなツールが存在することを望んでいた。残念ながら、まだそのような贅沢はありません。そして--followはまだ役に立ちます。
マイケルパーカー、

11
gitは実際--followにこれ以外の解決策をあなたに与えますか?
Griwes、2015

13
「ツリー全体」の考え方は--followデフォルトであることによって強化されると私は主張します。つまり、ファイル内のコードの履歴を確認する場合、通常はファイルの名前が変更されたかどうかは気にせず、名前の変更に関係なく、コードの履歴を確認するだけです。だから、私の意見では--follow、個々のファイルについては気にしないので、デフォルトであることが理にかなっています。--follow通常はかなり重要ではない個々のファイルの名前変更を無視するのに役立ちます。
17

2
それで...ファイルの代わりに「コンテンツ」を気にすることにした場合、現在このファイルにあるコンテンツに関連するコミットをどのように出力しますか?gitがさまざまなファイル全体を追跡し、すべての変更のログを報告してくれたらうれしいです-取得方法がわからないだけです。
Ed Avis、2018年

36

私はあなたが直面しているのとまったく同じ問題を抱えています。答えは出せませんが、Linusが2005年に書いたこのメールは読むことができると思います。これは非常に適切であり、問​​題の処理方法についてのヒントを与えるかもしれません。

…名前の変更が重要ではないため、内部的な理由で(つまり、効率的なデルタを許可するために)変更しない限り、名前の変更を追跡しようとするSCMは根本的に壊れていると私は主張しています。彼らはあなたを助けません、そして彼らはとにかくあなたが興味を持っていたものではありませ

重要なのは「これはどこから来たのか」を見つけることであり、gitアーキテクチャはそれを非常にうまく実行します。他のどこよりもはるかに優れています。…

私はそれがこのブログ投稿によって参照されていることを発見しましたこれは、実行可能な解決策を見つけるのにも役立つかもしれません。

Linusはメッセージの中で、理想的なコンテンツ追跡システムを使用して、コードブロックが現在の形になった方法を見つける方法を説明しました。ファイル内の現在のコードブロックから開始し、履歴に戻ってファイルを変更したコミットを見つけます。次に、コミットの変更を検査して、関心のあるコードのブロックがそれによって変更されているかどうかを確認します。ファイルを変更するコミットは、関心のあるコードのブロックには触れず、その他の一部の部分のみに触れる可能性があるためです。ファイル。

コミットの前にコードのブロックがファイルに存在しないことがわかった場合は、コミットをより詳細に検査します。これは、次のような多くの考えられる状況の1つであることがわかります。

  1. コミットは本当にコードのブロックを導入しました。コミットの作者は、あなたがその起源を探していたそのクールな機能の発明者(またはバグを導入した有罪者)でした。または
  2. コードのブロックはファイルには存在しませんでしたが、同じファイルの5つのコピーが異なるファイルに存在し、すべてコミット後に消えました。commitの作成者は、単一のヘルパー関数を導入することにより、重複したコードをリファクタリングしました。または
  3. (特殊なケースとして)コミットの前に、関心のあるコードのブロックが現在含まれているファイルは存在しませんでしたが、ほぼ同じ内容の別のファイルが存在し、関心のあるコードのブロックは、ファイル内の他のすべてのコンテンツと一緒に、当時存在していましたが、その他のファイルには存在していました。コミット後に消えました。コミットの作者はファイルに小さな変更を加えながら名前を変更しました。

gitでは、Linusの究極のコンテンツ追跡ツールはまだ完全に自動化された方法では存在しません。しかし、重要な成分のほとんどはすでに入手可能です。

これに関するあなたの進歩について私たちに投稿してください。


それらの記事を投稿していただきありがとうございます。コンテンツの歴史についての考えを完全に理解したのは、それらを読んだときでした。これを間違った方法で考えていました。
DavidG

Linusからのそのメールは素晴らしいです、これを投稿してくれてありがとう。
mik01aj

おかしな--color-movedことに、Git v2.15はその「理想的な追跡システム」への動きを追加しています。ファイル内の移動された行を追跡するために遊んでいましたが、diff全体で
マイケル-クレイシャーキーはどこにある

2
ライナスは複雑な状況を説明しています。しかし、ここでは単純な状況があります。ファイルの名前が変更された(または別のディレクトリに移動された)だけです。したがって、簡単な解決策があるはずです。問題はSubversionに反するという事実から来ていると思います、ユーザーはコミット時にファイルがどこから来るのかをGitに指示できず、それ--followは間違っている可能性があります(たとえば、2つのファイルが同じ内容である場合、または変更がある場合)ファイル移動に加えて)。
vinc17

13

ほとんどのグラフィカルgitフロントエンドとIDEプラグインは、ファイルの名前が変更されている場合、ファイルの履歴を表示できないようです。

いくつかの人気のあるGit UIツールがこれをサポートするようになったことを喜んで知っています。数十のGit UIツールが利用できるので、それらすべてをリストすることはしませんが、例えば:

  • SourceTreeのファイルログを表示すると、左下に「名前を変更したファイルを追跡する」チェックボックスがあります。
  • TortoiseGitには、左下のログウィンドウに「名前変更に従う」チェックボックスがあります。

Git UIツールの詳細:


ソースは、名前を1度変更した場合、2度変更した場合、変更前のコミットで変更の詳細を利用できない場合に最適です。私はここでバグを報告しました:jira.atlassian.com/browse/SRCTREE-5715
Intel

gitkは、履歴内でファイルの名前が2度変更された場合でも適切に機能します。コマンドは「gitk --follow path / to / file」のようになります
Intel

6

注:git 2.9(2016年6月)では、次の「バギー」な性質がかなり改善されますgit log --follow

参照してくださいca4e3caをコミットすることで(2016年3月30日)SZEDERガーボル(szeder
(合併によりJunio C浜野- gitster-26effb8コミット 2016年4月13日)

diffcore:名前変更の検出中の同一ファイルの反復順序を修正

2つのパス ' dir/A/file'と ' dir/B/file'の内容が同じで、親ディレクトリの名前が変更された場合(例: ' git mv dir other-dir') diffcore、次の正確な名前変更が報告されます。

renamed:    dir/B/file -> other-dir/A/file
renamed:    dir/A/file -> other-dir/B/file

(ここでの反転に注意してください:B/file -> A/file、およびA/file -> B/file

技術的には間違っている、これはユーザーのために、だけでなく、リネーム情報、たとえば、「に基づいて判断しますgitのコマンドのためだけではなく、混乱されていないがgit log --follow other-dir/A/file」次の「dir/B/file名前の変更を過ぎて」を。

この動作はcommit v2.0.0-rc4〜8 ^ 2〜14(diffcore-rename.c:正確な名前変更の検索を簡素化、2013-11-14)の副作用です。ソースを格納するハッシュマップは同じバケットからエントリを返します。つまり、現在の宛先に一致するソース、LIFO順。
したがって、反復は最初に「other-dir/A/file」と「dir/B/file」を調べ、同一のコンテンツとベース名を見つけると、正確な名前変更を報告します。


2

Linuxでは、SmartGitとGitEyeが特定のファイルの履歴を追跡するときに名前の変更を追跡できることを確認しました。ただし、gitkやGitEyeとは異なり、SmartGitは個別のファイルビューとリポジトリビューを表示します(これにはディレクトリ構造が含まれますが、中に含まれるファイルのリストは含まれません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.