Git history umschreiben, um alle CRLFs in LFs zu ersetzen?


32

Ich werde ein privates Git-Repository von der Win32-Box auf Ubuntu übertragen. Ich kann zwar ein abschließendes DOS2UNIX-Commit durchführen, möchte aber den gesamten Verlauf neu schreiben, damit auf einigen Git-GUIs log / diff korrekt angezeigt wird. ZB wird Gitg leere Zeilen für jedes CR / LF einfügen.

Antworten:


25

Sie können dazu git filter-branchmit der --tree-filterOption und Angabe --allfür die Verzweigung verwenden.

Hier ist ein Beispiel (in einem leeren Verzeichnis mit einer Textdatei vom Typ Unix gestartet:

Vorbereitung:

$ hexdump -C testfile 
00000000  61 0d 0a 62 0d 0a 63 0d  0a                       |a..b..c..|
00000009

$ git init
Initialized empty Git repository in /home/seigneur/tmp/a/.git/

$ git add testfile && git commit -m "dos file checked in"
[master (root-commit) df4970f] dos file checked in
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 testfile

Der Befehl:

$ git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all

Ausgabe:

Rewrite df4970f63e3196216d5986463f239e51eebb4014 (1/1)dos2unix: converting file testfile to Unix format ...

Ref 'refs/heads/master' was rewritten

$ hexdump -C testfile 
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006

Ich empfehle dringend , vorher eine vollständige Sicherung durchzuführen . Das Ausführen von Ihrem Linux-Computer aus (es sei denn, Sie haben eine gute Shell in Ihrer Windows-Umgebung eingerichtet) ist wahrscheinlich einfacher.

Edit: Hatte die Konvertierung beim ersten Mal umgekehrt.


1
Vielen Dank, dieser Beitrag hat mir sehr geholfen. Ich hatte ein paar Dateien mit Leerzeichen im Namen, eine kleine Änderung an den ursprünglichen Befehl fixierte es: git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. Markiert -zund -0sagt git ls-filesund xargsdruckt und interpretiert nullals Zeilenende.
Ivan

Eine andere Alternative zum Befehl dos2unix besteht darin, sich auf den git selbst zu verlassen:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas

6

Mat's Antwort hat das Problem direkt auf den Kopf getroffen. Leider sind unter Ubuntu Linux ab Version 10.04 (Lucid Lynx) die Befehle dos2unix / unix2dos nicht mehr verfügbar und wurden durch fromdos / todos ersetzt. Außerdem kennen beide Sätze der Konvertierungsbefehle die Existenz von Binärdateien in unterschiedlichem Maße nicht. Wenn Ihr Repository also Bilder, Schriftarten usw. enthält, werden sie durch diesen Prozess beschädigt.

Ich konnte eine Problemumgehung für das Problem der Beschädigung von Binärdateien finden, bei der der Linux-Befehl 'file' verwendet wird, um nur Textdateien wie unten gezeigt korrekt zu identifizieren und zu verarbeiten. Der folgende Befehl verwendet die Option --tag-name-filter, um die vorhandenen Tags zu erhalten, indem sie in die neu geänderten Commits verschoben werden. Außerdem wird das Flag --force verwendet, um sicherzustellen, dass der Befehl funktioniert, wenn Sie zuvor Tree-Filter für Ihr Repository ausgeführt haben.

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs fromdos' --tag-name-filter cat -- --all

3

Und ohne zusätzliche Tools (wie 'fromdos', 'dos2unix' usw.):

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs -0 sed -i"" -e "s/"$(printf "\015")"$//"' --tag-name-filter cat -- --all

Plattformübergreifend (OS X, FreeBSD, Linux) nützliche analoge 'fromdos', 'dos2unix':

sed -i'' -e 's/'"$(printf '\015')"'$//'

Vielleicht nützlich 'unix2dos':

sed -i '' -e 's|$|'"`printf '\015'`"'|' file.name

Wenn Sie absolut sicher sind, was Sie tun, können Sie mit diesem einfachen Inline-Befehl "/ r" aus allen Dateien im aktuellen Verzeichnis "." Löschen:

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;

1
Ändern Sie \ r \ n lieber in \ n, anstatt nur \ r zu entfernen
xdevs23

Ich denke, dass der entsprechende sedAufruf durch einen kürzeren ersetzt werden kann:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.