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.

Otto
źródło
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
mipadi
źródło
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.

akostajti
źródło
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.

Hades
źródło
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)

Brian Phillips
źródło
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.

Okonomiyaki3000
źródło
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
timh
źródło
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.

ArnaudR
źródło
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.

Christoph Böhmwalder
źródło
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).


źródło
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
Jason McKindly
źródło
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
nelsonenzo
źródło
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.

Erik Kaplun
źródło
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

Ubeogesh
źródło
-2

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

vanboom
źródło