Scegli la strategia di unione di Git per file specifici ("nostro", "mio", "loro")


207

Sono nel mezzo del rebasing dopo a git pull --rebase. Ho alcuni file che presentano conflitti di unione. Come posso accettare le "loro" modifiche o le "mie" modifiche per file specifici?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Normalmente apro semplicemente il file o uno strumento di unione e accetto manualmente tutte le "loro" o "mie" modifiche. Tuttavia, sospetto che mi manchi un comodo comando git.

Inoltre, nota che sarò in grado di scegliere una strategia di unione per ogni file quando vedrò quali file colpiscono i conflitti e forse quali sono i conflitti.


@AbeVoelker Non penso che risolva il mio problema. Voglio selezionare una strategia di unione per file specifici. Inoltre, noterai che saprò quale unione stragegy usare quando sono nel mio rebase e vedrò quali file hanno conflitti di conflitto e quali sono i conflitti.
Steven Wexler,

Ho modificato questa domanda per essere più generico: stackoverflow.com/questions/278081/… . Forse possiamo chiudere questa domanda come duplicato di quello? È appropriato?

@TheShadow Questo mi sembra ragionevole.
Steven Wexler,

Non ero sicuro che fosse appropriato cambiare il titolo dell'altra domanda in quello che ho fatto, perché ho eliminato la parte sulla risoluzione dei file binari. Ho ripristinato l'altra domanda su cosa fosse in precedenza, quindi questa domanda attuale aggiunge ancora valore.

Risposte:


251

Per ogni file in conflitto che ottieni, puoi specificare

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

Dai git checkoutdocumenti

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Quando si estraggono i percorsi dall'indice, controllare la fase # 2 ( ours) o # 3 ( theirs) per i percorsi non uniti.

L'indice può contenere voci non unite a causa di una precedente unione non riuscita. Per impostazione predefinita, se si tenta di estrarre tale voce dall'indice, l'operazione di verifica fallirà e non verrà eseguito il checkout. L'uso -fignora queste voci non unite. I contenuti di un lato specifico dell'unione possono essere estratti dall'indice utilizzando --ourso --theirs. Con -m, le modifiche apportate al file dell'albero di lavoro possono essere eliminate per ricreare il risultato dell'unione in conflitto originale.


9
È possibile accettare il loro per tutti i file che sono rimasti in ombra?
aslakjo,

41
@aslakjo git rebase -s recursive -X <ours/theirs>o git merge -s recursive -X <ours/theirs>. Tieni presente che per un rebase, "nostro" e "loro" sono invertiti da quello che sono durante una fusione. Probabilmente potresti semplicemente usare anche un file / shell glob, come git checkout --theirs -- *.txt.

2
Mille grazie, @Cupcake, l'inaspettata inversione di ours/theirscon rebase mi stava facendo impazzire !! (Ha senso ora che penso a come funziona effettivamente un rebase, ma per nulla intuitivo.)
Dan Lenski,

2
@DanLenski rebase in generale è solo uno strumento davvero complicato che le persone possono capire all'inizio, ma una volta capito come funziona, puoi fare tutti i tipi di cose davvero potenti con esso.

1
@VincentSels in realtà, è necessario mascherare il carattere *, altrimenti la shell tenterà di espanderlo. quindi nel tuo caso git checkout --outs -- "**/*.csproj"farà quello che vuoi dire. Lo stesso vale per es git lfs track "*.jpg". Se hai alcuni file jpg nel tuo CWD, senza le virgolette, verrebbero monitorati solo questi.
eFloh,

117

Anche se a questa domanda viene data una risposta, fornendo un esempio di cosa significano "loro" e "nostro" nel caso di git rebase vs merge. Vedi questo link

Git Rebase
theirs è in realtà il ramo corrente nel caso di rebase . Pertanto, il set di comandi di seguito accetta effettivamente le modifiche del ramo corrente sul ramo remoto.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Git Merge
Per merge , il significato di theirse oursè invertito. Quindi, per ottenere lo stesso effetto durante un'unione , ad esempio, mantenere le modifiche al ramo corrente ( ours) sul ramo remoto che viene unito ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b

2
bene, questa è una distinzione abbastanza importante! grazie per il chiarimento.
verboze

26

Si noti che git checkout --ours|--theirssi sovrascrivere i file del tutto , scegliendo uno theirso oursversione, che potrebbe essere o potrebbe non essere ciò che si vuole fare (se si dispone di tutte le modifiche non in conflitto provenienti dall'altro lato, saranno perse).

Se invece si desidera eseguire un'unione a tre vie sul file e risolvere solo gli hunk in conflitto utilizzando --ours|--theirs, mantenendo in posizione gli hunk non in conflitto da entrambi i lati, è possibile ricorrere a git merge-file; vedi i dettagli in questa risposta .


1
Per quanto riguarda le "modifiche non in conflitto" che andranno perse - ciò si riferisce solo ai file in cui vi sono modifiche non in conflitto in linee specifiche, altrimenti nello stesso file o tutte le modifiche da tutti i file in cronologie allineate?
ktamlyn,

2
@ktamlyn per "modifiche non in conflitto" intendevo cambiamenti nello stesso file. Per esempio, ci sono due tipi la modificati (parti) example.txtin oursversione, si è in conflitto (cambio anche nella theirsrevisione), altro è non in conflitto. Se lo fai git checkout --theirs example.txt, leggerà alla cieca l'intero file al momento della theirsrevisione e la parte non in conflitto del diff andrà persa.
jakub.g

1
Grazie! Questo è stato un chiarimento necessario per me, anche se "i cambiamenti nello stesso file" hanno più senso in questo contesto.
ktamlyn,

Questa dovrebbe essere la risposta accettata, beh, sebbene in realtà non dia una risposta, ma evidenzia un problema importante nell'altra soluzione proposta.
tomasyany

1
Se si desidera tornare al file originale in conflitto, è possibile eseguire git checkout --merge <path>.
Andrew Keeton,
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.