Cambiar el nombre de la rama maestra para repositorios Git locales y remotos

821

Tengo la rama masterque rastrea la rama remota origin/master.

Quiero cambiarles el nombre a master-oldambos localmente y en el control remoto. es posible?

Para otros usuarios que rastrearon origin/master(y que siempre actualizaron su mastersucursal local a través de git pull), ¿qué sucedería después de cambiar el nombre de la sucursal remota?
¿Seguiría git pullfuncionando o arrojaría un error que ya no podría encontrar origin/master?

Luego, más adelante, quiero crear una nueva masterrama (tanto local como remota). Nuevamente, después de hacer esto, ¿qué pasaría ahora si los otros usuarios lo hacen git pull?

Supongo que todo esto provocaría muchos problemas. ¿Hay una manera limpia de obtener lo que quiero? ¿O debería simplemente dejarlo mastercomo está y crear una nueva sucursal master-newy seguir trabajando allí más adelante?

Albert
fuente
2
La receta dada en la respuesta aceptada se aplica a una rama de cualquier nombre, pero las advertencias (como se indicó) no, debido al rol especial (por defecto) de la rama maestra en Git.
kynan
3
@kynan: Creo que no entiendo. ¿Qué advertencias se aplican al maestro y no se aplican a otras ramas? Si se tratara de una rama llamada xy y otras personas la hubieran rastreado, ¿cómo sería eso diferente?
Albert
44
La advertencia de que normalmente no puede eliminar el maestro remoto. Sin embargo, eso no se aplica a la respuesta de Aristóteles, por lo que es posible que desee marcar eso como la respuesta aceptada. Tienes razón, cualquiera git push -fafecta la capacidad pullde cualquier rama de seguimiento remoto.
kynan
puede crear una nueva rama master-oldque apunte a la misma confirmación que la masterrama anterior . Luego puede sobrescribir la masterrama con sus nuevos cambios haciendo un mergecon la oursestrategia. Hacer una fusión funciona cuando el control remoto no permite cambios no rápidos. Eso también significa que otros usuarios no tendrán actualizaciones forzadas.
dnozay
1
@kynan mastersolo es especial siempre que sea la única rama existente. Tan pronto como tenga más de una, todas las ramas estarán en pie de igualdad.
jub0bs

Respuestas:

615

Lo más parecido al cambio de nombre es eliminar y volver a crear en el control remoto. Por ejemplo:

git branch -m master master-old
git push remote :master         # delete master
git push remote master-old      # create master-old on remote

git checkout -b master some-ref # create a new local master
git push remote master          # create master on remote

Sin embargo, esto tiene muchas advertencias. Primero, ningún pago existente sabrá sobre el cambio de nombre: git no intenta rastrear los cambios de nombre de las sucursales. Si lo nuevo masteraún no existe, git pull generará un error. Si lo nuevo masterha sido creado. el tirón intentará fusionarse mastery master-old. Por lo tanto, generalmente es una mala idea a menos que cuente con la cooperación de todos los que han revisado el repositorio anteriormente.

Nota: Las versiones más recientes de git no le permitirán eliminar la rama maestra de forma remota de forma predeterminada. Puede anular esto estableciendo el receive.denyDeleteCurrentvalor de configuración en warno ignoreen el repositorio remoto . De lo contrario, si está listo para crear un nuevo maestro de inmediato, omita el git push remote :masterpaso y pase --forceal git push remote masterpaso. Tenga en cuenta que si no puede cambiar la configuración del control remoto, ¡no podrá eliminar completamente la rama maestra!

Esta advertencia solo se aplica a la rama actual (generalmente la masterrama); cualquier otra rama se puede eliminar y volver a crear como se indicó anteriormente.

bdonlan
fuente
2
las ramas son solo un par (nombre, hash), nada más y nada menos. Existe el reflog en las sucursales, pero nunca se expone a clientes remotos.
bdonlan
122
Crearía master-old en remoto antes de eliminar master en remoto. Solo estoy paranoico.
Adam Dymitruk
66
La respuesta de Aristóteles a continuación le permite hacer esto sin eliminar el maestro, por lo que creo que es preferible.
Clay Bridges
13
sería claro y SEGURO si puede usar new-branch-namey en old-branch-namelugar de master/ master-old, por lo tanto, este es un problema general.
Jaider
2
Si la rama eliminada (aquí: maestra) no está referenciada por otras ramas, git podría recolectar basura todas las confirmaciones en eso ... bueno ... "rama". - Algunos comandos de porcelana git desencadenan una recolección de basura. - Por lo tanto: cree primero el nuevo nombre (señalando el mismo commit), luego elimine el nombre anterior.
Robert Siemer
257

Asumiendo que estás actualmente en master:

git push origin master:master-old        # 1
git branch master-old origin/master-old  # 2
git reset --hard $new_master_commit      # 3
git push -f origin                       # 4
  1. Primero haga una master-oldbifurcación en el originrepositorio, basada en la masterconfirmación en el repositorio local.
  2. Cree una nueva sucursal local para esta nueva origin/master-oldsucursal (que se configurará automáticamente como una sucursal de seguimiento).
  3. Ahora señale a su local mastera cualquier compromiso que desee que señale.
  4. Finalmente, forzar el cambio masteren el originrepositorio para reflejar su nuevo local master.

(Si lo hace de otra manera, necesita al menos un paso más para asegurarse de que master-oldestá configurado correctamente para realizar un seguimiento origin/master-old. Ninguna de las otras soluciones publicadas en el momento de escribir este artículo incluye eso).

Aristóteles Pagaltzis
fuente
11
Esta es una mejor respuesta que "la respuesta", estoy de acuerdo, pero para las personas que vinieron aquí para cambiar el nombre de una rama (no explícitamente maestra), el tercer paso no tiene mucho sentido.
golpeado el
No hay absolutamente ninguna diferencia en la respuesta, ya sea que se encuentre en masteruna sucursal o en otra. Sin embargo, la pregunta estaba mal titulada, se trata de una tarea más compleja que simplemente cambiar el nombre de una rama.
Aristóteles Pagaltzis
3
Esta resultó ser la solución que funcionó para mí. Estaba tratando de reemplazar el maestro con otra rama. Hice un git log -1 origin / what_i_want_as_new_master para obtener el $ new_master_commit para el paso 3. Después del push (paso 4), otros desarrolladores tirarían y recibirían mensajes "su rama está por delante del maestro por 295 commits". Para solucionar esto, envié un correo electrónico para informarles de cada ejecución: git pull; git checkout some_random_branch; git branch -D master; git pull; git checkout master; Básicamente, necesitan eliminar su maestro local y extraer la nueva versión; de lo contrario, están localmente en el lugar equivocado.
nairbv
Podrías haberlo hecho mucho más fácilmente: suponiendo que ya estén encendidas, masterentonces podrían hacer git fetch && git reset --hard origin/masterque su local mastersea ​​el mismo que el que está encendido origin. He documentado esto, así como el caso más complejo en el que tiene compromisos locales además de los masterque desea mantener, en stackoverflow.com/q/4084868
Aristóteles Pagaltzis
Asegúrese de que el archivo de configuración remota tenga "denyNonFastforwards = false" o obtendrá "remote: error: denegando referencias / cabezas / master que no son de avance rápido (debe extraer primero)"
gjcamann
160

Con Git v1.7, creo que esto ha cambiado ligeramente. Actualizar la referencia de seguimiento de su sucursal local al nuevo control remoto ahora es muy fácil.

git branch -m old_branch new_branch         # Rename branch locally    
git push origin :old_branch                 # Delete the old branch    
git push --set-upstream origin new_branch   # Push the new branch, set local branch to track the new remote
Excalibur
fuente
10
Una alternativa a --set-upstreames el siguiente: Una vez que tenga su sucursal renombrada a nivel local y eliminado en el origen, sólo tiene que hacer: git push -u --all
lucifurious
44
Esto no funcionará con la rama maestra, ya que git no le permitirá eliminar el maestro remoto.
Alexandre Neto
44
@AlexandreNeto En este caso, puede ejecutar la 3ra línea antes de la 2da, establecer la rama predeterminada en new_branchy finalmente eliminar el control remoto mastercon la 2da línea.
Tristan Jahier
3
Pasos increíblemente simples. Esta es la mejor respuesta a la pregunta
siddhusingh
13
Para eliminar la rama remota git push origin --delete old_branches un poco más legible.
ThomasW
35
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name

Es posible que deba cambiar manualmente a new-branch-nameantes de eliminarold-branch-name

Treken
fuente
¿Alguna parte de esta solución elimina el nombre antiguo de la sucursal local, o es un ejercicio separado?
GreenAsJade
44
Creo que al final se debe ejecutar git branch -d old-branch-namepara eliminar la rama antigua local.
Nabi KAZ
Usted puede empujar cambios por un solo comando: git push remote-name new-branch-name :old-branch-name.
sigod
De esta manera, ¿no complicarás la historia de git? Debido a que está abriendo una nueva sucursal, simplemente renombra la actual.
androidevil
1
@androider No. Las ramas en git son referencias simples .
sigod
29

Hay muchas formas de cambiar el nombre de la sucursal, pero me voy a centrar en el problema más grande: "cómo permitir a los clientes avanzar rápidamente y no tener que meterse con sus sucursales localmente" .

Primero una foto rápida: renombrar la rama maestra y permitir que los clientes avancen rápidamente

Esto es algo realmente fácil de hacer; Pero no abuses de ello. Toda la idea depende de los compromisos de fusión; ya que permiten el avance rápido y vinculan las historias de una rama con otra.

renombrar la sucursal:

# rename the branch "master" to "master-old"
# this works even if you are on branch "master"
git branch -m master master-old

creando la nueva rama "maestra":

# create master from new starting point
git branch master <new-master-start-point>

crear un compromiso de fusión para tener un historial padre-hijo:

# now we've got to fix the new branch...
git checkout master

# ... by doing a merge commit that obsoletes
# "master-old" hence the "ours" strategy.
git merge -s ours master-old

y voilá.

git push origin master

Esto funciona porque crear una mergeconfirmación permite reenviar rápidamente la rama a una nueva revisión.

utilizando un mensaje de confirmación de fusión sensible:

renamed branch "master" to "master-old" and use commit ba2f9cc as new "master"
-- this is done by doing a merge commit with "ours" strategy which obsoletes
   the branch.

these are the steps I did:

git branch -m master master-old
git branch master ba2f9cc
git checkout master
git merge -s ours master-old
dnozay
fuente
3
¡Gracias! git merge -s ours master-oldes la pieza crucial que las otras respuestas pierden. Además, "fácil de hacer" no significa "fácil de entender o descubrir", lo que parece ser el caso con gran parte de git, pero estoy divagando.
Martin Vidner
3
Me encanta el hecho de que no se mencionan eliminaciones y que la transición para aquellos que trabajan con clones de upstream es "perfecta". ¡Gracias!
Piotrek
12

Supongo que todavía está preguntando sobre la misma situación que en su pregunta anterior . Es decir, master-new no contendrá master-old en su historial. * Si llama master-new "master", efectivamente habrá reescrito el historial. No importa cómo llegue a un estado en el que el maestro no sea un descendiente de una posición anterior del maestro, simplemente que está en ese estado.

A otros usuarios que intenten extraer mientras el maestro no existe simplemente les fallarán sus tirones (no existe tal referencia en el control remoto), y una vez que exista nuevamente en un nuevo lugar, sus tirones tendrán que intentar fusionar su maestro con el nuevo maestro remoto, tal como si combinaras master-old y master-new en tu repositorio. Dado lo que está tratando de hacer aquí, la fusión tendría conflictos. (Si se resolvieran y el resultado se volviera a colocar en el repositorio, estaría en un estado aún peor: ambas versiones de la historia allí).

Para responder a su pregunta simplemente: debe aceptar que a veces habrá errores en su historial. Esto está bien. Le pasa a todo el mundo. Hay confirmaciones revertidas en el repositorio git.git. Lo importante es que una vez que publicamos el historial, es algo en lo que todos pueden confiar.

* Si lo hiciera, esto sería equivalente a empujar algunos cambios al maestro y luego crear una nueva rama donde solía estar. No hay problema.

Cascabel
fuente
Sí, es el mismo problema, solo fue una idea de cómo resolverlo. Pero incluso si no hiciera este cambio de nombre de rama, me interesaba si fuera posible. Pensé que referencias como "maestro" son solo referencias a confirmaciones específicas. Realmente no quiero cambiar ninguna historia. Pensé que solo señalaría la referencia maestra a otra cabeza. Esto también significa que nunca podré volver a usar un nombre de sucursal si lo he usado antes.
Albert
De hecho, las sucursales son referentes, punteros a los compromisos. La cuestión es que esperamos que el jefe de una rama evolucione de una manera particular (es decir, siempre avanzando rápidamente). Desde el punto de vista de otra persona, mover una sucursal en su repositorio público es lo mismo que reescribir la historia de la sucursal. Ya no apunta a una confirmación que contiene todo lo que solía.
Cascabel el
8

La respuesta seleccionada falló cuando lo intenté. Se genera un error: refusing to delete the current branch: refs/heads/master. Creo que publicaré lo que funciona para mí:

git checkout master             # if not in master already

git branch placeholder          # create placeholder branch
git checkout placeholder        # checkout to placeholder
git push remote placeholder     # push placeholder to remote repository

git branch -d master            # remove master in local repository
git push remote :master         # remove master from remote repository.

El truco es pagar al marcador de posición justo antes de empujarlo al repositorio remoto. El resto se explica por sí mismo, eliminar la rama maestra y empujarla al repositorio remoto debería funcionar ahora. Extraído de aquí .

Hendra Uzia
fuente
Fallaría en git push remote: master si esto está marcado en el lado remoto: verá "remote: error:" como prefijo en las líneas de registro de errores.
rafalmag
2

Bueno. Mis 2 centavos ¿Qué hay de iniciar sesión en el servidor, ir al directorio git y cambiar el nombre de la sucursal en el repositorio vacío? Esto no tiene todos los problemas asociados con la recarga de la misma rama. En realidad, los 'clientes' reconocerán automáticamente el nombre modificado y cambiarán su referencia remota. Después (o antes) también puede modificar el nombre local de la sucursal.


fuente
8
He olvidado las credenciales para iniciar sesión en el servidor github. Cualquiera con credenciales
:-P
1

Qué pasa:

git checkout old-branch-name
git push remote-name new-branch-name
git push remote-name :old-branch-name
git branch -m new-branch-name
Hannes Tydén
fuente
se equivoca con el seguimiento de sucursales: ¿los usuarios pueden tener que arreglar su sucursal localmente?
dnozay
1

Esta es la forma más simple y 'legible' que conozco:

'Mover' sucursal local usando -m

git branch -m my_old_branch_name my_new_branch_name

Empuje la rama 'movida' al control remoto, establezca 'corriente arriba' usando -u

git push origin -u my_new_branch_name

(la configuración 'ascendente' esencialmente 'conecta' su rama local al control remoto, de modo que cosas como buscar, tirar y empujar funcionarán)

Eliminar la rama vieja del control remoto

git push origin -D <old_name>

(su sucursal local ya no está, porque la 'movió' en el primer paso)

Chris Halcrow
fuente
1

OK , cambiar el nombre de una sucursal localmente y en el control remoto es bastante fácil ...

Si está en la sucursal, puede hacer fácilmente:

git branch -m <branch>

o si no, debes hacer:

git branch -m <your_old_branch> <your_new_branch>

Luego, empuje la eliminación al control remoto de esta manera:

git push origin <your_old_branch>

Ahora que ha terminado, si obtiene un error ascendente mientras intenta presionar, simplemente haga lo siguiente:

git push --set-upstream origin <your_new_branch>

También creo la imagen a continuación para mostrar los pasos en la línea de comando real, solo siga los pasos y sería bueno:

ingrese la descripción de la imagen aquí

Alireza
fuente
0

Puede hacer lo siguiente:

git -m master master-old #rename current master
git checkout -b master   #create a new branch master
git push -f origin master #force push to master

Pero forzar el empuje es una mala idea si otras personas comparten este repositorio. El empuje forzado hará que su historial de revisiones entre en conflicto con el nuevo.

Riyafa Abdul Hameed
fuente
0

Lo siguiente se puede guardar en el script de shell para hacer el trabajo:

Por ejemplo:

remote="origin"

if [ "$#" -eq 0 ] # if there are no arguments, just quit
then
    echo "Usage: $0 oldName newName or $0 newName" >&2
    exit 1
elif
    [ "$#" -eq 1 ] # if only one argument is given, rename current branch
then 
    oldBranchName="$(git branch | grep \* | cut -d ' ' -f2)" #save current branch name
    newBranchName=$1
else
    oldBranchName=$1
    newBranchName=$2
fi

git branch -m $oldBranchName $newBranchName

git push $remote :$oldBranchName #delete old branch on remote
git push --set-upstream $remote $newBranchName # add new branch name on remote and track it

Tenga en cuenta que aquí el nombre remoto predeterminado "origen" está codificado, puede extender el script para que sea configurable.

Entonces este script se puede usar con alias bash, alias git o en, por ejemplo, acciones personalizadas de código fuente.

Do-do-new
fuente
-1

Creo que la clave es darse cuenta de que está realizando un doble cambio de nombre: masterto master-oldy master-newto to master.

De todas las otras respuestas, he sintetizado esto:

doublerename master-new master master-old

donde primero tenemos que definir la doublerenamefunción Bash:

# doublerename NEW CURRENT OLD
#   - arguments are branch names
#   - see COMMIT_MESSAGE below
#   - the result is pushed to origin, with upstream tracking info updated
doublerename() {
  local NEW=$1
  local CUR=$2
  local OLD=$3
  local COMMIT_MESSAGE="Double rename: $NEW -> $CUR -> $OLD.

This commit replaces the contents of '$CUR' with the contents of '$NEW'.
The old contents of '$CUR' now lives in '$OLD'.
The name '$NEW' will be deleted.

This way the public history of '$CUR' is not rewritten and clients do not have
to perform a Rebase Recovery.
"

  git branch --move $CUR $OLD
  git branch --move $NEW $CUR

  git checkout $CUR
  git merge -s ours $OLD -m $COMMIT_MESSAGE

  git push --set-upstream --atomic origin $OLD $CUR :$NEW
}

Esto es similar a un cambio de historial git rebaseen que el contenido de la rama es bastante diferente, pero difiere en que los clientes aún pueden avanzar de forma segura git pull master.

Martin Vidner
fuente
-5
git update-ref newref oldref
git update-ref -d oldref newref
dlamotte
fuente
2
Esto no parece funcionar para mí, obtengo: git update-ref trunk trunk2 fatal: trunk2: no es un SHA1 válido
Gregg Lind