Cambiar base de sucursal

145

Tengo un árbol como este:

(commit 1) - master
                \-- (commit 2) - (commit 3) - demo
                                                \-- (commit 4) - (commit 5) - PRO

y tengo que mover la rama PRO para dominar

(commit 1) - master
                |-- (commit 2) - (commit 3) - demo
                \-- (commit 4) - (commit 5) - PRO

He intentado con una git rebase masterrama PRO, pero no pasa nada.

Para aclarar : estaba trabajando en master y luego tuve que hacer una demostración del producto ( git checkout -b demoy algunos commits). Luego, por error, creo otra rama de la demostración ( git checkout -b PROy algunos commits) y ahora necesito mover la rama PRO a master y dejar la demo intacta. Al final, tanto la demo como PRO se colgarán del maestro.

Ivan
fuente
posible duplicado del cambio de punto de ramificación
Wladimir Palant

Respuestas:

281

Uso --ontopara eso:

git rebase --onto newBase oldBase feature/branch

Dado su caso:

git checkout PRO # Just to be clear which branch to be on.
git rebase --onto master demo PRO

Básicamente, tomas todos los commits desde después demohasta PRO, y los vuelves a basar en el mastercommit.

loganfsmyth
fuente
¿Es ese también el camino a seguir si la situación es la opuesta? == Comprobé -b desde master la segunda rama, pero quería hacerlo desde la primera. Así lo hice git rebase --onto first-branch second-branch second-branchpero no obtengo la sintaxis
Fla
1
@Fla en ese caso, seríagit rebase --onto first-branch master second-branch
nVitius
9
He leído esta guía en --onto, y la forma en que me escribió ayudógit rebase --onto newBase oldBase feature/branch
Gabe
@PhilipRego Eso es incorrecto. origin/newBasees el nombre de una rama, como newBaseen mi ejemplo. Solo dependería si está haciendo un rebase en una rama que existe en su repositorio local ( newBase), o en una que existe en el remoto ( origin/newBase).
loganfsmyth
@PhilipRego Esas no son cosas independientes. newBasees el nombre de una rama local y origin/newBasees el nombre de una rama remota. El que desea depende de lo que está haciendo rebase. No es que uno funcione y el otro no, es que se basan en cosas diferentes. La pregunta original nunca menciona los controles remotos, por lo que el uso de controles remotos en mi ejemplo no coincidiría con la pregunta que se hizo.
loganfsmyth
22

Intentaré ser lo más genérico posible. Primero, asegúrese de estar en la rama deseada:

git checkout current-branch

Luego use el siguiente comando (¿dónde new-base-branchestá la rama que desea que sea su nueva base y current-base-branches la rama que es su base actual?)

git rebase --onto new-base-branch current-base-branch

Si no tiene conflictos, entonces genial, ya está. Si lo hace (en la mayoría de los casos), siga leyendo.

Pueden surgir conflictos y deberá resolverlos manualmente. Git ahora trata de hacer una "fusión de 3 vías" entre su current-branch, current-base-branchy new-base-branch. Aproximadamente así es como git funcionará internamente:

  1. Git primero rebase la current-base-branchparte superior de la new-base-branch. Puede haber conflictos; que deberás resolver manualmente. Una vez hecho esto, generalmente lo haces git add .y git rebase --continue. Creará una nueva confirmación temporal temp-commit-hashpara esto.

  2. Después de esto, Git ahora rebase su current-branchsuperior sobre de temp-commit-hash. Puede haber más conflictos y nuevamente tendrá que resolverlos manualmente. Una vez hecho esto, continúe nuevamente con git add .y git rebase --continue, después de lo cual ha reubicado con éxito su current-branchen la parte superior new-base-branch.


Nota: Si comienza a equivocarse, puede hacerlo en git rebase --abortcualquier momento durante el proceso de rebase y volver al punto de partida.

ARCA
fuente
El rebasecomando publicado solo me da "fatal: no válido ascendente 'current-base-branch'". Además, ¿por qué es necesario decirle a GIT cuál es la rama principal actual de la rama actual? ¿No debería saber esto ya?
Matt Arnold
21

Pague en la PROrama, copie los hashes de confirmación más antiguos ( commit4 ) y más recientes ( commit5 ) de esta rama y péguelos en otro lugar:

$ git checkout PRO
$ git log            # see the commit history
# copy the oldest & latest commit-hash 

Elimine la PROrama (guarde una copia de seguridad solo por seguridad). Crear y pagar a una nueva PROsucursal desde master:

$ git branch PRO.bac    # create a new branch PRO.bac = PRO as backup

$ git checkout master
$ git branch -D PRO     # delete the local PRO branch
$ git checkout -b PRO   # create and checkout to a new 'PRO' branch from 'master'

Tome (selección de cereza ) el rango de confirmaciones de la PROrama anterior en la nueva PROrama:

$ git cherry-pick commit4^..commit5   # cherry-pick range of commits
# note the '^' after commit4

Ahora, si todo está bien, entonces forzar (-f) a la remote PRObifurcación y eliminar la PRO.bacbifurcación local :

$ git log                  # check the commit history

$ git push -f origin HEAD  # replace the remote PRO by local PRO branch history
# git branch -D PRO.bac    # delete local PRO.bac branch
Sajib Khan
fuente
1

Tuve un enfoque ligeramente diferente usando reset y stashes que evita eliminar y volver a crear ramas, así como eliminar la necesidad de cambiar de rama:

$ git checkout PRO
$ git reset commit4 # This will set PROs HEAD to be at commit 4, and leave the modified commit 5 files in ur working index
$ git stash save -m "Commit message"
$ git reset commit 3
$ git stash save -m "Commit message"
$ git reset master --hard
$ git stash pop
$ git stash pop
$ git push --force # force if its already been push remotely

Al restablecer la rama en una base de confirmación por confirmación, básicamente solo rebobina el historial de las ramas una confirmación a la vez.

madjase
fuente
¿Debería eliminar el espacio entre "commit" y "3" en la cuarta línea?
Alexis Wilke