Quelle est la différence entre «git init» et «git init --bare»?

162

Quelle est la différence entre git initet git init --bare? J'ai trouvé que beaucoup d'articles de blog nécessitent --barepour leur serveur Git?

Depuis la page de manuel , il est dit:

--bare

Créez un référentiel nu. Si l'environnement GIT_DIR n'est pas défini, il est défini sur le répertoire de travail actuel

Mais qu'est-ce que cela signifie réellement? Est-il nécessaire --barepour la configuration du serveur Git?

Kit Ho
la source

Réponses:

143

Repo Git non nu

Cette variante crée un référentiel avec un répertoire de travail afin que vous puissiez réellement travailler ( git clone). Après l'avoir créé, vous verrez que le répertoire contient un dossier .git où se trouvent l'historique et toute la plomberie git. Vous travaillez au niveau du dossier .git.

Bare Git Repo

L'autre variante crée un référentiel sans répertoire de travail ( git clone --bare). Vous n'obtenez pas de répertoire dans lequel vous pouvez travailler. Tout ce qui se trouve dans le répertoire est maintenant ce qui était contenu dans le dossier .git dans le cas ci-dessus.

Pourquoi vous utiliseriez l'un contre l'autre

Le besoin de dépôts git sans répertoire de travail est le fait que vous pouvez y pousser des branches et que cela ne gère pas ce sur quoi quelqu'un travaille. Vous pouvez toujours pousser vers un référentiel qui n'est pas nu, mais vous serez rejeté car vous pouvez potentiellement déplacer une branche sur laquelle quelqu'un travaille dans ce répertoire de travail.

Ainsi, dans un projet sans dossier de travail, vous ne pouvez voir les objets que lorsque git les stocke. Ils sont compressés et sérialisés et stockés sous le SHA1 (un hachage) de leur contenu. Afin d'obtenir un objet dans un référentiel nu, vous devez git show, puis spécifier le sha1 de l'objet que vous voulez voir. Vous ne verrez pas une structure semblable à celle de votre projet.

Les référentiels nus sont généralement des référentiels centraux vers lesquels chacun déplace son travail. Il n'est pas nécessaire de manipuler le travail réel. C'est un moyen de synchroniser les efforts entre plusieurs personnes. Vous ne pourrez pas voir directement vos fichiers de projet.

Vous n'aurez peut-être pas besoin de référentiels nus si vous êtes le seul à travailler sur le projet ou si vous ne voulez / n'avez pas besoin d'un référentiel "logiquement central". On pourrait préférer à git pull partir des autres référentiels dans ce cas. Cela évite les objections de git lors du transfert vers des référentiels non nus.

J'espère que cela t'aides

Adam Dymitruk
la source
Gardez le , jetez un de cette ligne - On préférerait tirer git d'un autre ... :-)
Arup Rakshit
10
Je trouve cette réponse très peu claire et déroutante. Certaines des raisons sont ici: meta.stackoverflow.com/questions/339837/…
Marko Avlijaš
Bare repositories are usually central repositories where everyone moves their work to.Voulez-vous dire qu'un référentiel nu est la source à partir de laquelle les autres collaborateurs du projet peuvent cloner un projet? Autrement dit, les collaborateurs traitent cela comme le remote?
Minh Tran
112

Réponse courte

Un référentiel nu est un référentiel git sans copie de travail, donc le contenu de .git est de niveau supérieur pour ce répertoire.

Utilisez un référentiel non nu pour travailler localement et un référentiel nu comme serveur / concentrateur central pour partager vos modifications avec d'autres personnes. Par exemple, lorsque vous créez un référentiel sur github.com, il est créé en tant que référentiel nu.

Donc, dans votre ordinateur:

git init
touch README
git add README
git commit -m "initial commit"

sur le serveur:

cd /srv/git/project
git init --bare

Puis sur le client, vous poussez:

git push username@server:/srv/git/project master

Vous pouvez ensuite vous enregistrer la saisie en l'ajoutant en tant que télécommande.

Le référentiel côté serveur va recevoir des validations via pull and push, et non en éditant des fichiers puis en les validant dans la machine serveur, c'est donc un référentiel nu.

Détails

Vous pouvez pousser vers un référentiel qui n'est pas un référentiel nu, et git découvrira qu'il y a un référentiel .git là-bas, mais comme la plupart des référentiels "hub" n'ont pas besoin d'une copie de travail, il est normal d'utiliser un référentiel nu pour et recommandé car il ne sert à rien d'avoir une copie de travail dans ce type de référentiels.

Cependant, si vous poussez vers un référentiel non nu, vous rendez la copie de travail incohérente, et git vous avertira:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

Vous pouvez ignorer cet avertissement. Mais la configuration recommandée est la suivante: utilisez un référentiel non nu pour travailler localement et un référentiel nu comme concentrateur ou serveur central à partir duquel pousser et extraire.

Si vous souhaitez partager le travail directement avec la copie de travail d'un autre développeur, vous pouvez extraire les uns des autres référentiels au lieu de pousser.

Duncan
la source
si je veux travailler mon projet sur le serveur git, il n'est donc pas nécessaire d'avoir l'option --bare, n'est-ce pas?
Kit Ho du
Vous utilisez bare pour le référentiel distant, pas pour le référentiel local.
duncan
C'est un peu de temps, mais voici une autre question. Si nous avons un référentiel distant nu, n'importe quel développeur peut y tirer une poussée, et le référentiel est un référentiel "central". Mais si nous travaillons sans référentiel nu, les développeurs devraient seulement tirer les uns des autres, mais jamais pousser. Le dernier scénario est tout simplement bon, s'il n'y a que 2 copies de travail du dépôt (aka dépôts locaux). Est-ce correct?
Asturio
60

Quand j'ai lu cette question il y a quelque temps, tout me déroutait. J'ai juste commencé à utiliser git et il y a ces copies de travail (qui ne signifiaient rien à ce moment-là). Je vais essayer d'expliquer cela du point de vue du gars, qui vient de commencer git sans aucune idée de la terminologie.

Un bel exemple des différences peut être décrit de la manière suivante :

--barevous donne juste un lieu de stockage (vous ne pouvez pas y développer). Sans --barecela vous donne la possibilité de vous y développer (et d'avoir un lieu de stockage).

git initcrée un référentiel git à partir de votre répertoire actuel. Il ajoute un dossier .git à l'intérieur de celui-ci et permet de démarrer votre historique des révisions.

git init --barecrée également un référentiel, mais il n'a pas de répertoire de travail. Cela signifie que vous ne pouvez pas modifier les fichiers, valider vos modifications, ajouter de nouveaux fichiers dans ce référentiel.

Quand --barepeut-il être utile? Vous et quelques autres gars travaillez sur le projet et utilisez git. Vous avez hébergé le projet sur un serveur ( amazon ec2). Chacun de vous possède sa propre machine et vous transmettez votre code ec2. Aucun de vous ne développe quoi que ce soit sur ec2(vous utilisez vos machines) - il vous suffit de pousser votre code. Donc, votre ec2n'est qu'un stockage pour tout votre code et devrait être créé au fur --bareet à mesure de toutes vos machines sans --bare(probablement une seule, et l'autre ne fera que tout cloner). Le flux de travail ressemble à ceci:

entrez la description de l'image ici

Salvador Dali
la source
1
Donc, nous pourrions dire qu'en utilisant un référentiel --bare, nous pouvons créer une sorte d'architecture client-serveur comme le fait la subversion?
Emiliano Sangoi
14

Un référentiel Git par défaut suppose que vous l'utiliserez comme répertoire de travail. En règle générale, lorsque vous êtes sur un serveur, vous n'avez pas besoin d'un répertoire de travail. Juste le référentiel. Dans ce cas, vous devez utiliser l' --bareoption.

Sandro Munda
la source
dans un dépôt avec l'option --bare, donc nous ne pouvons pas voir tout le fichier du projet? Il semble que je perds tout mon fichier projet avec l'option --bare ..
Kit Ho
11

Un référentiel non nu est la valeur par défaut. C'est ce qui est créé lorsque vous exécutez git init, ou ce que vous obtenez lorsque vous clonez (sans l' bareoption) à partir d'un serveur.

Lorsque vous travaillez avec un référentiel comme celui-ci, vous pouvez voir et modifier tous les fichiers qui se trouvent dans le référentiel. Lorsque vous interagissez avec le référentiel - par exemple en validant une modification - Git stocke vos modifications dans un répertoire caché appelé .git.

Lorsque vous avez un serveur git, il n'est pas nécessaire qu'il y ait des copies de travail des fichiers. Tout ce dont vous avez besoin, ce sont les données Git stockées .git. Un référentiel nu est exactement le .gitrépertoire, sans zone de travail pour modifier et valider les fichiers.

Lorsque vous clonez à partir d'un serveur, Git a toutes les informations dont il a besoin dans le .gitrépertoire pour créer votre copie de travail.

Andrew
la source
1

Une autre différence entre les référentiels --bare et Working Tree est que dans le premier cas, aucun commit perdu n'est stocké, mais seuls les commits appartenant à une piste de branche sont stockés. D'autre part, Working Tree conserve tous les commits pour toujours. Voir ci-dessous...

J'ai créé le premier dépôt (nom: git-bare ) avec git init --bare. C'est le serveur. C'est sur le côté gauche, où il n'y a pas de branches distantes car c'est le référentiel distant lui-même.

J'ai créé le deuxième référentiel (nom: git-working-tree ) avec git clonedu premier. C'est sur la droite. Il a des succursales locales liées à des succursales distantes.

(Les textes «premier», «deuxième», «troisième», «quatrième», «alpha», «beta» et «delta» sont les commentaires de commit. Les noms «master» et «greek» sont des noms de branche.)

Dépôts locaux et distants

Maintenant, je vais supprimer la branche nommée 'greek' à la fois dans git-bare (commande :)git push --delete origin greek et localement dans git-working-tree (commande:) git branch -D greek. Voici à quoi ressemble l'arbre:

Le dépôt git-bare supprime ce qui n'est plus référencé

Le dépôt git-bare supprime à la fois la branche et tous les comits référencés. Sur la photo, nous voyons que son arbre a été réduit pour cette raison.

D'un autre côté, le référentiel git-working-tree , qui équivaut à un référentiel local couramment utilisé, ne supprime pas les commits, qui ne peuvent désormais être référencés directement que par votre hachage avec une git checkout 7fa897b7commande. C'est pourquoi son arbre n'a pas sa structure modifiée.

EN BREF: Les validations ne sont jamais déposées dans les référentiels de l' arborescence de travail , mais sont supprimées dans les référentiels nus .

Concrètement, vous ne pouvez récupérer une branche supprimée sur le serveur que si elle existe dans un référentiel local.

Mais il est très étrange que la taille du référentiel nu ne diminue pas en taille de disque après la suppression d'une branche distante. Autrement dit, les fichiers sont toujours là d'une manière ou d'une autre.Pour vider le référentiel en supprimant ce qui n'est plus référencé ou ce qui ne peut jamais être référencé (ce dernier cas) utilisez la git gc --prunecommande

Sergio Cabral
la source
Pour tester les commandes git, essayez: github.com/sergiocabral/App.GitPlayground
Sergio Cabral