Git - jak wymusić konflikt scalania i ręczne scalanie na wybranym pliku

83

Utrzymujemy aplikację internetową, która ma wspólną gałąź główną i wiele gałęzi równoległych, po jednej dla każdej instalacji, każda ma kilka specyficznych zmian. Kod źródłowy jest zarządzany w git i jest świetnym narzędziem, gdy potrzebujemy przenoszenia funkcji i poprawek błędów z gałęzi głównej do równoległej. Ale jest kilka plików, które są wrażliwe, a automatyczne scalanie zwykle daje złe wyniki. Tak więc scalanie byłoby znacznie łatwiejsze, gdyby można je było w jakiś sposób oznaczyć, a każde scalenie powodowałoby konflikt wymagający ręcznego scalenia.

Szukałem odpowiedzi:

  1. Używam opcji scalania --no-commit i --no-ff , ale to nie to samo.
  2. Tu i tu ktoś zadaje to samo pytanie, ale bez rozwiązania.
  3. Wydaje się, że podobny przypadek dotyczy tego, jak zapobiec scalaniu pliku za pomocą .gitattributes zawierającego: somefile.php merge = ours . Próbowałem znaleźć opcję scalania, która generowałaby konflikt lub wymuszała ręczne scalanie, ale jak dotąd nie znalazłem.
  4. .gitattributes zawierające: somefile.php -merge nigdy nie jest scalane automatycznie i dlatego wymusza ręczne scalanie. Jest to rozwiązanie w 90%, ale szukam sposobu na automatyczne scalenie i oznaczenie go jako konfliktu, niezależnie od tego, czy się powiedzie, czy nie. Ale to jest jak dotąd najbliższe rozwiązania. (... dzięki Charlesowi Baileyowi za wyjaśnienie ...)
  5. Ktoś sugeruje napisanie niestandardowego sterownika scalania ( 1 , 2 ), ale jak to zrobić, nie jest dla mnie jasne.

edycja: wariant 4. opis

Stepan
źródło
6
Nie byłaby to dokładna odpowiedź, której szukasz, ale z tego samego powodu, dla którego git fetchnajpierw robię , a następnie używam git difftool <file> FETCH_HEAD, więc mogę ręcznie zastosować zmianę w oddziale zdalnym do lokalnego.
MHC
MHC: to fajna sztuczka (szczególnie jeśli jest zapisana w skrypcie dla każdej równoległej gałęzi + w połączeniu z zapobieganiem automatycznemu scalaniu plików). Główną wadą jest to, że w przepływie pracy zespołowej ktoś zapomina o tym kroku i zamiast tego dokonuje zwykłego scalenia.
Stepan
2
Ustawienie -mergenie uniemożliwia scalenia plików, po prostu zmusza do zrobienia tego ręcznie, np. Za pomocą narzędzia do łączenia. Czy nie tego potrzebujesz?
CB Bailey,
To 90% tego, czego chcę. Chciałbym, aby scalanie odbywało się automatycznie, ale w przypadku tego wrażliwego pliku scalanie jest uważane za konflikt, nawet jeśli nie ma żadnego, więc ręczne sprawdzenie jest wymuszane za każdym razem.
Stepan
@Stepan Jestem w podobnej sytuacji, więc chcę coś wyjaśnić. Co mówisz, że w programie -mergein .gitatttributes git mergenic nie działa, a cała praca musi zostać przerwana dzięki narzędziu do scalania? Nie ma więc <<<<< ===== >>>> narzędzia do scalania, prawda? A rozwiązanie Dana to zapewnia?
Nero gris

Odpowiedzi:

60

Opcja 5, niestandardowy sterownik scalania, jest prawdopodobnie sposobem na zbliżenie się do tego, co chcesz. Jest to zaskakująco łatwe. Poniżej znajduje się przykład takiego, który moim zdaniem powinien zbliżyć Cię do pożądanego zachowania.

Najpierw utwórz skrypt sterownika scalającego o nazwie merge-and-verify-driver. Spraw, aby był wykonywalny i umieść go w odpowiedniej lokalizacji (możesz rozważyć sprawdzenie tego skryptu w repozytorium, nawet jeśli plik konfiguracyjny repozytorium będzie od niego zależał). Git wykona ten skrypt powłoki, aby połączyć wrażliwe pliki:

#!/bin/bash
git merge-file "${1}" "${2}" "${3}"
exit 1

To po prostu robi domyślne zachowanie scalania, które normalnie robi sam Git. Kluczowa różnica polega na tym, że skrypt zawsze zwraca wartość różną od zera (aby wskazać, że wystąpił konflikt, nawet jeśli scalanie zostało faktycznie rozwiązane bez konfliktów).

Następnie musisz powiedzieć Gitowi o istnieniu Twojego niestandardowego sterownika scalającego. Robisz to w pliku konfiguracyjnym repozytorium ( .git/config):

[merge "verify"]
        name = merge and verify driver
        driver = ./merge-and-verify-driver %A %O %B

W tym przykładzie umieściłem merge-and-verify-driverw katalogu najwyższego poziomu repozytorium ( ./). Będziesz musiał odpowiednio określić ścieżkę do skryptu.

Teraz wystarczy nadać poufnym plikom odpowiednie atrybuty, aby podczas łączenia tych plików był używany niestandardowy sterownik scalania. Dodaj to do swojego .gitattributespliku:

*.sensitive merge=verify

Tutaj powiedziałem Gitowi, że każdy plik o nazwie pasującej do wzorca *.sensitivepowinien używać niestandardowego sterownika scalania. Oczywiście musisz użyć wzorca odpowiedniego dla twojego pliku (plików).

Dan Moulding
źródło
Wielkie dzięki za ten szczegółowy przewodnik!
Stepan
13
Wydaje się, że sterownik scalający nie jest wywoływany w rozwiązaniach „oczywistych”. Na przykład, jeśli plik został zmieniony tylko w jednej gałęzi i wykonujesz scalanie, "wrażliwy" plik zostanie nadpisany, a sterownik scalający nie zostanie wywołany. Czy jest sposób, aby to naprawić?
VitalyB,
Czy to naprawdę działałoby tak, jak sugeruje @VitalyB? dzięki!
filippo
1
To działa, ale czy istnieje sposób, aby uczynić tę opcję globalną we wszystkich repozytoriach na komputerze? Poza tym, jakikolwiek sposób wywołać go z wiersza poleceń? Żałuję, że nie ma sposobu na zrobienie tego w czymś tak prostym, jak zmiana strategii łączenia w wierszu poleceń.
user1748155
4
dodanie do komentarza @VitalyB. Scalanie również nie pojawia się, jeśli obie gałęzie dokonały takiej samej zmiany w pliku. Na przykład obie gałęzie zwiększyły wersję o 1, a chciałbyś zwiększyć o 2 podczas próby scalenia ... Bardzo praktyczny problem, jeszcze nierozwiązany. :(
VasiliNovikov
1

Wydaje się, że te dwa polecenia mają taki sam efekt, jak użycie niestandardowego sterownika scalania:

git merge --no-commit your_target_branch
git checkout --conflict merge .   (do not forget the . and run it in the top dir of the repository)

Pierwsze polecenie zatrzymuje scalanie przed utworzeniem zatwierdzenia scalającego, a drugie oznacza wszystkie pliki zmodyfikowane w dwóch gałęziach jako konflikt do rozwiązania, nawet jeśli pierwotnie nie było konfliktu.

louisiuol
źródło
Podoba mi się pomysł „jednorazowego” rozwiązania (właśnie wpadłem na taki przypadek), ale to nie zadziałało. Git wykonał FF, co spowodowało złe scalenie (było to zasadniczo i nasze scalenie).
Nero gris,
@Nerogris Rzeczywiście, nie będzie działać przy szybkich połączeniach do przodu. Zawsze możesz dodać opcję --no-ff, ale drugie polecenie nie spowoduje konfliktu, ponieważ w jednej z dwóch gałęzi scalania nie ma zmian od wspólnego przodka.
louisiuol
Mam ff ustawione na false w mojej konfiguracji globalnej. Kiedy powiedziałem, że jest to scalanie FF, mam na myśli, że gdybym nie powiedział Gitowi, aby tego nie robił, tak by się stało.
Nero gris
0

Uwaga: ten artykuł „ Pisanie sterownika git merge dla plików PO ” ilustruje rodzaj manipulacji, które można wykonać podczas ręcznego scalania pliku: można go wstępnie przetworzyć, aby ręczne scalanie było gotowe.

git merge-filemożna na przykład wykorzystać do ODSZYFROWANIA (i ponownego zaszyfrowania) plików przed scaleniem (!)

W twoim przypadku wychodzenie ze sterownika scalającego ze statusem innym niż 0 zapewnia, że ​​scalenie będzie ręczne.

VonC
źródło
2
Czy mógłbyś rozwinąć więcej informacji na temat linku „scal sterownik dla plików PO”, ponieważ wydaje się, że powoduje to odmowę dostępu dla mnie? Mam nadzieję, że dostarczy odpowiedź na pytanie stackoverflow.com/questions/16214067/…
Mikko Rantalainen
@MikkoRantalainen zablokowany w pracy, więc spróbuję tego wieczoru z domu.
VonC
1
„Sterownik scalający dla plików PO” też nie działa dla mnie :(
1
@sampablokuper Zgadzam się: artykuł jest zablokowany dla czytelników „nieautoryzowanych”. Nie wiedziałbym dlaczego.
VonC,
1
@sampablokuper Nie mam teraz dostępu do tego bloga. Będę szukał jego zawartości.
VonC,