git filter-branchで行末を修正しようとしていますが、運がありません


270

gitのWindows / Linuxの行末の問題に悩まされています。GitHub、MSysGit、およびその他のソースを介して、最適な解決策は、ローカルリポジトリにLinuxスタイルの行末を使用するように設定core.autocrlfすることtrueですが、に設定することです。残念ながら、私はこれを十分に早期に実行しなかったため、変更をプルするたびに、行末が中断されます。

私はここで答えを見つけたと思っていましたが、うまくいきません。Linuxコマンドラインの知識はせいぜい限られているので、彼のスクリプトで "xargs fromdos"行が何をするかさえわかりません。そのようなファイルやディレクトリが存在しないというメッセージが何度も表示され、既存のディレクトリを指すようにすると、権限がないことを通知します。

私はこれをWindowsのMSysGitとMac OS Xターミナルで試しました。


このスレッドに十分に賛成することはできません。+1 ++は、問題について最良の答えを提供します。
sjas 2012

チャールズに同意する。ただし、私の場合(Mac OS X 10.8を使用)> git config core.autocrlf falseは機能しましたが、> git config core.autocrlf inputは機能しませんでした
user1045085

回答:


187

gitattributesのgitドキュメントには、プロジェクトのすべての行末を「修正」または正規化するための別のアプローチが記載されています。その要点は次のとおりです。

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

正規化してはいけないファイルがgitステータスで表示される場合は、git add -uを実行する前に、テキスト属性を設定解除してください。

manual.pdf -text

逆に、gitが検出しないテキストファイルは、手動で正規化を有効にすることができます。

weirdchars.txt text

これは、--renormalize2018年1月にリリースされたgit v2.16.0で追加された新しいフラグを利用します。古いバージョンのgitでは、さらにいくつかの手順があります。

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

1
の目的を教えてgit resetください。
crdx

1
gitにインデックスの再構築を強制します。その間、各ファイルをスキャンして、そのバイナリかどうかを推測します。rmは古いインデックスを削除し、resetは新しいインデックスを構築します。
Russ Egan、2012年

16
ありがとう、これでうまくいきました。実行した後に便利なコマンドがgit status実行することであるgit diff --ignore-space-at-eolだけでは行末をしているコミットされて変化していることを確認するだけ。
zelanix 2014年

1
注:このソリューションと「古い」ソリューションの唯一の「実際の」違いは、(適切なコンテンツを含む).gitattributesが存在することです。これgit resetがないと、変更は検出されないため、役に立ちません。
Rob

3
gitattributesページの手順は、--renormalize2018年1月にリリースされたgit v2.16.0で追加されたフラグを利用するように更新されました。この--renormalizeフラグは、追跡された各ファイルの行末を再処理するプロセスを単一のコマンドに統合しますgit add --renormalize .
マイク・ヒル

389

これを修正する最も簡単な方法は、すべての行末を修正する1つのコミットを作成することです。変更されたファイルがない場合は、次のように実行できます。

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .

7
PS私はgithub.comの皆さんに修正をお勧めしました。彼らはあなたのソリューションを使用するようにヘルプガイドを更新しました(以前は、新しいクローンとハードリセットを推奨しただけで、すべてのファイルを取得していないようです) 。help.github。 COM /対処-で-lineendings
ブライアン・ドナヒュー

31
ありがとう...これは素晴らしい修正です。GitHubで見つけました。
PHLAK、2009年

4
また、config.safecrlfをチェックアウトして、非テキストファイル(バイナリなど)のcrlfを変更していないことを確認することもできます。docs kernel.org/pub/software/scm/git/docs/git-config.htmlで確認してください。
vrish88

4
@ vrish88:ただし、この状況の場合は、行末が混在している可能性が高く、core.safecrlfが必要な操作を実際に妨げる可能性があります。safecrlfを使用しない方がおそらく簡単です。gitがバイナリファイルを誤って検出することはあまりありません。検出された場合、手動で.gitattributeを使用してバイナリとしてマークし、以前のコミットから正しいバージョンを復元できます。
CBベイリー

26
以下のRuss Eganの回答で推奨されている新しいソリューションは単純で、すべてのソースコードを削除するなどの恐ろしいことは含まれていないため、この古いソリューションの投票数は10倍ですが、実際に使用することをお勧めします!
Porculus、2011

11

行末を処理するための私の手順は次のとおりです(多くのリポジトリで戦闘テスト済み)。

新しいリポジトリを作成する場合:

  • 置く.gitattributesには非常に最初の他の典型的ななどのファイルと一緒にコミット .gitignoreし、README.md

既存のリポジトリを扱う場合:

  • .gitattributesそれに応じて作成/変更
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n--no-verifyプリコミットフックをスキップすることです)
    • エイリアスとして定義するほど頻繁に行う必要があります alias fixCRLF="..."
  • 前のコマンドを繰り返します
    • うん、それはブードゥー教ですが、通常はコマンドを2回実行する必要があります。1回目は一部のファイルを正規化し、2回目はさらに多くのファイルを正規化します。一般に、新しいコミットが作成されなくなるまで繰り返すのがおそらく最善です:)
  • 古い(正規化の直前)ブランチと新しいブランチを何度か行き来します。ブランチを切り替えた後、gitは再正規化する必要があるさらに多くのファイルを見つけることがあります!

.gitattributesすべてのテキストファイルをLF EOLとして明示的に宣言します。これは、一般に、WindowsツールはLFと互換性があり、Windows以外のツールはCRLFと互換性がないためです。(でも多くのnodejsがラインツールは、LFを想定し、したがって、あなたのファイルでのEOLを変更することができコマンド)。

の内容 .gitattributes

.gitattributesは通常次のようになります:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

現在のリポジトリでgitが追跡している個別の拡張機能を確認するには、こちらをご覧ください

正規化後の問題

これが完了すると、もう1つの一般的な注意事項があります。

あなたmasterがすでに最新で正規化されているとしたら、チェックアウトしoutdated-branchます。そのブランチをチェックアウトした直後に、gitは多くのファイルを変更済みとしてマークします。

解決策は、偽のコミット(git add -A . && git commit -m 'fake commit')を実行してから実行することgit rebase masterです。リベース後、偽のコミットは消えるはずです。


1
指定された一連のコマンドも数回実行しなければならなかったので、あなたの投稿を読むまで、私は夢中になると思っていました。ブードゥー!;)
ショーンファセット

gitのバージョンでは2.7.0.windows.1、私は次のように使用: git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
ショーンFausett

4
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

説明:

  • git status --short

    これは、gitが認識している行と認識していない行をそれぞれ表示します。gitの管理下にないファイルには、行の先頭に「?」が付いています。変更されたファイルにはMのマークが付けられます。

  • grep "^ *M"

    これにより、変更されたファイルのみが除外されます。

  • awk '{print $2}'

    これは、マーカーなしでファイル名のみを表示します。

  • xargs fromdos

    これは、前のコマンドからファイル名を取得し、ユーティリティ 'fromdos'を介して実行して、行末を変換します。


これは素晴らしいです。ありがとうございました。のdos2unix代わりにHomebrewを使用してソリューションを探している人のためにfromdos
AlmirSarajčić2017

4

これは、を使用して履歴全体のすべての行末を修正する方法git filter-branchです。^M文字を使用して入力する必要があるCTRL-V+をCTRL-M。私が使用しdos2unix、これは自動的にバイナリファイルをスキップしますので、ファイルを変換します。

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'


3

"| xargs fromdos"は標準入力(ファイルfindが検出する)から読み取り、それをコマンドの引数として使用してfromdos、行末を変換します。(これらの環境ではfromdosは標準ですか?dos2unixに慣れています)。xargsの使用を回避できることに注意してください(特に、引数リストがxargsに対して長すぎるファイルが十分にある場合に役立ちます)。

find <path, tests...> -exec fromdos '{}' \;

または

find <path, tests...> | while read file; do fromdos $file; done

エラーメッセージについて完全にわかりません。私はこの方法をうまくテストしました。どのプログラムがそれぞれを作成していますか?どのファイル/ディレクトリにアクセス権がないのですか?しかし、これはあなたがそれが何であるかを推測することの試みです:

スクリプトの「ファイルが見つかりません」エラーを取得する簡単な方法の1つは、相対パスを使用することです。絶対パスを使用してください。同様に、スクリプトを実行可能にしていない場合(chmod + x)は、権限エラーが発生する可能性があります。

コメントを追加してください、私はあなたがそれを解決するのを助けます!


dos2unixの別の例を見たところ、これがなんとかしてファイルをその名前のフォルダーにコピーしていると思いましたが、今では取得できます。うわー、今は当たり前のようです。ご協力いただきありがとうございます!
ブライアンドナヒュー

1

わかりました... cygwinでは、fromdoを簡単に利用することはできません。変更されたファイルへのパスにスペースがあると、awk substebが爆発します。

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

このソリューションの大部分を@lloydに称賛


-2

他の回答でうまくいかない場合は、次の手順に従ってください。

  1. Windowsを使用している場合は、次のようにしgit config --global core.autocrlf trueます。Unixを使用している場合は、git config core.autocrlf input
  2. 走る git rm --cached -r .
  3. ファイルを削除する .gitattributes
  4. 走る git add -A
  5. 走る git reset --hard

その後、あなたのローカルは今きれいにする必要があります。


4
本当に?.gitattributesファイルの削除は行末の問題の解決策ですか?
Aleksandr M

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