Para que eu usaria o git-worktree?

210

Eu li o post do Github no git-worktree . Eles escrevem:

Suponha que você esteja trabalhando em um repositório Git em uma ramificação chamada feature, quando um usuário relatar um erro de alta urgência master. Primeiro, você cria uma árvore de trabalho vinculada com uma nova ramificação, com hotfixcheck-out relativo ao mestre […] Você pode corrigir o bug, enviar hotfix e criar uma solicitação de recebimento.

Quando estou trabalhando em uma ramificação chamada feature e algum bug de alta urgência no master é relatado, geralmente escondo o que estiver trabalhando e crio uma nova ramificação. Quando terminar, posso continuar trabalhando. Este é um modelo muito simples, eu trabalho assim há anos.

Por outro lado, o uso do git-worktree tem suas próprias limitações:

Por exemplo, não é permitido o check-out do mesmo ramo em duas árvores de trabalho vinculadas ao mesmo tempo, porque isso permitiria que as alterações confirmadas em uma árvore de trabalho deixassem a outra fora de sincronia.

Por que eu escolheria um fluxo de trabalho mais complicado para um problema que já foi resolvido?

Existe algo sobre git-worktreeisso que não possa ser feito antecipadamente e que justifique todo esse novo e complexo recurso?

awendt
fonte
12
Uma coisa que você não pode esconder são os caminhos não imersos, após uma mesclagem ou recuperação de conflitos.
Chirlu
11
Se você trabalha com idiomas compilados, esconder significa que você terá que recompilar tudo quando não estiver armazenando.
MB14
Temos vários produtos diferentes com base no mesmo código fonte (300 MB), e planejo combiná-los em um grande repositório e usar a worktree para manter cada produto em uma pasta diferente, em vez de ter um monte de clones que não ficam sincronizados
endolith 16/06

Respostas:

195

Para mim, o git worktree é a maior melhoria desde muito tempo. Estou trabalhando no desenvolvimento de software corporativo. Lá, é muito comum que você tenha que manter versões antigas como as que você lançou há 3 anos. É claro que você tem uma ramificação para cada versão, para poder alternar facilmente para ela e corrigir um bug. No entanto, a troca é cara, porque, entretanto, você reestruturou completamente o repositório e talvez construa o sistema. Se você alternar, seu IDE ficará louco ao tentar adaptar as configurações do projeto.

Com a árvore de trabalho, você pode evitar essa reconfiguração constante. Faça o checkout desses galhos antigos em pastas separadas usando a árvore de trabalho. Para cada filial, você tem um projeto IDE independente.

É claro que isso poderia ter sido feito no passado, clonando o repositório várias vezes e essa foi a minha abordagem até agora. No entanto, isso também significava desperdiçar espaço no disco rígido e pior necessidade de buscar as mesmas alterações no repositório várias vezes.

Sebi
fonte
4
Você não precisou buscar as mesmas alterações no repositório várias vezes. Você poderia ter simplesmente copiado o diretório .git do primeiro clone.
22717 Mispray_15
1
@ jdk1.0 desculpe pela confusão, o comentário foi direcionado para misiu_mp
mxttie
2
Como alguém que usou 2-3 repositórios altamente replicados para que eu possa construir um ramo de recursos enquanto desenvolvia outro, eu tinha cada repositório local como controles remotos dos outros e concordo completamente com as caracterizações de desvantagens de Sebi (muitas tentativas e tentativas! ) Além disso, depois de mudar para a área de trabalho, concluo que não precisarei mais me preocupar com as ramificações locais com o mesmo nome divergindo (o que acontece uma vez a cada 6 a 10 meses, à medida que sou interrompido várias vezes ao longo de um período de dias e termino trabalhando o mesmo ramo de recursos em vários repositórios, mas esqueça de sincronizá-los de volta ...)
sage
3
@iheanyi - (1). É mais rápido se o IDE mantiver arquivos de dados externos (como bancos de dados de indexação) associados a um determinado diretório. Se você compartilhar o conteúdo no mesmo diretório, isso geralmente invalidará os caches de dados do IDE e terá que re-indexar.
Steve Hollasch
5
@iheanyi - (2) Com o tempo, a história de tudo aumentará muito mais do que os arquivos da árvore de trabalho em um determinado momento. A história de tudo == o .gitdiretório. Com muitos clones locais do upstream, você tem muitas cópias locais do mesmo banco de dados, pois cada clone possui seu próprio .gitbanco de dados. Com muitas árvores de trabalho locais, cada árvore usa o mesmo .gitbanco de dados. Sim, se você tiver clones locais da sua árvore de trabalho local, o Git vinculará muito o conteúdo do .git, mas não no Windows.
9788 Steve Jobs #
70

Eu posso ver alguns usos para isso.

Se você tem um conjunto de testes que é executado por um longo período de tempo, imagine horas e o inicia, efetivamente bloqueia essa cópia de trabalho até que os testes sejam concluídos. A troca de ramificações durante esses testes os quebraria de maneiras difíceis de entender.

Então, com git-worktreeeu poderia ter uma segunda idéia lançada para outro ramo que trabalha lá.

Além disso, quando mudo para outra ramificação para fazer uma investigação rápida, meu IDE acha que muitos arquivos foram alterados repentinamente e indexarão todas essas alterações, apenas para ter que re-indexá-las novamente quando voltar.

Um terceiro caso de uso seria fazer a comparação de arquivos usando outras ferramentas além de git-diff, normalmente diff, entre dois diretórios em vez de duas ramificações.

Andreas Wederbrand
fonte
6
Não git clonefuncionaria tão bem para tudo isso?
jthill
12
Mas a clonagem de um grande repositório do controle remoto pode levar muito tempo. Estou trabalhando contra um repositório que leva vários minutos para clonar. Eu acho que você poderia fazê-lo git clone --reference. Além disso, o gerenciamento de todas as outras ramificações será feito apenas uma vez em vez de uma vez por diretório de trabalho.
Andreas Wederbrand
6
Não clone do controle remoto, clone do seu local. Não entendo a questão do gerenciamento de filiais, você pode esclarecer?
jthill
14
Tentei usar clones, e realmente há um problema de gerenciamento. Em vez de um único conjunto de ramificações, tenho um conjunto de clones, que não consigo ver todos juntos na única interface do usuário. Se eu precisar escolher algumas mudanças, preciso buscá-las ou pressioná-las. Ele adiciona etapas adicionais a todas as ações. Tudo é factível, mas sempre há algum atrito.
max630
2
E quando se trata de configurar um backup, o repositório único é muito mais fácil.
max630
64

Um uso óbvio é comparar simultaneamente o comportamento (não a fonte) de versões diferentes - por exemplo, versões diferentes de um site ou apenas uma página da web.

Eu tentei isso localmente.

  • criar um diretório page1.

  • dentro de criar o diretório srce git initele.

  • em srccriar page1.htmlcom um pouco de conteúdo e enviá-lo.

  • $ git branch ver0

  • $ git worktree add ../V0 ver0

  • no srcmaster adicione mais texto page1.htmle confirme.

  • $ git branch sty1

  • edite page1.htmlna sty1ramificação (adicione um estilo CSS distinto) e adicione commit.

  • $ git worktree add ../S1 sty1

Agora você pode usar um navegador da web para abrir e visualizar essas três versões simultaneamente:

  • ..\page1\src\page1.html // qualquer que seja o git atual

  • ..\page1\V0\page1.html // a versão inicial

  • ..\page1\S1\page1.html // a versão com estilo experimental

RodMcGuire
fonte
2
Não vejo como isso explica o benefício de usar a árvore de trabalho para esse fim em relação a um clone.
Iheanyi 25/10/19
@iheanyi Você poderia dizer o mesmo sobre branch; a resposta também é a mesma: é mais leve e foi desenvolvida para o trabalho.
OJFord
1
@OJFord esse é o ponto. Esta resposta não me explica o que a árvore de trabalho faz diferente. Obviamente, não é um alias para branch ou clone, mas o efeito que estou vendo aqui parece ser o mesmo. Não vejo como isso é mais leve do que usar ramificação ou clone.
iheanyi 27/02
@iheanyi É diferente de usar branch - você não pode usar branches sozinho para obter vários estados da área de trabalho de uma só vez - e ter peso menor que um segundo (.., enésimo) clone. O que eu quis dizer foi que você também pode dizer sobre ramificação 'por que não clonar e fazer suas alterações', mas várias ramificações em um único repositório são um peso mais leve e uma maneira mais fácil de gerenciar esse comportamento.
OJFord
@OJFord Acho que isso não resolve minha confusão com a árvore de trabalho. Deixe-me colocar desta maneira, se você usa branch ou clone ou outra coisa, o objetivo final do processo descrito aqui é comparar três versões diferentes de algo simultaneamente. Com base no que está na resposta, não entendo por que eu usaria a árvore de trabalho em vez de alguma alternativa. A resposta não explica o que a árvore de trabalho está fazendo que as alternativas não estão. Você afirma que algo é leve (ou mais leve), mas não vejo como a árvore de trabalho torna os galhos menos "pesados".
iheanyi
29
  1. Existem razões legítimas pelas quais você pode querer / precisar de várias árvores de trabalho no sistema de arquivos de uma só vez.

    • manipular os arquivos com check-out enquanto precisar fazer alterações em outro lugar (por exemplo, compilação / teste)

    • diferenciando os arquivos por meio de ferramentas diff normais

    • durante conflitos de mesclagem, geralmente desejo navegar pelo código-fonte, pois está do lado da fonte enquanto resolvo conflitos nos arquivos.

    • Se você precisar alternar muito, haverá perda de tempo no check-out e verificação de que você não precisa fazer com várias ruas de trabalho.

    • o custo mental da alternância do contexto mental entre os ramos por meio do armazenamento em cache do Git não é realmente mensurável. Algumas pessoas acham que existe um custo mental para esconder isso simplesmente abrindo arquivos de um diretório diferente.

  2. Algumas pessoas perguntam "por que não fazer vários clones locais". É verdade que, com o sinalizador "--local", você não precisa se preocupar com o uso extra de espaço em disco. Isso (ou idéias semelhantes) é o que eu fiz até este ponto. As vantagens funcionais das ruas de trabalho vinculadas aos clones locais são:

    1. Com os clones locais, suas ruas de trabalho extras (que estão nos clones locais) simplesmente não têm acesso à origem ou ramificações upstream. A 'origem' no clone não será a mesma que a 'origem' no primeiro clone.

      • Correr git log @{u}..ou git diff origin/feature/other-featurepode ser muito útil e isso não é mais possível ou é mais difícil. Tecnicamente, essas idéias são possíveis com clones locais por meio de uma variedade de soluções alternativas, mas todas as soluções alternativas que você pode executar são realizadas de maneira melhor e / ou mais simples por meio de ruas de trabalho vinculadas.
    2. Você pode compartilhar referências entre worktrees. Se você deseja comparar ou emprestar alterações de outra filial local, agora pode.

Alexander Bird
fonte
11
Além disso, você pode listar todas as ruas de trabalho com um único comando, com os clones necessários para acompanhá-los.
31816 Ian Ringrose
Hmm. A partir do git 2.7.0, esse parece ser o caso. Bom saber.
Alexander Bird
9

tl; dr: sempre que você quiser fazer o check-out de duas árvores de trabalho ao mesmo tempo, por qualquer motivo, git-worktree é uma maneira rápida e com economia de espaço.

Se você criar outra árvore de trabalho, a maior parte do repositório (ou seja .git) será compartilhada, ou seja, se você criar uma ramificação ou buscar dados enquanto estiver em uma árvore de trabalho, ele também estará acessível a partir de qualquer outra árvore de trabalho que você tenha. Digamos que você queira executar seu conjunto de testes no branch foo sem precisar empurrá-lo para algum lugar para cloná-lo, e deseja evitar o incômodo de clonar seu repositório localmente, usar git-worktreeuma boa maneira de criar apenas uma nova verificação de algum estado em um local separado, temporária ou permanentemente. Assim como em um clone, tudo o que você precisa fazer quando terminar é excluí-lo, e a referência a ele será coletada como lixo após algum tempo.

jsageryd
fonte
2
Os documentos dizem que você não pode ter a mesma ramificação nas duas cópias de trabalho, o que é uma limitação séria. Com o Mercurial, ele trabalhou apenas com pequenos problemas.
hypersw
Certamente você pode. A página do manual diz como; procure --force. Mas é inconveniente se você atualizar a ramificação em um local e esperar trabalhar em outro, pois a árvore de trabalho não é atualizada.
Jsageryd
Sim, filiais no Mercurial são um conceito mais transparente nesse aspecto. Como as ramificações de uma árvore de trabalho aparecem na outra? Da mesma maneira que vários uplinks? Minhas primeiras experiências com worktrees, com busca em execução em ambos, terminaram com dois (!) Ponteiros diferentes (!) Nomeados origin/master.
hypersw
Uma árvore de trabalho é (como o nome indica) apenas uma árvore de trabalho, com alguns recursos adicionais adicionados; o repositório é compartilhado entre todas as árvores de trabalho. A única diferença entre duas ruas de trabalho é que a ramificação com check-out pode ser (e para fluxos de trabalho sãos, é) diferente. É possível confirmar em uma árvore de trabalho separada, para que ele também tenha seu próprio índice (também conhecido como área de preparação) para fazer esse trabalho. O .gitarquivo na árvore de trabalho separada é um arquivo de texto que contém o caminho para sua configuração, que reside no repositório original.
jsageryd
2
@WilsonF: git checkout --ignore-other-worktrees <branch> git-scm.com/docs/git-checkout/…
jsageryd
7

Originalmente, eu tropecei nessa questão depois de me perguntar para que essas workstes sofisticadas poderiam ser usadas. Desde então, eu os integrei ao meu fluxo de trabalho e, apesar do meu ceticismo inicial, cheguei a considerá-los bastante úteis.

Eu trabalho em uma base de código bastante grande, que leva algum tempo para compilar. Normalmente, tenho a ramificação de desenvolvimento atual em minha máquina, juntamente com a ramificação de recursos em que estou trabalhando, mais a ramificação mestre, que representa o estado atual do sistema ativo.

Um dos maiores benefícios para mim é obviamente que não preciso recompilar a coisa toda toda vez que troco de ramificação (ou seja, ruas de trabalho). Um bom efeito colateral é que eu posso ir para a área de trabalho de desenvolvimento, fazer coisas lá, alterar o diretório para a área de trabalho da minha ramificação de recursos atual e depois refazê-la sem ter que puxar primeiro.

rethab
fonte
4

Eu tenho um problema bastante incomum: estou desenvolvendo o Windows e Linux na mesma máquina . Eu tenho um VirtualBox executando o Linux dentro da minha caixa do Windows. O VirtualBox monta alguns diretórios do Windows e os usa diretamente dentro da máquina Linux. Isso me permite usar o Windows para gerenciar arquivos, mas criar no Linux. Este é um projeto de plataforma cruzada, desenvolvido com base no Windows e Linux a partir da mesma estrutura de diretório.

O problema é que o Linux e o Windows constroem sistemas colidem um com o outro quando usados ​​no mesmo diretório; existem algumas etapas complicadas de compilação para fazer o download de bibliotecas, etc., que usam os mesmos nomes de diretório. A versão do Windows do sistema de construção baixa as bibliotecas específicas do Windows e a versão do Linux do sistema de construção baixa as bibliotecas específicas do Linux.

Em um mundo ideal, o sistema de compilação seria modificado para que o Windows e Linux coexistissem no diretório, mas, por enquanto, o problema está sendo resolvido com as ruas de trabalho. A pasta "Linux" pode gerar artefatos de construção específicos do Linux e a pasta "Windows" pode gerar artefatos de construção específicos do Windows. Embora essa dificilmente seja uma solução ideal, ela oferece uma boa pausa enquanto aguarda a correção dos erros do sistema de compilação.

É certo que a árvore de trabalho não foi projetada para isso; Eu tenho que manter a versão do Windows e a versão do Linux em ramificações separadas, mesmo que eu realmente prefira que elas estejam na mesma ramificação. Ainda assim, ele está fazendo o trabalho e é um caso não convencional de uma árvore de trabalho que salva o dia.

AHelps
fonte
+1 Isso parece ser uma solução muito eficaz para o Make não executar diretórios de saída de configuração por configuração nativamente. Eu tenho uma configuração semelhante à Estação de trabalho VMware com os convidados Ubuntu e macOS.
precisa saber é o seguinte
1

Em um novo projeto para mim, criei um recurso. Mas algumas especificações falharam. Para comparar os resultados master, criei um work-treerepositório. Comparei os resultados passo a passo no código de execução, até entender o que deu errado.

itsnikolay
fonte
Como uma árvore de trabalho torna isso mais fácil do que um clone? A questão não é pedir preferência pessoal, mas diferenças concretas.
11nspectable
1

Estou usando git worktreepara o desenvolvimento de aprendizado de máquina.

Eu tenho um código funcional principal e, em seguida, quero dividir ramificações de diferentes experimentos (algoritmos diferentes e hiperparâmetros diferentes). git worktreepermite integrar o dvc ao lado de diferentes versões do meu código, especializadas em diferentes algoritmos. Depois de executar todos os trabalhos de treinamento, avalio as métricas finais e mesclo para dominar o melhor ramo / modelo.

Ricardo MS
fonte