Risoluzione di un conflitto Git con file binari


464

Sto usando Git su Windows (msysgit) per tenere traccia delle modifiche per alcuni lavori di progettazione che ho fatto.

Oggi ho lavorato su un PC diverso (con repository remoto brian) e ora sto cercando di unire le modifiche apportate oggi nella mia versione locale normale sul mio laptop.

Sul mio laptop, ho usato git pull brian masterper inserire le modifiche nella mia versione locale. Tutto andava bene a parte il documento principale di InDesign - questo dimostra come un conflitto.

La versione sul PC ( brian) è l'ultima che voglio conservare, ma non so quali comandi indichino al repository di utilizzarla.

Ho provato a copiare direttamente il file sul mio laptop ma questo sembra interrompere l'intero processo di unione.

Qualcuno può indicarmi la giusta direzione?

Risposte:


854

git checkoutaccetta un'opzione --ourso --theirsper casi come questo. Quindi se hai un conflitto di unione e sai che vuoi solo il file dal ramo in cui ti stai unendo, puoi fare:

$ git checkout --theirs -- path/to/conflicted-file.txt

per usare quella versione del file. Allo stesso modo, se sai di volere la tua versione (non quella da unire) puoi usare

$ git checkout --ours -- path/to/conflicted-file.txt

47
Ho dovuto eseguire 'git reset HEAD path / to / conflted-file.txt' sul file prima di usare --ours, altrimenti sembrava non avere alcun effetto.
Zitrax,

6
@Zitrax Hai diff il file dopo l'esecuzione git checkout --ours? La pagina man suggerisce (IMHO) che il checkout --ours / - loro rimuoverà la modifica dalla lista "entrambe modificate, necessitano di unire" e la aggiungerà all'indice, e penso che non sia corretto. Credo che dovrai correre git adddopo il checkout.
Tim Keating,

15
Nota: si desidera comunque eseguire "git add conflitti-file.txt " e "commit git". Praticamente, quando l'ho provato, il messaggio di commit è stato precompilato con una nota sul conflitto.
Edward Falk,

2
il fraseggio di "il ramo in cui ti stai unendo" è pericolosamente vicino a "il ramo in cui ti stai unendo", penso che abbandonare la preposizione sarebbe meglio: "il ramo in cui ti stai unendo", che rifletterebbe anche il comando git (cioè git merge branch_name).
Andrybak,

13
Un paio di punti importanti che mancano sempre nelle spiegazioni di questo argomento. Quando si esegue rebase invece di unire, il significato di --theire --oursvengono scambiati, ovvero --their == ramo attualmente estratto e --ours è il ramo, di solito un ramo remoto o specifica del percorso che si sta tentando di unire nella corrente ramo. L' [space]--[space]opzione non chiarisce le specifiche del percorso tra nome del ramo e specifica del percorso che si verificano entrambe con lo stesso nome (ad esempio, un nome di ramo esistente è "abc" e una directory esiste chiamata "abc").
BoiseBaked

147

Devi risolvere il conflitto manualmente (copiando il file sopra) e quindi eseguire il commit del file (non importa se lo hai copiato o utilizzato la versione locale) in questo modo

git commit -a -m "Fix merge conflict in test.foo"

Git normalmente si autocommette dopo l'unione, ma quando rileva conflitti non può risolversi da solo, applica tutte le patch che ha capito e lascia il resto per risolvere e eseguire il commit manualmente. La pagina Man di Git Merge , il Git-SVN Crash Course o questo post di blog potrebbero far luce su come dovrebbe funzionare.

Modifica: vedi il post in basso, in realtà non devi copiare i file da solo, ma puoi usare

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

per selezionare la versione del file desiderato. La copia / modifica del file sarà necessaria solo se si desidera un mix di entrambe le versioni.

Si prega di contrassegnare la risposta mipadis come quella corretta.


1
Grazie per quello Non ero sicuro che esistesse una sorta di metodo integrato per contrassegnare un file come "corretto". Spiega perché non sono riuscito a trovare il comando inesistente!
Kevin Wilson,

Sì, è un po 'poco intuitivo - qualcosa come la risoluzione di git sarebbe bello, ma sarebbe anche un passo in più ...
VolkA

120

Puoi anche superare questo problema con

git mergetool

che provoca la gitcreazione di copie locali del file binario in conflitto e genera su di esso l'editor predefinito:

  • {conflicted}.HEAD
  • {conflicted}
  • {conflicted}.REMOTE

Ovviamente non è possibile modificare in modo utile i file binari in un editor di testo. Invece si copia il nuovo {conflicted}.REMOTEfile {conflicted}senza chiudere l'editor. Quindi quando chiuderai l'editor gitvedrà che la copia di lavoro non decorata è stata modificata e il conflitto di unione è risolto nel solito modo.


8
Se i file sono di grandi dimensioni o non vuoi rischiare di aprire il binario in un editor di testo, puoi premere ctrl + c al prompt di fusione (" Hit return to start merge resolution tool") e git lascerà in posizione i file extra. Quindi è possibile modificarli o unirli in uno strumento esterno (utile per formati di documenti binari come LibreOffice / OpenOffice / MSWord) e salvare il risultato nel nome file originale. Per informare git che il conflitto è stato risolto, git addil nome file originale e quindi è possibile completare il commit unione.
Felix,

18

Per risolvere mantenendo la versione nel tuo ramo corrente (ignora la versione dal ramo in cui ti stai unendo), aggiungi e esegui il commit del file:

git commit -a

Per risolvere sovrascrivendo la versione nel tuo ramo corrente con la versione del ramo in cui ti stai unendo, devi prima recuperare quella versione nella tua directory di lavoro, quindi aggiungerla / eseguirla:

git checkout otherbranch theconflictedfile
git commit -a

Spiegato in modo più dettagliato


1
Preferisco questa variante rispetto alla risposta accettata, perché è più intuitiva, soprattutto considerando che il significato di quei "--ours" e "--theirs" viene scambiato in caso di rebasing.
Antony Hatchkins,

11

La risposta di mipadi non ha funzionato abbastanza per me, dovevo farlo:

git checkout: il percorso / a / file.bin

oppure, per mantenere l'unione della versione in:

git checkout - il loro percorso / a / file.bin

poi

git aggiungi percorso / a / file.bin

E poi sono stato in grado di fare di nuovo "git mergetool" e continuare con il prossimo conflitto.


6

Dai git checkoutdocumenti

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

--ours
--theirs
Quando si verificano i percorsi dall'indice, vedere 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 pagamento non riuscirà 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.


4

Mi sono imbattuto in un problema simile (volendo eseguire un commit che includeva alcuni file binari che causavano conflitti durante l'unione), ma ho trovato una soluzione diversa che può essere fatta interamente usando git (cioè non dover copiare manualmente i file). Ho pensato di includerlo qui, per lo meno posso ricordarlo la prossima volta che ne ho bisogno. :) I passaggi si presentano così:

% git fetch

Questo recupera gli ultimi commit dal repository remoto (potrebbe essere necessario specificare un nome di ramo remoto, a seconda della configurazione), ma non tenta di unirli. Registra il commit in FETCH_HEAD

% git checkout FETCH_HEAD stuff/to/update

Questo prende la copia dei file binari che desidero e sovrascrive ciò che è nell'albero di lavoro con la versione recuperata dal ramo remoto. git non tenta di eseguire alcuna fusione, quindi si ottiene una copia esatta del file binario dal ramo remoto. Una volta fatto, puoi aggiungere / eseguire il commit della nuova copia come al solito.


4

Questa procedura è per risolvere i conflitti di file binari dopo aver inviato una richiesta pull a Github:

  1. Quindi su Github, hai trovato che la tua richiesta pull ha un conflitto su un file binario.
  2. Ora torna allo stesso ramo git sul tuo computer locale.
  3. (A) ri-creare / ricostruire nuovamente questo file binario e (b) eseguire il commit del file binario risultante nello stesso ramo git.
  4. Quindi spingi di nuovo lo stesso ramo git su Github.

Su Github, su tua richiesta pull, il conflitto dovrebbe scomparire.


Questa è esattamente la procedura di cui ho bisogno
Huifang Feng,

2

Se il binario è qualcosa di più di una dll o qualcosa che può essere modificato direttamente come un'immagine o un file di fusione (e non è necessario eliminare / selezionare un file o l'altro), una vera unione sarebbe un po 'come:

Suggerisco di cercare uno strumento diff orientato a quali sono i file binari, ad esempio ce ne sono alcuni gratuiti per i file di immagine, ad esempio

e confrontarli.

Se non esiste uno strumento diff per confrontare i tuoi file, allora se hai il generatore originale del file bin (cioè esiste un editor per esso ... come Blender 3d, puoi quindi ispezionare manualmente quei file, anche vedere i registri e chiedere all'altra persona cosa dovresti includere) e fare un output dei file con https://git-scm.com/book/es/v2/Git-Tools-Advanced-Merging#_manual_remerge

$ git show :1:hello.blend > hello.common.blend $ git show :2:hello.blend > hello.ours.blend $ git show :3:hello.blend > hello.theirs.blend


1

Ho trovato due strategie per gestire la differenza / unione di file binari con Git su Windows.

  1. Tortoise git ti consente di configurare strumenti diff / merge per diversi tipi di file in base alle loro estensioni di file. Vedi 2.35.4.3. Impostazioni avanzate Diff / Merge http://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html . Questa strategia ovviamente si basa sulla disponibilità di strumenti di diff / merge adeguati.

  2. Usando gli attributi git puoi specificare uno strumento / comando per convertire il tuo file binario in testo e poi lasciare che lo strumento diff / merge predefinito faccia la sua cosa. Vedi http://git-scm.com/book/it/v2/Customizing-Git-Git-Attributes . L'articolo fornisce anche un esempio dell'uso dei metadati per le immagini diff.

Ho avuto entrambe le strategie per lavorare con file binari di modelli software, ma siamo andati con tartaruga perché la configurazione era semplice.


0

Uso Git Workflow per Excel - https://www.xltrail.com/blog/git-workflow-for-excel per risolvere la maggior parte dei problemi di unione relativi ai miei file binari. Questa app open-source mi aiuta a risolvere i problemi in modo produttivo senza spendere troppo tempo e mi permette di scegliere la versione giusta del file senza alcuna confusione.


0

il mio caso sembra un bug .... usando git 2.21.0

Ho fatto un tiro ... si è lamentato dei file binari:

warning: Cannot merge binary files: <path>
Auto-merging <path>
CONFLICT (content): Merge conflict in <path>
Automatic merge failed; fix conflicts and then commit the result.

E poi nulla in nessuna delle risposte qui ha prodotto risultati che abbiano senso.

Se guardo quale file ho ora ... è quello che ho modificato. Se lo faccio uno dei due:

git checkout --theirs -- <path>
git checkout --ours -- <path>

Ottengo l'output:

Updated 0 paths from the index

e ho ancora la mia versione del file. Se rm e poi checkout, dirà invece 1, ma mi dà ancora la mia versione del file.

dice git mergetool

No files need merging

e lo stato git dice

    All conflicts fixed but you are still merging.
    (use "git commit" to conclude merge)

Un'opzione è annullare il commit ... ma sono stato sfortunato e ho avuto molti commit, e questo cattivo è stato il primo. Non voglio perdere tempo a ripeterlo.

quindi per risolvere questa follia:

Ho appena corso

git commit

che perde la versione remota e probabilmente spreca spazio per la memorizzazione di un file binario aggiuntivo ... quindi

git checkout <commit where the remote version exists> <path>

che mi restituisce la versione remota

quindi modificato nuovamente il file ... e quindi esegui il commit e il push, il che probabilmente significa sprecare spazio con un'altra copia del file binario.


Nel mio caso, dopo aver provato a git checkout --ours <path>averlo ricevuto Updated 0 paths from the index . L'ho risolto con il git add <path>comando, che fa lo stesso.
Andriy
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.