git rebase, tenendo traccia di "local" e "remote"


174

Quando faccio un git rebase, ho spesso difficoltà a capire cosa sta succedendo con il "locale" e il "remoto" quando risolvono i conflitti. A volte ho l'impressione che scambino i lati da un commit a quello successivo.

Questo è probabilmente (sicuramente) perché non ho ancora capito bene.

In caso di rebasing, chi è "locale" e chi è "remoto"?

(Uso P4Merge per risolvere i conflitti)


È possibile che leggere questo ti possa aiutare? Anche il resto del tutorial è molto utile ....
Ivan

Un'altra eccellente risorsa git .
Sconosciuto il

Stackoverflow.com/questions/2959443/… sarebbe d' aiuto? (non per la parte ' git svn', solo per la parte ' git rebase')
VonC

@VonC, sì, è esattamente così. Se vuoi copiare qui la parte pertinente della tua risposta, la selezionerò (questa volta lo farò davvero, lo prometto!)
Benjol

va bene ... morderò;) Estratti pertinenti pubblicati.
VonC,

Risposte:


244

TL; DR;

Riassumendo (come commenta Benubird ), quando:

git checkout A
git rebase   B    # rebase A on top of B
  • localè B(rinnova su ),
  • remote è A

E:

git checkout A
git merge    B    # merge B into A
  • localè A(unisci in ),
  • remote è B

Un rebase cambia ours(il ramo corrente prima dell'inizio del rebase) e theirs(il ramo sopra il quale si desidera ridisegnare).


kutschkem sottolinea che, in un contesto di fusione GUI :

  • riferimenti locali commessi dal parzialmente reimpostato : " ours" (il ramo a monte)
  • remote si riferisce alle modifiche in arrivo : " theirs" - il ramo corrente prima del rebase.

Vedi le illustrazioni nell'ultima parte di questa risposta.


Inversione quando rebase

La confusione potrebbe essere correlata all'inversione di ourse theirsdurante un rebase .
(estratti pertinenti)

git rebasepagina man :

Si noti che un'unione rebase funziona riproducendo ciascun commit dal ramo di lavoro in cima al <upstream>ramo.

Per questo motivo, quando si verifica un conflitto di unione:

  • il lato segnalato come " ours" è la serie finora riformata, a partire da <upstream>,
  • e ' theirs' è il ramo di lavoro. In altre parole, i lati vengono scambiati.

Inversione illustrata

In unione

x--x--x--x--x(*) <- current branch B ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

, non cambiamo l'attuale ramo "B", quindi quello che abbiamo è ciò su cui stavamo lavorando (e ci uniamo da un altro ramo)

x--x--x--x--x---------o(*)  MERGE, still on branch B
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              their

Su un rebase:

Ma su un rebase , cambiamo lato perché la prima cosa che fa un rebase è controllare il ramo a monte! (per ripetere gli attuali commit sopra di esso)

x--x--x--x--x(*) <- current branch B
    \
     \
      \--y--y--y <- upstream branch

A git rebase upstreamprima cambierà HEADB nel ramo a monte HEAD(da qui il passaggio tra 'nostro' e 'loro' rispetto al precedente ramo di lavoro "attuale".)

x--x--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- upstream branch with B reset on it,  
                       new "ours", to replay x's on it

, e quindi il rebase ripeterà 'loro' si impegna sul nuovo 'nostro' ramo B:

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
    \
     \
      \--y--y--y--x'--x'--x'(*) <-  branch B with HEAD updated ("ours")
               ^
               |
        upstream branch

Nota: la nozione "upstream" è l'insieme di dati di riferimento (un repository completo o, come qui, un ramo, che può essere un ramo locale ) da cui vengono letti i dati o ai quali vengono aggiunti / creati nuovi dati.


' local' e ' remote' vs. ' mine' e ' theirs'

Pandawood aggiunge nei commenti :

Per me, la domanda rimane ancora, che è "locale" e chi è "remoto" (dal momento che i termini "nostro" e "loro" non vengono utilizzati quando si ribatte in git, fare riferimento a loro sembra solo rendere una risposta più confusa) .

GUI git mergetool

kutschkem aggiunge, e giustamente:

Quando si risolvono i conflitti, git dirà qualcosa del tipo:

local: modified file and remote: modified file. 

Sono abbastanza sicuro che la domanda miri alla definizione di locale e remoto a questo punto. A quel punto, dalla mia esperienza, mi sembra che:

  • riferimenti locali commessi dal parzialmente reimpostato : " ours" (il ramo a monte)
  • remote si riferisce alle modifiche in arrivo : " theirs" - il ramo corrente prima del rebase.

git mergetoolparla infatti di "locale" e "remoto" :

Merging:
f.txt

Normal merge conflict for 'f.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3):

Per esempio, KDiff3 sarebbe visualizzare la risoluzione si fondono in questo modo :

KDiff3

E la fusione lo mostrerebbe anche :

Differenza di fusione

Lo stesso per VimDiff , che visualizza :

Invoca Vimdiff come un mergetool con git mergetool -t gvimdiff. Le versioni recenti di Git invocano Vimdiff con il seguente layout di finestra:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    Un file temporaneo contenente il contenuto del file sul ramo corrente.
  • BASE:
    Un file temporaneo contenente la base comune per l'unione.
  • REMOTE:
    Un file temporaneo contenente il contenuto del file da unire.
  • MERGED:
    Il file contenente gli indicatori di conflitto.

Git ha eseguito la massima risoluzione automatica dei conflitti e lo stato di questo file è una combinazione di entrambi LOCALe REMOTEcon indicatori di conflitto che circondano tutto ciò che Git non è riuscito a risolvere da solo.
L' mergetooldovrebbe scrivere il risultato della risoluzione a questo file.


13
Per me, la domanda rimane ancora, che è "locale" e chi è "remoto" (dal momento che i termini "nostro" e "loro" non vengono utilizzati quando si ribatte in git, fare riferimento a loro sembra solo rendere una risposta più confusa) . La domanda è "chi è locale e chi è remoto" - quindi una risposta richiede sicuramente la menzione delle parole "locale" e "remoto"
PandaWood,

@PandaWood: "local" è "ramo corrente" (che diventa "loro"), "remoto" è "ramo a monte" (che diventa "nostro").
VonC,

3
Quindi, per riassumere: quando il tuo git checkout A; git rebase Blocale è B, il telecomando è A. Tutto quello che dovevo sapere ...
Benubird,

1
git è un tale clusterfk di usabilità. questo non ha senso: quando git checkout A; git rebase Blocale è B, a distanza è un . Se checkout Apoi sto guardando i file così come sono A, come è in qualche modo il telecomando ? (Non sto dicendo che Benubird abbia torto; sto dicendo che git ha una stupida UX)
Rafa,

1
@VonC sicuro; il mio (ranting) punto è che non dovrebbe prendere la lettura della documentazione, guardare i diagrammi e dover sfogliare StackOverflow. Se solo il comando fornisse un feedback chiaro e inequivocabile. Ad esempio, invece di local / remote / theirs / ours / mine / yours, mostra {branch A}e / {branch B}o simili.
Rafa,

45

La linea di fondo

git rebase

  • LOCALE = la base si sta rebasing su
  • REMOTO = i commit che stai passando in alto

git merge

  • LOCAL = il ramo originale in cui ti stai unendo
  • REMOTO = l'altro ramo di cui ti stai unendo

In altre parole, LOCAL è sempre l'originale e REMOTE è sempre il ragazzo i cui impegni non erano mai stati presenti prima, perché vengono uniti o rielaborati in cima

Provalo!

Certamente. Non crederci sulla parola! Ecco un semplice esperimento che puoi fare per vedere di persona.

Innanzitutto, assicurati di aver configurato correttamente git mergetool. (In caso contrario, probabilmente non leggeresti comunque questa domanda.) Quindi trova una directory in cui lavorare.

Imposta il tuo repository:

md LocalRemoteTest
cd LocalRemoteTest

Crea un commit iniziale (con un file vuoto):

git init
notepad file.txt  (use the text editor of your choice)
  (save the file as an empty file)
git add -A
git commit -m "Initial commit."

Crea un commit su un ramo che non è master:

git checkout -b notmaster
notepad file.txt
  (add the text: notmaster)
  (save and exit)
git commit -a -m "Add notmaster text."

Creare un commit sul ramo master:

git checkout master
notepad file.txt
  (add the text: master)
  (save and exit)
git commit -a -m "Add master text."

gitk --all

A questo punto il tuo repository dovrebbe assomigliare a questo:

Repository con un commit di base e due rami con un commit

Ora per il test rebase:

git checkout notmaster
git rebase master
  (you'll get a conflict message)
git mergetool
  LOCAL: master
  REMOTE: notmaster

Ora il test di unione. Chiudi la tua fusione senza salvare le modifiche, quindi annulla il rebase:

git rebase --abort

Poi:

git checkout master
git merge notmaster
git mergetool
  LOCAL: master
  REMOTE: notmaster
git reset --hard  (cancels the merge)

I risultati dovrebbero essere gli stessi di quelli mostrati in alto.


1
+1. Ciò chiarisce gli aspetti local/ con cui remoteho lottato nella mia risposta sopra (che riguarda più l'inversione di oursvs theirscomunque)
VonC

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.