Czy git-merge może ignorować różnice w końcówkach linii?


150

Czy można git mergezignorować różnice w końcówkach linii?

Może zadaję złe pytanie ... ale:

Próbowałem uisng, config.crlf inputale sprawy trochę się pogmatwały i wymknęły się spod kontroli, szczególnie gdy zastosowałem go po fakcie .

Po pierwsze, zastosowanie tej konfiguracji po fakcie nie wydaje się wpływać na pliki, które zostały zatwierdzone do repozytorium przed zastosowaniem tej opcji. Inną rzeczą jest to, że nagle wszystkie zatwierdzenia powodują teraz wiele irytujących komunikatów ostrzegawczych o konwersji CRLF do LF.

Szczerze mówiąc, nie obchodzi mnie, jakie zakończenie linii jest używane, osobiście wolę styl uniksowy \n, ale nieważne. Wszystko, na czym mi zależy, to git mergebyć nieco mądrzejszym i ignorować różnice w zakończeniach linii.

Czasami mam dwa identyczne pliki, ale git oznaczyłby je jako będące w konflikcie (a konflikt dotyczy całego pliku) po prostu dlatego, że używają innego znaku końca linii.

Aktualizacja:

Dowiedziałem się, że git diffakceptuje --ignore-space-at-eolopcję, czy byłoby możliwe, aby git mergeskorzystać z tej opcji?


28
Och, chciałbym. To zakończenie linii w git jest całkowicie zepsute
1800 INFORMACJA

Właśnie dodano przypadek testowy ilustrujący, że narzędzie do scalania innej firmy będzie ignorowało styl eol podczas scalania
VonC

Tak więc, aby wyjaśnić (z tego, co mogę ustalić): nie ma sposobu, aby git ignorował CR, ale narzekał na wszystkie inne końcowe spacje?
Stephen

git config merge.renormalize true
Koniecznie

Odpowiedzi:


115

Aktualizacja 2013:

Nowsze wersje git autoryzacji za pomocą seryjnej ze strategią recursivei strategia opcji ( -X):

git merge -s recursive -Xignore-space-at-eol

Ale użycie „ -Xignore-space-changejest również możliwe

  • Fab-V wspomina poniżej :
    git merge master -s recursive -X renormalize
    
    

jakub.g komentuje również, że strategie działają również przy wybieraniu wiśni :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Działa to znacznie lepiej niż ignore-all-space.


Oryginalna odpowiedź (maj 2009)

Łatka do ignorowania stylu eol została zaproponowana w czerwcu 2007 roku , ale dotyczy tylko git diff --ignore-space-at-eol, nie git merge.

W tym czasie zadawano pytanie:

Czy powinna --ignore-space-at-eolbyć opcja git-merge?
W przypadku fuzji ta funkcjonalność ma znaczenie.
Jaka jest semantyka automatycznie rozstrzygniętego scalania z tymi opcjami w efekcie - czy są one używane tylko do wykrywania zmian nazwy, czy np. Nie powodujemy konfliktów flag tylko ze zmianami spacji? A jeśli nie, którą wersję akceptujemy automatycznie?

Julio C Hamano nie był zbyt entuzjastyczny:

Z pewnością jest to kuszące, ale podejrzewam, że należy to odłożyć na później.
Podejrzewam, że wprowadziłoby to koncepcję dwóch różnych rodzajów różnic, z których jeden byłby przetwarzany mechanicznie (tj. Używany w połączeniu z „git-merge-recursive”, a stosowany z „git-am”), a drugi do sprawdzenia przez ludzi do zrozumienia.
W tym drugim przypadku często przydatne może być pogrzebanie danych wejściowych, nawet jeśli dane wyjściowe z porównania zmontowanych plików wejściowych mogą nie być łatwe do wykorzystania w zastosowaniach mechanicznych.

Ogólną ideą git mergejest poleganie na narzędziu do scalania innej firmy.

Na przykład skonfigurowałem DiffMerge jako narzędzie do scalania Git, ustawiając zestaw reguł, który pozwala temu narzędziu scalającemu ignorować eol dla określonego typu plików.


Konfiguracja w systemie Windows z MSysGit1.6.3, dla sesji bash DOS lub Git, z DiffMerge lub KDiff3:

  • ustaw katalog w swojej PATH (tutaj:) c:\HOMEWARE\cmd.
  • dodaj do tego katalogu skrypt merge.sh (opakowanie dla twojego ulubionego narzędzia do scalania)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Zadeklaruj opakowanie scalania dla Git

Polecenia konfiguracyjne Git:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Sprawdź, czy autoCRLF ma wartość false

Konfiguracja git na poziomie systemu:

git config ---system core.autoCRLF=false
  • Sprawdź, czy jeśli dwie linie są identyczne (ale ich znaki eol), zarówno DiffMerge, jak i KDiff3 zignorują te linie podczas scalania.

Skrypt DOS (uwaga: polecenie dos2unix pochodzi stąd i jest używane do symulacji uniksowego stylu eol. To polecenie zostało skopiowane do katalogu wymienionego na początku tej odpowiedzi.):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

W tym momencie (naciśnięcie „return”) otworzy się DiffMerge lub KDiff3 i sam zobaczysz, które linie są faktycznie scalane, a które ignorowane.

Ostrzeżenie : plik wynikowy zawsze będzie w trybie eol systemu Windows (CRLF) z DiffMerge ...
KDiff3 oferuje zapisywanie w taki czy inny sposób.


Dziękuję za wskazówkę! Meld i FileMerge na Macu również wydają się być świetnymi aplikacjami.
Léo Léopold Hertz 준영

1
Dla informacji, strategie działają również z wybieraniem wiśni : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (działa to znacznie lepiej niż ignore-all-space)
jakub.g

1
@ jakub.g dobra uwaga! Zawarłem to w odpowiedzi dla większej widoczności.
VonC

98

Szukałem tej samej odpowiedzi i znalazłem to

Scalanie gałęzi z różnymi atrybutami checkin / checkout

Jeśli dodałeś atrybuty do pliku, które powodują zmianę formatu repozytorium kanonicznego dla tego pliku, na przykład dodanie filtra clean / smudge lub atrybuty text / eol / ident, scalanie wszystkiego, gdzie atrybut nie jest na miejscu, normalnie powodowałoby konflikty scalania .

Aby zapobiec tym niepotrzebnym konfliktom scalania, można poinstruować git, aby uruchomił wirtualne wyewidencjonowywanie i zaewidencjonowywanie wszystkich trzech etapów pliku podczas rozwiązywania scalania trójstronnego, ustawiając zmienną konfiguracyjną merge.renormalize. Zapobiega to powodowaniu przez zmiany spowodowane konwersją zaewidencjonowania fałszywych konfliktów scalania, gdy przekonwertowany plik jest scalany z nieprzekonwertowanym plikiem.

Dopóki „smuga → wyczyść” daje taki sam wynik jak „czysty”, nawet w przypadku plików, które są już zamazane, ta strategia automatycznie rozwiąże wszystkie konflikty związane z filtrami. Filtry, które nie działają w ten sposób, mogą powodować dodatkowe konflikty scalania, które należy rozwiązać ręcznie.

Więc uruchomienie tego polecenia w dowolnym repozytorium załatwi sprawę:

git config merge.renormalize true

20
To zasługuje teraz na domyślną odpowiedź. Wiele się zmieniło od czasu pierwszego zadania pytania, obsługa tego przez git jest teraz wbudowana w merge.renormalize, jak mówisz.
Anton I. Sipos

To jest po prostu niesamowite… ratuje mi dzień
Mateusz



4

Pozostawiłem wszystko jako domyślne (np. Autocrlf = true), dotknąłem wszystkich plików (find. -Exec touch {} \;), pozwoliłem gitowi zobaczyć je jako „zmodyfikowane” i zatwierdzić je z powrotem i skończono z tym. W przeciwnym razie zawsze będziesz nękany irytującymi wiadomościami lub zaskakującymi różnicami lub będziesz musiał wyłączyć wszystkie funkcje białych znaków git.

Stracisz informacje o winie, ale lepiej zrobić to wcześniej niż później :)





0

Wydaje mi się teraz, że najlepszym sposobem jest znormalizowanie końcówek linii na obu gałęziach (i zatwierdzenie) przed ich połączeniem.

Wyszukałem w Google „Convert crlf to lf” i znalazłem to jako pierwszy wynik:
http://stahlforce.com/dev/index.php?tool=remcrlf

Ściągnąłem go i użyłem, wygląda na fajne narzędzie.

>sfk remcr . .py

Upewnij się jednak, że podałeś katalog i typ pliku (np. .Py), w przeciwnym razie może spróbować zepsuć zawartość .gitkatalogu!


0

ODPOWIEDŹ, (nie próbowałem tego), możesz użyć git diffdo porównania gałęzi, którą chcesz scalić ze wspólnym przodkiem, a następnie zastosować wyniki git apply. Oba polecenia mają --ignore-whitespaceopcje ignorowania błędów końca linii i białych znaków.

Niestety, jeśli łatka nie nakłada się poprawnie, cała operacja jest przerywana. Nie możesz naprawić konfliktów scalania. Istnieje --rejectopcja pozostawienia niezaktualizowanych porcji w .rejplikach, co pomaga, ale nie jest tym samym, co wyświetlanie konfliktów scalania w jednym pliku.


-1

Po przeczytaniu Rozwiąż konflikty scalania: Wymuś nadpisanie wszystkich plików

W końcu rozwiązałem moją wersję tego problemu. Próbowałem pobrać aktualizacje z zewnętrznego repozytorium, ale moje obecne miało problemy związane z CRLF i nie było w stanie scalić w rezultacie. Należy zauważyć, że NIE MIAŁEM ŻADNYCH LOKALNYCH ZMIAN, o które musiałem się martwić. Poniższe kroki rozwiązały mój problem:

Zgodnie z instrukcjami github dotyczącymi synchronizacji widelców ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Moje ograniczone rozumienie git mówi mi, że robi to, co chcę - ponowne bazowanie mojego forka (bez rzeczywistych niezatwierdzonych zmian), aby uzyskać wszystkie zmiany wprowadzone w zewnętrznym źródle. Według strony źródłowej ten krok nie powinien być zwykle wymagany, ale problem CRLF spowodował, że był wymagany.

  3. git merge upstream/master

  4. git push

1
Zdajesz sobie sprawę, że git reset --hard upstream/masterwyrzuca twój lokalny oddział i wskazuje go upstream/master, nie dając git merge upstream/mastersię oprzeć?
Christoffer Hammarström

-1

jednak sugeruję użycie narzędzia takiego jak sed, aby uzyskać poprawne zakończenia linii, a następnie pliki różnic. Spędziłem kilka godzin na różnych projektach z różnymi zakończeniami linii.

Najlepszym sposobem było:

  1. kopiuj tylko pliki projektu (pomiń .gitkatalog) do innego katalogu utwórz w nim repozytorium, a następnie dodaj pliki i zatwierdzaj je (powinno znajdować się w gałęzi master w nowym repozytorium).
  2. skopiuj pliki z drugiego projektu do tego samego folderu, ale na przykład z innej gałęzi dev( git checkout -b dev), zatwierdź pliki w tej gałęzi i uruchom (jeśli pierwszy projekt jest w głównym): git diff master..dev --names-only aby zobaczyć tylko nazwy zmienionych plików
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.