Come posso archiviare i rami git?


305

Ho alcuni vecchi rami nel mio repository git che non sono più in fase di sviluppo attivo. Vorrei archiviare i rami in modo che non vengano visualizzati per impostazione predefinita durante l'esecuzionegit branch -l -r . Non voglio eliminarli, perché voglio conservare la cronologia. Come posso fare questo?

So che è possibile creare un riferimento al di fuori di riferimenti / teste. Ad esempio refs/archive/old_branch,. Ci sono delle conseguenze nel farlo?


git-rm non elimina le risorse dal repository, le rimuove solo dall'indice kernel.org/pub/software/scm/git/docs/git-rm.html Puoi facilmente ripristinare queste risorse usandogit checkout [rev] file
Dana the Sane

1
Non che io sappia. Uso Attic/<branchname>tag leggeri per archiviare i rami, però.
Jakub Narębski,

i tag sono la scelta rapida, sicura e sana.
kch

Risposte:


401

Credo che il modo corretto per farlo sia etichettare il ramo. Se elimini il ramo dopo averlo taggato, hai effettivamente tenuto il ramo intorno ma non ingombrerà l'elenco dei rami.

Se devi tornare alla filiale, dai un'occhiata al tag. Ripristinerà efficacemente il ramo dal tag.

Per archiviare ed eliminare il ramo:

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

Per ripristinare il ramo qualche tempo dopo:

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

La storia del ramo verrà preservata esattamente come quando l'hai taggata.


11
Sono un principiante Git, ma nel provare questo, penso che il comando corretto per ripristinare il ramo sia:git checkout -b <branchname> archive/<branchname>
Steve

6
C'è qualche motivo per non usare un tag oggetto in questo caso? Essere in grado di vedere chi ha archiviato il ramo e quando potrebbe essere interessante.
Grégory Joseph,

7
@ GrégoryJoseph: è un cosiddetto "tag annotato". E sì, usarlo può avere molto senso, direi.
onnodb,

22
piccola nota, probabilmente lo vorrai branch -Ddal momento che è probabile che non si
fonda

5
Molto bella. Ecco un tutorial completo con spiegazioni.
Guyaloni,

123

La risposta di Jeremy è corretta in linea di principio, ma IMHO i comandi che specifica non sono del tutto giusti.

Ecco come archiviare un ramo in un tag senza dover effettuare il checkout del ramo (e, quindi, senza dover effettuare il checkout in un altro ramo prima di poter eliminare quel ramo):

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

Ed ecco come ripristinare un ramo:

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

18
Immagino che non avessi ancora abbastanza punti, ma sarebbe meglio quando lo fai solo per modificare la risposta esistente - +1 comunque comunque :)
jkp

5
La modifica di @jkp al codice e ai comandi di altri utenti è solitamente disapprovata perché sottili cambiamenti in un comando git possono fare cose drasticamente diverse e potresti non capire perché l'autore originale abbia scritto qualcosa nel modo in cui lo hanno fatto. meglio fare la tua risposta o lasciare un commento.
Dan Bechard,

O anche peggio di cose drasticamente diverse, un sottile cambiamento nei comandi o nel codice potrebbe portare a risultati leggermente diversi, che potrebbero essere davvero difficili da capire, suggerirei di lasciare un commento in modo che il poster della risposta possa modificarsi o rispondere con una domanda riconvenzionale che fa riferimento a risultati potenzialmente diversi (che sono piuttosto comuni)
Nicholas Pipitone,

22

Sì, è possibile creare un riferimento con un prefisso non standard utilizzando git update-ref. per esempio

  • Archivia il ramo: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Ripristina il ramo (se necessario): git branch topic refs/archive/old-topic

I riferimenti con prefisso non standard (qui refs/archive) non verranno visualizzati come al solito git branch, git loggit tag. Tuttavia, puoi elencarli con git for-each-ref.

Sto usando i seguenti 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

Inoltre, potresti voler configurare telecomandi come push = +refs/archive/*:refs/archive/*spingere i rami archiviati automaticamente (o git push origin refs/archive/*:refs/archive/*per uno scatto).

Un altro modo è scrivere SHA1 da qualche parte prima di eliminare il ramo, ma ha dei limiti. Gli impegni senza alcun riferimento verranno eseguiti dopo 3 mesi (o un paio di settimane senza reflog) , per non parlare del manuale git gc --prune. Gli commit indicati dagli ref sono al sicuro da GC.

Modifica: trovata un'implementazione perl della stessa idea di @ap :git-attic

Modifica ^ 2: trovato un post sul blog in cui Gitster stesso utilizza la stessa tecnica.


3
Eccellente, a parte tutti gli altri su questo thread, hai effettivamente risposto alla domanda.
tzrlk,

20

Ho fatto l' estensione della risposta di Steve per riflettere le modifiche sul telecomando

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

Per ripristinare dal telecomando, vedere questa domanda .


18

È possibile archiviare i rami in un altro repository. Non altrettanto elegante, ma direi che è una valida alternativa.

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

4
È possibile creare git-bundleinvece di repository separato.
Jakub Narębski,

9

Ecco un alias per questo:

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

Aggiungilo così:

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

Tieni presente che esiste git archivegià un comando, quindi non puoi usarlo archivecome nome alias.

Inoltre è possibile definire un alias per visualizzare l'elenco dei rami 'archiviati':

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

sull'aggiunta di alias


3
Con le versioni più recenti di git (come suggerito qui ), questo alias fornisce il completamento:!git tag archive/$1 $1 && git branch -D
Mancanza del

5

Sto usando i seguenti alias per nascondere i rami archiviati:

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

Quindi git brper mostrare rami sviluppati attivamente e git braper mostrare tutti i rami compresi quelli "archiviati" .


5
Il fatto che un ramo sia stato unito in master non ha nulla a che fare con il suo stato di archivio. Ad esempio, nel mio team di sviluppo abbiamo alcuni rami creati appositamente per testare le cose. Vogliamo mantenere quei rami nel nostro archivio, ma sicuramente non vogliamo unirli in master.
Bart,

4

Non archiverei i rami. In altre parole, i rami si archiviano da soli. Quello che vuoi è garantire che le informazioni rilevanti per gli archeologi possano essere trovate con mezzi affidabili. Affidabili in quanto aiutano lo sviluppo quotidiano e non aggiungono un ulteriore passo al processo di completamento del lavoro. Cioè, non credo che la gente ricorderà di aggiungere un tag una volta che hanno finito con un ramo.

Ecco due semplici passaggi che aiuteranno notevolmente l'archeologia e lo sviluppo.

  1. Collega ogni ramo di attività a un problema associato nel tracker problemi utilizzando una semplice convenzione di denominazione .
  2. Utilizzare sempre git merge --no-ffper unire i rami delle attività; vuoi che unisci il commit e la bolla della cronologia, anche per un solo commit.

Questo è tutto. Perché? Perché come archeologo di codice, raramente inizio con la voglia di sapere che lavoro è stato fatto su una filiale. Molto più spesso è il motivo per cui in tutti i nove inferni urlanti è il codice scritto in questo modo ?!Devo cambiare il codice, ma ha alcune caratteristiche strane e devo risolverle per evitare di rompere qualcosa di importante.

Il prossimo passo è git blame trovare i commit associati e quindi sperare che il messaggio di log sia esplicativo. Se ho bisogno di scavare più a fondo, scoprirò se il lavoro è stato svolto in un ramo e leggerò il ramo nel suo insieme (insieme al suo commento nel tracker dei problemi).

Diciamo git blamepunti su commit XYZ. Apro un browser della cronologia di Git (gitk, GitX git log --decorate --graph, ecc ...), trovo commit XYZ e vedo ...

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

C'è il mio ramo! So che QQ, UU, XYZ, JJ e MM fanno tutti parte dello stesso ramo e dovrei guardare i loro messaggi di registro per i dettagli. So che GG sarà un commit di unione e avrà il nome del ramo che si spera sia associato a un problema nel tracker.

Se, per qualche motivo, voglio trovare un vecchio ramo, posso eseguirlo git loge cercare il nome del ramo nel commit di unione. È abbastanza veloce anche su repository molto grandi.

Questo è ciò che intendo quando dico che i rami si archiviano da soli.

La codifica di ogni ramo aggiunge un lavoro inutile per portare a termine le cose (un processo critico che dovrebbe essere spietatamente semplificato), eleva la lista dei tag (non parlando di prestazioni, ma leggibilità umana) con centinaia di tag che sono solo occasionalmente utili, e non è è anche molto utile per l'archeologia.


2
Ma che dire del disordine? Forse se ci fosse un modo per nascondere i vecchi rami sotto 10 metri cubi di terra.
bvj

1
Questo è utile, ma non è applicabile ai rami non uniti. A volte è stato fatto un esperimento su un ramo e si desidera conservare il contenuto nel caso in cui alcuni di essi diventino utili in un secondo momento.
Neil Mayhew,

1
@bvj Penso che questa risposta suggerisca che dovresti sempre eliminare i rami uniti, perché puoi sempre tornare indietro tramite il commit di unione. Sono d'accordo con questo.
Neil Mayhew,

@NeilMayhew Sì, ho circa 10 rami non uniti come quello aperto da me. Ciascuno di essi è associato a un'attività aperta in modo che io possa ricordare cosa stavo facendo. O farò qualcosa con loro, o diventeranno così obsoleti che non sono più pertinenti e li cancellerò. Ho lavorato su un progetto assolutamente affogando nei rami "Potrei averne bisogno in seguito", così non potevamo vedere cosa stavamo facendo. È stata davvero una scusa per alcuni sviluppatori di non dover ripulire da soli. Un po 'di margine di manovra va bene, ma non lasciare che sfugga al controllo.
Schwern,

@Schwern Sono d'accordo. Ho partecipato anche a progetti del genere. Penso che convertire i rami in tag sia un buon modo per sbarazzarsi del disordine, perché l'elenco dei tag crescerà sempre mentre l'elenco dei rami non dovrebbe (perché rappresenta la quantità di lavoro in corso). L'uso dello spazio dei nomi per i tag rende l'elenco più gestibile, ma le tendenze packrat devono assolutamente essere resistite. Uno sviluppatore dovrebbe conservare i commit sulla propria macchina a meno che non ci siano buone probabilità che qualcun altro li utilizzi alla fine.
Neil Mayhew,

2

Il mio approccio è quello di rinominare tutti i rami che non mi interessano con un prefisso "trash_", quindi utilizzare:

git branch | grep -v trash

(con un'associazione chiave shell)

Per conservare la colorazione del ramo attivo, è necessario:

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

2
Se rinomini i rami, potresti anche metterli in uno spazio dei nomi "archivio /"
qneill

1

Puoi usare uno script che archivierà il ramo per te

archbranch

Crea un tag per te con l'archivio prefisso / e quindi elimina il ramo. Ma controlla il codice prima di usarlo.


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

Se vuoi eseguire lo script senza scrivere la posizione in esso aggiungilo al tuo percorso

Quindi puoi chiamarlo da

$ archbranch [branchname] [defaultbranch]

Il [defaultbranch]è il ramo che si andrà a quando l'archiviazione è fatto. Ci sono alcuni problemi con la codifica a colori, ma altri che dovrebbero funzionare. Lo uso da tempo nei progetti, ma è ancora in fase di sviluppo.


1
Per StackTranslate.it Aiuto , devi rivelare la tua affiliazione con il tuo prodotto.
LittleBobbyTables - Au Revoir,

Oh, scusa, non lo sapevo. Sono l'autore della sceneggiatura.
Banezaka,

0

A volte archivio i rami come segue:

  1. Genera file patch, ad es. format-patch <branchName> <firstHash>^..<lastHash>(Ottieni firstHash e lastHash usando git log <branchName>.
  2. Spostare i file patch generati nella directory su un file server.
  3. Elimina il ramo, ad es. git branch -D <branchName>

"Applica" la patch quando è necessario utilizzare nuovamente il ramo; tuttavia, l'applicazione dei file patch (vedi git am) può essere impegnativa a seconda dello stato del ramo di destinazione. Tra i lati positivi, questo approccio ha il vantaggio di consentire la raccolta dei rifiuti della filiale e di risparmiare spazio nel repository.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.