4

我有一个 git 存储库,其中包含 LF 和 CRLF 文件的细微变化。

在进行可能的切换之前,我想重写父提交和当前提交具有​​不同 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 回答