Przepisz historię git, aby zastąpić wszystkie CRLF na LF?

32

Zamierzam przenieść prywatne repozytorium Git z win32 box do Ubuntu. Chociaż mogę zrobić ostatnie zatwierdzenie dos2unix, ale chciałbym przepisać całą historię, więc niektóre GUI Git będą poprawnie wyświetlać log / diff. Np. Gitg wstawi puste linie dla każdego CR / LF.

Xiè Jìléi
źródło

Odpowiedzi:

25

Możesz git filter-branchdo tego użyć z --tree-filteropcją i podać --allgałąź.

Oto przykład (rozpoczęty w pustym katalogu z plikiem tekstowym typu Unix:

Przygotowanie:

$ 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

Komenda:

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

Wydajność:

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

Ja zdecydowanie polecam to zrobić pełną kopię zapasową wcześniej . Uruchamianie go z komputera z systemem Linux (chyba że masz dobrą powłokę skonfigurowaną w środowisku Windows) jest prawdopodobnie łatwiejsze.

Edycja: czy konwersja została odwrócona za pierwszym razem.

Mata
źródło
1
Dziękuję, ten post bardzo mi pomógł. Miałem kilka plików ze spacjami w nazwie, mała zmiana w oryginalnym poleceniu ustalone to: git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. Flagi -zi -0powiedzieć git ls-filesi xargswydrukować i zinterpretować nulljako koniec linii.
Ivan
Inną alternatywą dla komendy dos2unix jest poleganie na samym git:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas,
6

Odpowiedź Mata trafiła w sedno problemu. Niestety w systemie Ubuntu Linux, począwszy od wersji 10.04 (Lucid Lynx), polecenia dos2unix / unix2dos nie są już dostępne i zostały zastąpione przez fromdos / todos. Co więcej, oba zestawy poleceń konwersji mają różny stopień ignorancji w stosunku do istnienia plików binarnych, dlatego jeśli twoje repozytorium zawiera obrazy, czcionki itp., Zostaną one uszkodzone przez ten proces.

Udało mi się znaleźć sposób na obejście problemu uszkodzenia pliku binarnego, który używa polecenia Linux „file” do prawidłowej identyfikacji i przetwarzania tylko plików tekstowych, jak pokazano poniżej. Poniższe polecenie używa opcji --tag-name-filter, aby zachować istniejące znaczniki, przenosząc je do nowo zmienionych zatwierdzeń. Używa także flagi --force, aby upewnić się, że polecenie będzie działać w przypadku wcześniejszego uruchomienia filtru drzewa w repozytorium.

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
mgorovoy
źródło
3

I bez żadnych dodatkowych narzędzi (takich jak „fromdos”, „dos2unix” itp.):

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

Crossplatform (OS X, FreeBSD, Linux) przydatne analogowe „fromdos”, „dos2unix”:

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

Być może przydatne „unix2dos”:

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

Jeśli absolutnie wiesz, co robisz, możesz użyć tego prostego polecenia wbudowanego do usunięcia „/ r” ze wszystkich plików w bieżącym katalogu ”.”:

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;
METAJIJI
źródło
1
Raczej zmień \ r \ n na \ n zamiast usuwać tylko r
xdevs23
Myślę, że odpowiednie sedwywołanie można zastąpić krótszym:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k