Comment organisez-vous plusieurs référentiels git, de sorte qu'ils soient tous sauvegardés ensemble?

98

Avec SVN, j'avais un seul grand référentiel que je conservais sur un serveur et que je retirais sur quelques machines. C'était un très bon système de sauvegarde et cela m'a permis de travailler facilement sur n'importe laquelle des machines. Je pourrais vérifier un projet spécifique, commettre et mettre à jour le projet «maître», ou je pourrais vérifier le tout.

Maintenant, j'ai un tas de dépôts git, pour divers projets, dont plusieurs sont sur github. J'ai aussi le référentiel SVN que j'ai mentionné, importé via la commande git-svn ..

Fondamentalement, j'aime avoir tout mon code (pas seulement des projets, mais des extraits et des scripts aléatoires, certaines choses comme mon CV, les articles que j'ai écrits, les sites Web que j'ai créés, etc.) dans un grand référentiel que je peux facilement cloner à distance machines, ou clés USB / disques durs comme sauvegarde.

Le problème est que, puisqu'il s'agit d'un référentiel privé, et que git ne permet pas l'extraction d'un dossier spécifique (que je pourrais pousser vers github en tant que projet séparé, mais que les modifications apparaissent à la fois dans le référentiel maître et dans le sous-dossier. repos)

Je pourrais utiliser le système de sous-modules git, mais il n'agit pas non plus comme je le souhaite (les sous-modules sont des pointeurs vers d'autres référentiels, et ne contiennent pas vraiment le code réel, donc c'est inutile pour la sauvegarde)

Actuellement, j'ai un dossier de git-repos (par exemple, ~ / code_projects / proj1 / .git / ~ / code_projects / proj2 / .git /), et après avoir modifié proj1 git push github, je copie les fichiers dans ~ / Documents / code / python / projects / proj1 / et faites un seul commit (au lieu des nombreux dans les dépôts individuels). Alors fais git push backupdrive1, git push mymemorysticketc.

Donc, la question: comment votre code personnel et vos projets avec les référentiels git, et les garder synchronisés et sauvegardés?

dbr
la source

Réponses:

74

Je déconseille fortement de mettre des données non liées dans un référentiel Git donné. La surcharge liée à la création de nouveaux référentiels est assez faible, et c'est une fonctionnalité qui permet de séparer complètement les différentes lignées.

Lutter contre cette idée signifie se retrouver avec une histoire inutilement enchevêtrée, ce qui rend l'administration plus difficile et, plus important encore, les outils «archéologiques» moins utiles en raison de la dilution qui en résulte. De plus, comme vous l'avez mentionné, Git suppose que "l'unité de clonage" est le référentiel, et doit pratiquement le faire en raison de sa nature distribuée.

Une solution consiste à conserver chaque projet / package / etc. comme son propre référentiel nu (c'est-à-dire sans arbre de travail) sous une hiérarchie bénie, comme:

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

Une fois que quelques conventions ont été établies, il devient trivial d'appliquer les opérations administratives (sauvegarde, emballage, publication Web) à la hiérarchie complète, qui joue un rôle pas tout à fait différent des dépôts SVN «monolithiques». Travailler avec ces référentiels devient également quelque peu similaire aux workflows SVN, avec l'ajout que l'on peut utiliser des commits et des branches locaux:

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

Vous pouvez avoir plusieurs télécommandes dans chaque clone actif, pour faciliter la synchronisation entre les multiples parties:

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

Vous pouvez ensuite récupérer / extraire de chacune des «sources», travailler et valider localement, puis pousser («sauvegarde») vers chacune de ces télécommandes lorsque vous êtes prêt avec quelque chose comme (notez comment cela pousse les mêmes validations et historique vers chacune des télécommandes!):

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

Le moyen le plus simple de transformer un référentiel de travail existant ~/dev/foo en un référentiel aussi nu est probablement:

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

qui équivaut en grande partie à un svn import- mais ne jette pas de côté l'histoire «locale» existante.

Remarque: les sous - modules sont un mécanisme pour inclure des lignées associées partagées , donc je ne les considérerais pas comme un outil approprié pour le problème que vous essayez de résoudre.

Damien Diederen
la source
18
Le fait que je continue à me retrouver avec beaucoup de référentiels séparés et à écrire des scripts simples pour les gérer tous me fait sentir qu'il manque quelque chose dans git. Je ne peux tout simplement pas décider exactement de quoi il s'agit ou quoi faire à ce sujet.
DonGar
Eh bien, gérez-vous aussi beaucoup de projets séparés? Une relation un-à-un entre les projets et les référentiels semble raisonnable dans un monde distribué, mais je continuerais d'organiser les référentiels nus dans une arborescence de répertoires commune pour faciliter la sauvegarde et l'administration. (En d'autres termes, Git / Hg / Bzr vous oblige à séparer l'administration des tâches de projet, alors que la plupart des workflows SVN confondent les deux; il est maintenant courant de voir des gens déléguer la partie administrative à GitHub ou à d'autres fournisseurs de ce type.)
Damien Diederen
2
cette idée n'a de sens que si vous hébergez vos propres projets et / ou ils sont tous open source. Sinon, vous auriez besoin sur github, vous auriez besoin de projets privés illimités qui pourraient devenir coûteux
dkinzer
2
Au lieu de "for remote in origin github memorystick; do git push $ remote; done", on peut également configurer une télécommande spéciale pour pousser avec une seule commande vers plusieurs télécommandes: stackoverflow.com/questions/36862/… . (Peut-être plus pratique dans certains cas.)
imz - Ivan Zakharyaschev
2
Je pense que la chose manquante est un moyen pour git de garder ses objets séparés par sous-arbre afin qu'un seul "référentiel" puisse être composé d'unités séparées synchronisées mais séparables (téléchargées individuellement sans le reste) de manière à ce que les gens puissent travailler sur des sous-ensembles sans en connaître le reste.
peterk
28

Je veux ajouter à la réponse de Damien où il recommande:

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

Vous pouvez configurer une télécommande spéciale pour pousser vers toutes les télécommandes réelles individuelles avec 1 commande; Je l'ai trouvé sur http://marc.info/?l=git&m=116231242118202&w=2 :

Donc, pour "git push" (où il est logique de pousser les mêmes branches plusieurs fois), vous pouvez réellement faire ce que je fais:

  • .git / config contient:

    [remote "all"]
    url = master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
    url = login.osdl.org:linux-2.6.git
    
  • et maintenant git push all masterva pousser la branche "master" vers ces deux
    référentiels distants.

Vous pouvez également vous éviter de taper deux fois les URL en utilisant la contruction:

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

Je suis également curieux de savoir comment gérer cela et je décrirai la configuration actuelle que j'utilise (avec SVN). J'ai essentiellement créé un référentiel qui contient une hiérarchie de mini-systèmes de fichiers comprenant ses propres répertoires bin et lib. Il y a un script à la racine de cet arbre qui configurera votre environnement pour ajouter ces répertoires bin, lib, etc ... aux variables d'environnement appropriées. Le répertoire racine ressemble donc essentiellement à:

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

Maintenant, dans / bin et / lib, il y a les multiples projets et leurs bibliothèques correspondantes. Je sais que ce n'est pas un projet standard, mais il est très facile pour quelqu'un d'autre dans mon groupe de récupérer le dépôt, d'exécuter le script 'setup_env.bash' et d'avoir les versions les plus à jour de tous les projets localement dans leur check-out. Ils n'ont pas à s'inquiéter de l'installation / de la mise à jour de / usr / bin ou / usr / lib et il est simple d'avoir plusieurs extractions et un environnement très localisé par caisse. Quelqu'un peut également simplement rm l'ensemble du référentiel sans se soucier de désinstaller des programmes.

Cela fonctionne bien pour nous, et je ne sais pas si nous allons le changer. Le problème avec ceci est qu'il y a de nombreux projets dans ce seul grand référentiel. Existe-t-il un moyen standard git / Hg / bzr de créer un environnement comme celui-ci et de décomposer les projets dans leurs propres référentiels?

Danny G
la source
3

, Je n'ai pas encore essayé d'imbriquer des dépôts git parce que je n'ai pas rencontré de situation où j'en ai besoin. Comme je l'ai lu sur le canal #git, git semble être confus en imbriquant les dépôts, c'est-à-dire que vous essayez de git-init dans un dépôt git. La seule façon de gérer une structure git imbriquée est d'utiliser git-submoduleou de l' repoutilitaire d'Android .

Quant à cette responsabilité de sauvegarde que vous décrivez, je dis la déléguer ... Pour moi, je place généralement le référentiel «d'origine» de chaque projet sur un lecteur réseau au travail qui est régulièrement sauvegardé par les techniciens informatiques par leur stratégie de sauvegarde de choix. C'est simple et je n'ai pas à m'en soucier. ;)

Spoike
la source
2

Qu'en est-il de l'utilisation de mr pour gérer vos multiples dépôts Git à la fois:

La commande mr (1) peut extraire, mettre à jour ou effectuer d'autres actions sur un ensemble de référentiels comme s'il s'agissait d'un référentiel combiné. Il prend en charge toute combinaison de dépôts subversion, git, cvs, mercurial, bzr, darcs, cvs, vcsh, fossil et véracité, et le support d'autres systèmes de contrôle de révision peut facilement être ajouté. [...]

Il est extrêmement configurable via un simple script shell. Voici quelques exemples de choses qu'il peut faire:

[...]

  • Lors de la mise à jour d'un référentiel git, tirez à partir de deux amont différents et fusionnez les deux ensemble.
  • Exécutez plusieurs mises à jour du référentiel en parallèle, ce qui accélère considérablement le processus de mise à jour.
  • Souvenez-vous des actions qui ont échoué en raison de la mise hors ligne d'un ordinateur portable, afin qu'elles puissent être réessayées lors de sa remise en ligne.
imz - Ivan Zakharyaschev
la source
1

Il existe une autre méthode pour avoir des dépôts git imbriqués, mais cela ne résout pas le problème que vous recherchez. Pourtant, pour les autres qui recherchent la solution, j'étais:

Dans le repo git de niveau supérieur, masquez simplement le dossier dans .gitignore contenant le repo git imbriqué. Cela facilite la création de deux dépôts git séparés (mais imbriqués!).

arxpoetica
la source