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?
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.)
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.