Esiste un'opzione gd-merge --dry-run?


725

Mi sto unendo in un ramo remoto che potrebbe avere molti conflitti. Come posso sapere se ci saranno conflitti o no?

Non vedo niente di simile a un --dry-runon git-merge.


5
Poiché la ramificazione è economica con Git, perché non fare il checkout di una copia e quindi non è necessario eseguire una corsa a secco? Puoi semplicemente buttare fuori la copia in seguito.
Alexander Mills,

Risposte:


812

Come notato in precedenza, passa la --no-commitbandiera, ma per evitare un commit ad avanzamento rapido, passa anche in questo --no-ffmodo:

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

Per esaminare le modifiche organizzate:

$ git diff --cached

E puoi annullare l'unione, anche se si tratta di un'unione con avanzamento rapido:

$ git merge --abort

51
Questo è fantastico, ma modificherà comunque la tua copia di lavoro. Se il tuo repository è un server web live, potresti servire file con conflitti.
dave1010

21
Non puoi davvero fare una fusione senza influire sulla copia di lavoro.
mipadi,

55
Vero, ma qualcosa di simile git merge --only-if-there-wont-be-any-conflictso git diff --show-conflicts <commit>sarebbe davvero utile. Peccato che non sia ancora possibile o mi sto perdendo qualcosa?
dave1010,

344
@ dave1010 Non dovresti mai gestire le fusioni su un server web live !!! Ecco a cosa serve la tua scatola di sviluppo! Correggi il ramo "prod" e poi spingilo sul server web reale.
jpswain,

52
Se lavori su un server live / di produzione non vuoi fare altro che git pull --ff-only!
ThiefMaster

237

Ho dovuto solo implementare un metodo che trova automaticamente conflitti tra un repository e il suo telecomando. Questa soluzione esegue l'unione in memoria in modo che non tocchi l'indice né l'albero di lavoro. Penso che questo sia il modo più sicuro possibile per risolvere questo problema. Ecco come funziona:

  1. Porta il telecomando nel tuo repository. Per esempio: git fetch origin master
  2. Esegui git merge-base: git merge-base FETCH_HEAD master
  3. Esegui git merge-tree: git merge-tree mergebase master FETCH_HEAD( mergebase è l'id esadecimale che merge-base stampato nel passaggio precedente)

Supponiamo ora che tu voglia unire il master remoto con il tuo master locale, ma puoi usare tutti i rami. git merge-treeeseguirà l'unione in memoria e stamperà il risultato sull'output standard. Grep per il modello <<o >>. Oppure puoi stampare l'output su un file e verificarlo. Se trovi una riga che inizia con "cambiato in entrambi", molto probabilmente ci sarà un conflitto.


41
Questa risposta è decisamente sottovalutata, IMHO, in quanto è una soluzione pulita senza toccare la copia o l'indice di lavoro.
sschuberth,

23
A proposito, i passaggi 2 e 3 possono essere uniti in un unico passaggio, utilizzando l'operatore backtick della console Linux, che valuta sul posto i suoi contenuti:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
jakub.g

15
Aggiungi a [alias] in .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "#controlla come andrà la fusione di dev in master: git dry dev master
Noel,

8
La mia nuova linea GIT preferita: git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"semplicemente fantastica! +100
Rudie,

4
Nel testare questo ho trovato grepping per l'unione di flag "cambiati in entrambi" in cui entrambi i rami modificano lo stesso file, anche se non provocano un conflitto di unione. Per identificare solo i conflitti effettivi ho trovato la necessità di grep per il markup del conflitto che inizia in questo +<<<<<<< .ourmodo:, quindi uso un'espressione grep comegrep -q '^+<* \.our$'
Guy

55

La mia semplice soluzione a forza bruta a questo è:

  1. Crea un ramo "pre-master" (dal master ovviamente)

  2. Unisci tutte le cose che vuoi in questo pre-master.
    Quindi puoi vedere come è avvenuta la fusione senza toccare il master.

    • Unisci pre-master in master OR
    • Unisci tutti i rami rilasciati dagli aspiranti nel maestro

Ad ogni modo, seguirei i consigli di @ orange80.


5
Mi piace la soluzione @akostajti, ma questa è ancora un'altra opzione sottovalutata. In effetti preferisco essere difensivo e creare un nuovo ramo temporaneo (ovviamente solo quando mi aspetto conflitti, altrimenti sarà eccessivo), e se qualcosa va storto, semplicemente cancellalo.
jakub.g

1
non so se questa è una soluzione "sporca" o no, ma fa davvero il lavoro. Mi piace! (Y)
sara,

3
Questa dovrebbe essere la soluzione accettata, imo. È veloce, facile, sicuro, reversibile, intuitivo e fino a quando non ci sono modifiche non impegnate prima di iniziare, non avrà effetti collaterali.
Bob Ray,

3
Questa soluzione ti dice di non capire come funziona git. Branch sono solo puntatori e stai solo creando un puntatore ridondante. Hai la brutta sensazione di poter in qualche modo ferire la fusione del tuo ramo ma non puoi. Puoi sempre fare git merge --abortse ci sono conflitti, git reset --hard HEAD~1se c'è stata un'unione o git reset --hard origin/master. La creazione di un altro ramo ti dà una sensazione di sicurezza ma se impari come funziona git capirai che è una paura fuori posto. Quando la preoccupazione è di non modificare la copia di lavoro, ciò non offre alcuna soluzione.
Thibault D.

@ thibault-d Pensa a quanto è complessa la soluzione quando non inizi con un ramo pulito. git merge --no-commitnon interromperà un'unione se può essere inoltrato rapidamente. git merge --abortnon funziona se è stato unito. Se vuoi scrivere questo come uno script, è imbarazzante, dal momento git mergeche non risponde con abbastanza buoni codici di errore per spiegare i diversi tipi di conflitti. Lavorare con un nuovo ramo impedisce a uno script interrotto di lasciare il repository in uno stato che richiede un intervento manuale. Sicuro che non puoi perdere nulla. Ma è più facile costruire diversamente.
Erik Aronesty,

47

Annullare un'unione con git è così facile che non dovresti nemmeno preoccuparti della corsa a secco:

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

MODIFICA: Come notato nei commenti qui sotto, se hai cambiamenti nella directory di lavoro o nell'area di gestione temporanea, probabilmente vorrai riporli prima di fare quanto sopra (altrimenti scompariranno seguendo quanto git resetsopra)


7
Controllare semplicemente se un'unione sarà un avanzamento rapido (FF) è una questione di controllare l'elenco git branch --contains HEADo anche più direttamente, basta usaregit merge --ff-only
Brian Phillips il

7
git reset --hard è uno dei pochi comandi di eliminazione delle informazioni senza backout che git ha, quindi dovrebbe essere usato con estrema cautela. Pertanto, -1
Kzqai,

8
@Tchalvak c'è ancora reflog.
Kissaki,

3
--dry-runnon "controllerebbe semplicemente se un'unione avanza rapidamente". Restituirebbe l'output esatto di un'unione: file, conflitti ecc. Se la volontà non è davvero interessante, vero?
Rudie,

3
che ne dici git stash; git reset --hard? @BrianPhillips
Whisperer di codice

41

Ho creato un alias per farlo e funziona come un incantesimo, lo faccio:

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

Adesso chiamo e basta

git mergetest <branchname>

Per scoprire se ci sono conflitti.


Brillante! Lo sto mantenendo.
qbert65536

28

Differisci il tuo ramo corrente contro il ramo remoto, questo ti dirà cosa cambierà quando fai un pull / merge.

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

1
Idea interessante. Come potrei guardare quell'output e determinare se la fusione funzionerà o no?
MatrixFrog,

6
Questo non ti dirà se si verificheranno dei conflitti ... ma ti darà un'idea generale di cosa accadrà se hai fatto un pull / merge.
tim

10
Questo ti dirà solo la differenza tra i due rami, non ti dirà quale sarà il risultato della fusione. Questa è una distinzione importante poiché in alcuni casi la fusione prenderà automaticamente le modifiche da diverse filiali a seconda di quando sono state commesse. Quindi, in sostanza, fare un diff potrebbe farti pensare che alcune delle tue modifiche verranno ripristinate quando, in realtà, il processo di fusione prenderà automaticamente le modifiche più recenti rispetto a quelle più vecchie. Spero che abbia un senso.
markquezada,

3
Per basarsi sul commento di @ mirthlab, ci sarà una differenza significativa tra diff e merge se qualcuno ha precedentemente eseguito una fusione con la strategia di unione "nostra" (o qualche altro fixup di unione manuale); il diff mostrerà anche le differenze che sono già conteggiate come "unite".
Tao

21

Per farlo uso il comando request-pull git. Ti consente di vedere ogni cambiamento che potrebbe accadere durante l'unione, ma senza fare nulla sui tuoi repository locali o remoti .

Ad esempio, immagina di voler unire un ramo chiamato "feature-x" nel tuo ramo principale

git request-pull master origin feature-x

ti mostrerà un riepilogo di ciò che accadrebbe (senza fare nulla):

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

Se aggiungi il -pparametro, otterrai anche il testo completo della patch, esattamente come se stessi facendo un git diff su ogni file modificato.


3
Potresti renderlo un po 'più chiaro aggiungendo cosa mastere cosa originfare nelle opzioni della riga di comando, e se mi trovassi ad esempio in un locale branch1e volessi fare un request-pullramo di una caratteristica locale branch2? Ho ancora bisogno origin? Certo, si può sempre leggere la documentazione.
Ela782,

Purtroppo questo comando funziona solo se Rev # 2 è un nome di ramo, non funziona per gli hash: /
Jared Grubb

20

Sono sorpreso che nessuno abbia ancora suggerito di usare le patch.

Supponiamo che desideri testare un'unione da your_branchin master(suppongo che tu abbia masterverificato):

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

Questo dovrebbe fare il trucco.

Se ricevi errori come

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

ciò significa che la patch non ha avuto successo e un'unione produrrebbe conflitti. Nessun output indica che la patch è pulita e si sarebbe in grado di unire facilmente il ramo


Nota che questo non cambierà effettivamente l'albero di lavoro (oltre a creare ovviamente il file patch, ma puoi tranquillamente eliminarlo in seguito). Dalla documentazione di 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".

Nota a chiunque sia più intelligente / più esperto di git di me: per favore fatemi sapere se ho torto qui e questo metodo mostra un comportamento diverso rispetto a una fusione normale. Sembra strano che negli ultimi 8 anni che questa domanda non esistesse nessuno suggerirebbe questa soluzione apparentemente ovvia.


Questo metodo è la risposta accettata per questa domanda e ci sono alcuni avvertimenti nei commenti come "git non è stato in grado di usare la strategia di unione" ricorsiva "" e "il file patch fornisce errori per i nuovi file". Altrimenti, sembra grandioso.
neno,

1
Un modo più breve senza creare un file di patch temporanea: git diff master your_branch | git apply --check.
ks1322,

9

Questo potrebbe essere interessante: dalla documentazione:

Se hai provato un'unione che ha provocato conflitti complessi e vuoi ricominciare da capo, puoi recuperare con git merge --abort .

Ma potresti anche farlo nel modo ingenuo (ma lento):

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

(Nota: non funzionerà solo clonando su / tmp, avresti bisogno di una copia, per essere sicuro che le modifiche non confermate non entrino in conflitto).


2
Se tutto ciò di cui hai bisogno è un martello ... :) +1
kaiser

Pulire copia può essere ottenuto con cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(per buona misura), git status(per controllare che è pulito).
ADTC,

8

Sono consapevole che questa è una vecchia domanda, ma è la prima a comparire su una ricerca su Google.

Git ha introdotto un'opzione --ff-only durante l'unione.

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


--ff-only

Rifiuta di unire ed uscire con uno stato diverso da zero a meno che l'attuale HEAD non sia già aggiornato o l'unione non possa essere risolta come avanzamento rapido.

In questo modo si tenterà di unire e avanzare rapidamente, e in caso contrario si interrompe e viene richiesto che non è possibile eseguire l'avanzamento rapido, ma che non viene toccato il ramo operativo. Se è in grado di avanzare rapidamente, eseguirà l'unione sul ramo di lavoro. Questa opzione è disponibile anche su git pull. Pertanto, è possibile effettuare le seguenti operazioni:

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
Questo farà la fusione se si può fare con l'avanzamento veloce che non è quello che volevo nella domanda originale. Penso che la risposta accettata abbia l'altra metà che la risolve.
Otto,

In realtà, però, le fantasiose richieste di git evitano il bisogno che ho di questo genere di cose.
Otto,

2
Non è proprio lo stesso. Uscire con stato diverso da zero perché l'unione non può essere risolta poiché l'avanzamento rapido non significa che ci siano conflitti . Significa solo che la storia è divergente ed è necessario un commit di unione.
ADTC,

7

Uso git log per vedere cosa è cambiato in un ramo di funzionalità dal ramo principale

git log does_this_branch..contain_this_branch_changes

ad es. - per vedere quali sono i commit in un ramo di funzionalità che è stato / non è stato unito al master:

git log master..feature_branch

3

Se vuoi avanzare rapidamente da B ad A, allora assicurati che git log B..A non ti mostri nulla, cioè che A non abbia nulla che B non abbia. Ma anche se B..A ha qualcosa, potresti comunque essere in grado di unire senza conflitti, quindi quanto sopra mostra due cose: che ci sarà un avanzamento veloce e quindi non otterrai un conflitto.


2

La mia soluzione è unire all'indietro.

Invece di unire il tuo ramo nel ramo "target" remoto, unisci quel ramo nel tuo.

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

Vedrai se ci sono conflitti e puoi pianificare come risolverli.

Dopodiché puoi annullare l'unione tramite git merge --aborto (se non ci sono stati conflitti e se si è verificata l'unione) tornare indietro al commit precedente tramitegit reset --hard HEAD~1


-2

Crea una copia temporanea della tua copia di lavoro, quindi unisci in quella e diff le due.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.