Git rebase Conflict: qui est HEAD?

j'ai ce projet où le repo à distance a la branche de développement principale, et j'ai une fourchette contenant la branche expérimentale. Je dois changer rebase de la branche développement à ma branche expérimentale avant de passer à ma fourchette.

git checkout experimentalbranch
git fetch remoterepo
git rebase remoterepo/developmentbranch

à ce moment-là, j'ai frappé conflits. Cependant, Je ne suis pas familier avec l'un de ces changements (Je rebasé semaines de changements, parce qu'ils n'ont pas fusionné mes modifications immédiatement). C'est aussi la première fois que je fais rebase . Je suis plus habitué à merge .

en fusion, il est généralement comme <<LOCAL||REMOTE>> pour merge , ce qui semble très intuitif. Mais dans rebase , c'est <<HEAD||COMMIT MESSAGE>> . Qui est HEAD ? Est-ce le HEAD de la direction du développement? Est-ce le dernier code de la branche développement ou ailleurs?

43
demandé sur Joseph 2014-04-22 03:33:16

2 réponses

TL; DR (ajouté en mai 2018)

l'ensemble est fondamentalement au moins un peu confus parce que Git laisse son fonctionnement interne se montrer à vous.

notez que les cas qui nous intéressent ici se produisent lorsque vous exécutez:

git checkout somebranch; git rebase origin/their-branch

ou similaire. Le rebase s'est arrêté temporairement pour vous forcer à résoudre un conflit de fusion, après quoi vous êtes censé git add le conflit résolu et Lancez git rebase --continue . (Si vous utilisez un outil de fusion avec git mergetool , ou une interface graphique de fantaisie, cette interface peut faire une partie ou tout cela pour vous d'une autre manière, mais en dessous, c'est git add ing les fichiers résolus et l'exécution git rebase --continue .)

au tout début, le HEAD commit est leur branche, de sorte que si vous utilisez git checkout --ours ou git checkout --theirs , --ours signifie la leur - la Commission finale de origin/their-branch - alors que --theirs signifie votre , le premier commit que vous rebasez. Il s'agit de la confusion habituelle de Git (voir ). Quelle est la signification précise de "Notre" et "la leur" dans git? ) et n'est pas ce qui a conduit à la question initiale.

plus tard, cependant, le HEAD commit est en fait une sorte de mélange . C'est le résultat de copier un certain nombre de votre commits atop leur dernier commit . Vous obtenez maintenant un conflit entre votre propre partiellement construit "nouvelle série de commits, et votre propre originale commits. La source de ce conflit est habituellement quelque chose "qu'ils" ont fait (quelque chose qui a changé en cours de route dans origin/their-branch ). Vous avez encore à résoudre ce conflit. Lorsque vous le faites, vous pouvez voir le même conflit se reproduire plus tard s'engage.

de nouveau, HEAD ou local ou --ours est un commit que rebase a construit en combinant vos modifications et leurs changements , et l'autre commit ( remote ou >>>>>>> ou --theirs ) est votre propre commit, que rebase essaie de copier au-dessus de HEAD .

Plus

lors de la fusion (y compris le rebasement, qui est un cas particulier de "fusion" répétée en interne), il y a deux "les chefs" (deux branche spécifique-conseils). Appelons-les your-branch et origin/their-branch :

              G - H --------      <-- HEAD=your-branch
            /               \
... - E - F                   M   <-- desired merge commit [requires manual merge]
            \               /
              I - J - K - L       <-- origin/their-branch

ce point est souvent (et sans surprise) confus, bien que quand étiqueté comme ceci il est assez clair.

ce qui le rend pire, bien que git utilise --ours et --theirs pour se référer aux deux têtes commet pendant une fusion, avec "notre" étant celui que vous étiez sur (commit H ) quand vous avez couru git merge , et " leurs" être, bien, le leur (commit L ). Mais quand vous faites un rebase, les deux têtes sont inversées, de sorte que "la nôtre" est la tête que vous rebasez sur-c'est-à-dire leur code mis à jour-et "la leur" est la propagation que vous rebasez actuellement, c'est-à-dire votre propre code.

c'est parce que rebase utilise en fait une série d'opérations de cueillette. Vous commencez avec à peu près la même image:

              G - H           <-- HEAD=your-branch
            /
... - E - F
            \
              I - J - K - L   <-- origin/their-branch

ce que git doit faire ici est de copy l'effet de commits G et H , c'est à dire, git cherry-pick commit G , puis faire à nouveau avec le commettre H . Mais pour ce faire, git doit switch to commit L first, internally (using" detached HEAD "mode):

              G - H           <-- your-branch
            /
... - E - F
            \
              I - J - K - L   <-- HEAD, origin/their-branch

maintenant il peut commencer l'opération de rebase en comparant les arbres pour commits F et G (pour voir ce que vous avez changé), puis comparer F vs L (pour voir si une partie de votre travail est déjà dans L ) et en prenant n'importe quels changements pas déjà dans L et l'ajouter. Il s'agit d'une opération de" fusion " interne.

              G - H           <-- your-branch
            /
... - E - F                   G'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch

si la fusion ne se passe pas bien, HEAD reste à commit L (car commit G' n'existe pas encore). Ainsi, Oui, HEAD est le chef de leur branche de développement-du moins, il est maintenant.

une fois que la copie de G existe, bien que, HEAD se déplace à G' et git tente de copier les changements de H , de la même manière (diff G vs H , puis diff F vs G' , et fusionner les résultats):

              G - H           <-- your-branch
            /
... - E - F                   G' - H'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch

encore une fois, si la fusion échoue et a besoin d'aide, vous êtes laissé avec HEAD pointant vers G' au lieu de H' comme H' n'existe pas encore.

une fois que les fusions tout réussir et commet G' et H' do existent, git supprime l'étiquette your-branch de commit H , et le fait de commit H' à la place:

              G - H
            /
... - E - F                   G' - H'   <-- HEAD=your-branch
            \               /
              I - J - K - L   <-- origin/their-branch

et vous êtes maintenant relocalisée et HEAD est une fois de plus ce que vous attendez. Mais pendant le rebase, HEAD est soit leur branche-pointe (commit L ), soit l'un des nouveaux --ours signifie la branche étant cultivée à la fin de L tandis que --theirs signifie la propagation étant copiée-de ( G ou H ci-dessus).

(c'est essentiellement git exposer le mécanisme brut de comment il fait ce qu'il fait, ce qui se produit plutôt beaucoup dans git.)

65
répondu torek 2018-05-17 15:10:04

Définitions

dans cette section nous allons voir les deficiones qui nous sont demandés dans la réponse:

qui est HEAD?

HEAD : le fichier commit actuel est sur . La plupart du temps, HEAD pointe vers le dernier commit de votre branche, mais cela n'a pas à être le cas. HEAD signifie vraiment: "qu'est-ce que mon repo pointé".

dans le cas où la commit HEAD se réfère à n'est pas la pointe d'une branche, cela est appelé" detached head ".

est-ce le chef de la direction du développement?

au moment où une fusion ou une rebase est faite, le HEAD passe immédiatement au point créé ou refactorized commettre et va donc être dirigée vers le développement de la branche .

Dans git bash nous pouvons voir le HEAD de la situation, l'inscription s'engager:

# Normal commit list
git log
# List of commit in a single line
git log --oneline 
# All commits graphically-linear (Recommended as alias)
git log --all --graph --decorate --oneline

pratique

dans cette section, nous verrons _how_ works quelques actions effectuées par l'utilisateur

Lorsque l'utilisateur passe à :

# Command to change from the branch to the current one to experimentalbranch
git checkout experimentalbranch
# Command that traverses the typical workflow to synchronize its local repository with the main branch of the central repository (remoterepo)
git fetch remoterepo
# git fetch origin
# git fetch origin branch:branch
# With the command git rebase, you can take all the changes confirmed in one branch (remoterepo), and reapply them over another developmentbranch
git rebase remoterepo/developmentbranch

à ce moment-là, j'ai frappé conflits. Cependant, je ne suis pas familier avec aucun de ces changements (je rebaptise des semaines de changements, parce qu'ils n'ont pas fusionné mes changements immédiatement). C'est aussi la première fois que je fais rebase. Je suis plus habitué à fusionner.

l'union des branches se fait de deux façons:

  • git merge

  • git rebase.

Note :

pour les exemples, nous utiliserons l'arbre suivant :

* a122f6d (HEAD -> remoterepo) Commit END
* 9667bfb Commit MASTER
| * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
| * 110b2fb Commit 2
| * e597c60 Commit 1
|/
* 0e834f4 (origin/remoterepo) First commit

git merge

la forme la plus connue est git merge , qui effectue une fusion à trois bandes entre les deux derniers instantanés de chaque branche et l'ancêtre commun aux deux, créant un nouveau commit avec des changements mélangés.

par exemple:

git checkout remoterepo
git merge experimentalbranch

il nous produirait:

*   003e576 (HEAD -> remoterepo) Merge branch 'experimentalbranch' in remoterepo
|\
| * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
| * 110b2fb Commit 2
| * e597c60 Commit 1
* | a122f6d Commit END
* | 9667bfb Commit MASTER
|/
* 0e834f4 (origin/remoterepo) First commit

git rebase

git rebase fondamentalement, ce qu'il fait est de recueillir un par un les changements confirmés dans une branche, et les appliquer à nouveau sur une autre .

l'utilisation de rebase peut nous aider à éviter les conflits chaque fois qu'elle est appliquée à des commits qui sont locaux et n'ont pas été téléchargés vers tout dépôt distant . Si vous n'êtes pas prudent avec ce dernier et un partenaire utilise les changements touchés, vous aurez certainement des problèmes depuis ces types de conflits sont généralement difficiles à réparer .

par exemple:

git checkout remoterepo
git rebase experimentalbranch


* f8a74be (HEAD -> remoterepo) Commit END
* 4293e9d Commit MASTER
* b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
* 110b2fb Commit 2
* e597c60 Commit 1
* 0e834f4 (origin/remoterepo) First commit

Qu'est-ce que l'origine?

origin : le nom par défaut que git donne à votre main remote repo . Votre boîte a son propre repo, et vous poussez très probablement à un repo à distance que vous et tous vos collègues poussez. Distance repo est presque toujours appelé origine, mais il n'a pas à être.

3
répondu Nicolás Alarcón R. 2018-06-14 10:08:09