Próbuję naprawić zakończenia linii za pomocą git filter-branch, ale bez powodzenia


270

Ugryzł mnie problem zakończenia linii w systemie Windows / Linux w programie git. Wydaje się, za pośrednictwem GitHub, MSysGit i innych źródeł, że najlepszym rozwiązaniem jest skonfigurowanie lokalnych repozytoriów do używania zakończeń linii w stylu linux, ale ustawionych core.autocrlfna true. Niestety nie zrobiłem tego wystarczająco wcześnie, więc teraz za każdym razem, gdy pociągam zmiany, zakończenia linii są przerywane.

Myślałem, że znalazłem tutaj odpowiedź , ale nie mogę zmusić jej do działania. Moja wiedza na temat wiersza poleceń w Linuksie jest w najlepszym wypadku ograniczona, więc nie jestem nawet pewien, co robi wiersz „xargs fromdos” w jego skrypcie. Ciągle otrzymuję wiadomości o braku takiego pliku lub katalogu, a kiedy udaje mi się wskazać istniejący katalog, mówi mi, że nie mam uprawnień.

Próbowałem tego z MSysGit w systemie Windows i za pomocą terminala Mac OS X.


Nie mogę głosować nawet za tym wątkiem. +1 ++ za to, że zapewnia najlepszą odpowiedź w tej sprawie.
— sjas,

Zgadzam się z Charlesem. Jednak w moim przypadku (przy użyciu Mac OS X 10.8)> git config core.autocrlf false działał, a nie> git config core.autocrlf input
— user1045085

Odpowiedzi:


187

Dokumentacja git dla gitattributes dokumentuje teraz inne podejście do „naprawy” lub normalizacji wszystkich zakończeń linii w twoim projekcie. Oto jego sedno:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

Jeśli jakieś pliki, które nie powinny być znormalizowane, wyświetlają się w stanie git, usuń ich atrybut tekstowy przed uruchomieniem git add -u.

manual.pdf -text

I odwrotnie, w plikach tekstowych, których git nie wykrywa, można ręcznie włączyć normalizację.

weirdchars.txt text

Wykorzystuje to nową --renormalizeflagę dodaną w git v2.16.0, wydanym w styczniu 2018 r. W przypadku starszych wersji git jest jeszcze kilka kroków:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

1
Czy możesz mi powiedzieć, jaki jest cel tego git reset, proszę?
— crdx

1
zmusza git do przebudowania indeksu, podczas którego skanuje każdy plik, aby zgadnąć, czy jest on binarny. Rm usuwa stary indeks, reset tworzy nowy indeks.
— Russ Egan

16
Dzięki, to zadziałało dla mnie. Przydatnym poleceniem po uruchomieniu git statusjest uruchomienie, git diff --ignore-space-at-eolaby upewnić się, że jedynymi zatwierdzanymi przez ciebie zmianami są zakończenia linii.
— zelanix

1
Uwaga: jedyną „prawdziwą” różnicą między tym a „starym” rozwiązaniem jest obecność .gitattributes (z odpowiednią zawartością). Bez tego git resetnie wykryje żadnych modyfikacji, a zatem jest bezużyteczny.
— Rob

3
Instrukcje dotyczące gitattributes stronie zostały zaktualizowane do skorzystania z --renormalizeflagą dodanej w git v2.16.0 który został wydany w styczniu 2018 roku --renormalizeflaga konsoliduje proces ponownego przetwarzania zakończeń linii dla każdego pliku śledzona do jednego polecenia: git add --renormalize ..
— Mike Hill

389

Najprostszym sposobem, aby to naprawić, jest dokonanie jednego zatwierdzenia, który naprawia wszystkie zakończenia linii. Zakładając, że nie masz żadnych zmodyfikowanych plików, możesz to zrobić w następujący sposób.

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .

7
PS Poleciłem waszą poprawkę chłopakom na github.com, a oni zaktualizowali swój przewodnik pomocy, aby użyć waszego rozwiązania (wcześniej zalecał świeżego klonowanie i twardy reset, który nie wydawał się uzyskać wszystkich plików.) Help.github. com / radzenie sobie z liniami
— Brian Donahue

31
Dzięki ... to świetna poprawka. Znaleziono go na GitHub.
— PHLAK

4
Możesz także sprawdzić config.safecrlf, aby upewnić się, że nie zmieniasz crlfs w plikach nietekstowych (takich jak binarne). Sprawdź to w dokumentacji kernel.org/pub/software/scm/git/docs/git-config.html .
— vrish88

4
@ vrish88: Jeśli jednak znajdujesz się w takiej sytuacji, prawdopodobnie cierpisz na mieszane zakończenia z podszewką i rdzeń.safecrlf może faktycznie uniemożliwić ci wykonanie tego, co musisz zrobić. Prawdopodobnie łatwiej jest nie używać safecrlf. git często błędnie wykrywa pliki binarne, a jeśli tak, możesz ręcznie oznaczyć go jako plik binarny za pomocą .gitattribute i odzyskać poprawną wersję z poprzedniego zatwierdzenia.
— CB Bailey,

26
Nowsze rozwiązanie zalecane w poniższej odpowiedzi Russa Egana jest prostsze i nie wiąże się ze strasznymi rzeczami, takimi jak usunięcie całego kodu źródłowego , więc naprawdę polecam ludziom korzystanie z niego, nawet jeśli to stare rozwiązanie ma 10 razy więcej głosów!
— Porculus,

11

Moja procedura postępowania z zakończeniami linii jest następująca (przetestowana na wielu repozytoriach):

Podczas tworzenia nowego repozytorium:

  • wstaw .gitattributespierwsze zatwierdzenie wraz z innymi typowymi plikami jako .gitignoreiREADME.md

W przypadku istniejącego repozytorium:

  • Utwórz / zmodyfikuj .gitattributesodpowiednio
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n( --no-verifyma pominąć haczyki poprzedzające zatwierdzenie)
    • Muszę to robić wystarczająco często, by zdefiniować to jako alias alias fixCRLF="..."
  • powtórz poprzednie polecenie
    • tak, to voodoo, ale generalnie muszę uruchomić polecenie dwa razy, za pierwszym razem normalizuje niektóre pliki, za drugim razem jeszcze więcej plików. Generalnie najlepiej chyba powtarzać, dopóki nie zostanie utworzone nowe zatwierdzenie :)
  • przejdź kilka razy między starą (tuż przed normalizacją) a nową gałęzią. Po zmianie gałęzi czasami git znajdzie jeszcze więcej plików, które wymagają ponownej normalizacji!

W .gitattributesoświadczam jawnie, że wszystkie pliki tekstowe mają LOL EOL, ponieważ ogólnie narzędzia Windows są kompatybilne z LF, podczas gdy narzędzia inne niż Windows nie są kompatybilne z CRLF (nawet wiele narzędzi wiersza poleceń nodejs zakłada LF i dlatego może zmieniać EOL w twoich plikach).

Zawartość .gitattributes

Mój .gitattributeszwykle wygląda jak:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

Aby dowiedzieć się, jakie różne rozszerzenia są śledzone przez git w bieżącym repozytorium, spójrz tutaj

Problemy po normalizacji

Po wykonaniu tej czynności istnieje jeszcze jedno wspólne zastrzeżenie.

Powiedz, że Twój masterjest już aktualny i znormalizowany, a następnie do kasy outdated-branch. Dość często zaraz po sprawdzeniu tej gałęzi, git zaznacza wiele plików jako zmodyfikowanych.

Rozwiązaniem jest wykonanie fałszywego commit ( git add -A . && git commit -m 'fake commit'), a następnie git rebase master. Po zmianie bazy fałszywe zatwierdzenie powinno zniknąć.


1
Myślałem, że wariuję, dopóki nie przeczytałem twojego postu, ponieważ musiałem kilka razy uruchomić określoną sekwencję poleceń. Wiara w czary! ;)
— Sean Fausett

W wersji git 2.7.0.windows.1użyłem następujących opcji: git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
— Sean Fausett

4
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Wyjaśnienie:

  • git status --short

    Wyświetla każdą linię, której git jest i nie jest świadomy. Pliki, które nie są kontrolowane przez git są oznaczone na początku linii znakiem „?”. Pliki, które są modyfikowane, są oznaczone literą M.

  • grep "^ *M"

    To odfiltrowuje tylko te pliki, które zostały zmodyfikowane.

  • awk '{print $2}'

    Pokazuje tylko nazwę pliku bez żadnych znaczników.

  • xargs fromdos

    Pobiera nazwy plików z poprzedniego polecenia i uruchamia je za pomocą narzędzia „fromdos” w celu konwersji końcówek linii.


To jest niesamowite. Dziękuję Ci. Dla każdego, kto szuka rozwiązania korzystającego z Homebrew dos2unixzamiast fromdos.
— Almir Sarajčić


3

„| Xargs fromdos” odczytuje ze standardowego wejścia ( findznalezione pliki ) i używa go jako argumentu polecenia fromdos, które konwertuje zakończenia linii. (Czy fromdos jest standardem w tych środowiskach? Jestem przyzwyczajony do dos2unix). Zauważ, że możesz uniknąć używania xargs (szczególnie przydatne, jeśli masz wystarczającą liczbę plików, aby lista argumentów była zbyt długa dla xargs):

find <path, tests...> -exec fromdos '{}' \;

lub

find <path, tests...> | while read file; do fromdos $file; done

Nie jestem całkowicie pewien twoich komunikatów o błędach. Z powodzeniem przetestowałem tę metodę. Jaki program produkuje każdy? Do jakich plików / katalogów nie masz uprawnień? Oto jednak próba zgadnięcia, co to może być:

Jednym prostym sposobem na uzyskanie błędu „nie znaleziono pliku” dla skryptu jest użycie ścieżki względnej - użyj bezwzględnej. Podobnie możesz otrzymać błąd uprawnień, jeśli skrypt nie jest wykonywalny (chmod + x).

Dodaj komentarze, a postaram się pomóc.


Widziałem inny przykład z dos2unix i pomyślałem, że to jakoś kopiowanie plików do folderu o nazwie tak, ale teraz rozumiem. Wow, wydaje się teraz oczywiste. Dzięki za pomoc!
— Brian Donahue

1

ok ... w cygwinie nie mamy łatwo dostępnych fromdos, a ta awk podmuch pojawia się na twojej twarzy, jeśli masz jakieś spacje w ścieżkach do zmodyfikowanych plików (które mieliśmy), więc musiałem to zrobić nieco inaczej:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

podziękowania dla @lloyd za większość tego rozwiązania


-2

Wykonaj następujące kroki, jeśli żadna inna odpowiedź nie działa dla Ciebie:

  1. Jeśli korzystasz z systemu Windows, zrób git config --global core.autocrlf true; jeśli korzystasz z Uniksa, zróbgit config core.autocrlf input
  2. Biegać git rm --cached -r .
  3. Usuń plik .gitattributes
  4. Biegać git add -A
  5. Biegać git reset --hard

W takim razie twój lokal powinien być teraz czysty.


4
Naprawdę? Usunięcie .gitattributespliku jest rozwiązaniem problemu z zakończeniami linii?
— Aleksandr M

Tak proszę zająć komentarz przez @AleksandrM
— Mr_and_Mrs_D
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.