web-dev-qa-db-ja.com

Gitでスペースとタブを無視するにはどうすればよいですか?

"Droid XX-XX-XX"という1つのディレクトリに5つの異なるソースファイルで構成される小さなスクリプトプロジェクトがあります。ソースディレクトリの新しいバックアップコピーを作成するたびに、日付をXに入れました。したがって、異なる日付から約15の異なるバージョンがあります。これらのそれぞれを、最初から新しい裸のGitリポジトリに追加したいと思います。

しかし、私はいくつかの問題に遭遇しました。

  1. 1つの問題は、インデントにタブを使用しているファイルもあれば、スペースを使用しているファイルもあります。ただし、Gitはタブとスペースの問題のみが異なる場合でも、行全体を別のものとして扱います。 Gitでインデントのフォーマットを無視するにはどうすればよいですか?

  2. 別の問題は、一部のファイル名にはスペースがないのに、他のファイル名にはスペースがあるということですが、Gitはそれらを別のファイルとして扱います。さらに悪いことに、実際の理由なしに、ファイル名が別の名前に変更された(「PatrolPlan」が単に「Patrol」に変更されたなど)。新しいファイルのセットを追加するとき、ファイル名が異なっていても、特定の古いファイルの新しいバージョンにすぎないことをGitにどのように伝えることができますか?さらに良いことに、これが発生したときに自動検出するように設定できますか?

  3. 最後の問題は、開発中の特定の時点で、2つのソースファイルを1つにマージするか、1つを2つに分割することです。ただし、Gitは類似点を自動的に検出して何が起こったかを推測しません。何が起こったのかをGitに伝えるにはどうすればよいですか?さらに良いことに、2つのソースファイルが結合されたとき、または1つが分割されたときに自動検出するように設定するにはどうすればよいですか?

(2)と(3)の質問は関連性が高いと思います。助けてくれてありがとう!

20
CommaToast

開発プロセスのより多くの制御と標準化が必要であるように思えます。変更をコミットするのは、ファイルを変更するのと同じ人でなければなりません。または、少なくともコミッターは何が変更されたかを正確に知っている必要があります。

git diffの出力を注意深く調べ、-wフラグを使用してスペースを無視します。行内の違いを表示するオプションもあります。以下の行内の差分を参照してください。

コミット時にスペースの変更をスキップするようにgitに指示できないことに注意してください。私はGitXを使用することをお勧めします(私は "brotherbard"フォークを好みます)。これにより、コミットする前に対話的にハンクを破棄できます。

コミットするときに説明メッセージを使用します。たとえば、ファイルが分割された場合は、そのように言います。コミットを小さくしてください。長いコミットメッセージを書いている場合は、コミットを小さな部分に分割してください。そうすれば、後でログを調べるときに、何が変わったのかがわかりやすくなります。

行内の差分

Gitには、「Word」の違いを1行で表示する機能があります。最も簡単な方法は、git diff --color-wordsを使用することです。

ただし、diff.wordRegex構成を使用して「Word」の意味をカスタマイズするのが好きです。また、plain Word-diff形式が好きです。違いがどこにあるかがより明確にわかるからです(色の使用に加えて、変更の前後に角かっこを挿入します)。

コマンド:

git diff --Word-diff=plain

これと一緒に私の設定:

[diff]
        wordRegex = [[:alnum:]_]+|[^[:alnum:]_[:space:]]+

この正規表現はこれらを「単語」として扱います。

  • 英数字とアンダースコアの連続した文字列
  • 英数字、アンダースコア、スペース以外の連続した文字列(演算子の検出に適しています)

gitを使用するには、最新バージョンのwordRegexが必要です。オプションがリストされているかどうかを確認するには、git-configのマニュアルページを参照してください。

[〜#〜]更新[〜#〜]

git mvを使用してファイルの名前を変更すると(別のツールやOSを使用して名前を変更するよりも望ましい)、gitが名前の変更を検出しているのを確認できます。ファイルの内容に対する編集とは別に、名前の変更をコミットすることを強くお勧めします。これは、gitが名前を変更したという事実を実際には保存しないためです。ファイルの変更量に基づくヒューリスティックを使用して、同じファイルかどうかを推測します。 rename-commit中に変更を少なくすればするほど、良い結果が得られます。

ファイルの内容を少し変更した場合は、-C param to git diffおよびgit logを使用して、コピーの検出と名前の変更をさらに試行することができます。パーセンテージ(-C75%など)を追加して、違いに対してgitをより寛大にします。パーセントは、コンテンツが一致と見なされるために必要な類似性を表します。

27
Kelvin

Gitについてもっと知ったので、自分の質問に答えることができます。

  1. 正規表現を使用してグローバル検索置換を実行し、プロジェクトのさまざまなバージョンのすべてのファイル間の空白を標準化することをお勧めします。これにより、ファイルが順次コミットされるときに、空白の変更にコミットが不要になります。そうは言っても、Atlassian SourceTreeのdiffツールを使用すると、空白の変更を非表示にできるため、少なくともそれらは表示されません。

  2. ファイル名の変更を処理する鍵は、ファイル名のみが変更されるコミットを作成することです(他の変更はステージングしないでください)。次に、内容が変更されたところでコミットします。そうすれば、大量のヒューリスティックと深い掘り下げを行わない通常のdiffツールは、何が起こったかを理解することができます。問題は、名前と多くのコンテンツのように、ファイルに関する変更が多すぎる場合、ほとんどのdiffツールはそれを要約削除および新しいファイルとして扱うことです。 (正解で述べたように)

  3. これはもっと難しいものです。それを回避するための本当に良い方法はありません。ファイルを2つに分割したり、2つをマージしたりすると、diffで見苦しくなります。分割と同時に多くの変更を行わないようにしてください。分割が1つの処理になり、その後の変更は別の処理になります。

3
CommaToast
  1. Gitがタブ/スペースを無視するようにすることはできません。gitは各ファイルのハッシュを作成し、ハッシュが異なる場合、ファイルは異なると見なされます。

  2. Gitはツリー(ディレクトリ)をファイルと同じように扱います。コンテンツが変更された場合、それらは別のツリーです。

ただし、これらの変更について心配する必要はないと思います。それらは開発中に発生します。私はあなたのための最良のアプローチはgitを使用した開発replayつまり、最初のバージョンから始めて、必要な変更を(最初に行ったように)行うと、gitは何をしているかを記憶します。

オプション:変更の日時を最初に行ったものとほぼ同じように記録したい場合は、--dateへのコマンドラインオプションgit commitこれらの変更がいつ行われたかをgitに伝えます。

2
trojanfoe