Como arquivar ramos git?

305

Eu tenho algumas ramificações antigas no meu repositório git que não estão mais em desenvolvimento ativo. Gostaria de arquivar os ramos para que eles não apareçam por padrão durante a execução git branch -l -r. Não quero excluí-los, porque quero manter o histórico. Como posso fazer isso?

Eu sei que é possível criar uma referência fora de refs / heads. Por exemplo refs/archive/old_branch,. Há alguma conseqüência disso?

dan-manges
fonte
O git-rm não exclui recursos do repositório, apenas os remove do índice kernel.org/pub/software/scm/git/docs/git-rm.html Você pode restaurar esses recursos facilmente usandogit checkout [rev] file
Dana the Sane
1
Não que eu saiba. Eu uso Attic/<branchname>tags leves para arquivar ramos, no entanto.
Jakub Narębski 20/08/09
as tags são a escolha rápida, segura e sã.
kch

Respostas:

401

Acredito que a maneira correta de fazer isso é marcar o ramo. Se você excluir o ramo depois de marcá-lo, manterá o ramo efetivamente por perto, mas isso não irá desorganizar sua lista de ramos.

Se você precisar voltar para o ramo, verifique a tag. Ele efetivamente restaurará a ramificação da tag.

Para arquivar e excluir a ramificação:

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

Para restaurar a ramificação algum tempo depois:

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

O histórico do ramo será preservado exatamente como estava quando você o marcou.

Jeremy Wall
fonte
11
Eu sou um novato no Git, mas, ao tentar fazer isso, acho que o comando adequado para restaurar a ramificação é: #git checkout -b <branchname> archive/<branchname>
277 Steve Steve
6
Existe alguma razão para não usar uma tag de objeto nesse caso? Ser capaz de ver quem arquivou o ramo e quando pode ser interessante.
Gregory Joseph
7
@ GrégoryJoseph: Essa é a chamada "tag anotada". E sim, usar isso pode fazer muito sentido, eu diria.
Onnodb
22
nota pequena: você provavelmente quer, branch -Dpois provavelmente não será totalmente mesclado, se o estiver arquivando dessa maneira
Arkadiy Kukarkin
5
Muito agradável. Aqui está um tutorial completo com explicações.
guyaloni
123

A resposta de Jeremy está correta em princípio, mas IMHO os comandos que ele especifica não estão certos.

Veja como arquivar um ramo em uma tag sem precisar fazer check-out do ramo (e, portanto, sem ter que fazer check-out para outro ramo antes de poder excluir esse ramo):

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

E aqui está como restaurar um ramo:

> git checkout -b <branchname> archive/<branchname>
Steve
fonte
18
Eu acho que você não tinha pontos suficientes ainda, mas seria melhor quando você faz apenas para editar a resposta existente - uma de qualquer maneira embora :)
jkp
5
O @jkp que edita o código e os comandos de outros usuários geralmente é desaprovado, porque mudanças sutis em um comando git podem fazer coisas drasticamente diferentes, e você pode não entender por que o autor original escreveu algo da maneira que fez. melhor apenas fazer sua própria resposta ou deixar um comentário.
Dan Bechard
Ou ainda pior do que coisas drasticamente diferentes, uma mudança sutil nos comandos ou no código pode levar a resultados sutilmente diferentes, o que pode ser realmente difícil de entender, sugiro deixar como um comentário para que o pôster da resposta possa se editar ou responder com uma contra-reivindicação referenciando os resultados potencialmente diferentes (que tais contra-reivindicações são bastante comuns)
Nicholas Pipitone 19/02
22

Sim, você pode criar uma ref com algum prefixo não padrão usando git update-ref. por exemplo

  • Arquive o ramo: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Restaure a ramificação (se necessário): git branch topic refs/archive/old-topic

Referências com prefixo não padrão (aqui refs/archive) não aparecerão normalmente git branch, git lognem git tag. Ainda assim, você pode listá-los com git for-each-ref.

Estou usando os seguintes aliases:

[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

Além disso, convém configurar os controles remotos, como push = +refs/archive/*:refs/archive/*empurrar ramificações arquivadas automaticamente (ou git push origin refs/archive/*:refs/archive/*de uma só vez).

Outra maneira é escrever o SHA1 em algum lugar antes de excluir o ramo, mas ele tem limitações. As confirmações sem qualquer referência serão submetidas ao GC após 3 meses (ou algumas semanas sem reflog) , e muito menos manual git gc --prune. As confirmações apontadas pelos árbitros estão a salvo do GC.

Edit: Encontrou uma implementação perl da mesma ideia por @ap :git-attic

Editar ^ 2: Encontrou um post no qual o próprio Gitster usava a mesma técnica.

snipsnipsnip
fonte
3
Excelente, além de todos os outros neste segmento, você realmente respondeu à pergunta.
21417 tlrlk em
20

Estendendo a resposta de Steve para refletir as mudanças no controle remoto, eu fiz

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

Para restaurar a partir do controle remoto, consulte esta pergunta .

Liam
fonte
18

Você pode arquivar as ramificações em outro repositório. Não é tão elegante, mas eu diria que é uma alternativa viável.

git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch
August Lilleaas
fonte
4
Você pode criar em git-bundlevez de repositório separado.
Jakub Narębski 20/08/09
9

Aqui está um alias para isso:

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

Adicione assim:

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

Lembre-se de que git archivejá existe um comando, portanto você não pode usá-lo archivecomo um nome alternativo.

Também é possível definir alias para visualizar a lista dos ramos 'arquivados':

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

sobre como adicionar aliases

Alexey
fonte
3
Nas versões mais recentes do git (como sugerido aqui ), esse alias dá conclusão:!git tag archive/$1 $1 && git branch -D
Falta
5

Estou usando os seguintes aliases para ocultar ramificações arquivadas:

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

Então, git brpara mostrar ramificações ativamente desenvolvidas e git bramostrar todas as ramificações, incluindo as "arquivadas" .

Pitr
fonte
5
Se uma ramificação foi mesclada no mestre não tem nada a ver com seu estado de arquivamento. Por exemplo, na minha equipe de desenvolvimento, temos alguns ramos que foram criados especificamente para testar coisas. Queremos manter essas ramificações em nosso arquivo, mas definitivamente não queremos mesclá-las no master.
236 Bart Bart
4

Eu não arquivaria ramos. Dito de outra maneira, os ramos se arquivam. O que você deseja é garantir que as informações relevantes para os arqueólogos possam ser encontradas por meios confiáveis. Confiáveis, pois ajudam no desenvolvimento diário e não adicionam uma etapa extra ao processo de realização do trabalho. Ou seja, não acredito que as pessoas se lembrem de adicionar uma tag depois de concluir uma ramificação.

Aqui estão duas etapas simples que ajudarão muito a arqueologia e o desenvolvimento.

  1. Vincule cada ramo de tarefa a um problema associado no rastreador de problemas usando uma convenção de nomenclatura simples .
  2. Sempre use git merge --no-ffpara mesclar ramificações de tarefas; você deseja que a consolidação de mesclagem e a bolha do histórico, mesmo para apenas uma consolidação.

É isso aí. Por quê? Porque como arqueólogo de código, raramente começo a querer saber o que foi feito em uma ramificação. Muito mais frequentemente , é por que em todos os nove infernos que gritamos o código está escrito dessa maneira ?! Preciso alterar o código, mas ele tem alguns recursos estranhos e preciso decifrá-los para evitar que algo importante seja quebrado.

O próximo passo é git blameencontrar as confirmações associadas e esperar que a mensagem de log seja explicativa. Se eu precisar aprofundar, vou descobrir se o trabalho foi feito em uma ramificação e ler a ramificação como um todo (junto com seus comentários no rastreador de problemas).

Digamos git blamepontos em confirmar XYZ. Eu abro um navegador de histórico do Git (gitk, GitX git log --decorate --graph, etc ...), localizo commit XYZ e vejo ...

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

Aqui está o meu ramo! Sei que QQ, UU, XYZ, JJ e MM fazem parte da mesma ramificação e devo ver suas mensagens de log para obter detalhes. Eu sei que o GG será um commit de mesclagem e tem o nome da ramificação que, espero, está associada a um problema no rastreador.

Se, por algum motivo, desejar encontrar um ramo antigo, eu possa executar git loge procurar o nome do ramo no commit de mesclagem. É rápido o suficiente, mesmo em repositórios muito grandes.

É isso que quero dizer quando digo que os próprios arquivos se ramificam.

Marcar cada ramificação adiciona trabalho desnecessário à realização de tarefas (um processo crítico que deve ser simplificado de forma implacável), organiza a lista de tags (sem falar em desempenho, mas legibilidade humana) com centenas de tags que são apenas ocasionalmente úteis e não é ' mesmo muito útil para arqueologia.

Schwern
fonte
2
Mas e a desordem? Talvez se houvesse uma maneira de esconder os galhos antigos sob 10 metros cúbicos de terra.
BVJ
1
Isso é útil, mas não é aplicável a ramificações não imersas. Às vezes, um experimento foi realizado em uma ramificação e você deseja manter o conteúdo, caso algum deles se torne útil posteriormente.
Neil Mayhew
1
@bvj Acho que esta resposta está sugerindo que você sempre exclua ramos mesclados, porque você sempre pode voltar a eles através do commit de mesclagem. Eu concordo com isto.
Neil Mayhew
@ NeilMayhew Sim, eu tenho cerca de 10 galhos imersos como esse que me abrem. Cada um deles está associado a uma tarefa aberta, para que eu possa lembrar o que estava fazendo. Farei algo com eles ou eles ficarão desatualizados e não serão mais relevantes e os excluirei. Eu trabalhei em um projeto absolutamente afogado nas filiais "Talvez eu precise mais tarde" para que mal pudéssemos ver o que estávamos fazendo. Foi realmente uma desculpa para alguns desenvolvedores não precisarem se limpar. Um pouco de margem de manobra é bom, mas não deixe que fique fora de controle.
Schwern 30/03/19
@ Schwern, eu concordo. Também participei de projetos como esse. Eu acho que converter as ramificações em tags é uma boa maneira de se livrar da bagunça, porque a lista de tags sempre aumentará, enquanto a lista de ramificações não deve crescer (porque representa a quantidade de trabalho em andamento). O uso do namespacing para tags torna a lista mais gerenciável, mas as tendências do packrat definitivamente precisam ser resistidas. Um desenvolvedor deve reter os commits em sua própria máquina, a menos que haja uma boa chance de alguém os usar eventualmente.
Neil Mayhew
2

Minha abordagem é renomear todos os ramos com os quais não me importo com o prefixo "lixeira_" e, em seguida, use:

git branch | grep -v trash

(com uma ligação de chave shell)

Para manter a coloração do ramo ativo, seria necessário:

git branch --color=always | grep --color=never --invert-match trash
Sridhar Sarnobat
fonte
2
Se renomear ramos, assim como você pode colocá-los em um espaço de nomes "archive /"
qneill
1

Você pode usar um script que arquivará a ramificação para você

archbranch

Ele cria uma tag para você com o prefixo archive / e exclui a ramificação. Mas verifique o código antes de usá-lo.


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

Se você deseja executar o script sem escrever o local, adicione-o ao seu caminho

Então você pode chamá-lo

$ archbranch [branchname] [defaultbranch]

O [defaultbranch]é o ramo para o qual ele irá quando o arquivamento for concluído. Existem alguns problemas com o código de cores, mas outros ainda devem funcionar. Uso-o em projetos há muito tempo, mas ele ainda está em desenvolvimento.

Banezaka
fonte
1
Por Ajuda de estouro de pilha , você precisa divulgar sua afiliação ao seu produto.
LittleBobbyTables - Au Revoir
Oh, desculpe, não sabia. Eu sou o autor do roteiro.
Banezaka
0

Às vezes, eu arquivo ramificações da seguinte maneira:

  1. Gere arquivos de correção, por exemplo, format-patch <branchName> <firstHash>^..<lastHash>(get firstHash e lastHash usandogit log <branchName> .
  2. Mova os arquivos de correção gerados para o diretório em um servidor de arquivos.
  3. Exclua o ramo, por exemplo, git branch -D <branchName>

"Aplique" o patch quando precisar usar o ramo novamente; no entanto, a aplicação dos arquivos de correção (consulte git am) pode ser um desafio, dependendo do estado da ramificação de destino. No lado positivo, essa abordagem tem o benefício de permitir que os commits da filial sejam coletados de lixo e economizando espaço em seu repositório.

Bill Hoag
fonte