J'ai une branche principale et une branche principale.
La branche principale a évolué et je veux avoir ces mises à jour pour que nous divergions le moins possible de la branche principale.
Donc, je git pull
dans les deux branches, git checkout feature/branch
et enfin git rebase master
.
Maintenant, ici, je m'attends soit à ce que tout fonctionne correctement ou que des conflits apparaissent et que je dois les résoudre avant de continuer à rebaser jusqu'à ce que toutes les validations principales soient réappliquées avec succès sur la branche de fonctionnalité.
Maintenant, ce qui m'est vraiment arrivé est quelque chose que je ne comprends pas:
$>git rebase master
First, rewinding head to replay your work on top of it...
Applying: myFirstCommitDoneOnTheBranch
Applying: myOtherCommitDoneOnTheBranch
$>git status
On branch feature/branch
Your branch and 'Origin/feature/feature' have diverged,
and have 27 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
$>git pull
*load of conflicts*
Maintenant, autant que je puisse comprendre, il charge de conflits après le pull; Je ne comprends pas la nécessité d'un pull. Logiquement, il devrait revenir en arrière au maître quand il a été créé, sauvegarder les validations effectuées sur la branche, transférer au dernier commit sur maître, puis appliquer les validations enregistrées.
Je ne comprends pas à quoi le message Applying
fait référence: quelle est l'application des commits sur quelle version?
tl; dr Vous devez mettre à jour master
et feature
avec git pull
et git pull --rebase
before rebasant feature
par-dessus master
. Il n'est pas nécessaire de faire ungit pull
après que vous ayez rebasé votre branche feature
au-dessus de master
.
Avec votre flux de travail actuel, la raison pour laquelle git status
vous dit ceci:
Votre branche et votre 'origine/caractéristique' ont divergé, et ont respectivement 27 et 2 commits différents.
c'est parce que votre branche feature
rebasée a maintenant 25 nouveaux commits qui ne sont pas accessibles depuis Origin/feature
(puisqu'ils sont issus de la base de base master
) plus 2 commet que sont accessible depuis Origin/feature
mais ont différents ID de validation. Ces commits contiennent les mêmes modifications (c'est-à-dire équivalent du correctif) mais ils ont des hachages SHA-1 différents, car ils sont basés sur un commit différent de Origin/feature
que celui sur lequel vous les avez rebasés dans votre référentiel local. .
Voici un exemple. Supposons qu'il s'agit de votre historique avant faisant git pull
sur master
:
A - B - C (master)
\
D - E (feature)
Après git pull
, master
a reçu commit F
:
A - B - C - F (master, Origin/master)
\
D - E (feature)
À ce stade, vous redéfinissez feature
au-dessus de master
, qui s'appliqueD
et E
:
A - B - C - F (master, Origin/master)
\
D - E (feature)
Entre-temps, la branche distante Origin/feature
est toujours basée sur commit C
:
A - B - C - F (master, Origin/master)
\ \
\ D' - E' (feature)
\
D - E (Origin/feature)
Si vous faites un git status
sur feature
, Git vous dira que votre branche feature
a divergé de Origin/feature
avec 3 (F
, D'
, E'
) et 2 (D
, E
), respectivement.
Notez que
D'
etE'
contiennent les mêmes modifications queD
etE
mais ont des ID de validation différents car ils ont été redéfinis au-dessus deF
.
La solution consiste à faire git pull
à la fois sur master
et feature
avant rebasant feature
sur master
. Cependant, étant donné que vous pouvez avoir des validations sur feature
que vous n'avez pas encore poussées vers Origin
, vous voudrez faire:
git checkout feature && git pull --rebase
pour éviter de créer un fusion fusionner entre Origin/feature
et votre feature
locale.
À la lumière de ce commentaire , j’ai développé les branches divergentes. La raison pour laquelle git status
rapporte que feature
et Origin/feature
divergence après la modification de la base est due au fait que la redéfinition de la base amène de nouveaux commits à feature
, auxquels s'ajoute réécrit les validations précédemment transférées à Origin/feature
.
Considérons la situation après le pull mais avant le rebase:
A - B - C - F (master)
\
D - E (feature, Origin/feature)
À ce stade, feature
et Origin/feature
pointent vers le même commit E
- en d'autres termes, ils sont dans "sync}". Après rebasement de feature
par-dessus master
, l’historique ressemblera à ceci:
A - B - C - F (master)
\ \
\ D' - E' (feature)
\
D - E (Origin/feature)
Comme vous pouvez le constater, feature
et Origin/feature
ont divergé, leur ancêtre commun étant commit C
. Ceci est dû au fait que feature
contient maintenant les nouveaux commit F
de master
plus D'
et E'
(comme "D prime" et "E prime") qui sont des validations D
et E
appliquées en haut de F
. Même s'ils contiennent les mêmes modifications, Git considère qu'elles sont différentes car elles ont des identifiants de validation différents. Pendant ce temps, Origin/feature
fait toujours référence à D
et E
.
À ce stade, vous avez historique réécrit: vous avez modifié les commits existants en les rebasonnant, ce qui en crée effectivement de "nouveaux".
Maintenant, si vous exécutiez git pull
sur feature
, voici ce qui se produirait:
A - B - C - F (master)
\ \
\ D' - E'- M (feature)
\ /
D - E - (Origin/feature)
Puisque git pull
fait git fetch
+ git merge
, cela entraînerait la création du commit de fusion M
, dont les parents sont E'
et E
.
Si vous exécutiez plutôt git pull --rebase
(c'est-à-dire git fetch
+ git rebase
), alors Git:
feature
pour commettre C
(ancêtre commun de feature
et Origin/feature
)D
et E
à partir de Origin/feature
F
, D'
et E'
Cependant, remarquant que D'
et E'
contiennent les mêmes modifications que D
et E
, Git les écarterait simplement, ce qui donnerait un historique ressemblant à ceci:
A - B - C - F (master)
\
D - E - F' (feature)
^
(Origin/feature)
Remarquez comment commit F
, précédemment accessible à partir de feature
, s’applique au-dessus de Origin/feature
, ce qui donne F'
. À ce stade, git status
vous dira ceci:
Votre branche est en avance sur 'Origine/fonctionnalité' de 1 commit.
Ce commit étant bien sûr, F'
.
Si les versions distantes de master
et feature/branch
sont à jour individuellement, réinitialisez simplement votre branche de fonctions locale
git checkout feature/branch
git fetch Origin feature/branch
git reset --hard Origin/feature/branch
alors si vous voulez apporter des modifications dans la branche master
,
git rebase Origin/master
Le have 27 and 2 different commits each
vous indique que vous avez maintenant 27 nouveaux commits de master
et 2 nouveaux commits dans votre branche qui ne sont pas présents dans Origin/<yourbranch>
.
Étant donné que Origin/<yourbranch>
a été modifié massivement par la base, celle-ci n'a plus de base commune avec Origin/<yourbranch>
. Par conséquent, vous ne voulez pas extraire les modifications de Origin/<yourbranch>
après la base, car, comme vous le voyez, tout H *** se détache.
Si vous savez que Origin/<yourbranch>
contient les modifications dont vous avez besoin dans votre branche locale, retirez-les avant de modifier votre base.
Si vous êtes sûr que personne n'a changé de Origin/<yourbranch>
depuis votre dernier Push (une valeur sûre s'il s'agit de votre propre branche), vous pouvez utiliser Push --force
pour les synchroniser à nouveau. Ensuite, Origin/<yourbranch>
aura à nouveau la même base que votre branche locale et cette base contiendra toutes les dernières modifications master
.
Lorsque vous avez modifié la base de votre branche de fonctionnalité par rapport au maître, vous avez créé un ensemble de nouveaux commits. Cependant, votre branche Origin/feature
pointe toujours sur les anciennes. Voici la situation après le rebase:
C' (feature)
B'
A'
* (master, Origin/master)
*
*
| C (Origin/feature)
| B
| A
|/
* some base commit
Alors que commit A'
contient un jeu de modifications similaire à commit A
, il ne s’agit en aucun cas du même commit. Il contient un arbre différent et a un parent différent.
Maintenant, lorsque vous essayez de tirer à nouveau feature
, vous essayez de créer cet historique:
* (feature)
|\
C'|
B'|
A'|
* | (master, Origin/master)
* |
* |
| C (Origin/feature)
| B
| A
|/
* some base commit
Vous fusionnez deux branches qui ont introduit des changements très similaires et très différents. Ceci est voué à créer une tonne de conflits, en plus d'être totalement inutile.
Ce que vous devez faire, c'est informer votre référent en amont de la base en utilisant git Push -f
. Cela va perdre l'ancienne histoire, et le remplacer par celui réécrit .
L'alternative consiste à éviter d'utiliser git rebase
sur les branches que vous avez déjà insérées dans un autre référentiel, ou à éviter git rebase
complètement. C’est l’approche plus propre : Il en résulte que l’histoire est telle qu’elle s’est produite, au lieu de dire des mensonges sur l’histoire comme le fait git rebase
. C'est du moins ce que je préfère.