Cambiar de rama de Git sin pago de archivos

100

¿Es posible en Git cambiar a otra rama sin verificar todos los archivos?

Después de cambiar de rama, necesito eliminar todos los archivos, regenerarlos, confirmar y volver a cambiar. Por lo tanto, retirar archivos es solo una pérdida de tiempo (y hay alrededor de 14.000 archivos; es una operación larga).

Para dejarlo todo claro:

Necesito todo esto para cargar la documentación en GitHub.

Tengo un repositorio con la rama gh-pages . Cuando reconstruyo la documentación localmente, la copio al directorio del repositorio, la confirmo y la envío a GitHub. Pero no estaba contento, porque tenía dos copias de documentación localmente. Y decidí crear una rama vacía y después de comprometerme, cambiar a vacía y eliminar archivos. Pero volver a cambiar es una operación larga, así que hice esta pregunta.

Sé que puedo dejar la rama gh-pages y eliminar archivos, pero no me gustan los árboles de trabajo sucio.

tig
fuente
¿Cuánto tiempo es "largo" para ti? ¿En qué plataforma estás trabajando? ¿Está trabajando en una red como NFS u otro intercambio de archivos?
Greg Hewgill
¿Cuál es el propósito de este ejercicio? ¿Desea tener dos ramas, una con confirmaciones detalladas, la segunda que registre solo los cambios importantes (de grano grueso)?
Jakub Narębski
Quizás sea más económico crear un clon temporal (¿o permanente?) De su copia de trabajo. Mi respuesta relacionada y un artículo muestran cómo funciona esto incluso como un subdirectorio del repositorio principal.
krlmlr

Respuestas:

106

Sí, usted puede hacer esto.

git symbolic-ref HEAD refs/heads/otherbranch

Si necesita confirmar en esta rama, también querrá restablecer el índice, de lo contrario, terminará cometiendo algo basado en la última rama extraída.

git reset
CB Bailey
fuente
1
Use echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADseguido de git resetpara señalar una referencia en lugar de una rama.
cadorn
1
Escribir directamente en el archivo HEAD es menos confiable. ¿Qué pasa si estás en un subdirectorio? Para la cabeza separada (la cabeza apuntando directamente a SHA1), intente esto: git update-ref HEAD refs/heads/otherbranch
Alexander Bird
2
Si desea realizar el check-out en una sucursal nueva de la sucursal actual, otra forma de hacerlo es 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny
@AlexanderBird: git update-refes útil, pero también mueve la punta de la rama actual.
tomekwi
47

Usando solo comandos básicos de git:

Esta respuesta es un poco más larga que la de Charles, pero consiste únicamente en comandos básicos de git que puedo entender y así recordar, eliminando la necesidad de seguir buscándola.

Marque su ubicación actual (confirme primero si es necesario):

git checkout -b temp

Reinicia (mueve) el marcador a la otra rama sin cambiar el directorio de trabajo:

git reset <branch where you want to go>

ahora temp y otra rama apuntan a la misma confirmación, y su directorio de trabajo está intacto.

git checkout <branch where you want to go>

dado que su HEAD ya apunta a la misma confirmación, el directorio de trabajo no se toca

git branch -d temp

Tenga en cuenta que estos comandos también están disponibles desde cualquier cliente gráfico.


fuente
7
Preferiría git reset --soft <branch where you want to go>evitar actualizar el índice
JoelFan
7
Estoy de acuerdo con su estrategia de evitar los comandos de plomería de git y favorecer los de porcelana.
user64141
26

En v2.24 git switches algo así como una caja fuerte git checkout.
Por lo tanto, cambié el nombre del alias a continuación git hoppara
"saltar a la rama sin cambiar el árbol de trabajo"

Para beneficio del lector:

Si bien creo que la solución de Charles Bailey es correcta, esta solución necesita un ajuste al cambiar a algo, que no es una sucursal local. También debería haber alguna forma de cómo hacerlo con comandos regulares que sea fácil de entender. Esto es lo que se me ocurrió:

git checkout --detach
git reset --soft commitish
git checkout commitish

Explicado:

  • git checkout --detaches el mismo git checkout HEAD^{}que deja atrás la rama actual y entra en "estado de cabeza separada". Entonces, la próxima modificación de HEADno más afecta a ninguna rama. Extracción HEADno afecta a la worktree ni el índice.
  • git reset --soft commitishluego pasa HEADal SHA de lo dado commitish. Si también desea actualizar el índice, déjelo --soft, pero no recomiendo hacerlo. Esto, de nuevo, no toca el árbol de trabajo y ( --soft) no el índice.
  • git checkout commitishluego se une HEADa la commitish(rama) dada nuevamente. (Si commitishes un SHA, no pasa nada). Esto tampoco afecta al índice ni al árbol de trabajo.

Esta solución acepta todo lo que se refiere a un compromiso, por lo que es ideal para algunos gitalias. Lo rev-parsesiguiente es solo una prueba para asegurarse de que nada se rompa en la cadena, de modo que los errores tipográficos no cambien accidentalmente al estado de la cabeza separada (la recuperación de errores sería mucho más compleja).

Esto conduce al siguiente git hop treeishalias:

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

Para su información, puede encontrarlo en mi lista de gitalias .

Tino
fuente
¿No quieres usar en $@lugar de $*? La diferencia es que $ @ sin expandir los argumentos entre comillas, que tienen espacios dentro.
kyb
1
@kyb El truco de la función se roba de otra respuesta SO . Y $@definitivamente no se refiere aquí. $*se usa en lugar de $1, de modo que se git switch -f bconvierta en lo mismo git switch '-f b'que debería ser un error. De esta manera puedo acortar el alias dejando de lado algunos errores de manejo como!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino
Muy buena solucion. ¡Especialmente, que se puede usar para sucursales remotas!
Nils-o-mat
14

¿No sería una mejor solución tener dos directorios de trabajo (dos áreas de trabajo) con un repositorio, o incluso dos repositorios?

Hay una herramienta git-new-workdir en la contrib/sección para ayudarlo con esto.

Jakub Narębski
fuente
¿Es git-new-workdir lo mismo que el propio comando de árbol de trabajo de git? Utilizo worktree cuando quiero retirar una rama en una carpeta diferente (sin tener que clonar todo el repositorio).
Ryuu
La git-new-worktreesecuencia de comandos es anterior al git worktreesubcomando; este comando no estaba disponible cuando se escribió la respuesta. El script, por ejemplo, requiere soporte de enlace simbólico; En mi humilde opinión, es mejor utilizar soporte nativo.
Jakub Narębski
8

Creo que estás buscando el comando de plomería git read-tree. Esto actualizará el índice pero no actualizará ningún archivo en su directorio de trabajo. Por ejemplo, asumiendo que branches el nombre de la rama a leer:

rama de árbol de lectura de git

Si desea luego comprometerse con la rama que acaba de leer, también deberá:

git simbólico-ref HEAD refs / cabezas / rama
Greg Hewgill
fuente
no, solo necesito cambiar de rama, sin ningún otro cambio, por lo que la referencia simbólica es lo suficientemente buena
tig
read-treegenera el error: fatal: Not a valid object name branchsi no había ninguno git switch branchtodavía
Andry
7

Puede sobrescribir su archivo HEAD con un nombre de rama diferente:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD

usuario157005
fuente
13
Probablemente sea mejor utilizar el comando symbolic-ref para hacer esto por usted: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill
@GregHewgill, esta es la única forma que conozco de mover HEAD a un hash de confirmación. ¿Puedes hacer eso con git symbolic-ref?
tomekwi
0

Con tantos archivos, puede que sea mejor mantener dos repositorios, uno para cada rama. Puede realizar cambios hacia adelante y hacia atrás según sea necesario. Esto va a ser menos sorprendente que intentar jugar una mala pasada con git.

Norman Ramsey
fuente
Puede usar git-new-worktreepara eso en su lugar (en contrib/)
Jakub Narębski
A menudo hice algo similar, que es copiar mi directorio local antes de hacer "cosas de git aterradoras" como novato (como cambiar de rama, etc.). Animaría a las personas a que sigan ese camino hasta que se sienta seguro de su git-fu, pero que se alejen de él cuando sea posible. Mantener dos repositorios distintos está bien, pero agrega una capa de complicación y no le permite aprovechar las muchas funciones útiles de git (fusión, selección, etc.).
David
0

Si simplemente está intentando cambiar dónde apunta una rama remota, puede hacerlo con "git push" sin tocar su copia local.

http://kernel.org/pub/software/scm/git/docs/git-push.html

El formato de un parámetro <refspec> es un signo más + opcional, seguido de la referencia de origen <src>, seguido de dos puntos:, seguido de la referencia de destino <dst>. Se utiliza para especificar con qué objeto <src> se actualizará la referencia <dst> en el repositorio remoto.

por ejemplo, para actualizar foo para confirmar c5f7eba, haga lo siguiente:

git push origin c5f7eba:foo

No estoy seguro de si eso es lo que buscabas o no.

Tim Abell
fuente
La pregunta ya tiene una respuesta: stackoverflow.com/questions/1282639/…
tig
0

puedes hacer uso de

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

previous-branch-commit-id es la confirmación desde donde desea copiar los datos antiguos.

Haseena Parkar
fuente
0

O simplemente use un archivo de parche para parchear desde su otra rama a su maestro

git diff otherbranch master > ~/tmp/otherbranch.diff
git checkout master
git apply ~/tmp/otherbranch.diff
Tomer Ben David
fuente
-1

Diga que quiere estar en la rama A, pero con los archivos de la rama B

encuentre la referencia de confirmación actual de la rama A con git log, por ejemplo, "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

ahora debería estar en la rama A, con una estructura de carpetas correspondiente a B, que se muestran como cambios sin etapas (un historial no ha cambiado).

Dugas
fuente