Jaka jest najlepsza strategia obsługi CRLF (carriage return, line feed) z Gitem?

Próbowałem zatwierdzić pliki z liniami końcowymi CRLF, ale się nie udało.

Spędziłem cały dzień pracy na moim komputerze z systemem Windows, próbując różnych strategii i prawie ciągnęło mnie, aby przestać próbować używać Gita i zamiast tego spróbować Mercurial .

Proszę podzielić się tylko jedną najlepszą praktyką na odpowiedź.

Author: Peter Mortensen, 2008-10-04

9 answers

[7]}prawie cztery lata po zadaniu tego pytania, w końcu znalazłem odpowiedź, która całkowicie mnie satysfakcjonuje !

[[7]}Zobacz szczegóły w github: help's guide to zajmowanie się zakończeniami linii.

Git pozwala na ustawienie właściwości zakończenia linii dla repo bezpośrednio przy użyciu atrybutu tekstowego W .gitattributes plik. Ten plik jest przypisany do repo i nadpisuje ustawienie core.autocrlf, pozwalając na zapewnienie spójnego zachowanie dla wszystkich użytkowników bez względu na ich ustawienia git.

I tak

Zaletą tego jest to, że twój koniec linii konfiguracja teraz podróżuje z repozytorium i Ty nie musisz się martwić o to, czy współpracownicy mieć odpowiednie ustawienia globalne.

Oto przykład .gitattributes plik

# Auto detect text files and perform LF normalization
*        text=auto

*.cs     text diff=csharp
*.java   text diff=java
*.html   text diff=html
*.css    text
*.js     text
*.sql    text

*.csproj text merge=union
*.sln    text merge=union eol=crlf

*.docx   diff=astextplain
*.DOCX   diff=astextplain

# absolute paths are ok, as are globs
/**/postinst* text eol=lf

# paths that don't start with / are treated relative to the .gitattributes folder
relative/path/*.txt text eol=lf

Istnieje wygodny zbiór gotowych do użycia .gitattributes files for the most popular języki programowania. Warto zacząć.

Po utworzeniu lub dostosowaniu swojego .gitattributes, należy wykonać raz na zawsze ponowną normalizację zakończeń linii.

Zauważ, że aplikacja GitHub Desktop może sugerować i tworzyć .gitattributes plik po otwarciu projektu Git repo w aplikacji. Aby spróbować, kliknij ikonę koła zębatego (w prawym górnym rogu) > Ustawienia repozytorium ... > Zakończenia linii i atrybuty. Zostaniesz poproszony o dodanie polecane .gitattributes a jeśli się zgodzisz, aplikacja przeprowadzi również normalizację wszystkich plików w Twoim repozytorium.

Wreszcie, uważaj na koniec swojej linii artykuł zapewnia więcej tła i wyjaśnia, jak Git ewoluował w sprawach. Uważam to za lekturę wymaganą .

Prawdopodobnie masz użytkowników w swoim zespole, którzy używają EGit lub JGit (narzędzia takie jak Eclipse i TeamCity używają ich) do zatwierdzania zmian. Wtedy masz pecha, Jak @gatinueta wyjaśnione w komentarzach tej odpowiedzi:

To ustawienie nie zadowoli cię całkowicie, jeśli masz ludzi pracujących z Egit lub JGit w swoim zespole, ponieważ te narzędzia po prostu zignorują .gitattributes i szczęśliwie sprawdza w plikach CRLF https://bugs.eclipse.org/bugs/show_bug.cgi?id=342372

Jedną z sztuczek może być zmuszenie ich do zmiany w innym kliencie, powiedzmy SourceTree . Nasz zespół wtedy wolał to narzędzie od Egit Eclipse ' a do wielu zastosowań.

Kto powiedział, że oprogramowanie jest łatwe? :-/
 781
Author: Daniel Jomphe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-07 14:04:37

Nie Konwertuj zakończeń linii. To nie jest zadanie VCS, aby interpretować dane -- po prostu przechowywać i wersja go. Każdy nowoczesny edytor tekstu może odczytać oba rodzaje zakończeń linii.

 122
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-04 20:42:06

Prawie zawsze chcesz autocrlf=input, chyba że naprawdę wiesz, co robisz.

Jakiś dodatkowy kontekst poniżej:

Powinno być albo core.autocrlf=true jeśli chcesz DOS ending lub core.autocrlf=input jeśli wolisz unix-newlines. W obu przypadkach, Twoje repozytorium Git będzie mieć tylko LF, co jest słuszne. Jedyny argumentem dla core.autocrlf=false było to, że automatyczne heurystyczne może nieprawidłowo wykryć niektóre binarne jako tekst a następnie twój kafelek zostanie uszkodzony. Więc, core.safecrlf opcja była wprowadzono, aby ostrzec użytkownika, jeśli następuje nieodwracalna zmiana. W rzeczywistości są dwa możliwości nieodwracalnych zmian-mieszane linia-kończąca się w pliku tekstowym, w tej normalizacji jest pożądane, więc ostrzeżenie to można zignorować, lub (bardzo mało prawdopodobne), że Git nieprawidłowo wykrył Twój plik binarny jako tekst. Następnie musisz użyć atrybutów, aby powiedz Gitowi, że ten plik jest binarny.

Powyższy akapit został pierwotnie wyciągnięty z wątku na gmane.org ale od tego czasu już nie ma na ziemię.

 84
Author: Cory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-20 09:02:55

Dwie alternatywne strategie dla uzyskać spójne o końcówkach linii w środowiskach mieszanych (Microsoft + Linux + Mac):

A. Globalny dla konfiguracji wszystkich repozytoriów

1) Konwertuj wszystkie do jednego formatu

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) Ustaw core.autocrlf na input w systemie Linux/UNIX lub true w systemie MS Windows (repozytorium lub globalny)

git config --global core.autocrlf input

3) [opcjonalnie ] Ustaw core.safecrlf na true (aby zatrzymać) lub warn (aby zaśpiewać:) aby dodać dodatkowy strażnik jeśli odwrócona transformacja nowej linii spowoduje powstanie tego samego pliku

git config --global core.safecrlf true


B. Or per repozytorium Setup

1) Konwertuj wszystkie do jednego formatu

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) Dodaj plik .gitattributes do repozytorium

echo "* text=auto" > .gitattributes
git add .gitattributes
git commit -m 'adding .gitattributes for unified line-ending'

Nie martw się o swoje pliki binarne-Git powinien być wystarczająco inteligentny.


Więcej o zmiennych safecrlf / autocrlf

 59
Author: lukmdo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-07 15:00:45

Spróbuj ustawić opcję konfiguracji core.autocrlf na true. Zobacz też opcję core.safecrlf.

Właściwie to brzmi jakby core.safecrlf mogło być już ustawione w Twoim repozytorium, ponieważ (podkreślenie moje):

Jeśli tak nie jest w przypadku bieżącego ustawienia core ' a.autocrlf, git odrzuci plik.

Jeśli tak jest, możesz sprawdzić, czy twój edytor tekstowy jest skonfigurowany tak, aby konsekwentnie używać końcówek linii. Prawdopodobnie napotkasz problemy, jeśli plik tekstowy zawiera kombinację zakończeń linii LF i CRLF.

W końcu uważam, że zalecenie, aby po prostu "używać tego, co Ci podano" i używać zakończonych linii LF w Windows spowoduje więcej problemów niż rozwiązuje. Git posiada powyższe opcje, aby próbować obsługiwać zakończenia linii w rozsądny sposób, więc warto z nich korzystać.

 10
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-05 03:50:12

Użycie core.autocrlf=false przestało oznaczać wszystkie pliki, gdy tylko sprawdziłem je w moim projekcie Visual Studio 2010. Pozostali dwaj członkowie zespołu deweloperskiego również używają systemów Windows, więc mieszane środowisko nie wchodziło w grę, ale domyślne ustawienia, które pojawiły się w repozytorium, zawsze oznaczały wszystkie pliki jako zaktualizowane natychmiast po klonowaniu.

Myślę, że najważniejsze jest, aby dowiedzieć się, co ustawienie CRLF działa dla Twojego środowiska. Zwłaszcza, że w wielu inne repozytoria w naszym ustawieniu Linux boxes autocrlf = true dają lepsze wyniki.

20+ lat później i wciąż mamy do czynienia z nierównościami końcowymi między osami... smutne.

 10
Author: Lance Cleveland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 16:08:23

[[57]}--- UPDATE 3 - - - (nie koliduje z UPDATE 2)

Biorąc pod uwagę przypadek, że użytkownicy windows wolą pracować na CRLF i użytkownicy linux/mac wolą pracować na LF na plikach tekstowych. Odpowiedź z perspektywy opiekuna repozytorium :

Dla mnie najlepsza strategia (mniej problemów do rozwiązania) to: zachowaj wszystkie pliki tekstowe Z LF wewnątrz git repo, nawet jeśli pracujesz nad projektem tylko dla windows. Następnie daj klienci mogą pracować na w preferowanym przez siebie stylu zakończenia linii, pod warunkiem, że wybierają core.autocrlf wartość właściwości, która będzie respektować Twoją strategię (LF na repo) podczas wstawiania plików do commita.

Staging jest tym, co wielu ludzi myli, próbujączrozumieć jak działają strategie newline. Przed wybraniem prawidłowej wartości dla właściwości core.autocrlf Ważne jest, aby odwrócić następujące punkty:

  • dodawanie a plik tekstowy dla commita (staging it) jest jak skopiowanie pliku do innego miejsca wewnątrz podkatalogu .git/ z przekonwertowanymi zakończeniami linii (w zależności od wartości core.autocrlf w konfiguracji klienta). Wszystko to odbywa się lokalnie.
  • W tym samym czasie, na początku gry, gracz będzie miał do wyboru kilka opcji, które pozwolą mu na zdobycie kolejnych punktów.]}
    • "Should Git-client a. Konwertuj LF-na-CRLF podczas sprawdzania (wyciągania) repo zmienia się z pilot lub b. przekonwertować CRLF - na-LF podczas dodawania pliku do commita? " A możliwe odpowiedzi (wartości) to:
    • false: "do brak Z powyższego",
    • input: "do tylko b"
    • true: "do a i b"
    • zauważ, że nie ma "Rób tylko "

Na szczęście

  • Git Client defaults (windows: core.autocrlf: true, linux / mac: core.autocrlf: false) będzie kompatybilny ze strategią LF-only-repo .
    Znaczenie: klienci windows będą domyślnie konwertować na CRLF podczas sprawdzania repozytorium i konwertować na LF podczas dodawania commit. A klienci Linuksa domyślnie nie będą wykonywać żadnych konwersji. To teoretycznie zatrzyma Twój repo LF-only.

Niestety:

  • mogą być klienci GUI, którzy nie respektują Gita core.autocrlf wartość
  • mogą być ludzie, którzy nie używają wartości, aby szanować Twoją strategię LF-repo. Np. używają core.autocrlf=false i dodają Plik z CRLF do commita.

Aby wykryć pliki tekstowe ASAP nie-lf popełnione przez powyższych klientów można śledzić to, co jest opisane na - - - update 2 ---: (git grep -I --files-with-matches --perl-regexp '\r' HEAD, na kliencie skompilowanym przy użyciu flagi --with-libpcre)

I tu jest haczyk: . Jako repo maintainer przechowuję git.autocrlf=input, aby naprawić wszystkie niesłusznie popełnione pliki tylko przez dodanie ich ponownie do commit. I podaję tekst commit: "naprawianie niesłusznie popełnionych plików".

O ile .gitattributes jest wymyślona. Nie liczę na to, ponieważ jest więcej klientów ui, którzy tego nie rozumieją. Używam go tylko do podpowiedzi dla plików tekstowych i binarnych, a może znaczę niektóre wyjątkowe pliki, które powinny wszędzie mieć te same zakończenia linii: {]}

*.java          text !eol # Don't do auto-detection. Treat as text (don't set any eol rule. use client's)
*.jpg           -text     # Don't do auto-detection. Treat as binary
*.sh            text eol=lf # Don't do auto-detection. Treat as text. Checkout and add with eol=lf
*.bat           text eol=crlf # Treat as text. Checkout and add with eol=crlf

Pytanie: ale dlaczego w ogóle interesuje nas strategia obsługi newline?

Odpowiedź: To unikaj commita zmiany pojedynczej litery, pojawiającego się jako zmiana 5000 linii , tylko dlatego, że klient, który dokonał zmiany, automatycznie przekonwertował pełny plik z crlf na lf (lub odwrotnie) przed dodaniem go do commita. Może to być dość bolesne, gdy w grę wchodzi rozwiązywanie konfliktów. W niektórych przypadkach może to być przyczyną nierozsądnych konfliktów.


--- UPDATE 2 - - -

Dafaults klienta git będzie działać w większości przypadków. Nawet jeśli mają tylko klientów windows, tylko klientów linux lub obu. Są to:

  • okna: core.autocrlf=true oznacza konwersję linii do CRLF przy kasie i konwersję linii do LF podczas dodawania plików.
  • linux: core.autocrlf=input oznacza, że nie konwertuje linii przy kasie (nie ma potrzeby, ponieważ oczekuje się, że pliki będą zatwierdzane przez LF) i konwertuje linie do LF (jeśli jest to konieczne) podczas dodawania plików. (-- update3 -- : wygląda na to, że jest to false domyślnie, ale znowu jest fine)

Właściwość może być ustawiona w różnych zakresach. Sugerowałbym wyraźne ustawienie zakresu --global, aby uniknąć niektórych problemów IDE opisanych na końcu.

git config core.autocrlf
git config --global core.autocrlf
git config --system core.autocrlf
git config --local core.autocrlf
git config --show-origin core.autocrlf

Również zdecydowanie zniechęcałbym do używania w systemie windows git config --global core.autocrlf false (W przypadku, gdy masz tylko klientów windows) W przeciwieństwie do tego, co jest proponowane do dokumentacja git . Ustawienie na false spowoduje zatwierdzenie plików z CRLF w repo. Ale naprawdę nie ma powodu. Nigdy nie wiesz czy będziesz musiał udostępnić projekt użytkownikom Linuksa. Dodatkowo jest to jeden dodatkowy krok dla każdego klienta, który dołącza do projektu, zamiast używać domyślnych.

Teraz dla niektórych szczególnych przypadków plików (np. *.bat *.sh) które chcesz, aby były sprawdzane z LF lub z CRLF możesz użyć .gitattributes

Podsumowując dla mnie najlepsza praktyka to:

  • upewnij się, że każdy plik niebinarny jest przypisany z LF na git repo (domyślne zachowanie).
  • Użyj tego polecenie, aby upewnić się, że żadne pliki nie są zatwierdzane przez CRLF: git grep -I --files-with-matches --perl-regexp '\r' HEAD (Uwaga: na klientach systemu windows działa tylko poprzez git-bash, a na klientach Linuksa tylko jeśli jest skompilowany przy użyciu --with-libpcre w ./configure).
  • jeśli znajdziesz takie pliki wykonując powyższe polecenie, popraw je. To dotyczy (przynajmniej na Linuksie):
    • zestaw core.autocrlf=input (--- Aktualizacja 3 --)
    • Zmień plik
    • Odwróć zmianę (plik jest nadal wyświetlany jako zmieniony)
    • commit it
  • używaj tylko minimum .gitattributes
  • poinstruuj użytkowników, aby ustawili core.autocrlf opisane powyżej wartości domyślne.
  • nie licz w 100% na obecność .gitattributes. Git-klienci IDE mogą je ignorować lub traktować inaczej.

Jak powiedział niektóre rzeczy mogą być dodane w atrybutach Gita:

# Always checkout with LF
*.sh            text eol=lf
# Always checkout with CRLF
*.bat           text eol=crlf

Myślę, że inne bezpieczne opcje dla .gitattributes zamiast automatycznego wykrywania plików binarnych:

  • -text (np. dla *.zip lub *.jpg pliki: nie będą traktowane jako tekst. W ten sposób nie będą próbowane żadne konwersje kończące linię. Diff może być możliwe dzięki programom konwersji)
  • text !eol (np. dla *.java,*.html: traktowane jako tekst, ale preferencje stylu eol nie są ustawione. Tak więc używane jest ustawienie klienta.)
  • -text -diff -merge (np. dla *.hugefile: nie traktowany jako tekst. Brak możliwości różnicowania / scalania)

--- POPRZEDNIA AKTUALIZACJA - - -

Jeden bolesny przykład klienta, który błędnie zatwierdzi pliki:

Netbeans 8.2 (w systemie windows) błędnie zatwierdzi wszystkie pliki tekstowe z CRLFs, chyba że masz jawnie ustawione core.autocrlf jako globalny . Jest to sprzeczne ze standardowym zachowaniem klienta git i powoduje wiele problemów później, podczas aktualizacji/scalania. To sprawia, że niektóre pliki wyglądają inaczej (chociaż nie są) nawet po przywróceniu .
To samo zachowanie w netbeans dzieje się nawet jeśli dodałeś poprawne .gitattributes do twojego projektu.

Użycie następującego polecenia po zatwierdzeniu, pomoże Ci przynajmniej wcześnie wykryć, czy twój Git repo ma problemy z zakończeniem linii: git grep -I --files-with-matches --perl-regexp '\r' HEAD

spędziłem wiele godzin, aby wymyślić jak najlepsze wykorzystanie .gitattributes, aby w końcu uświadomić sobie, że nie mogę na to liczyć.
Niestety, dopóki istnieją edytory oparte na JGit (które nie mogą poprawnie obsługiwać .gitattributes), bezpiecznym rozwiązaniem jest wymuszanie LF wszędzie, nawet na poziomie edytora.

Użyj po anti-CRLF środkach dezynfekcyjnych.

 8
Author: Marinos An,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-13 16:50:22

Są to dwie opcje dla Windows i Visual Studio użytkowników, którzy dzielą kod z Mac lub Linux użytkowników. Aby uzyskać rozszerzone Wyjaśnienie, przeczytaj gitattributes manual .

* text = auto

W pliku repo .gitattributes Dodaj:

*   text=auto

To znormalizuje wszystkie pliki z LF zakończeniami linii w repo.

I w zależności od ustawienia systemu operacyjnego (core.eol), pliki w drzewie roboczym będą znormalizowany do LF dla systemów opartych na Uniksie lub CRLF dla Systemów Windows.

Jest to konfiguracja używana przez Microsoft. NET.

Przykład:

Hello\r\nWorld

Będzie znormalizowane w repo zawsze jako:

Hello\nWorld

Przy kasie drzewo robocze w systemie Windows zostanie przekonwertowane do:

Hello\r\nWorld
Po zakończeniu procesu płatności drzewo robocze w komputerze Mac będzie pozostawione jako:]}
Hello\nWorld

Uwaga: Jeśli twój repo zawiera już pliki nie znormalizowane, git status będzie Pokaż Te pliki jako całkowicie zmodyfikowane przy następnej zmianie na nich, a może to być ból dla innych użytkowników, aby połączyć swoje zmiany później. Zobacz odświeżanie repozytorium po zmianie zakończeń linii , aby uzyskać więcej informacji.

Rdzeń.autocrlf = true

Jeśli text jest nieokreślony w pliku .gitattributes, Git używa zmiennej konfiguracyjnej core.autocrlf do określenia, czy plik powinien zostać przekonwertowany.

Dla użytkowników Windows, git config --global core.autocrlf true jest świetną opcją ponieważ:

  • pliki są znormalizowane do LF zakończenia linii tylko po dodaniu do repo. Jeśli w repo znajdują się pliki, które nie są znormalizowane, to ustawienie ich nie dotknie.
  • wszystkie pliki tekstowe są konwertowane na CRLF zakończenia linii w katalogu roboczym.

Problem z tym podejściem polega na tym, że:

  • jeśli jesteś użytkownikiem systemu Windows z autocrlf = input, zobaczysz kilka plików z zakończeniami linii LF. Nie stanowi zagrożenia dla reszty zespołu, ponieważ twoje commity nadal będą znormalizowane z LF zakończeniami linii.
  • jeśli jesteś użytkownikiem systemu Windows z core.autocrlf = false, zobaczysz kilka plików z zakończeniami linii LF i możesz wprowadzić pliki z zakończeniami linii CRLF do repo.
  • większość użytkowników komputerów Mac używa autocrlf = input i może pobierać pliki z zakończeniami CRLF, prawdopodobnie od użytkowników Windows z core.autocrlf = false.
 7
Author: kiewic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-24 14:54:58

To jest tylko obejście rozwiązanie:

W normalnych przypadkach, używaj rozwiązań dostarczanych z Gitem. W większości przypadków działają one świetnie. Wymuś na LF, jeśli współdzielisz rozwój na systemach Windows i Unix, ustawiając .gitattributes .

W moim przypadku było >10 programistów tworzących projekt w Windows. Ten projekt został sprawdzony w CRLF i nie było opcji, aby wymusić LF.

Niektóre ustawienia zostały wewnętrznie napisane na moim maszyna bez żadnego wpływu na format LF; w ten sposób niektóre pliki były zmieniane globalnie na LF przy każdej małej zmianie Pliku.

Moje rozwiązanie:

Windows-Maszyny: Niech wszystko jak jest. Nie dbaj o nic, ponieważ jesteś domyślnym programistą windows 'lone wolf' i musisz sobie z tym poradzić: "nie ma innego systemu na całym świecie, prawda?"

Unix-Maszyny

  1. Dodaj następujące wiersze do sekcji [alias] konfiguracji. To polecenie lista wszystkich plików zmienionych (np. zmodyfikowanych/nowych):

    lc = "!f() { git status --porcelain \
                 | egrep -r \"^(\?| ).\*\\(.[a-zA-Z])*\" \
                 | cut -c 4- ; }; f "
    
  2. Konwertuj wszystkie zmienione pliki do formatu dos:

    unix2dos $(git lc)
    
  3. Opcjonalnie ...

    1. Utwórz git hook dla tej akcji, aby zautomatyzować ten proces

    2. Użyj params i dołącz go i zmodyfikuj funkcję grep, aby pasowała tylko do określonych nazw plików, np.:

      ... | egrep -r "^(\?| ).*\.(txt|conf)" | ...
      
    3. Możesz uczynić go jeszcze wygodniejszym, korzystając z dodatkowego Skrót:

      c2dos = "!f() { unix2dos $(git lc) ; }; f "
      

      ... i odpalić przerobione rzeczy wpisując

      git c2dos
      
 5
Author: John Rumpel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-26 18:51:58