Jak mogę wyświetlić podgląd scalenia w git?

397

Mam gałąź git (na przykład główną linię) i chcę połączyć się z inną gałęzią programistyczną. A może ja?

Aby zdecydować, czy naprawdę chcę scalić tę gałąź, chciałbym zobaczyć podgląd tego, co zrobi scalenie. Najlepiej z możliwością zobaczenia listy stosowanych zmian.

Jak dotąd najlepiej wymyślić merge --no-ff --no-commit, a potem diff HEAD.

Glenjamin
źródło
17
Po prostu git mergei git reset --keep HEAD@{1}jeśli nie podoba mi się wynik.
Jan Hudec
3
Zauważ, że zobaczenie listy zatwierdzeń z ich różnicą niekoniecznie opowiada całą historię - jeśli scalenie nie jest trywialne, a zwłaszcza jeśli występują konflikty, faktyczny wynik scalenia może być nieco interesujący.
Cascabel
2
Twoja oryginalna metoda robi dokładnie to. Chodzi mi o to, że chociaż patrzenie na poszczególne różnice jest dobre i dobre, jeśli masz złożone scalenie, możesz skończyć z zaskakującymi wynikami, nawet jeśli wszystkie połączone zatwierdzenia są niezależnie dobre.
Cascabel
2
@Jan: Z jakichś powodów, git reset --keep HEAD@{1}zwróconej fatal: Cannot do a keep reset in the middle of a merge.pomocy?
moey
3
Dlaczego nie ma --previewopcji git-merge?
Gaui

Odpowiedzi:

283

Przekonałem się, że najlepszym rozwiązaniem dla mnie jest po prostu scalenie i przerwanie go, jeśli wystąpią konflikty . Ta szczególna składnia jest dla mnie czysta i prosta. To jest strategia 2 poniżej.

Jeśli jednak chcesz mieć pewność, że nie zepsujesz swojej bieżącej gałęzi lub po prostu nie jesteś gotowy do scalenia niezależnie od istnienia konfliktów, po prostu stwórz z niej nową pod-gałąź i scal:

Strategia 1: Bezpieczny sposób - połącz oddział tymczasowy:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

W ten sposób możesz po prostu wyrzucić gałąź tymczasową, jeśli chcesz zobaczyć, jakie są konflikty. Nie musisz zawracać sobie głowy „przerywaniem” scalania i możesz wrócić do swojej pracy - po prostu ponownie zaznacz „mybranch” i nie będziesz mieć żadnego scalonego kodu ani scalania konfliktów w swoim oddziale.

Jest to zasadniczo sucha próba.

Strategia 2: Kiedy zdecydowanie chcesz się połączyć, ale tylko wtedy, gdy nie ma konfliktów

git checkout mybranch
git merge some-other-branch

Jeśli git zgłasza konflikty (i TYLKO JEŚLI SĄ konflikty), możesz wtedy:

git merge --abort

Jeśli scalenie się powiedzie, nie możesz go przerwać (tylko zresetuj).

Jeśli nie jesteś gotowy do scalenia, użyj bezpieczniejszego sposobu powyżej.

[EDYCJA: 2016-lis - Zamieniłem strategię 1 na 2, ponieważ wydaje się, że większość ludzi szuka „bezpiecznej drogi”. Strategia 2 jest teraz bardziej notatką, że możesz po prostu przerwać scalanie, jeśli scalenie ma konflikty, z którymi nie jesteś gotowy poradzić sobie. Pamiętaj, jeśli czytasz komentarze!]

Kasapo
źródło
2
+1 za strategię 2. Tymczasowa gałąź, która dokładnie pokazuje, co wejdzie podczas łączenia. Strategia 1 jest tym, czego staram się unikać w tym konkretnym przypadku.
Gordolio
2
Sugeruję zmianę strategii, aby bezpieczniejsza była pierwsza (mój trening psychiczny przechodzi - większość ludzi uznałaby, że najlepszą opcją byłaby pierwsza, pomimo wyraźnego użycia słowa „bezpieczniejszy”), ale poza tym doskonała praca.
paxdiablo
6
Możesz to zrobić, git merge --no-ff --no-commitjeśli nie chcesz bezpośrednio zatwierdzać zmian. Eliminuje to „potrzebę” innej gałęzi i ułatwia przeglądanie zmian, imo.
Gerard van Helden
a jeśli zdecydujesz, że w ogóle nie chcesz się łączyć, a raczej wolisz napisać więcej kodu, a następnie zatwierdzić swój oddział, abyś mógł wdrożyć TYLKO swój oddział na serwerze testowym, czy nadal nie musiałbyś przywracać git merge --no-ff --no-commit? Myślę, że nadal możesz to zrobić git merge --abort, jeśli nie podoba ci się to, co widzisz? Nawet jeśli scalenie nie powoduje konfliktów?
Kasapo,
Większość ludzi lubi kopiować i wklejać i nie myśli za dużo. Dlatego w przypadku Strategii 1 dodaj może także sposób przerwania scalania w tymczasowym oddziale lokalnym, git reset --hard HEADa następnie wypisania innego oddziału git checkout <different branch name>i usunięcia tymczasowego oddziału git delete -b <name of temporary branch>.
user3613932
400
  • git log ..otherbranch
    • lista zmian, które zostaną scalone w bieżący oddział.
  • git diff ...otherbranch
    • różnią się od wspólnego przodka (baza scalania) do kierownika tego, co zostanie scalone. Zwróć uwagę na trzy kropki , które mają specjalne znaczenie w porównaniu do dwóch kropek (patrz poniżej).
  • gitk ...otherbranch
    • graficzna reprezentacja gałęzi od czasu ich ostatniego połączenia.

Pusty ciąg oznacza HEAD, więc właśnie dlatego ..otherbranchzamiast HEAD..otherbranch.

Dwie vs. trzy kropki mają nieco inne znaczenie dla diff niż dla poleceń wyświetlających wersje (log, gitk itp.). Dla log i innych dwie kropki ( a..b) oznaczają wszystko, co jest w środku, bale nie atrzy, a trzy kropki ( a...b) oznaczają wszystko, co jest tylko w jednym alub b. Ale diff działa z dwiema wersjami i tam prostszy przypadek reprezentowany przez dwie kropki ( a..b) jest prostą różnicą od ado, ba trzy kropki ( a...b) oznaczają różnicę między wspólnym przodkiem i b( git diff $(git merge-base a b)..b).

Jan Hudec
źródło
7
Trzecia kropka to część, której mi brakowało, dzięki! Podejście oparte na logach również działa dobrze, log -p - odwrotny .. inna gałąź wydaje się dobrym sposobem na sprawdzenie, co zostanie scalone.
Glenjamin
1
Zaginęłam, git checkout masterzanim spróbowałam tego. Zastanawiałem się, dlaczego to mówi, że wszystkie moje zmiany zostaną
nadpisane
5
git show ..otherbranchpokaże listę zmian i różnic, które zostaną połączone w bieżącym oddziale.
Gaui
4
Nie jest to do końca dokładne, szczególnie w przypadku czereśni.
void.pointer
2
@ void.pointer, git nie traktuje kilofów specjalnie podczas normalnego scalania, więc tutaj też nie. Można by napisać strategię scalania, która by była, ale o ile wiem, nigdy nie była.
Jan Hudec
19

Jeśli jesteś podobny do mnie, szukasz odpowiednika svn update -n. Wygląda na to, że można to zrobić. Pamiętaj, aby zrobić git fetchpierwszy, aby lokalne repozytorium zawierało odpowiednie aktualizacje do porównania.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

lub jeśli chcesz różnicę między głową a pilotem:

$ git fetch origin
$ git diff origin/master

IMO to rozwiązanie jest znacznie łatwiejsze i mniej podatne na błędy (a przez to znacznie mniej ryzykowne) niż najlepsze rozwiązanie, które proponuje „scalenie, a następnie przerwanie”.

djschny
źródło
1
powinno być $ git checkout target-branchi wtedy $ git diff --name-status ...branch-to-be-merged(trzy kropki są niezbędne, więc wpisz je bez
zmian
Jednej rzeczy brakuje: nie pokazuje, które pliki miałyby konflikt - mają ten sam znacznik „M”, co pliki zmodyfikowane w gałęzi, ale można je łączyć bez żadnych konfliktów.
peterflynn
Być może w 2012 r. Było inaczej, ale w dzisiejszych czasach przerwanie łączenia wydaje się dość wiarygodne, więc nie sądzę, aby można było teraz określić to jako „znacznie łatwiejsze i mniej podatne na błędy”.
David Z
8

Większość odpowiedzi tutaj albo wymaga czystego katalogu roboczego i wielu interaktywnych kroków (źle dla skryptów), albo nie działa we wszystkich przypadkach, np. Przeszłe scalenia, które już wprowadzają niektóre z zaległych zmian w gałęzi docelowej, lub wybieranie wiśni podobnie.

Aby naprawdę zobaczyć, co zmieni się w masteroddziale, jeśli połączysz developsię z nim, teraz:

git merge-tree $(git merge-base master develop) master develop

Ponieważ jest to polecenie hydrauliczne, nie zgaduje, co masz na myśli, musisz być jawny. Nie koloryzuje on również danych wyjściowych ani nie korzysta z pagera, więc pełne polecenie to:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(dzięki Davidowi Normingtonowi za link)

PS:

Jeśli wystąpią konflikty scalania, pojawią się one ze zwykłymi znacznikami konfliktu w danych wyjściowych, np .:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

Użytkownik @dreftymac ma dobrą rację: sprawia, że ​​nie nadaje się do skryptów, ponieważ nie można tego łatwo odczytać z kodu stanu. Znaczniki konfliktu mogą być bardzo różne w zależności od okoliczności (usunięte vs zmodyfikowane itp.), Co również utrudnia grepowanie. Strzec się.

Hraban
źródło
1
@hraban Wygląda to na poprawną odpowiedź, jednak najwyraźniej nadal brakuje jednego elementu. Takie podejście wymaga od użytkownika „gałki ocznej” wyjścia, aby sprawdzić, czy występują znaczniki konfliktu. Czy masz podejście, które po prostu powraca, truejeśli występują konflikty i falsejeśli nie ma konfliktów (np. Wartość logiczna, która nie wymaga testu „gałki ocznej” ani jakiejkolwiek interwencji człowieka)?
dreftymac
1
@dreftymac nie może znaleźć czegoś takiego. możesz użyć czegoś takiego, git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergeale jest drobny; Prawdopodobnie zapominam o sprawie. może zamiast tego chcesz sprawdzić znaczniki konfliktu? np. to prawdopodobnie nie łapie konfliktów stylów „ich usunięte, nasze zmienione”. (Właśnie sprawdziłem, a to nawet nie pokazuje znaczników konfliktu, więc potrzebujesz skrupulatnego wyrażenia regularnego, aby być tutaj bezpiecznym)
hraban
1
Służy less -Rdo obsługi kolorowych wydruków bez zmiany konfiguracji.
Giacomo Alzetta
Dzięki @GiacomoAlzetta, zaktualizowałem to.
hraban
6

Jeśli zmiany zostały już pobrane, moim ulubionym jest:

git log ...@{u}

To chyba wymaga git 1.7.x. @{u}Notacja jest „skrótem” do górnej gałęzi, więc jest to trochę bardziej wszechstronny niż git log ...origin/master.

Uwaga: jeśli używasz zsh i rozszerzonego glogu, prawdopodobnie będziesz musiał zrobić coś takiego:

git log ...@\{u\}
Pablo Olmos de Aguilera C.
źródło
6

Dodając do istniejących odpowiedzi, można utworzyć alias pokazujący różnicę i / lub log przed scaleniem. Wiele odpowiedzi pomija czynności fetchdo wykonania przed „podglądem” scalenia; jest to alias, który łączy te dwa kroki w jeden (emulując coś podobnego do mercurial's hg incoming/ outgoing)

Opierając się na „ git log ..otherbranch”, możesz dodać następujące elementy do ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

W przypadku symetrii można użyć następującego aliasu, aby pokazać, co zostało zatwierdzone i zostanie wypchnięte przed wypchnięciem:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

Następnie możesz uruchomić „ git incoming”, aby wyświetlić wiele zmian, lub „ git incoming -p”, aby wyświetlić poprawkę (tj. „Diff”), „ git incoming --pretty=oneline”, aby uzyskać krótkie podsumowanie itp. Następnie możesz (opcjonalnie) uruchomić „ git pull”, aby faktycznie się łączą. (Chociaż, ponieważ już pobrałeś, scalanie można wykonać bezpośrednio.)

Podobnie „ git outgoing” pokazuje, co byś popchnął, gdybyś miał uruchomić „ git push”.

Michał
źródło
3

git log currentbranch..otherbranchda ci listę zatwierdzeń, które przejdą do bieżącego oddziału, jeśli wykonasz scalenie. Zwykłe argumenty do zalogowania, które zawierają szczegółowe informacje na temat zatwierdzeń, dostarczą więcej informacji.

git diff currentbranch otherbranchda ci różnicę między dwoma zatwierdzeniami, które staną się jednym. To będzie różnica, która da ci wszystko, co zostanie scalone.

Czy te pomogłyby?

Noufal Ibrahim
źródło
2
Właściwie źle. git log otherbranch..currentbranchpodaje listę zatwierdzeń w currentbranch . git diff otherbranch currentbranchDaje diff z wersji do-połączyły bieżącym cynk, który jest tak bezużyteczne, jak to może być, bo to, co chcesz, jest diff od podstawy seryjnej do głowy seryjnej.
Jan Hudec
Dzięki. Zmieniłem nazwy drzewiastych.
Noufal Ibrahim
3

Polecenie ściągnięcia - korzystałem z większości już przesłanych pomysłów, ale często z niego korzystam (zwłaszcza jeśli pochodzi od innego dewelopera), wykonując polecenie ściągnięcia, które daje wygodny sposób na przejrzenie wszystkich zmian w scaleniu przed jego pobraniem miejsce. Wiem, że GitHub nie jest gitem, ale z pewnością jest przydatny.

G-Man
źródło
2

Poza faktycznym wykonaniem scalenia w sposób wyrzucany (patrz odpowiedź Kasapo), wydaje się, że nie ma wiarygodnego sposobu, aby to zobaczyć.

Powiedziawszy to, oto metoda, która jest marginalnie bliska:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Daje to uczciwe wskazanie, które zatwierdzenia doprowadzą do scalenia. Aby zobaczyć różnice, dodaj -p. Aby zobaczyć nazwy plików, dodać jeden z --raw, --stat, --name-only, --name-status.

Problem z tym git diff TARGET_BRANCH...SOURCE_BRANCHpodejściem (patrz odpowiedź Jana Hudeca) polega na tym, że różnice w zmianach już znajdują się w gałęzi docelowej, jeśli gałąź źródłowa zawiera scalenia krzyżowe.

antak
źródło
1

Może to może ci pomóc? git-diff-tree - porównuje zawartość i tryb obiektów blob znalezionych przez dwa obiekty drzewa

Chugaister
źródło
1

Nie chcę używać polecenia git merge jako prekursora do przeglądania plików w konflikcie. Nie chcę wykonywać scalania, chcę zidentyfikować potencjalne problemy przed scaleniem - problemy, które automatyczne scalanie mogą przede mną ukryć. Rozwiązaniem, którego szukałem, jest to, jak git wypluł listę plików, które zostały zmienione w obu gałęziach, które zostaną scalone w przyszłości, w odniesieniu do jakiegoś wspólnego przodka. Po uzyskaniu tej listy mogę użyć innych narzędzi do porównywania plików, aby dalej badać sprawy. Szukałem wiele razy i nadal nie znalazłem tego, czego chcę w natywnym poleceniu git.

Oto moje obejście na wypadek, gdyby to pomogło komukolwiek innemu:

W tym scenariuszu mam oddział o nazwie QA, który ma wiele zmian w stosunku do ostatniej wersji produkcyjnej. Nasze ostatnie wydanie produkcyjne jest oznaczone tagiem „15.20.1”. Mam inną gałąź programistyczną o nazwie new_stuff, którą chcę scalić z gałęzią kontroli jakości. Zarówno QA, jak i new_stuff wskazują na zatwierdzenia, które „podążają” (jak donosi gitk) znacznik 15.20.1.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Oto kilka dyskusji na temat tego, dlaczego jestem zainteresowany kierowaniem na te konkretne pliki:

Jak mogę zaufać scaleniu Git?

/software/199780/how-far-do-you-trust-automerge

Laura
źródło