web-dev-qa-db-fra.com

git rebase, gardant une trace de «local» et «distant»

Lors d'une refonte de git, j'ai souvent du mal à comprendre ce qui se passe avec le "local" et le "distant" lors de la résolution des conflits. J'ai parfois l'impression qu'ils changent de côté d'un commit à l'autre.

C'est probablement (définitivement) parce que je n'ai toujours pas bien compris.

Lors du rebasage, qui est "local" et qui est "distant"?

(J'utilise P4Merge pour résoudre les conflits)

158
Benjol

TL; DR;

Pour résumer (As Benubirdcomments ), quand:

git checkout A
git rebase   B    # rebase A on top of B
  • local est B (rebase sur ),
  • remote est A

Et:

git checkout A
git merge    B    # merge B into A
  • local est A (fusionner en ),
  • remote est B

Un rebase bascule ours (branche courante avant le démarrage du rebase) et theirs (la branche au dessus de laquelle vous voulez rebaser).


kutschkem souligne que, dans un contexte de mergetool GUI :

  • local fait référence aux validations partiellement rebasées : "ours" (la branche amont)
  • remote fait référence aux changements entrants : "theirs" - la branche courante avant le rebase.

Voir les illustrations dans la dernière partie de cette réponse.


Inversion lors du rebasage

La confusion peut être liée à inversion de ours et theirs lors d'un rebase .
(extraits pertinents)

git rebase page de manuel :

Notez qu'une fusion de rebase fonctionne en relisant chaque commit à partir de la branche de travail en haut de <upstream> branche.

Pour cette raison, lorsqu'un conflit de fusion se produit:

  • le côté signalé comme 'ours' est la série rebasée jusqu'à présent, commençant par <upstream>,
  • et 'theirs' est la branche de travail. En d'autres termes, les côtés sont échangés.

Inversion illustrée

Sur une fusion

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

, nous ne changeons pas la branche actuelle 'B', donc ce que nous avons est toujours ce sur quoi nous travaillions (et nous fusionnons à partir d'une autre branche)

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

Sur un rebase:

Mais sur un rebase , nous changeons de côté car la première chose qu'un rebase fait est de vérifier la branche en amont! (pour rejouer les validations actuelles par-dessus)

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

A git rebase upstream changera d'abord HEAD de B en la branche amont HEAD (d'où le basculement de 'nôtre' et 'leur' ​​par rapport au précédent "courant") "branche de travail.)

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

, puis le rebase rejouera "leurs" commits sur la nouvelle "notre" branche 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

Remarque: la notion "en amont" est l'ensemble référentiel de données (un tout repo ou, comme ici, une branche, qui peut être une locale branche) à partir de laquelle les données sont lues ou auxquelles de nouvelles données sont ajoutées/créées.


'local' et 'remote' vs 'mine' et 'theirs'

Pandawood ajoute les commentaires :

Pour moi, la question demeure, qui est "locale" et qui est "distante" (puisque les termes "les nôtres" et "les leurs" ne sont pas utilisés lors du rebasage en git, y faire référence semble simplement rendre la réponse plus confuse) .

GUI git mergetool

kutschkem ajoute, et à juste titre:

Lors de la résolution des conflits, git dira quelque chose comme:

local: modified file and remote: modified file. 

Je suis tout à fait sûr que la question vise la définition de local et distant à ce stade. À ce stade, il me semble, d'après mon expérience, que:

  • local fait référence aux validations partiellement rebasées : "ours" (la branche amont)
  • remote fait référence aux changements entrants : "theirs" - la branche courante avant le rebase.

git mergetool mentionne en effet 'local' et 'remote' :

Merging:
f.txt

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

Par exemple, KDiff serait afficher la résolution de fusion comme ceci :

kdiff3

Et fusionner serait l'afficher aussi :

Meld diff

Idem pour VimDiff , qui affiche :

Appelez Vimdiff en tant que mergetool avec git mergetool -t gvimdiff. Les versions récentes de Git invoquent Vimdiff avec la disposition de fenêtre suivante:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    Un fichier temporaire contenant le contenu du fichier sur la branche actuelle.
  • BASE:
    Un fichier temporaire contenant la base commune pour la fusion.
  • REMOTE:
    Un fichier temporaire contenant le contenu du fichier à fusionner.
  • MERGED:
    Le fichier contenant les marqueurs de conflit.

Git a effectué autant de résolution automatique des conflits que possible et l'état de ce fichier est une combinaison de LOCAL et REMOTE avec des marqueurs de conflit entourant tout ce que Git n'a pas pu résoudre lui-même.
Le mergetool doit écrire le résultat de la résolution dans ce fichier.

216
VonC

La ligne du bas

git rebase

  • LOCAL = la base que vous rebasez sur
  • REMOTE = les commits que vous montez en haut

fusion git

  • LOCAL = la branche d'origine dans laquelle vous fusionnez
  • REMOTE = l'autre branche dont vous fusionnez les validations

En d'autres termes, [[# #]] local [~ # ~] est toujours l'original, et DISTANT est toujours le gars dont les engagements n'étaient pas là avant, car ils sont fusionnés ou rebasés au-dessus

Prouvez-le!

Certainement. Ne prenez pas ma parole pour ça! Voici une expérience simple que vous pouvez faire par vous-même.

Tout d'abord, assurez-vous que git mergetool est correctement configuré. (Si vous ne l'avez pas fait, vous ne liriez probablement pas cette question de toute façon.) Trouvez ensuite un répertoire dans lequel travailler.

Configurez votre référentiel:

md LocalRemoteTest
cd LocalRemoteTest

Créez un commit initial (avec un fichier vide):

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."

Créez un commit sur une branche qui n'est pas maître:

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

Créez un commit sur la branche master:

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

gitk --all

À ce stade, votre référentiel devrait ressembler à ceci:

Repository with a base commit and two one-commit branches

Maintenant, pour le test de rebase:

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

Maintenant, le test de fusion. Fermez votre mergetool sans enregistrer les modifications, puis annulez le rebase:

git rebase --abort

Ensuite:

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

Vos résultats doivent être les mêmes que ceux affichés en haut.

41
Ryan Lundy

Je n'ai pas compris exactement votre problème, mais je pense que le diagramme suivant résout votre problème. (Rebase: référentiel distant ---> espace de travail)

http://assets.osteele.com/images/2008/git-transport.png

Source: Mon flux de travail Git