¿Cómo puedo archivar ramas git?

305

Tengo algunas ramas viejas en mi repositorio git que ya no están en desarrollo activo. Me gustaría archivar las ramas para que no se muestren de forma predeterminada cuando se ejecutan git branch -l -r. No quiero eliminarlos, porque quiero mantener el historial. ¿Cómo puedo hacer esto?

Sé que es posible crear una referencia fuera de referencias / cabezas. Por ejemplo, refs/archive/old_branch. ¿Hay alguna consecuencia de hacer eso?

dan-manges
fuente
git-rm no elimina recursos del repositorio, solo los elimina del índice kernel.org/pub/software/scm/git/docs/git-rm.html Puede restaurar fácilmente estos recursos usandogit checkout [rev] file
Dana the Sane
1
No que yo sepa. Sin Attic/<branchname>embargo, uso etiquetas livianas para archivar ramas.
Jakub Narębski
Las etiquetas son la opción rápida, segura y sensata.
kch

Respuestas:

401

Creo que la forma correcta de hacer esto es etiquetar la rama. Si elimina la rama después de haberla etiquetado, entonces efectivamente la ha mantenido pero no saturará su lista de ramas.

Si necesita volver a la sucursal, simplemente revise la etiqueta. Efectivamente restaurará la rama de la etiqueta.

Para archivar y eliminar la sucursal:

git tag archive/<branchname> <branchname>
git branch -d <branchname>

Para restaurar la rama algún tiempo después:

git checkout -b <branchname> archive/<branchname>

La historia de la rama se conservará exactamente como estaba cuando la etiquetó.

Jeremy Wall
fuente
11
Soy un novato Git, pero al tratar de esto, creo que el comando adecuado para la restauración de la rama es:git checkout -b <branchname> archive/<branchname>
Steve
66
¿Hay alguna razón para no usar una etiqueta de objeto en este caso? Poder ver quién archivó la sucursal y cuándo podría ser interesante.
Grégory Joseph
77
@ GrégoryJoseph: Esa es una llamada "etiqueta anotada". Y sí, usar eso puede tener mucho sentido, diría.
onnodb
22
pequeña nota, es probable que desee, branch -Dya que es probable que no se fusione por completo si lo archiva de esta manera
Arkadiy Kukarkin
55
Muy agradable. Aquí hay un tutorial completo con explicaciones.
guyaloni
123

La respuesta de Jeremy es correcta en principio, pero en mi humilde opinión los comandos que especifica no son del todo correctos.

Aquí se explica cómo archivar una rama en una etiqueta sin tener que pagar la rama (y, por lo tanto, sin tener que pagar con otra rama antes de poder eliminar esa rama):

> git tag archive/<branchname> <branchname>
> git branch -D <branchname>

Y aquí está cómo restaurar una rama:

> git checkout -b <branchname> archive/<branchname>
Steve
fuente
18
Supongo que todavía no tenía suficientes puntos, pero sería mejor cuando solo editara la respuesta existente, aunque de todos modos :)
jkp
55
@jkp editar el código y los comandos de otros usuarios generalmente está mal visto porque los cambios sutiles en un comando git pueden hacer cosas drásticamente diferentes, y es posible que no entiendas por qué el autor original escribió algo de la manera en que lo hizo. es mejor hacer su propia respuesta o dejar un comentario.
Dan Bechard
O incluso peor que cosas drásticamente diferentes, un cambio sutil en los comandos o el código podría conducir a resultados sutilmente diferentes, lo que podría ser realmente difícil de entender, sugeriría dejarlo como un comentario para que el afiche de la respuesta pueda editarse o responder con una contrademanda que hace referencia a los resultados potencialmente diferentes (que tales contrademandas son bastante comunes)
Nicholas Pipitone
22

Sí, puede crear una referencia con algún prefijo no estándar usando git update-ref. p.ej

  • Archivar la sucursal: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Restaurar la rama (si es necesario): git branch topic refs/archive/old-topic

Las referencias con prefijo no estándar (aquí refs/archive) no se mostrarán de la forma habitual git branch, git logni git tag. Aún así, puedes enumerarlos con git for-each-ref.

Estoy usando los siguientes alias:

[alias]
    add-archive = "!git update-ref refs/archive/$(date '+%Y%m%d-%s')"
    list-archive = for-each-ref --sort=-authordate --format='%(refname) %(objectname:short) %(contents:subject)' refs/archive/
    rem = !git add-archive
    lsrem = !git list-archive

Además, es posible que desee configurar controles remotos como push = +refs/archive/*:refs/archive/*empujar ramas archivadas automáticamente (o git push origin refs/archive/*:refs/archive/*para una sola vez).

Otra forma es escribir SHA1 en algún lugar antes de eliminar una rama, pero tiene limitaciones. Los commits sin ningún tipo de referencia serán sometidos a GC después de 3 meses (o un par de semanas sin registro) , y mucho menos el manual git gc --prune. Los compromisos señalados por los árbitros están a salvo de GC.

Editar: Encontramos una implementación perl de la misma idea por @ap :git-attic

Editar ^ 2: Encontré una publicación de blog donde el mismo Gitster usa la misma técnica.

snipsnipsnip
fuente
3
Excelente, aparte de todos los demás en este hilo, realmente respondiste la pregunta.
tzrlk
20

Extendiendo la respuesta de Steve para reflejar los cambios en el control remoto, hice

 git tag archive/<branchname> <branchname>
 git branch -D <branchname>
 git branch -d -r origin/<branchname>
 git push --tags
 git push origin :<branchname>

Para restaurar desde el control remoto, vea esta pregunta .

Liam
fuente
18

Puede archivar las ramas en otro repositorio. No es tan elegante, pero diría que es una alternativa viable.

git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch
August Lilleaas
fuente
44
Puede crear en git-bundlelugar de un repositorio separado.
Jakub Narębski
9

Aquí hay un alias para eso:

arc    = "! f() { git tag archive/$1 $1 && git branch -D $1;}; f"

Añádelo así:

git config --global alias.arc '! f() { git tag archive/$1 $1 && git branch -D $1;}; f'

Tenga en cuenta que ya hay un git archivecomando, por lo que no puede usarlo archivecomo nombre de alias.

También puede definir un alias para ver la lista de las ramas 'archivadas':

arcl   = "! f() { git tag | grep '^archive/';}; f"

acerca de agregar alias

Alexey
fuente
3
Con versiones más nuevas de git (como se sugiere aquí ), este alias se completa:!git tag archive/$1 $1 && git branch -D
Falta el
5

Estoy usando los siguientes alias para ocultar ramas archivadas:

[alias]
    br = branch --no-merge master # show only branches not merged into master
    bra = branch                  # show all branches

Para git brmostrar ramas desarrolladas activamente y git brapara mostrar todas las ramas, incluidas las "archivadas" .

Pitr
fuente
55
Si una rama se ha fusionado con master no tiene nada que ver con su estado de archivo. Por ejemplo, en mi equipo de desarrollo tenemos algunas ramas que fueron creadas específicamente para probar cosas. Queremos mantener esas ramas en nuestro archivo, pero definitivamente no queremos fusionarlas en master.
Bart
4

No archivaría sucursales. Dicho de otra manera, las sucursales se archivan a sí mismas. Lo que desea es asegurarse de que la información relevante para los arqueólogos se pueda encontrar por medios confiables. Confiables en que ayudan al desarrollo diario y no agregan un paso adicional al proceso de hacer el trabajo. Es decir, no creo que las personas recuerden agregar una etiqueta una vez que hayan terminado con una rama.

Aquí hay dos pasos simples que ayudarán en gran medida a la arqueología y el desarrollo.

  1. Enlace cada rama de tarea con un problema asociado en el rastreador de problemas utilizando una convención de nomenclatura simple .
  2. Siempre se usa git merge --no-ffpara fusionar ramas de tareas; desea esa burbuja de compromiso e historial de fusión, incluso para un solo compromiso.

Eso es. ¿Por qué? Porque como arqueólogo de códigos, rara vez empiezo con querer saber qué trabajo se realizó en una sucursal. ¡Mucho más a menudo es por qué en todos los nueve infiernos gritos se escribe el código de esta manera? Necesito cambiar el código, pero tiene algunas características extrañas, y necesito descifrarlas para evitar romper algo importante.

El siguiente paso es git blameencontrar las confirmaciones asociadas y luego esperar que el mensaje de registro sea explicativo. Si necesito profundizar más, averiguaré si el trabajo se realizó en una rama y leeré la rama en su conjunto (junto con sus comentarios en el rastreador de problemas).

Digamos git blamepuntos en commit XYZ. Abro un navegador de historial de Git (gitk, GitX git log --decorate --graph, etc.), encuentro commit XYZ y veo ...

AA - BB - CC - DD - EE - FF - GG - II ...
     \                       /
      QQ - UU - XYZ - JJ - MM

Ahí está mi rama! Sé que QQ, UU, XYZ, JJ y MM son parte de la misma rama y debería consultar sus mensajes de registro para obtener más detalles. Sé que GG será un commit de fusión y tendrá el nombre de la rama que, con suerte, está asociada con un problema en el rastreador.

Si, por alguna razón, quiero encontrar una rama vieja que puedo ejecutar git logy buscar el nombre de la rama en la confirmación de fusión. Es lo suficientemente rápido incluso en repositorios muy grandes.

A eso me refiero cuando digo que las ramas se archivan a sí mismas.

Etiquetar cada rama agrega un trabajo innecesario para hacer las cosas (un proceso crítico que debería simplificarse sin piedad), engulle la lista de etiquetas (sin hablar de rendimiento, sino de legibilidad humana) con cientos de etiquetas que solo ocasionalmente son útiles, y no es Incluso muy útil para la arqueología.

Schwern
fuente
2
¿Pero qué hay del desorden? Quizás si hubiera una manera de ocultar las viejas ramas bajo 10 yardas cúbicas de tierra.
bvj
1
Esto es útil, pero no es aplicable a las ramas no fusionadas. A veces, se realizó un experimento en una rama y desea conservar el contenido en caso de que algo se vuelva útil más adelante.
Neil Mayhew
1
@bvj Creo que esta respuesta sugiere que siempre debe eliminar las ramas fusionadas, porque siempre puede volver a ellas a través de la confirmación de fusión. Estoy de acuerdo con ésto.
Neil Mayhew
@NeilMayhew Sí, tengo unas 10 ramas no fusionadas como esa que me abrí. Cada uno está asociado con una tarea abierta para que pueda recordar lo que estaba haciendo. Haré algo con ellos o quedarán tan desactualizados que ya no serán relevantes y los eliminaré. Trabajé en un proyecto que se ahogaba completamente en las ramas "Podría necesitarlo más tarde" para que apenas pudiéramos ver lo que estábamos haciendo. Fue realmente una excusa para algunos desarrolladores no tener que limpiar después de ellos mismos. Un poco de margen está bien, pero no dejes que se salga de control.
Schwern
@Schwern Estoy de acuerdo. He estado en proyectos como ese también. Creo que convertir las ramas en etiquetas es una buena manera de deshacerse del desorden, porque la lista de etiquetas siempre va a crecer, mientras que la lista de ramas no debería (porque representa la cantidad de trabajo que está en curso). El uso del espacio de nombres para las etiquetas hace que la lista sea más manejable, pero las tendencias de packrat definitivamente deben ser resistidas. Un desarrollador debe retener los commits en su propia máquina a menos que haya una buena posibilidad de que alguien más los use eventualmente.
Neil Mayhew
2

Mi enfoque es renombrar todas las ramas que no me importan con un prefijo "trash_", luego usar:

git branch | grep -v trash

(con un enlace de tecla de shell)

Para retener el color de la rama activa, uno necesitaría:

git branch --color=always | grep --color=never --invert-match trash
Sridhar Sarnobat
fuente
2
Si cambia el nombre de las ramas, también podría colocarlas en un "archivo /" de espacio de nombres
qneill
1

Puede usar un script que archivará la rama por usted

ramillete

Crea una etiqueta para usted con el archivo de prefijos / y luego elimina la rama. Pero revise el código antes de usarlo.


Uso - $/your/location/of/script/archbranch [branchname] [defaultbranch]

Si desea ejecutar el script sin escribir la ubicación, agréguelo a su ruta

Entonces puedes llamarlo por

$ archbranch [branchname] [defaultbranch]

La [defaultbranch]es la rama a la que irá cuando finalice el archivado. Hay algunos problemas con la codificación de colores, pero otros no deberían funcionar. Lo he estado usando en proyectos durante mucho tiempo, pero todavía está en desarrollo.

Banezaka
fuente
1
Por ayuda de desbordamiento de pila , debe divulgar su afiliación con su producto.
LittleBobbyTables - Au Revoir
Oh, lo siento, no lo sabía. Soy el autor del guión.
Banezaka
0

A veces archivo sucursales de la siguiente manera:

  1. Genere archivos de parche, por ejemplo, format-patch <branchName> <firstHash>^..<lastHash>(obtenga firstHash y lastHash usando git log <branchName>.
  2. Mueva los archivos de parche generados al directorio en un servidor de archivos.
  3. Eliminar la rama, por ejemplo, git branch -D <branchName>

"Aplique" el parche cuando necesite usar la rama nuevamente; sin embargo, aplicar los archivos de parche (ver git am) puede ser un desafío dependiendo del estado de la rama de destino. En el lado positivo, este enfoque tiene la ventaja de permitir que los compromisos de la sucursal se recolecten como basura y ahorre espacio en su repositorio.

Bill Hoag
fuente