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.