Wymuś LF eol w repozytorium git i kopii roboczej

170

Mam repozytorium git hostowane na github. Wiele plików zostało początkowo opracowanych w systemie Windows i nie byłem zbyt ostrożny z zakończeniami linii. Kiedy wykonywałem początkowe zatwierdzenie, nie miałem też żadnej konfiguracji git, która wymuszałaby poprawne zakończenia linii. Rezultat jest taki, że mam kilka plików z zakończeniami linii CRLF w moim repozytorium github.

Obecnie rozwijam się częściowo na Linuksie i chciałbym wyczyścić zakończenia linii. Jak mogę się upewnić, że pliki są poprawnie przechowywane w LF na github i że LF jest w mojej kopii roboczej?

Ustawiłem .gitattributesplik zawierający text eol=LF; czy to jest poprawne? Mając to zaangażowane i pchane, czy mogę po prostu rmmoje lokalne repozytorium i ponownie sklonować z github, aby uzyskać pożądany efekt?

Chowlett
źródło
1
możliwy duplikat gita zastępującego LF przez CRLF
Lazy Badger
Żadne z nich nie jest tym, o co proszę. Jestem jedynym programistą i jestem skłonny skonfigurować wszystkie moje maszyny tak samo. Mam istniejące repozytorium z kilkoma plikami CRLF już przeznaczonymi do tego i kilkoma klonami na różnych maszynach. Jak mogę zaktualizować repozytorium i każdą kopię roboczą, aby wszędzie były LF?
Chowlett
Czy obejrzałeś ten przewodnik po Githubie?
Andy

Odpowiedzi:

237

Bez odrobiny informacji o tym, jakie pliki są w Twoim repozytorium (czysty kod źródłowy, obrazy, pliki wykonywalne, ...) trochę trudno odpowiedzieć na pytanie :)

Poza tym uznam, że chcesz domyślnie ustawić LF jako zakończenia linii w swoim katalogu roboczym, ponieważ chcesz się upewnić, że pliki tekstowe mają zakończenia linii LF w repozytorium .git, niezależnie od tego, czy pracujesz w systemie Windows czy Linux . Rzeczywiście, lepiej bezpiecznie niż żałować ....

Istnieje jednak lepsza alternatywa: skorzystaj z końcówek linii LF w swoim katalogu roboczym Linuksa, zakończeń linii CRLF w katalogu roboczym Windows ORAZ końców linii LF w repozytorium.

Ponieważ częściowo pracujesz w systemie Linux i Windows, upewnij się, że core.eoljest ustawiony nanative i core.autocrlfjest ustawiony na true.

Następnie zamień zawartość pliku .gitattributes pliku na następujący

* text=auto

Pozwoli to Gitowi obsłużyć automatyczną konwersję zakończeń linii za Ciebie, przy zatwierdzeniach i zakupach. Pliki binarne nie zostaną zmienione, a pliki wykryte jako pliki tekstowe będą konwertowane na bieżąco.

Jednak znając zawartość swojego repozytorium, możesz pomóc Gitowi w wykryciu plików tekstowych z plików binarnych.

Pod warunkiem, że pracujesz nad projektem przetwarzania obrazu opartym na języku C, zastąp zawartość .gitattributespliku następującym

* text=auto
*.txt text
*.c text
*.h text
*.jpg binary

Dzięki temu pliki z rozszerzeniem c, h lub txt będą przechowywane z zakończeniami linii LF w repozytorium i będą miały natywne zakończenia linii w katalogu roboczym. Pliki JPEG nie zostaną dotknięte. Wszystkie inne skorzystają na tym samym filtrowaniu automagicznym, jak pokazano powyżej.

Aby uzyskać głębsze zrozumienie wewnętrznych szczegółów tego wszystkiego, proponuję zagłębić się w ten bardzo dobry post „Mind the end of your line” autorstwa Tima Clema, Githubbera.

Jako przykład z prawdziwego świata możesz również zerknąć na to zatwierdzenie, w którym .gitattributespokazane są te zmiany w pliku.

UPDATE do odpowiedzi, biorąc pod uwagę następujący komentarz

Właściwie nie chcę CRLF w moich katalogach Windows, ponieważ moje środowisko Linux jest w rzeczywistości VirtualBoxem współdzielącym katalog Windows

Ma sens. Dziękuję za wyjaśnienie. W tym kontekście sam .gitattributesplik nie wystarczy.

Uruchom następujące polecenia w swoim repozytorium

$ git config core.eol lf
$ git config core.autocrlf input

Ponieważ repozytorium jest współdzielone między środowiskiem Linux i Windows, zaktualizuje to lokalny plik konfiguracyjny dla obu środowisk. core.eolupewni się, że pliki tekstowe będą miały zakończenia linii LF w kasach. core.autocrlfzapewni potencjał CRLF w plikach tekstowych (wynikające na przykład z operacji kopiuj / wklej) zostaną przekonwertowane na LF w twoim repozytorium.

Opcjonalnie możesz pomóc Gitowi rozróżnić, co to jest plik tekstowy, tworząc .gitattributesplik zawierający coś podobnego do następującego:

# Autodetect text files
* text=auto

# ...Unless the name matches the following
# overriding patterns

# Definitively text files 
*.txt text
*.c text
*.h text

# Ensure those won't be messed up with
*.jpg binary
*.data binary

Jeśli zdecydowałeś się utworzyć .gitattributesplik, zatwierdź go .

Na koniec upewnij się, że jest git statusnapisane „nic do zatwierdzenia (katalog roboczy czysty)” , a następnie wykonaj następującą operację

$ git checkout-index --force --all

Spowoduje to odtworzenie plików w katalogu roboczym, biorąc pod uwagę zmiany konfiguracji i rozszerzenie .gitattributes plik oraz zastąpienie ewentualnych przeoczonych CRLF w plikach tekstowych.

Gdy to zrobisz, każdy plik tekstowy w katalogu roboczym BĘDZIE git statuszawierał zakończenia linii LF i nadal powinien uważać katalog roboczy za czysty.

nulltoken
źródło
34
Właściwie nie chcę CRLF w moich katalogach Windows, ponieważ moje środowisko Linux jest w rzeczywistości VirtualBoxem współdzielącym katalog Windows; i chociaż Notepad ++ itp. może obsługiwać tylko LF w systemie Windows, vijest mniej zadowolony z CRLF. Czy chcę to zmienić, aby to core.autocrlfbyło false(lub input)?
Chowlett
5
Doskonała odpowiedź. Krótka uwaga dla każdego, kto używa tej konfiguracji: wiersz "* text = auto" powinien być pierwszym wierszem w pliku .gitattributes, aby kolejne wiersze mogły zastąpić to ustawienie.
Ari Patrick
9
@CMCDragonkai W zależności od powłoki git checkout-index --force --allmoże działać lepiej. Drugi punkt wydaje się nieco nie na temat, jeśli chodzi o pierwotne pytanie. Co powiesz na zadanie specjalnego pytania?
nulltoken
8
Nie rozumiem, dlaczego .gitattributes nie radzi sobie z przypadkiem udostępniania kopii roboczej między Linuksem i Windowsem. Czy nie możemy ustawić texti eol=lfosiągnąć tego samego wyniku, jaki opisano w Twojej odpowiedzi za pomocą core.eoli core.autocrlf?
DanielSank
10
git checkout-index --force --allnic dla mnie nie robi. To, co działa, to lista poleceń w instrukcjach GitHub dotyczących radzenia sobie z tym problemem.
Roman Starkov,
126

Począwszy od git 2.10 (wydany 03.09.2016), nie jest konieczne osobne wyliczanie każdego pliku tekstowego. Git 2.10 naprawił zachowanie text = auto razem z eol = lf . Źródło .

.gitattributes plik w katalogu głównym repozytorium git:

* text=auto eol=lf

Dodaj i zatwierdź.

Następnie możesz wykonać następujące czynności, a wszystkie pliki są teraz znormalizowane:

git rm --cached -r .  # Remove every file from git's index.
git reset --hard      # Rewrite git's index to pick up all the new line endings.

Źródło: odpowiedź kenorb .

koppor
źródło
7
Git 2.10 został wydany 3 września 2016 r.
nadal
Uruchomiłem to i zepsuło wszystkie moje pliki nietekstowe
Anthony
Możesz jawnie ustawić tryb binarny na określone pliki. - Zastanawiam się, dlaczego automatyczne wykrywanie jest (nadal ?!) zepsute na niektórych plikach
koppor
To powinna być akceptowana odpowiedź.
Cletus W.
25

Aby wymusić zakończenia linii LF dla wszystkich plików tekstowych, możesz utworzyć .gitattributesplik na najwyższym poziomie repozytorium z następującymi wierszami (zmień według potrzeb):

# Ensure all C and PHP files use LF.
*.c         eol=lf
*.php       eol=lf

co zapewnia, że ​​wszystkie pliki, które Git uważa za pliki tekstowe, mają LFw repozytorium znormalizowane ( ) zakończenia wierszy (normalniecore.eol konfiguracja kontroluje, który z nich masz domyślnie).

Opierając się na nowych ustawieniach atrybutów, wszystkie pliki tekstowe zawierające CRLF powinny zostać znormalizowane przez Git. Jeśli nie stanie się to automatycznie, możesz odświeżyć repozytorium ręcznie po zmianie końców linii, dzięki czemu możesz ponownie przeskanować i zatwierdzić katalog roboczy, wykonując następujące kroki (mając czysty katalog roboczy):

$ 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"

lub zgodnie z dokumentacją GitHub :

git add . -u
git commit -m "Saving files before refreshing line endings"
git rm --cached -r . # Remove every file from Git's index.
git reset --hard # Rewrite the Git index to pick up all the new line endings.
git add . # Add all your changed files back, and prepare them for a commit.
git commit -m "Normalize all the line endings" # Commit the changes to your repository.

Zobacz też: post @Charles Bailey .

Dodatkowo, jeśli chciałbyś wykluczyć jakiekolwiek pliki, które nie są traktowane jako tekst, odznacz ich atrybut tekstowy, np

manual.pdf      -text

Lub zaznacz to wyraźnie jako binarne:

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Aby zobaczyć jakiś bardziej zaawansowany plik git normalizacji, sprawdź .gitattributesna Drupal rdzenia :

# Drupal git normalization
# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# @see https://www.drupal.org/node/1542048

# Normally these settings would be done with macro attributes for improved
# readability and easier maintenance. However macros can only be defined at the
# repository root directory. Drupal avoids making any assumptions about where it
# is installed.

# Define text file attributes.
# - Treat them as text.
# - Ensure no CRLF line-endings, neither on checkout nor on checkin.
# - Detect whitespace errors.
#   - Exposed by default in `git diff --color` on the CLI.
#   - Validate with `git diff --check`.
#   - Deny applying with `git apply --whitespace=error-all`.
#   - Fix automatically with `git apply --whitespace=fix`.

*.config  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.css     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.dist    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.engine  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.html    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html
*.inc     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.js      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.json    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.lock    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.map     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.module  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.php     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.po      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.script  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.sh      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.sql     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.svg     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.theme   text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.twig    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.txt     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.xml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.yml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

# Define binary file attributes.
# - Do not treat them as text.
# - Include binary diff in patches instead of "binary files differ."
*.eot     -text diff
*.exe     -text diff
*.gif     -text diff
*.gz      -text diff
*.ico     -text diff
*.jpeg    -text diff
*.jpg     -text diff
*.otf     -text diff
*.phar    -text diff
*.png     -text diff
*.svgz    -text diff
*.ttf     -text diff
*.woff    -text diff
*.woff2   -text diff

Zobacz też:

kenorb
źródło
2
1. text=autowprowadza w błąd. Nie możesz używać text=autoi eolrazem. Ustawienie eolwyłącza automatyczne wykrywanie plików tekstowych. Dlatego musisz określić wszystkie te typy plików. Gdyby autobyła włączona, nie potrzebowałbyś tego wszystkiego. 2. Nie potrzebujesz texti eol=lf. eol=lfskutecznie ustawia text.
Ben
2
Po drugie, co powiedział @Ben, ta konfiguracja jest obecnie błędna i niebezpieczna, jeśli nie zaznaczysz jawnie wszystkich plików binarnych.
Michael R
1
Czytałem, że * text=auto eol=lfpierwsze text=autojest zastępowane przez eol=lf. Gdzie znalazłeś tę funkcję? Oto moje źródło: stackoverflow.com/questions/29435156/ ...
CMCDragonkai
Usunięto * text=auto eol=lfz przykładu, ponieważ został również usunięty z Drupala. Rozważ również usunięcie komentarzy.
kenorb
4
Należy zauważyć, że to, co powiedział @Ben, nie jest już prawdą i zawsze był to błąd, a nie zamierzone zachowanie.
Semmel,