Esiste un & # 8220; loro & # 8221; versione di & # 8220; git merge -s ours & # 8221 ;?

StackOverflow https://stackoverflow.com/questions/173919

  •  05-07-2019
  •  | 
  •  

Domanda

Quando si uniscono la sezione tematica "B" in " A " usando git merge , ottengo alcuni conflitti. So che tutti i conflitti possono essere risolti utilizzando la versione in " B " ;.

Sono a conoscenza di git merge -s our . Ma quello che voglio è qualcosa come git merge -s their .

Perché non esiste? Come posso ottenere lo stesso risultato dopo l'unione in conflitto con i comandi git esistenti? ( git checkout ogni file non unito da B)

AGGIORNAMENTO: la "soluzione" di scartare qualsiasi cosa dal ramo A (il punto di commit unione alla versione B dell'albero) non è quello che sto cercando.

È stato utile?

Soluzione

Aggiungi l'opzione -X su loro . Ad esempio:

git checkout branchA
git merge -X theirs branchB

Tutto si fonderà nel modo desiderato.

L'unica cosa che ho visto causa problemi è se i file sono stati eliminati da branchB. Si presentano come conflitti se qualcosa di diverso da git ha fatto la rimozione.

La correzione è semplice. Basta eseguire git rm con il nome di tutti i file che sono stati eliminati:

git rm {DELETED-FILE-NAME}

Dopodiché, il -X loro dovrebbe funzionare come previsto.

Ovviamente, eseguire la rimozione effettiva con il comando git rm impedirà in primo luogo che il conflitto si verifichi.


Nota : esiste anche un'opzione di modulo più lungo. Per usarlo, sostituisci:

-X theirs

con:

--strategy-option=theirs

Altri suggerimenti

Una soluzione possibile e testata per unire branchB nella nostra filiale check-out A:

# in case branchA is not our current branch
git checkout branchA

# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB    

# make temporary branch to merged commit
git branch branchTEMP         

# get contents of working tree and index to the one of branchB
git reset --hard branchB

# reset to our merged commit but 
# keep contents of working tree and index
git reset --soft branchTEMP

# change the contents of the merged commit
# with the contents of branchB
git commit --amend

# get rid off our temporary branch
git branch -D branchTEMP

# verify that the merge commit contains only contents of branchB
git diff HEAD branchB

Per automatizzarlo puoi avvolgerlo in uno script usando branchA e branchB come argomenti.

Questa soluzione conserva il primo e il secondo genitore del commit di merge, proprio come ci si aspetterebbe da git merge -s their branch B .

Le versioni precedenti di git ti consentivano di utilizzare il "loro" strategia di unione:

git pull --strategy=theirs remote_branch

Ma da allora è stato rimosso, come spiegato in questo messaggio da Junio ??Hamano (il manutentore Git). Come indicato nel link, invece dovresti farlo:

git fetch origin
git reset --hard origin

Attenzione, tuttavia, che questo è diverso da una fusione effettiva. La tua soluzione è probabilmente l'opzione che stai davvero cercando.

Ho usato la risposta di Paul Pladijs da ora. Ho scoperto che puoi fare un "normale" si fondono, si verificano conflitti, quindi si

git checkout --theirs <file>

per risolvere il conflitto usando la revisione dell'altro ramo. Se lo fai per ogni file, hai lo stesso comportamento che ti aspetteresti da

git merge <branch> -s theirs

Comunque, lo sforzo è più di quanto sarebbe con la strategia di unione! (Questo è stato testato con git versione 1.8.0)

Non è del tutto chiaro quale sia il risultato desiderato, quindi c'è un po 'di confusione riguardo al "corretto". modo di farlo nelle risposte e nei loro commenti. Cerco di dare una panoramica e di vedere le tre opzioni seguenti:

Prova a unire e usa B per conflitti

Questa è non la loro versione " per git merge -s our " ma la "loro versione per git merge -X our " (che è l'abbreviazione di git merge -s recursive -X our ):

git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB

Questo è ciò che ad es. La risposta di Alan W. Smith sì.

Usa contenuti solo da B

Questo crea un commit di unione per entrambi i rami ma scarta tutte le modifiche da branchA e mantiene solo i contenuti da branchB .

# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB

# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA

# Set branchA to current commit and check it out.
git checkout -B branchA

Nota che l'unione commette il primo genitore ora è quello da branchB e solo il secondo proviene da branchA . Questo è ciò che ad es. La risposta di Gandalf458 sì.

Usa i contenuti solo da B e mantieni l'ordine genitore corretto

Questa è la vera versione di "quot" per git merge -s our " ;. Ha lo stesso contenuto dell'opzione precedente (ovvero solo quella da branchB ) ma l'ordine dei genitori è corretto, ovvero il primo genitore proviene da branchA e il secondo da branchB .

git checkout branchA

# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB

# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB

# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA

# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA

# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD

Questo è ciò che la risposta di Paul Pladijs (senza richiedere una filiale temporanea).

Ho risolto il mio problema usando

git checkout -m old
git checkout -b new B
git merge -s ours old

Se sei nel ramo A fai:

git merge -s recursive -X theirs B

Testato su git versione 1.7.8

  

Quando si uniscono la sezione tematica "B" in "A" usando git merge, ho dei conflitti. So che tutti i conflitti possono essere risolti utilizzando la versione in " B " ;.

     

Sono a conoscenza di git merge -s our. Ma quello che voglio è qualcosa come git merge > -s loro.

Suppongo che tu abbia creato un ramo fuori dal master e ora desideri ricollegarti al master, sovrascrivendo tutte le vecchie cose nel master. Questo è esattamente quello che volevo fare quando mi sono imbattuto in questo post.

Fai esattamente quello che vuoi fare, tranne unire prima un ramo nell'altro. Ho appena fatto questo e ha funzionato alla grande.

git checkout Branch
git merge master -s ours

Quindi, controlla il master e unisci il tuo ramo (andrà liscio ora):

git checkout master
git merge Branch

Per fare davvero un'unione che prende solo input dal ramo che stai unendo puoi fare

git merge --strategy = il nostro ref-to-be-merged

git diff - Rif. binario da unire | git apply --reverse --index

git commit --amend

Non ci saranno conflitti in nessuno scenario che conosco, non è necessario creare ulteriori rami e si comporta come un normale commit di unione.

Tuttavia, questo non funziona bene con i sottomoduli.

Vedi La risposta ampiamente citata di Junio ??Hamano : se hai intenzione di scartare l'impegno contenuto, scartare semplicemente gli commit o comunque tenerlo fuori dalla cronologia principale. Perché disturbare tutti in futuro a leggere i messaggi di commit di commit che non hanno nulla da offrire?

Ma a volte ci sono requisiti amministrativi, o forse qualche altro motivo. Per quelle situazioni in cui devi davvero registrare commit che non contribuiscono a nulla, vuoi:

(modifica: wow, sono riuscito a sbagliare prima. Questo funziona.)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard
  

Perché non esiste?

Mentre menziono in " comando git per creare un ramo come un altro " come simulare git merge -s their , nota che Git 2.15 (Q4 2017) è ora più chiaro:

  

La documentazione per ' -X < option > ' per le fusioni era fuorviante   scritto per suggerire che " -s loro " esiste, il che non è il caso.

Vedi commit c25d98b (25 set 2017) di Junio ??C Hamano ( gitster ) .
(Uniti da Junio ??C Hamano - gitster - in commit 4da3e23 , 28 set 2017)

  

strategie di unione: evita di sottintendere che " -s loro " esiste

     

La descrizione dell'opzione di unione -Xours ha una nota tra parentesi   che dice ai lettori che è molto diverso da -s our ,   che è corretto, ma la descrizione di -Xtheirs che lo segue   dice distrattamente " questo è l'opposto di our " dando un falso   impressione che anche i lettori debbano essere avvertiti che è molto   diverso dal -s loro , che in realtà non esiste nemmeno.

-Xtheirs è una opzione di strategia applicata alla strategia ricorsiva. Ciò significa che la strategia ricorsiva unirà ancora tutto ciò che può e tornerà solo a " loro " logica in caso di conflitto.

Quel dibattito per la pertinenza o meno di una strategia di unione theirs è stato riportato di recente in questa discussione del settembre 2017 .
Riconosce thread precedenti (2008)

  

In breve, la discussione precedente può essere riassunta in " non vogliamo ' -s their ' poiché incoraggia il flusso di lavoro sbagliato " ;.

Menziona l'alias:

mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -

Yaroslav Halchenko cerca ancora una volta di sostenere questa strategia, ma Junio ??C. Hamano aggiunge :

  

La ragione per cui la nostra e la loro non sono simmetriche è perché tu e non loro --- il controllo e la proprietà della nostra storia e della loro storia non sono simmetrici.

     

Dopo aver deciso che la loro storia è la linea principale, preferiresti considerare la tua linea di sviluppo come un ramo laterale e fare una fusione in quella direzione, cioè il primo genitore della fusione risultante è un impegno sulla loro storia e il secondo genitore è l'ultimo cattivo della tua storia. Quindi finirai per usare " checkout loro-storia & amp; & amp; unisci la nostra tua storia " a   mantenere sensibile la prima genitorialità.

     

E a quel punto, usa " -s our " non è più una soluzione alternativa per mancanza di " -s loro " ;.
   È una parte propria della semantica desiderata, cioè dal punto di vista della linea di storia canonica sopravvissuta, vuoi preservare ciò che ha fatto, annullando ciò che ha fatto l'altra linea di storia .

Questo usa un comando git plumbing read-tree, ma riduce il flusso di lavoro complessivo.

git checkout <base-branch>

git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit

# Check your work!
git diff <their-branch>

Questo unirà il tuo newBranch in baseBranch esistente

git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch

Penso che ciò che vuoi veramente sia:

git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch

Sembra goffo, ma dovrebbe funzionare. L'unica cosa che non mi piace di questa soluzione è che la cronologia git sarà confusa ... Ma almeno la cronologia sarà completamente preservata e non dovrai fare qualcosa di speciale per i file eliminati.

L'equivalente (che mantiene l'ordine principale) di 'git merge -s their branchB'

Prima dell'unione:  inserisci qui la descrizione dell'immagine

!!! Assicurati di essere in uno stato pulito !!!

Effettua l'unione:

git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command

Cosa abbiamo fatto?  Abbiamo creato un nuovo commit che due nostri genitori e loro e la contnet del commit è branchB - loro

Dopo l'unione:  inserisci qui la descrizione dell'immagine

Più precisamente:

git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'

Questa risposta è stata data da Paul Pladijs. Ho appena preso i suoi comandi e ho creato un alias git per comodità.

Modifica il tuo .gitconfig e aggiungi quanto segue:

[alias]
    mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"

Quindi puoi " git unire -s loro A " eseguendo:

git checkout B (optional, just making sure we're on branch B)
git mergetheirs A

Di recente ho dovuto farlo per due repository separati che condividono una cronologia comune. Ho iniziato con:

  • Org / repository1 master
  • Org / repository2 master

Volevo che tutte le modifiche da repository2 master fossero applicate a repository1 master , accettando tutte le modifiche che repository2 avrebbe apportato. In termini di git, questo dovrebbe essere una strategia chiamata -s their MA non esiste. Fai attenzione perché -X theirs è chiamato come sarebbe quello che vuoi, ma è NON lo stesso (lo dice anche nella pagina man).

Il modo in cui ho risolto questo è stato andare su repository2 e creare un nuovo ramo repo1-merge . In quel ramo, ho eseguito git pull git@gitlab.com: Org / repository1 -s our e si fonde perfettamente senza problemi. Lo spingo poi sul telecomando.

Quindi torno a repository1 e creo un nuovo ramo repo2-merge . In quel ramo, eseguo git pull git@gitlab.com: Org / repository2 repo1-merge che completerà con problemi.

Infine, dovresti o emettere una richiesta di unione in repository1 per renderlo il nuovo master o semplicemente tenerlo come ramo.

Un modo semplice e intuitivo (secondo me) in due passaggi per farlo è

git checkout branchB .
git commit -m "Picked up the content from branchB"

seguito da

git merge -s ours branchB

(che contrassegna i due rami come uniti)

L'unico svantaggio è che non rimuove i file che sono stati eliminati in branchB dal tuo ramo attuale. Una semplice differenza tra i due rami in seguito mostrerà se ci sono tali file.

Questo approccio chiarisce anche successivamente dal registro delle revisioni ciò che è stato fatto e ciò che era previsto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top