4

LF および CRLF ファイルの細かいバリエーションを持つ git リポジトリがあります。

可能な切り替えを行う前に、親と現在のコミットの LR/CRLF エンコーディングが異なるコミットを書き直したいと思います。

todosそこで、ファイルの親バージョンに CR が含まれている場合に実行しようとする次の「ワンライナー」(少し編集) を試しました。

$ git filter-branch --tree-filter '
  echo
  P=$GIT_COMMIT^;
  FILES=$(git diff --name-only $P);
  for a in $FILES; do
     if ! git cat-file -e $P:$a; then echo "no parent"; continue; fi;
     if git show $:$a | grep -qUP '\r'; then
        echo "parent is dos";
        todos $a;
     else
        echo "parent is unix";
        fromdos $a;
     fi;
  done' 23498f..HEAD

うまくいきません。誰でもエラーを見つけたり、この問題の解決策を提供できますか?

4

2 に答える 2

2

I am answering my own question. The bug in my original solution is that the FILES set is wrong because the diff is not taken between the rewritten parent and the current commit, but between the original parent and the current commit.

When traversing a set of commits like this, the files that need to be changed isn't the set of files touched by a commit, but also the set of files where some parent commit messed up the line endings.

This means that I don't get the correct set of files. There is a map function provided to filter-branch expressions that can transform an "original" rev to the rewritten rev. When I use that function, it works correctly.

The resulting "one-liner" looks like this:

$ git filter-branch -f --tree-filter '                         
    echo "\n $GIT_COMMIT";
    P=$(git rev-parse $GIT_COMMIT^);
    echo $P;
    P=$(map $P);
    echo $P;
    git cat-file commit $GIT_COMMIT;
    FILES=$(git diff --name-only $GIT_COMMIT $P);
    echo "FILES:\n$FILES"; 
    for a in $FILES; do
        git cat-file -e $P:$a > /dev/null 2>&1 || continue;
        if git show $P:$a | grep -qUP '\r'; then
           echo "parent is dos $a";
           todos $a;
        else
           echo "parent is unix $a";
           fromdos $a;
        fi;
    done;
    git add $FILES;' a6d9e..HEAD 

Most of the aI don't think the last 'git add $FILES' is needed, but that is the command that I used, and I don't want to provide an incorrect answer.

Note: It should also be possible to define FILES=$(git diff --name-only a6d9e HEAD) and thus use a fixed set when traversing the commits. That is probably much simpler, but I didn't do that.

于 2013-05-22T18:59:17.103 に答える
1

あなたは本当に歴史を書き換えたいですか?

組み込みの構成オプションを使用すると、これらを透過的にすることができます。私はこれと似たようなことをしてきましたが、ここ数年、Windows、Mac、および Linux システムで人々と仕事をしていても、行末の問題はまだありません。

GitHub の行末の処理を参照してください。

構成ファイルについて彼らが言わなければならないことは次のとおりです。

.gitattributes ファイルの例を次に示します。これをすべてのリポジトリのテンプレートとして使用できます。

# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto

# Explicitly declare text files we want to always be normalized and converted 
# to native line endings on checkout.
*.c text
*.h text

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary The advantage of this is that your end of line configuration now travels with your repository and you don't need to worry about whether or not collaborators have the proper global settings.

彼らは続けて、現在のリポジトリがあり、これらの設定をそれに適用する必要がある場合に何ができるかについて話します。

リポジトリの再正規化

core.autocrlf オプションを設定して .gitattributes ファイルをコミットした後、変更していないファイルを git がコミットしようとしていることに気付く場合があります。これは、git が行末を正規化したいためです。これを行う最善の方法は、作業ツリー (.git ディレクトリを除くすべてのファイル) を消去してから復元することです。これを行う前に、すべての作業をコミットしたことを確認してください。そうしないと、失われます。

git rm --cached -r .
# Remove everything from the index.

git reset --hard
# Write both the index and working directory from git's database.

git add .
# Prepare to make a commit by staging all the files that will get normalized.
# This is your chance to inspect which files were never normalized. You should
# get lots of messages like: "warning: CRLF will be replaced by LF in file."

git commit -m "Normalize line endings"
# Commit
于 2013-05-22T08:49:32.297 に答える