Comment archiver des branches git?


305

J'ai quelques anciennes branches dans mon référentiel git qui ne sont plus en développement actif. Je voudrais archiver les branches afin qu'elles n'apparaissent pas par défaut lors de l'exécution git branch -l -r. Je ne veux pas les supprimer, car je veux garder l'historique. Comment puis-je faire ceci?

Je sais qu'il est possible de créer une référence en dehors des références / têtes. Par exemple refs/archive/old_branch,. Y a-t-il des conséquences à le faire?


git-rm ne supprime pas les ressources du référentiel, il les supprime uniquement de l'index kernel.org/pub/software/scm/git/docs/git-rm.html Vous pouvez facilement restaurer ces ressources à l'aide degit checkout [rev] file
Dana the Sane

1
Pas que je sache de. J'utilise des Attic/<branchname>balises légères pour archiver les branches.
Jakub Narębski

les étiquettes sont le choix rapide, sûr et sensé.
kch

Réponses:


401

Je crois que la bonne façon de procéder est de baliser la branche. Si vous supprimez la branche après l'avoir étiquetée, vous avez effectivement conservé la branche, mais cela n'encombrera pas votre liste de branches.

Si vous devez retourner à la succursale, vérifiez simplement la balise. Il restaurera efficacement la branche à partir de la balise.

Pour archiver et supprimer la branche:

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

Pour restaurer la branche un peu plus tard:

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

L'historique de la branche sera conservé exactement tel qu'il était lorsque vous l'avez taguée.


11
Je suis un débutant Git, mais en essayant cela, je pense que la commande appropriée pour restaurer la branche est:git checkout -b <branchname> archive/<branchname>
Steve

6
Y a-t-il une raison de ne pas utiliser de balise d'objet dans ce cas? Être capable de voir qui a archivé la branche et quand cela pourrait être intéressant.
Grégory Joseph

7
@ GrégoryJoseph: C'est une soi-disant "balise annotée". Et oui, utiliser cela peut avoir beaucoup de sens, je dirais.
onnodb

22
petite note, vous le voulez probablement branch -Dcar il est probable qu'il ne sera pas complètement fusionné si vous l'archivez de cette façon
Arkadiy Kukarkin

5
Très agréable. Voici un tutoriel complet avec des explications.
guyaloni

123

La réponse de Jeremy est correcte en principe, mais à mon humble avis, les commandes qu'il spécifie ne sont pas tout à fait exactes.

Voici comment archiver une branche dans une balise sans avoir à extraire la branche (et, par conséquent, sans avoir à extraire une autre branche avant de pouvoir supprimer cette branche):

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

Et voici comment restaurer une branche:

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

18
Je suppose que vous n'aviez pas encore assez de points, mais il serait préférable de simplement modifier la réponse existante - +1 quand même :)
jkp

5
@jkp éditer le code et les commandes d'autres utilisateurs est généralement mal vu car des changements subtils dans une commande git peuvent faire des choses radicalement différentes, et vous pourriez ne pas comprendre pourquoi l'auteur original a écrit quelque chose comme ils l'ont fait. il vaut mieux faire votre propre réponse ou laisser un commentaire.
Dan Bechard

Ou pire encore que des choses radicalement différentes, un changement subtil dans les commandes ou le code pourrait conduire à des résultats subtilement différents, ce qui pourrait être très difficile à comprendre, je suggérerais de laisser un commentaire afin que l'affiche de la réponse puisse s'éditer ou répondre avec une demande reconventionnelle faisant référence aux résultats potentiellement différents (lesquels de telles demandes reconventionnelles sont plutôt courants)
Nicholas Pipitone

22

Oui, vous pouvez créer une référence avec un préfixe non standard en utilisant git update-ref. par exemple

  • Archiver la branche: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Restaurez la branche (si nécessaire): git branch topic refs/archive/old-topic

Les références avec un préfixe non standard (ici refs/archive) n'apparaîtront pas comme d'habitude git branch, git logni git tag. Pourtant, vous pouvez les répertorier avec git for-each-ref.

J'utilise les alias suivants:

[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

En outre, vous souhaiterez peut-être configurer des télécommandes, comme push = +refs/archive/*:refs/archive/*pousser automatiquement les branches archivées (ou git push origin refs/archive/*:refs/archive/*pour une seule fois).

Une autre façon consiste à écrire SHA1 quelque part avant de supprimer la branche, mais elle a ses limites. Les engagements sans aucune référence seront GC'd après 3 mois (ou quelques semaines sans reflog) , sans parler du manuel git gc --prune. Les commits pointés par les références sont à l'abri du GC.

Edit: Trouvé une implémentation perl de la même idée par @ap :git-attic

Edit ^ 2: Trouvé un article de blog où Gitster lui-même utilise la même technique.


3
Excellent, à part tout le monde sur ce sujet, vous avez effectivement répondu à la question.
tzrlk

20

En étendant la réponse de Steve pour refléter les changements sur la télécommande, je l'ai fait

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

Pour restaurer à partir de la télécommande, consultez cette question .


18

Vous pouvez archiver les branches dans un autre référentiel. Pas tout à fait aussi élégant, mais je dirais que c'est une alternative viable.

git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch

4
Vous pouvez créer git-bundleau lieu d'un référentiel séparé.
Jakub Narębski

9

Voici un alias pour cela:

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

Ajoutez-le comme ceci:

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

Gardez à l'esprit qu'il y a git archive déjà une commande, vous ne pouvez donc pas utiliserarchive comme nom d'alias.

Vous pouvez également définir un alias pour afficher la liste des branches «archivées»:

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

sur l'ajout d'alias


3
Avec les versions plus récentes de git (comme suggéré ici ), cet alias donne l'achèvement:!git tag archive/$1 $1 && git branch -D
Lack

5

J'utilise les alias suivants pour masquer les branches archivées:

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

Donc, git brpour montrer les branches développées activement et git brapour montrer toutes les branches, y compris celles "archivées" .


5
Si une branche a été fusionnée en master n'a rien à voir avec son état d'archivage. Par exemple, dans mon équipe de développement, nous avons quelques branches qui ont été créées spécifiquement pour tester des choses. Nous voulons conserver ces branches dans nos archives, mais nous ne voulons certainement pas les fusionner dans master.
Bart

4

Je n'archiverais pas de succursales. Autrement dit, les succursales s'archivent. Ce que vous voulez, c'est vous assurer que les informations pertinentes pour les archéologues peuvent être trouvées par des moyens fiables. Fiable dans la mesure où il facilite le développement quotidien et n'ajoute pas d'étape supplémentaire au processus de réalisation du travail. Autrement dit, je ne pense pas que les gens se souviendront d'ajouter une balise une fois qu'ils auront terminé avec une branche.

Voici deux étapes simples qui aideront grandement l'archéologie et le développement.

  1. Liez chaque branche de tâche à un problème associé dans le suivi des problèmes à l'aide d'une convention de dénomination simple .
  2. Utilisez toujours git merge --no-ffpour fusionner les branches de tâches; vous voulez que le commit de fusion et la bulle historique, même pour un seul commit.

C'est tout. Pourquoi? Parce qu'en tant qu'archéologue du code, je commence rarement par vouloir savoir quel travail a été effectué sur une branche. Bien plus souvent, c'est pourquoi dans tous les neuf hurlements, le code est écrit de cette façon?!Je dois changer le code, mais il a des fonctionnalités étranges, et je dois les énigmer pour éviter de casser quelque chose d'important.

La prochaine étape est git blame à rechercher les validations associées et à espérer que le message du journal soit explicatif. Si j'ai besoin de creuser plus profondément, je vais savoir si le travail a été effectué dans une branche et lire la branche dans son ensemble (avec ses commentaires dans le tracker de problème).

Disons des git blamepoints à valider XYZ. J'ouvre un navigateur d'historique Git (gitk, GitX,, git log --decorate --graphetc ...), trouve commit XYZ et vois ...

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

Voilà ma branche! Je sais que QQ, UU, XYZ, JJ et MM font tous partie de la même branche et je devrais consulter leurs messages de journal pour plus de détails. Je sais que GG sera un commit de fusion et aura le nom de la branche qui, espérons-le, est associée à un problème dans le tracker.

Si, pour une raison quelconque, je souhaite trouver une ancienne branche, je peux l'exécuter git loget rechercher le nom de la branche dans le commit de fusion. Il est assez rapide même sur de très grands référentiels.

C'est ce que je veux dire quand je dis que les succursales s'archivent elles-mêmes.

Le balisage de chaque branche ajoute un travail inutile pour faire avancer les choses (un processus critique qui devrait être impitoyablement rationalisé), résume la liste des balises (sans parler des performances, mais de la lisibilité humaine) avec des centaines de balises qui ne sont utiles que très occasionnellement, et qui ne sont pas '' t même très utile pour l'archéologie.


2
Mais qu'en est-il du désordre? Peut-être s'il y avait un moyen de cacher les vieilles branches sous 10 mètres cubes de terre.
bvj

1
C'est utile, mais cela ne s'applique pas aux branches non fusionnées. Parfois, une expérience a été effectuée sur une branche et vous souhaitez conserver le contenu au cas où une partie deviendrait utile plus tard.
Neil Mayhew

1
@bvj Je pense que cette réponse suggère que vous devez toujours supprimer les branches fusionnées, car vous pouvez toujours y revenir via le commit de fusion. Je suis d'accord avec ça.
Neil Mayhew

@NeilMayhew Oui, j'ai moi-même environ 10 succursales non fusionnées qui s'ouvrent. Chacun est associé à une tâche ouverte afin que je puisse me souvenir de ce que je faisais. Soit je fais quelque chose avec eux, soit ils deviennent tellement obsolètes qu'ils ne sont plus pertinents et je les supprime. J'ai travaillé sur un projet complètement noyé dans des branches "j'en aurais peut-être besoin plus tard" pour que nous puissions à peine voir ce que nous faisions. C'était vraiment une excuse pour certains développeurs de ne pas avoir à nettoyer après eux-mêmes. Un peu de latitude, c'est bien, mais ne le laissez pas devenir incontrôlable.
Schwern

@Schwern, je suis d'accord. J'ai aussi été sur des projets comme ça. Je pense que la conversion des branches en balises est un bon moyen de se débarrasser de l'encombrement, car la liste des balises va toujours augmenter alors que la liste des branches ne devrait pas (car elle représente la quantité de travail en cours). L'utilisation de l'espace de noms pour les balises rend la liste plus facile à gérer, mais il faut absolument résister aux tendances packrat. Un développeur doit conserver les validations sur sa propre machine, sauf s'il y a de fortes chances que quelqu'un d'autre les utilise éventuellement.
Neil Mayhew

2

Mon approche consiste à renommer toutes les branches dont je ne me soucie pas avec un préfixe "trash_", puis à utiliser:

git branch | grep -v trash

(avec une liaison de touches shell)

Pour conserver la coloration de la branche active, il faudrait:

git branch --color=always | grep --color=never --invert-match trash

2
Si vous renommez des branches, vous pourriez aussi bien les mettre dans un espace de noms "archive /"
qneill

1

Vous pouvez utiliser un script qui archivera la branche pour vous

archbranch

Il crée une balise pour vous avec l'archive de préfixe / puis supprime la branche. Mais vérifiez le code avant de l'utiliser.


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

Si vous souhaitez exécuter le script sans y écrire l'emplacement, ajoutez-le à votre chemin

Ensuite, vous pouvez l'appeler par

$ archbranch [branchname] [defaultbranch]

C'est [defaultbranch]la branche vers laquelle il ira lorsque l'archivage sera terminé. Il y a quelques problèmes avec le codage couleur mais d'autres alors qu'il devrait fonctionner. Je l'utilise depuis longtemps dans des projets, mais il est encore en développement.


1
Par Stack Overflow Help , vous devez divulguer votre affiliation avec votre produit.
LittleBobbyTables - Au Revoir

Oh, désolé, je ne savais pas. Je suis l'auteur du script.
Banezaka

0

J'archive parfois des branches comme suit:

  1. Générez des fichiers de patch, par exemple, format-patch <branchName> <firstHash>^..<lastHash>(obtenez firstHash et lastHash en utilisant git log <branchName>.
  2. Déplacez les fichiers de correctifs générés vers un répertoire sur un serveur de fichiers.
  3. Supprimez la branche, par exemple, git branch -D <branchName>

"Appliquez" le patch lorsque vous devez réutiliser la branche; cependant, l'application des fichiers de correctifs (voir git am) peut être difficile en fonction de l'état de la branche cible. Sur le plan positif, cette approche a l'avantage de permettre aux commits de la branche d'être récupérés et d'économiser de l'espace dans votre référentiel.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.