Como você organiza vários repositórios git, de modo que todos eles sejam armazenados em backup juntos?

98

Com o SVN, eu tinha um único grande repositório que mantive em um servidor e fiz check-out em algumas máquinas. Este era um sistema de backup muito bom e me permitiu trabalhar facilmente em qualquer uma das máquinas. Eu poderia fazer o checkout de um projeto específico, fazer um commit e atualizar o projeto 'master', ou eu poderia fazer o checkout de tudo.

Agora, eu tenho um monte de repositórios git, para vários projetos, vários dos quais estão no github. Também tenho o repositório SVN que mencionei, importado por meio do comando git-svn ..

Basicamente, gosto de ter todo o meu código (não apenas projetos, mas trechos e scripts aleatórios, algumas coisas como meu currículo, artigos que escrevi, sites que fiz e assim por diante) em um grande repositório que posso facilmente clonar em um remoto máquinas ou memory-sticks / harddrives como backup.

O problema é que, uma vez que é um repositório privado, e o git não permite o check-out de uma pasta específica (que eu poderia enviar para o github como um projeto separado, mas as alterações aparecem no master-repo e no sub- repos)

Eu poderia usar o sistema de submódulo git, mas ele também não age como eu quero (submódulos são ponteiros para outros repositórios e não contêm realmente o código real, portanto, é inútil para backup)

Atualmente, tenho uma pasta de git-repos (por exemplo, ~ / code_projects / proj1 / .git / ~ / code_projects / proj2 / .git /), e depois de fazer alterações em proj1 eu faço git push githube copio os arquivos em ~ / Documents / code / python / projects / proj1 / e faz um único commit (ao invés dos numerosos nos repositórios individuais). Então faça git push backupdrive1, git push mymemorysticketc

Então, a pergunta: como fazer seu código pessoal e projetos com repositórios git e mantê-los sincronizados e com backup?

dbr
fonte

Respostas:

74

Eu desaconselho fortemente colocar dados não relacionados em um determinado repositório Git. A sobrecarga de criação de novos repositórios é bastante baixa, e esse é um recurso que torna possível manter diferentes linhagens completamente separadas.

Combater essa ideia significa acabar com uma história desnecessariamente emaranhada, o que torna a administração mais difícil e - mais importante - as ferramentas de "arqueologia" menos úteis por causa da diluição resultante. Além disso, como você mencionou, o Git assume que a "unidade de clonagem" é o repositório, e praticamente tem que fazer isso por causa de sua natureza distribuída.

Uma solução é manter todos os projetos / pacotes / etc. como seu próprio repositório vazio (ou seja, sem árvore de trabalho) sob uma hierarquia abençoada, como:

/repos/a.git
/repos/b.git
/repos/c.git

Depois que algumas convenções foram estabelecidas, torna-se trivial aplicar operações administrativas (backup, embalagem, publicação na web) à hierarquia completa, que desempenha uma função não totalmente diferente dos repositórios SVN "monolíticos". Trabalhar com esses repositórios também se torna um tanto semelhante aos fluxos de trabalho SVN, com a adição de que se pode usar commits e branches locais:

svn checkout   --> git clone
svn update     --> git pull
svn commit     --> git push

Você pode ter vários controles remotos em cada clone de trabalho, para facilitar a sincronização entre as várias partes:

$ cd ~/dev
$ git clone /repos/foo.git       # or the one from github, ...
$ cd foo
$ git remote add github ...
$ git remote add memorystick ...

Você pode então buscar / puxar de cada uma das "fontes", trabalhar e fazer commit localmente, e então enviar ("backup") para cada um desses remotos quando estiver pronto com algo como (observe como isso empurra os mesmos commits e histórico para cada um dos controles remotos!):

$ for remote in origin github memorystick; do git push $remote; done

A maneira mais fácil de transformar um repositório de trabalho existente ~/dev/foo em um repositório vazio é provavelmente:

$ cd ~/dev
$ git clone --bare foo /repos/foo.git
$ mv foo foo.old
$ git clone /repos/foo.git

que é equivalente a - svn importmas não descarta a história "local" existente.

Nota: os submódulos são um mecanismo para incluir linhagens relacionadas compartilhadas , então eu realmente não os consideraria uma ferramenta apropriada para o problema que você está tentando resolver.

Damien Diederen
fonte
18
O fato de continuar terminando com muitos repositórios separados e escrevendo scripts simples para ajudar a gerenciar todos eles me faz sentir que há algo faltando no git. Simplesmente não consigo decidir exatamente o que é ou o que fazer a respeito.
DonGar
Bem, você gerencia muitos projetos separados também? Um relacionamento um-para-um entre projetos e repositórios parece razoável em um mundo distribuído, mas eu ainda organizaria repositórios vazios em uma árvore de diretório comum para facilitar o backup e a administração. (Em outras palavras, Git / Hg / Bzr força você a separar a administração das tarefas do projeto, enquanto a maioria dos fluxos de trabalho SVN combinam as duas; agora é comum ver pessoas delegando a parte administrativa ao GitHub ou outros provedores.)
Damien Diederen
2
essa ideia só faz sentido se você hospedar seus próprios projetos e / ou se eles forem todos de código aberto. Caso contrário, você precisaria do github, você precisaria de projetos privados ilimitados que podem sair caros
dkinzer
2
Em vez de "para remoto na origem github memorystick; faça git push $ remote; done", também é possível configurar um controle remoto especial para enviar por push com um único comando para vários remotos: stackoverflow.com/questions/36862/… . (Pode ser mais conveniente em alguns casos.)
imz - Ivan Zakharyaschev
2
Acho que o que está faltando é uma maneira que o git possa manter seus objetos separados por subárvore para que um único "repositório" possa ser composto de unidades separadas sincronizadas, embora separáveis ​​(baixadas individualmente sem o resto) de tal forma que as pessoas possam trabalhar em unidades específicas subconjuntos sem saber sobre o resto.
peterk,
28

Quero acrescentar à resposta de Damien, onde ele recomenda:

$ for remote in origin github memorystick; do git push $remote; done

Você pode configurar um controle remoto especial para acessar todos os controles remotos reais individuais com 1 comando; Encontrei-o em http://marc.info/?l=git&m=116231242118202&w=2 :

Portanto, para "git push" (onde faz sentido enviar os mesmos branches várias vezes), você pode realmente fazer o que eu faço:

  • .git / config contém:

    [remote "all"]
    url = master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
    url = login.osdl.org:linux-2.6.git
    
  • e agora git push all masterirá enviar o branch "master" para ambos
    os repositórios remotos.

Você também pode evitar digitar os URLs duas vezes usando a construção:

[url "<actual url base>"]
    insteadOf = <other url base>
imz - Ivan Zakharyaschev
fonte
3

Também estou curioso sobre as maneiras sugeridas de lidar com isso e irei descrever a configuração atual que uso (com o SVN). Basicamente, criei um repositório que contém uma hierarquia de mini-sistema de arquivos, incluindo seus próprios diretórios bin e lib. Há um script na raiz desta árvore que configurará seu ambiente para adicionar esses bin, lib, etc ... outros diretórios às variáveis ​​de ambiente adequadas. Portanto, o diretório raiz se parece essencialmente com:

./bin/            # prepended to $PATH
./lib/            # prepended to $LD_LIBRARY_PATH
./lib/python/     # prepended to $PYTHONPATH
./setup_env.bash  # sets up the environment

Agora, dentro de / bin e / lib existem vários projetos e suas bibliotecas correspondentes. Eu sei que este não é um projeto padrão, mas é muito fácil para outra pessoa do meu grupo verificar o repo, executar o script 'setup_env.bash' e ter as versões mais atualizadas de todos os projetos localmente em seu Verificação de saída. Eles não precisam se preocupar em instalar / atualizar / usr / bin ou / usr / lib e mantém a simplicidade de ter vários checkouts e um ambiente muito localizado por checkout. Alguém também pode simplesmente executar o rm em todo o repositório e não se preocupar em desinstalar nenhum programa.

Isso está funcionando bem para nós e não tenho certeza se iremos alterá-lo. O problema com isso é que existem muitos projetos neste grande repositório. Existe uma maneira padrão git / Hg / bzr de criar um ambiente como este e dividir os projetos em seus próprios repositórios?

Danny G
fonte
3

, Ainda não tentei aninhar repositórios git porque não me deparei com uma situação em que seja necessário. Como li no canal #git, git parece ficar confuso aninhando os repositórios, ou seja, você está tentando fazer git-init dentro de um repositório git. A única maneira de gerenciar uma estrutura git aninhada é usar git-submoduleo repoutilitário ou o Android .

Quanto à responsabilidade de backup que você está descrevendo, digo delegue -a ... Para mim, geralmente coloco o repositório de "origem" para cada projeto em uma unidade de rede no trabalho que é regularmente apoiada pelos técnicos de TI por sua estratégia de backup de escolha. É simples e não preciso me preocupar com isso. ;)

Spoike
fonte
2

Que tal usar mr para gerenciar seus vários repositórios Git de uma vez:

O comando mr (1) pode verificar, atualizar ou executar outras ações em um conjunto de repositórios como se fossem um único repositório combinado. Ele suporta qualquer combinação de repositórios subversion, git, cvs, mercurial, bzr, darcs, cvs, vcsh, fossil e veracity, e suporte para outros sistemas de controle de revisão podem ser facilmente adicionados. [...]

É extremamente configurável por meio de scripts de shell simples. Alguns exemplos de coisas que ele pode fazer incluem:

[...]

  • Ao atualizar um repositório git, extraia de dois upstreams diferentes e mescle os dois.
  • Execute várias atualizações de repositório em paralelo, acelerando bastante o processo de atualização.
  • Lembre-se de ações que falharam devido a um laptop estar offline, para que possam ser tentadas novamente quando ele estiver online novamente.
imz - Ivan Zakharyaschev
fonte
1

Há outro método para aninhar repositórios git, mas ele não resolve o problema que você está procurando. Ainda assim, para outros que estão procurando a solução que eu estava:

No nível superior git repo apenas esconda a pasta em .gitignore que contém o git repo aninhado. Isso torna mais fácil ter dois repositórios git separados (mas aninhados!).

arxpoetica
fonte