web-dev-qa-db-ja.com

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

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

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

これをWindows上のMSysGitで、Mac OS Xターミナル経由で試しました。

266
Brian Donahue

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

これは、2018年1月にリリースされたgit v2.16.0で追加された新しい--renormalizeフラグを活用します。古いバージョンの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"
184
Russ Egan

これを修正する最も簡単な方法は、すべての行末を修正する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 .
385
CB Bailey

行末を処理するための私の手順は次のとおりです(多くのリポジトリでバトルがテストされています)。

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

  • .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回実行する必要があります。最初はいくつかのファイルを正規化し、2番目はさらに多くのファイルを正規化します。通常、新しいコミットが作成されなくなるまで繰り返すのがおそらく最善です:)
  • 古い(正規化の直前)ブランチと新しいブランチの間を数回往復します。ブランチを切り替えた後、gitが再正規化する必要があるファイルをさらに見つけることがあります!

.gitattributesでは、すべてのテキストファイルを明示的にLF EOLとして宣言します。これは一般に、WindowsツールはLFと互換性があるためです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を実行することです。リベース後、偽のコミットはなくなります。

11
jakub.g

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

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'
4
pfrenssen
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

説明:

  • git status --short

    これにより、gitが認識している各行が表示されます。 gitの制御下にないファイルは、行の先頭に「?」でマークされます。変更されたファイルにはMのマークが付けられます。

  • grep "^ *M"

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

  • awk '{print $2}'

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

  • xargs fromdos

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

4
Lloyd Moore

"| 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)アクセス許可エラーが発生する可能性があります。

コメントを追加してください

3
Cascabel

わかりました... cygwinではfromdosを簡単に使用できません。変更されたファイルへのパスにスペースがあると、awk substebが顔に吹き飛ばされます(私たちは持っていました)。

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

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

1
Anton K