Czy istnieje opcja git-merge --dry-run?


724

Łączę się w odległej gałęzi, która może mieć wiele konfliktów. Jak mogę stwierdzić, czy będzie to powodować konflikty, czy nie?

Nie widzę niczego podobnego w --dry-runpozycji ON git-merge.


5
Ponieważ rozgałęzianie jest tanie w Git, dlaczego nie sprawdzić kopii, a następnie nie musisz wykonywać suchego rozruchu? Możesz po prostu wyrzucić kopię później.
— Alexander Mills

Odpowiedzi:


811

Jak wspomniano wcześniej, przekaż --no-commitflagę, ale aby uniknąć zatwierdzenia przewijania do przodu, przekaż także --no-ff:

$ git merge --no-commit --no-ff $BRANCH

Aby zbadać zmiany etapowe:

$ git diff --cached

Możesz cofnąć scalanie, nawet jeśli jest to scalanie do przodu:

$ git merge --abort

51
To świetnie, ale nadal modyfikuje kopię roboczą. Jeśli Twoje repozytorium jest serwerem na żywo, możesz udostępniać pliki z konfliktami.
— dave1010

21
Naprawdę nie można wykonać scalenia bez wpływu na kopię roboczą.
— mipadi

55
To prawda, ale coś takiego git merge --only-if-there-wont-be-any-conflictslub git diff --show-conflicts <commit>byłoby naprawdę przydatne. Szkoda, że ​​to jeszcze nie możliwe, czy coś mi umknęło?
— dave1010

344
@ dave1010 Nigdy nie powinieneś zajmować się scalaniem na serwerze internetowym na żywo !!! Do tego właśnie służy twoje pudełko programistyczne! Napraw gałąź „prod”, a następnie prześlij ją na prawdziwy serwer WWW.
— jpswain 12.01.11

52
Jeśli pracujesz na serwerze na żywo / produkcyjnym, nigdy nie chcesz nic robić, tylko git pull --ff-only!
— ThiefMaster

237

Musiałem tylko zaimplementować metodę, która automatycznie wykryje konflikty między repozytorium a jego zdalnym. To rozwiązanie scala pamięć, aby nie dotknąć indeksu ani drzewa roboczego. Myślę, że jest to najbezpieczniejszy możliwy sposób rozwiązania tego problemu. Oto jak to działa:

  1. Pobierz pilota do swojego repozytorium. Na przykład: git fetch origin master
  2. Uruchom git merge-base: git merge-base FETCH_HEAD master
  3. Uruchom git merge-tree: git merge-tree mergebase master FETCH_HEAD( mergebase to szesnastkowy identyfikator, który scalono -bazę wydrukowano w poprzednim kroku)

Załóżmy teraz, że chcesz połączyć zdalny master z lokalnym master, ale możesz użyć dowolnych gałęzi. git merge-treewykona scalenie w pamięci i wydrukuje wynik na standardowe wyjście. Grep dla wzoru <<lub >>. Lub możesz wydrukować dane wyjściowe do pliku i to sprawdzić. Jeśli znajdziesz linię zaczynającą się od „zmieniono w obu”, najprawdopodobniej wystąpi konflikt.


41
Ta odpowiedź jest niedoceniana, IMHO, ponieważ jest to czyste rozwiązanie bez dotykania kopii roboczej lub indeksu.
— sschuberth

23
BTW, kroki 2 i 3 można połączyć w jeden krok, używając operatora backtick konsoli Linux, który ocenia na miejscu jego zawartość:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
— jakub.g

15
Dodaj do [alias] w .gitconfig: dry = "! F () {git merge-tree` git merge-base 2 $ 1 $ 2 $ 1 $;}; f "# sprawdź, jak przebiegnie scalenie dev w master: git dry mistrz dev
— Noel

8
Moja nowa ulubiona linia GIT: po git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"prostu niesamowita! +100
— Rudie

4
Podczas testowania tego stwierdziłem, że grepowanie dla scalonych flag „zmieniono w obu”, w których obie gałęzie modyfikują ten sam plik, nawet jeśli nie powodują konfliktu scalenia. Aby zidentyfikować tylko rzeczywiste konflikty, uznałem za konieczne grep dla znacznika konfliktu, który zaczyna się w ten sposób: +<<<<<<< .ourwięc używam wyrażenia grep, takiego jakgrep -q '^+<* \.our$'
— Guy

55

Moje proste rozwiązanie tego problemu to:

  1. Utwórz gałąź „pre-master” (oczywiście od master)

  2. Połącz wszystkie rzeczy, które chcesz, w ten przed-mistrz.
    Następnie możesz zobaczyć, jak doszło do scalenia bez dotykania wzorca.

    • Scal pre-master w master OR
    • Scal wszystkie niedbale wypuszczone gałęzie w master

W każdym razie postępowałbym zgodnie z radą @ orange80.


5
Lubię rozwiązanie @akostajti, ale jest to kolejna niedoceniana opcja. W rzeczywistości wolę być defensywny i utworzyć nową gałąź tymczasową (oczywiście tylko wtedy, gdy oczekuję konfliktów, w przeciwnym razie będzie to przesada), a jeśli coś pójdzie nie tak, po prostu ją usuń.
— jakub.g

1
nie wiem, czy jest to „brudne” rozwiązanie, czy nie, ale naprawdę działa. Lubię to! (Y)
— sara,

3
To powinno być przyjęte rozwiązanie, imo. Jest szybki, łatwy, bezpieczny, odwracalny, intuicyjny i dopóki nie rozpoczniesz żadnych nieprzewidzianych zmian, nie będzie miał żadnych skutków ubocznych.
— Bob Ray

3
To rozwiązanie informuje, że nie rozumiesz, jak działa git. Rozgałęzienia są tylko wskaźnikami, a Ty tworzysz tylko zbędny wskaźnik. Masz złe przeczucie, że możesz w jakiś sposób zaszkodzić łączeniu się oddziałów, ale nie możesz. Zawsze możesz to zrobićgit merge --abort jeśli występują konflikty, git reset --hard HEAD~1jeśli nastąpiło scalenie lub git reset --hard origin/master. Utworzenie kolejnej gałęzi daje poczucie bezpieczeństwa, ale jeśli nauczysz się, jak działa git, zrozumiesz, że to stracony strach. Jeśli chodzi o to, aby nie zmieniać kopii roboczej, nie ma rozwiązania.
— Thibault D.

@ thibault-d Pomyśl o tym, jak skomplikowane jest rozwiązanie, gdy nie zaczynasz od czystej gałęzi. git merge --no-commitnie przerwie scalania, jeśli można je szybko przesłać dalej. git merge --abortnie działa, jeśli został scalony. Jeśli chcesz napisać to jako skrypt, jest to niewygodne, ponieważ git mergenie odpowiada wystarczająco dobrymi kodami błędów, aby wyjaśnić różne typy konfliktów. Praca z nową gałęzią zapobiega pozostawieniu uszkodzonego skryptu w repozytorium w stanie wymagającym ręcznej interwencji. Pewnie, że nic nie możesz stracić. Ale łatwiej jest zbudować inaczej.
— Erik Aronesty,

47

Cofanie scalenia za pomocą git jest tak łatwe, że nie powinieneś nawet martwić się suchym przebiegiem:

$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world

EDYCJA: Jak zauważono w komentarzach poniżej, jeśli masz zmiany w katalogu roboczym lub obszarze przejściowym, prawdopodobnie zechcesz je ukryć przed wykonaniem powyższej czynności (w przeciwnym razie znikną po wykonaniu git resetpowyższych czynności)


7
Po prostu sprawdzenie, czy scalenie zostanie przewinięte do przodu (FF), polega na sprawdzeniu listy, git branch --contains HEADa nawet bardziej bezpośrednio, wystarczy użyćgit merge --ff-only
— Brian Phillips

7
git reset --hard jest jedną z niewielu komend usuwania informacji bez wycofywania, które ma git, dlatego należy go używać z najwyższą ostrożnością. Jako taki -1
— Kzqai

8
@Tchalvak nadal jest rejestrowany.
— Kissaki,

3
--dry-runnie „po prostu sprawdzałby, czy scalenie będzie przewijać do przodu”. Zwróciłoby to dokładnie dane wyjściowe scalenia: pliki, konflikty itp. Czy ff nie jest tak naprawdę interesujące, prawda?
— Rudie,

3
jak o git stash; git reset --hard? @BrianPhillips
— Code Whisperer

41

Stworzyłem alias, aby to zrobić i działa jak urok, robię to:

 git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '

Teraz dzwonię

git mergetest <branchname>

Aby dowiedzieć się, czy są jakieś konflikty.


Znakomity! Trzymam to.
— qbert65536

28

Po prostu różnicuj swoją obecną gałąź z gałęzią zdalną, to powie ci, co się zmieni, kiedy wykonasz ściąganie / scalanie.

#see diff between current master and remote branch
git diff master origin/master

1
Ciekawy pomysł. Jak spojrzę na ten wynik i ustalę, czy scalenie zadziała, czy nie?
— MatrixFrog,

6
Nie powie ci to, czy wystąpią jakiekolwiek konflikty ... ale da ci ogólne wyobrażenie o tym, co się stanie, jeśli wykonasz pull / merge.
— timh

10
To powie ci tylko różnicę między dwiema gałęziami, nie powie ci, jaki będzie wynik połączenia. Jest to ważne rozróżnienie, ponieważ łączenie w niektórych przypadkach automatycznie przyjmuje zmiany z różnych gałęzi, w zależności od tego, kiedy zostały zatwierdzone. Zasadniczo więc zrobienie różnicy może sprawić, że pomyślisz, że niektóre z twoich zmian zostaną cofnięte, gdy w rzeczywistości proces scalania automatycznie przyjmie nowsze zmiany niż starsze. Mam nadzieję, że to ma sens.
— markquezada

3
Aby oprzeć się na komentarzu @ mirthlab, będzie istniała znacząca różnica między różnicowaniem i scalaniem, jeśli ktoś wcześniej przeprowadził scalanie ze strategią scalania „naszą” (lub innymi ręcznymi poprawkami scalania); diff pokaże również różnice, które są już liczone jako „scalone”.
— Tao

21

Używam do tego polecenia git request-pull . Pozwala zobaczyć każdą zmianę, która miałaby miejsce podczas łączenia, ale bez robienia czegokolwiek na lokalnych lub zdalnych repozytoriach .

Na przykład wyobraź sobie, że chcesz scalić gałąź o nazwie „feature-x” z gałęzią master

git request-pull master origin feature-x

pokaże podsumowanie tego, co by się stało (bez robienia czegokolwiek):

The following changes since commit fc01dde318:
    Layout updates (2015-06-25 11:00:47 +0200)
are available in the git repository at:
    http://fakeurl.com/myrepo.git/ feature-x
for you to fetch changes up to 841d3b41ad:
----------------------------------------------------------------
john (2):
    Adding some layout
    Refactoring
ioserver.js            |   8 +++---
package.json           |   7 +++++-
server.js              |   4 +--
layout/ldkdsd.js       | 277 +++++++++++++++++++++++++++++++++++++
4 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 layout/ldkdsd.js

Jeśli dodasz -pparametr, otrzymasz również pełny tekst poprawki, dokładnie tak, jakbyś robił różnicę git dla każdego zmienionego pliku.


3
Możesz to uczynić nieco jaśniejszym, dodając co masteri originrobię w opcjach wiersza poleceń, a co jeśli na przykład jestem na komputerze lokalnym branch1i chcę zrobić request-pullna lokalnej gałęzi funkcji branch2? Czy nadal potrzebuję origin? Oczywiście zawsze można przeczytać dokumentację.
— Ela782

Niestety to polecenie działa tylko wtedy, gdy Rev # 2 jest nazwą gałęzi, nie działa dla skrótów: /
— Jared Grubb

20

Dziwię się, że nikt jeszcze nie sugerował używania łatek.

Że chcesz przetestować scalania od your_branchdo master(Ja zakładając masz masterwyrejestrowany):

$ git diff master your_branch > your_branch.patch
$ git apply --check your_branch.patch
$ rm your_branch.patch

To powinno wystarczyć.

Jeśli wystąpią błędy, takie jak

error: patch failed: test.txt:1
error: test.txt: patch does not apply

oznacza to, że łatka nie powiodła się, a scalenie spowodowałoby konflikty. Brak danych wyjściowych oznacza, że ​​łatka jest czysta i można łatwo połączyć gałąź


Zauważ, że tak naprawdę nie zmieni to twojego działającego drzewa (oprócz tworzenia pliku łatki oczywiście, ale później możesz go bezpiecznie usunąć). Z dokumentacji git-Apply:

--check
    Instead of applying the patch, see if the patch is applicable to the
    current working tree and/or the index file and detects errors. Turns
    off "apply".

Uwaga dla każdego, kto jest mądrzejszy / bardziej doświadczony w git ode mnie: daj mi znać, jeśli się mylę, a ta metoda wykazuje inne zachowanie niż zwykłe scalanie. Dziwne wydaje się, że w ciągu ponad 8 lat istnienia tego pytania nikt nie sugerowałby tego pozornie oczywistego rozwiązania.


Ta metoda jest przyjętą odpowiedzią na to pytanie, aw komentarzach są pewne zastrzeżenia, takie jak: „git nie był w stanie użyć„ rekurencyjnej ”strategii scalania” i „plik łatek podaje błąd dla nowych plików”. W przeciwnym razie wydaje się świetnie.
— neno

1
Krótsza droga bez tworzenia pliku tymczasowego patch: git diff master your_branch | git apply --check.
— ks1322

9

To może być interesujące: Z dokumentacji:

Jeśli próbowałeś scalenia, które zakończyły się złożonymi konfliktami i chcesz zacząć od nowa, możesz odzyskać za pomocą git merge --abort .

Ale możesz to zrobić naiwnie (ale powoli):

rm -Rf /tmp/repository
cp -r repository /tmp/
cd /tmp/repository
git merge ...
...if successful, do the real merge. :)

(Uwaga: nie będzie działało po prostu klonowanie do / tmp, potrzebujesz kopii, aby mieć pewność, że niezatwierdzone zmiany nie spowodują konfliktu).


2
Jeśli potrzebujesz tylko młotka ... :) +1
— kaiser

Czysty egzemplarz można uzyskać cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(na wszelki wypadek), git status(aby sprawdzić, że jest czysty).
— ADTC

8

Wiem, że to stare pytanie, ale pierwsze pojawia się w wyszukiwarce Google.

Podczas łączenia Git wprowadził opcję --ff-only.

Od: http://git-scm.com/docs/git-merge


--ff-only

Odmów scalenia i wyjdź ze stanu niezerowego, chyba że bieżący HEAD jest już aktualny lub scalenie można rozwiązać jako przewijanie do przodu.

Wykonanie tego spowoduje połączenie i szybkie przewijanie do przodu, a jeśli nie będzie możliwe, przerywa działanie i wyświetla monit o niemożność wykonania szybkiego przewijania do przodu, ale pozostawia działającą gałąź bez zmian. Jeśli może szybko przewinąć do przodu, wówczas wykona scalenie w działającym oddziale. Ta opcja jest również dostępna w dniu git pull. W ten sposób możesz wykonać następujące czynności:

git pull --ff-only origin branchA #See if you can pull down and merge branchA

git merge --ff-only branchA branchB #See if you can merge branchA into branchB

1
To zrobi scalenie, jeśli można to zrobić za pomocą szybkiego przewijania do przodu, czego nie chciałem w pierwotnym pytaniu. Myślę, że zaakceptowana odpowiedź ma drugą połowę, która ją naprawia.
— Otto

Naprawdę jednak fantazyjne podpowiedzi gitów eliminują potrzebę, jaką mam do tego rodzaju rzeczy.
— Otto

2
To nie jest tak samo. Wyjście ze statusem niezerowym, ponieważ scalenie nie może zostać rozwiązane, ponieważ przewijanie do przodu nie oznacza, że ​​występują konflikty . Oznacza to po prostu, że historia się rozdzieliła i konieczne jest zatwierdzenie przez scalenie.
— ADTC

7

Używam git log, aby zobaczyć, co zmieniło się w gałęzi funkcji od gałęzi master

git log does_this_branch..contain_this_branch_changes

np. - aby zobaczyć, jakie zatwierdzenia znajdują się w gałęzi funkcji, która została / nie została scalona z master:

git log master..feature_branch

3

Jeśli chcesz przewinąć do przodu z B do A, musisz upewnić się, że git log B..A niczego nie pokazuje, tzn. A nie ma niczego, czego B nie ma. Ale nawet jeśli B..A ma coś, nadal możesz być w stanie łączyć się bez konfliktów, więc powyższe pokazuje dwie rzeczy: że nastąpi szybkie przewijanie do przodu, a zatem nie dostaniesz konfliktu.


2

Moim rozwiązaniem jest scalenie wstecz.

Zamiast scalać gałąź w zdalną gałąź „docelową”, scal ją z własną.

git checkout my-branch
git merge origin/target-branch

Zobaczysz, czy są jakieś konflikty i możesz zaplanować, jak je rozwiązać.

Następnie możesz albo przerwać scalanie za pomocą git merge --abort, albo (jeśli nie było żadnych konfliktów i scalenie się zdarzyło) wycofać do poprzedniego zatwierdzenia przezgit reset --hard HEAD~1


-2

Utwórz tymczasową kopię swojej kopii roboczej, a następnie połącz ją i rozróżnij obie.

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.