Respuesta corta
Omitió el hecho de que ejecutó git push
, obtuvo el siguiente error y luego procedió a ejecutar git pull
:
To git@bitbucket.org:username/test1.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
A pesar de que Git intenta ser útil, su consejo de 'git pull' probablemente no sea lo que quieres hacer .
Si usted es:
- Trabajando en una "rama de la característica" o "rama desarrollador" solos , entonces se puede ejecutar
git push --force
para actualizar el mando a distancia con sus confirmaciones post-rebase ( según respuesta de user4405677 ).
- Trabajando en una rama con múltiples desarrolladores al mismo tiempo, entonces probablemente no deberías estar usando
git rebase
en primer lugar. Para actualizar dev
con los cambios desde master
, debe, en lugar de ejecutar git rebase master dev
, ejecutar git merge master
mientras está encendido dev
( según la respuesta de Justin ).
Una explicación un poco más larga.
Cada hash de commit en Git se basa en una serie de factores, uno de los cuales es el hash del commit que viene antes.
Si reordena los commits, cambiará los hash de commit; rebasar (cuando hace algo) cambiará los hash de confirmación. Con eso, el resultado de la ejecución git rebase master dev
, donde no dev
está sincronizado master
, creará nuevos commits (y, por lo tanto, hashes) con el mismo contenido que los activados dev
pero con los commits master
insertados antes que ellos.
Puede terminar en una situación como esta de múltiples maneras. Dos maneras en las que puedo pensar:
- Podría tener compromisos en los
master
que quiera basar su dev
trabajo
- Podría haber confirmaciones
dev
que ya han sido enviadas a un control remoto, que luego procede a cambiar (reformular mensajes de confirmación, reordenar confirmaciones, confirmaciones de squash, etc.)
Comprendamos mejor lo que sucedió. Aquí hay un ejemplo:
Tienes un repositorio:
2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0
Luego procedes a cambiar los commits.
git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing
(Aquí es donde tendrá que aceptar mi palabra: hay varias maneras de cambiar los commits en Git. En este ejemplo, cambié la hora de C3
, pero estará insertando nuevos commits, cambiando mensajes de commit, reordenando commits, aplastar cometas juntos, etc.)
ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0
Aquí es donde es importante notar que los hashes de confirmación son diferentes. Este es el comportamiento esperado ya que ha cambiado algo (cualquier cosa) sobre ellos. Esto está bien, PERO:
Intentar presionar le mostrará un error (y le indicará que debe ejecutar git pull
).
$ git push origin master
To git@bitbucket.org:username/test1.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Si corremos git pull
, vemos este registro:
7df65f2 (HEAD, master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 (origin/master) C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
O, mostrado de otra manera:
Y ahora tenemos confirmaciones duplicadas localmente. Si tuviéramos que ejecutar git push
, los enviaríamos al servidor.
Para evitar llegar a esta etapa, podríamos haber corrido git push --force
(donde corrimos git pull
). Esto habría enviado nuestras confirmaciones con los nuevos hashes al servidor sin problemas. Para solucionar el problema en esta etapa, podemos restablecerlo antes de ejecutarlo git pull
:
Mire el reflog ( git reflog
) para ver cuál era el hash de confirmación antes de ejecutar git pull
.
070e71d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
ba7688a HEAD@{2}: rebase -i (finish): returning to refs/heads/master
ba7688a HEAD@{3}: rebase -i (pick): C5
44085d5 HEAD@{4}: rebase -i (pick): C4
961390d HEAD@{5}: commit (amend): C3
3cb46a9 HEAD@{6}: cherry-pick: fast-forward
85f59ab HEAD@{7}: rebase -i (start): checkout HEAD~~~
2a2e220 HEAD@{8}: rebase -i (finish): returning to refs/heads/master
2a2e220 HEAD@{9}: rebase -i (start): checkout refs/remotes/origin/master
2a2e220 HEAD@{10}: commit: C5
ab1bda4 HEAD@{11}: commit: C4
3cb46a9 HEAD@{12}: commit: C3
85f59ab HEAD@{13}: commit: C2
4516164 HEAD@{14}: commit: C1
0e783a3 HEAD@{15}: commit (initial): C0
Arriba vemos que ba7688a
fue el commit en el que estábamos antes de correr git pull
. Con ese hash de confirmación en la mano, podemos restablecer eso ( git reset --hard ba7688a
) y luego ejecutarlo git push --force
.
Y ya hemos terminado.
Pero espera, seguí basando el trabajo en las confirmaciones duplicadas
Si de alguna manera no te diste cuenta de que los commits estaban duplicados y procediste a continuar trabajando encima de los commits duplicados, realmente has hecho un desastre por ti mismo. El tamaño del desorden es proporcional al número de confirmaciones que tiene encima de los duplicados.
Cómo se ve esto:
3b959b4 (HEAD, master) C10
8f84379 C9
0110e93 C8
6c4a525 C7
630e7b4 C6
070e71d (origin/master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
O, mostrado de otra manera:
En este escenario, queremos eliminar las confirmaciones duplicadas, pero mantener las confirmaciones que tenemos basadas en ellas; queremos mantener C6 a C10. Como con la mayoría de las cosas, hay varias maneras de hacerlo:
Ya sea:
- Cree una nueva rama en el último commit 1 duplicado ,
cherry-pick
cada commit (C6 a C10 inclusive) en esa nueva rama, y trate esa nueva rama como canónica.
- Ejecutar
git rebase --interactive $commit
, donde $commit
está la confirmación antes de las dos confirmaciones duplicadas 2 . Aquí podemos eliminar directamente las líneas de los duplicados.
1 No importa cuál de los dos elija, ya sea ba7688a
o 2a2e220
funciona bien.
2 En el ejemplo sería 85f59ab
.
TL; DR
Establecer advice.pushNonFastForward
en false
:
git config --global advice.pushNonFastForward false