Comment puis-je ajouter un répertoire vide à un référentiel Git?

4268

Comment puis-je ajouter un répertoire vide (qui ne contient aucun fichier) à un référentiel Git?

Laurie Young
la source
16
Bien que ce ne soit pas utile, il existe un moyen de pirater un répertoire vide (vraiment vide) dans votre référentiel . checkoutCependant, ce ne sera pas le cas avec les versions actuelles de Git.
tiwo
335
@tiwo Je ne suis pas d'accord pour dire que ce n'est pas utile. Votre hiérarchie de répertoires fait partie de votre projet, elle doit donc être contrôlée par version.
JBentley
114
Dans mon cas, je voudrais ajouter une structure de répertoires pour les fichiers tmp, mais pas les fichiers tmp eux-mêmes. En faisant cela, mon testeur a la bonne structure (sinon il y a des erreurs) mais je n'obstrue pas mes commits avec des données tmp. Alors oui, ça m'est utile!
Adam Marshall
45
@AdamMarshall Je pense que tiwo disait que le hack n'est pas utile, car il est ignoré par la caisse. Les répertoires Tmp sonnent comme une fonctionnalité utile pour un VCS.
Quantum7
31
Pourquoi la procédure de création des fichiers tmp ne crée-t-elle pas également le répertoire tmp?
RyPeck

Réponses:

4128

Une autre façon de rendre un répertoire (presque) vide (dans le référentiel) est de créer un .gitignorefichier à l'intérieur de ce répertoire qui contient ces quatre lignes:

# Ignore everything in this directory
*
# Except this file
!.gitignore

Ensuite, vous n'avez pas besoin de passer la commande comme vous le feriez dans la solution de m104 .

Cela donne également l'avantage que les fichiers de ce répertoire ne s'affichent pas comme "non suivis" lorsque vous effectuez un statut git.

Rendre le commentaire de @GreenAsJade persistant:

Je pense que cela vaut la peine de noter que cette solution fait exactement ce que la question demandait, mais ce n'est peut-être pas ce que beaucoup de gens qui ont examiné cette question auraient cherché. Cette solution garantit que le répertoire reste vide. Il dit "Je ne veux vraiment pas que les fichiers soient enregistrés ici". Par opposition à "Je n'ai pas encore de fichiers à enregistrer ici, mais j'ai besoin du répertoire ici, les fichiers peuvent arriver plus tard".

Jamie Flournoy
la source
25
Je pense que la solution README proposée par @JohnMee devrait être utilisée avec celle-ci; le fichier .gitignore fournit une explication de ce que nous voulons garder hors du contrôle de version, tandis que le fichier README explique quel est le but du répertoire, qui sont tous deux des informations très importantes.
pedromanoel
18
@pedromanoel J'écris la documentation que vous mettriez à l' READMEintérieur du .gitignorefichier (sous forme de commentaires).
Carlos Campderrós
69
repérez la différence 1: 1.) un dossier vide, 2.) un dossier contenant un fichier .gitignore. ;-)
Peter Perháč
6
C'est parfait pour les dossiers de cache .
renouvelé
10
Malheureusement, cela se traduit par un répertoire non vide, il a un seul fichier caché.
pedorro
1091

Tu ne peux pas. Voir la FAQ Git .

Actuellement, la conception de l'index git (zone de transit) ne permet que la liste des fichiers, et personne suffisamment compétent pour effectuer la modification pour autoriser les répertoires vides ne s'est suffisamment soucié de cette situation pour y remédier.

Les répertoires sont ajoutés automatiquement lors de l'ajout de fichiers à l'intérieur. Autrement dit, les répertoires ne doivent jamais être ajoutés au référentiel et ne sont pas suivis par eux-mêmes.

Vous pouvez dire " git add <dir>" et il y ajoutera des fichiers.

Si vous avez vraiment besoin qu'un répertoire existe dans les caisses, vous devez y créer un fichier. .gitignore fonctionne bien à cet effet; vous pouvez le laisser vide ou remplir les noms des fichiers que vous prévoyez d'afficher dans le répertoire.

Andy Lester
la source
67
La réponse ci-dessous est BEAUCOUP mieux. Le fait que git le logiciel de bas niveau ne le permette pas autant pour moi que COMMENT utiliser réellement Git quand j'ai besoin d'un répertoire vide. L'ajout d'un .gitignore 2 lignes me semble acceptable.
Amala
1
Eh bien, si l'on veut déplacer des fichiers dans un nouveau répertoire, ils ne peuvent pas le faire git mvcar git se plaindra que le nouveau répertoire n'est pas sous contrôle de version
lulalala
16
Vous pouvez lire " c'est impossible, vous ne pouvez pas, etc. " partout sur Internet pour cette question fréquente. L' .gitignoreastuce est une réponse fréquente et répond à de nombreux besoins. Cependant, il est possible de faire de git track un répertoire vraiment vide , voir ma réponse
ofavre
2
Bien que plus j'y pense, plus ça ressemble à "SHA hash de la chaîne vide", s'il existe, serait en fait un identifiant bien défini pour un arbre vide, à moins qu'il ne soit impossible de dire si cet objet est un arbre ou une goutte.
Emil Lundberg
21
J'ai vu beaucoup de dépôts qui utilisent un fichier vide appelé .gitkeepà cet effet.
Sukima
759

Créez un fichier vide appelé .gitkeepdans le répertoire et ajoutez-le.

Artur79
la source
58
J'ai ajouté une réponse encourageant à créer à la .keepplace.
Acumenus
206
.gitkeepn'a pas été prescrit par Git et va inciter les gens à deviner sa signification, ce qui les mènera à des recherches Google, qui les mèneront ici. La .gitconvention de préfixe doit être réservée aux fichiers et répertoires que Git lui-même utilise.
t-mart
10
@ t-mart "La .gitconvention de préfixe doit être réservée ..." Pourquoi? Git demande-t-il cette réservation?
Expiation limitée du
9
Dans ce cas, un fichier READMEou ABOUTserait tout aussi bon ou meilleur. Laisser une note pour le prochain gars, comme nous le faisions tous avant les URL.
Dave
5
Ne fonctionne pas si vous écrivez un test unitaire qui devrait tester le code sur un répertoire vide ...
thebjorn
437

Vous pouvez toujours mettre un fichier README dans le répertoire avec une explication de la raison pour laquelle vous voulez ce répertoire, sinon vide, dans le référentiel.

John Mee
la source
39
+1, bonne suggestion, un répertoire vide n'a de sens que s'il sera utilisé à l'avenir. Créez donc un fichier README à l'intérieur et écrivez à quoi sert ce répertoire, et quels fichiers y seront placés à l'avenir. Cela résout les deux problèmes.
saeedgnu
63
@ilius Nonsense. Une structure de répertoires contenant des répertoires vides peut être hautement souhaitable dans de nombreuses situations (comme une application MVC où vous voulez un répertoire de modèles mais n'avez pas encore réussi à créer de modèles, ou un répertoire de vues partagées auquel vous prévoyez d'ajouter des vues partagées ultérieurement). ). De plus, mettre un README dans chacun d'entre eux est exagéré car il est évident à quoi ils servent, et il est facile d'oublier de mettre un README dans chacun d'eux. ET vous devez vous rappeler de supprimer le fichier README lorsque vous y ajoutez d'autres fichiers. Fondamentalement, git devrait définitivement autoriser les répertoires vides.
Jez
20
@Jez: Je ne suis pas d'accord. Le fait est que git est conçu pour contrôler (et indexer) le code source. Surtout, l'id d'un commit est un hachage du contenu. Autrement dit, il doit avoir un contenu. Vous n'avez pas besoin d'un fichier README dans chaque partie de l'arbre, seulement des nœuds feuilles. Si vous avez des endroits où vous avez l'intention de mettre du code, mais pas de code, et que vous ne prendrez même pas le temps de faire écho à "place pour les modèles" >> README, alors ce que vous avez est une idée et non un commit. Ce n'est pas intéressant de git. Dire "Je veux que l'application en cours d'exécution ait des répertoires vides XYZ" est un problème d' exécution , pas un problème de source. Gérez-le avec votre installateur.
Joe Atzberger
6
@JoeAtzberger C'est une fonctionnalité manquante, pas une limitation intentionnelle. De la FAQ Git: Actuellement, la conception de l'index Git (zone de transit) ne permet que la liste des fichiers, et personne suffisamment compétent pour effectuer la modification pour autoriser les répertoires vides ne s'est suffisamment soucié de cette situation pour y remédier.
jbo5112
7
@ jbo5112 Oui, le "code spécial" auquel vous faites référence est l '"installateur" que j'ai mentionné. Votre installation Webapp doit déjà gérer la création d'une base de données, une configuration locale, l'extraction de dépendances ou 100 autres opérations, mais quelques répertoires vides sont au-delà? Essayez gradle, passager, chef, un Makefile primitif, etc. Il n'y a aucune différence de sécurité entre la création de répertoires et les autres travaux (potentiellement beaucoup plus compliqués / dangereux) d'installation d'une application. Et si vous n'avez vraiment aucun deps, config, DB, etc., et aucun installateur, utilisez simplement le README. Aucun cas ne vous oblige à faire les deux.
Joe Atzberger
349
touch .keep

Sous Linux, cela crée un fichier vide nommé .keep. Pour ce qu'il vaut, ce nom est agnostique pour Git, alors .gitkeepqu'il serait spécifique à Git. Deuxièmement, comme un autre utilisateur l'a noté, la .gitconvention de préfixe devrait être réservée aux fichiers et répertoires que Git lui-même utilise.

Alternativement, comme indiqué dans une autre réponse , le répertoire peut contenir un descriptif READMEou un README.mdfichier à la place.

Bien sûr, cela nécessite que la présence du fichier n'entraîne pas la rupture de votre application.

Acumenus
la source
1
C'est bon pour un répertoire nu initial, mais que se passe-t-il s'il commence à se remplir de fichiers? Ensuite, Git les remarquera et les revendiquera en tant que fichiers non suivis. La réponse sélectionnée ici fonctionne de manière beaucoup plus élégante pour permettre à l'utilisateur de conserver un répertoire mais d'ignorer le contenu en toute sécurité.
JakeGould
14
La question et la préoccupation générale prédominante concernent l'ajout d'un répertoire vide. S'il a plus tard un fichier résident, supprimez évidemment le .keepfichier ou ignorez-le. Si, à la place, les fichiers du répertoire doivent être ignorés, c'est une toute autre question.
Acumenus du
3
Il a été suggéré de git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep"le faire dans tous les répertoires vides non suivis.
Acumenus
1
N'aimez pas cette solution, il est difficile de deviner ce que fait ce fichier. De plus, si vous générez des fichiers dans votre environnement de développement (comme des journaux ou des images, etc.), cela n'empêche pas ces fichiers d'être versionnés et de se rendre en production, ce qui n'est pas agréable.
danielrvt
1
Windows n'aime pas les fichiers sans nom et nécessite une magie spéciale pour accomplir cela (alias une application de terminal de type bash ou équivalent).
EntangledLoops
303

Pourquoi aurions-nous besoin de dossiers versionnés vides

Tout d'abord:

Un répertoire vide ne peut pas faire partie d'une arborescence sous le système de gestion de versions Git .

Il ne sera tout simplement pas suivi. Mais il existe des scénarios dans lesquels le "versioning" des répertoires vides peut être significatif, par exemple:

  • l'échafaudage d'une structure de dossiers prédéfinie , la mettant à la disposition de chaque utilisateur / contributeur du référentiel; ou, dans un cas particulier de ce qui précède, créer un dossier pour les fichiers temporaires , tels que les répertoires cache/ou logs/, où nous voulons fournir le dossier mais .gitignoreson contenu
  • liés à ce qui précède, certains projets ne fonctionneront pas sans certains dossiers (ce qui est souvent le signe d'un projet mal conçu, mais c'est un scénario fréquent et réel et peut-être qu'il pourrait y avoir, par exemple, des problèmes d'autorisation à résoudre).

Quelques solutions de contournement suggérées

De nombreux utilisateurs suggèrent:

  1. Placer un READMEfichier ou un autre fichier avec du contenu afin de rendre le répertoire non vide, ou
  2. Créer un .gitignorefichier avec une sorte de "logique inverse" (c'est-à-dire pour inclure tous les fichiers) qui, au final, sert le même but de l'approche # 1.

Bien que les deux solutions fonctionnent sûrement, je les trouve incompatibles avec une approche significative du versioning de Git.

  • Pourquoi êtes-vous censé mettre de faux fichiers ou README que vous ne voulez peut-être pas vraiment dans votre projet?
  • Pourquoi utiliser .gitignorepour faire une chose ( conserver des fichiers) qui est tout le contraire de ce à quoi elle est destinée (à l' exclusion des fichiers), même si c'est possible?

Approche .gitkeep

Utilisez un fichier vide appelé .gitkeepafin de forcer la présence du dossier dans le système de versioning.

Bien que cela ne semble pas être une si grande différence:

  • Vous utilisez un fichier dont le seul but est de conserver le dossier. Vous ne mettez là aucune information que vous ne voulez pas mettre.

    Par exemple, vous devez utiliser des fichiers README ainsi que des fichiers README contenant des informations utiles, et non pas comme une excuse pour conserver le dossier.

    La séparation des préoccupations est toujours une bonne chose, et vous pouvez toujours ajouter un .gitignorepour ignorer les fichiers indésirables.

  • Le nommer .gitkeeprend très clair et simple à partir du nom de fichier lui-même (et aussi pour d'autres développeurs , ce qui est bon pour un projet partagé et l'un des objectifs principaux d'un référentiel Git) que ce fichier est

    • Un fichier sans rapport avec le code (à cause du premier point et du nom)
    • Un dossier clairement lié à Git
    • Son but ( garder ) est clairement énoncé et cohérent et sémantiquement opposé dans son sens d' ignorer

Adoption

J'ai vu l' .gitkeepapproche adoptée par des frameworks très importants comme Laravel , Angular-CLI .

Cranio
la source
8
Vous avez manqué une pensée - quelle est la raison de conserver et de vider le dossier (par exemple / logs, / tmp, / uploads)? Oui - c'est pour garder le dossier vide. :) Donc, si vous voulez garder un dossier vide, vous devez ignorer les fichiers qu'il contient.
Roman
14
@RomanAllenstein: pas nécessairement. Il se peut que vous créiez un dépôt avec une structure donnée qui puisse être remplie plus tard. Ces fichiers seront ajoutés au référentiel dès qu'ils seront créés, et ce sera ennuyeux de commencer à supprimer ou éditer des fichiers .gitignore (et dangereux, car vous ne réalisez probablement même pas qu'ils ne sont pas suivis: git les ignore )
blueFast
45
@Behnam: Je vais prendre le vote négatif, mais mes recherches sur la méta SO ne montrent aucune préoccupation envers les réponses verbeuses, tant qu'elles fournissent suffisamment de détails et de clarté pour être utiles à chaque lecteur (et à chaque niveau de compétence). Je suis toujours très ouvert à toute critique et merci d'avoir déclaré publiquement la raison, je la prends très positivement.
Cranio
4
Si vous modifiez votre réponse pour la remplacer .gitkeeppar un autre nom de fichier sans préfixe git, vous obtenez mon vote positif, je pense que celui-ci est la meilleure et la plus informative. Raison: je pense que ".git *" devrait être réservé aux fichiers prescrits par git, alors que ce n'est qu'un simple espace réservé. Ma première supposition quand j'ai vu que c'est par exemple qu'un fichier ".gitkeep" serait ignoré automatiquement (ce serait une fonctionnalité intéressante) mais ce n'est pas le cas, non?
Johnny
5
Je me demande pourquoi les gens ont tant de mal à comprendre pourquoi on veut ajouter des dossiers "vides" à git. Vous devez commencer quelque part, non? Donc, généralement, vous commencez avec la structure de vos dossiers de projets et - hélas - au début du projet, il n'y a encore rien. Une fois le repo de votre projet terminé, les collaborateurs peuvent cloner et commencer à travailler sur la même structure.
BitTickler
127

Comme décrit dans d'autres réponses, Git ne peut pas représenter les répertoires vides dans sa zone de transfert. (Voir la FAQ Git .) Cependant, si, pour vos besoins, un répertoire est suffisamment vide s'il contient .gitignoreuniquement un fichier, vous pouvez créer des .gitignorefichiers dans des répertoires vides uniquement via:

find . -type d -empty -exec touch {}/.gitignore \;
mjs
la source
21
Vous pouvez ignorer le répertoire .git: find . -name .git -prune -o -type d -empty -exec touch {}/.gitignore \;
steffen
3
Une variation plus simple pour la plupart des situations estfind * -type d -empty -exec touch {}/.gitignore \;
akhan
2
Étant donné qu'OS X crée un fichier .DS_Store dans presque tous les répertoires, cela ne fonctionne pas là-bas. La seule solution de contournement (DANGEREUSE!) Que j'ai trouvée était de supprimer d'abord tous les fichiers .DS_Store find . -name .DS_Store -exec rm {} \;, puis d'utiliser la variante préférée de cette réponse. Assurez-vous de ne l'exécuter que dans le bon dossier!
zerweck
1
Quelqu'un connaît-il un moyen de le faire dans Windows à partir de la ligne de commande? J'ai vu quelques solutions ici en Ruby et Python, mais j'aimerais une solution barebones si elle peut être gérée.
Mig82
1
@akhan Ajouter quelque chose à .gitignoren'a aucune influence sur le -emptydrapeau de la findcommande. Mon commentaire concerne la suppression des .DS_Storefichiers dans une arborescence de répertoires, afin que l' -emptyindicateur puisse être appliqué.
zerweck
68

Andy Lester a raison, mais si votre répertoire doit simplement être vide, et non vide vide, vous pouvez y placer un .gitignorefichier vide comme solution de contournement.

En passant, c'est un problème d'implémentation, pas un problème fondamental de conception de stockage Git. Comme cela a été mentionné à plusieurs reprises sur la liste de diffusion Git, la raison pour laquelle cela n'a pas été implémenté est que personne ne s'est suffisamment soucié de soumettre un correctif, pas que cela ne pouvait ou ne devait pas être fait.

Aristote Pagaltzis
la source
4
C'est exactement ce que j'ai dit. Les deux paragraphes sont traités dans l'extrait de FAQ que j'ai publié.
Andy Lester
1
Je pense que le côté est peu intéressant et utile à savoir - il peut être corrigé, ne vous y attendez pas de sitôt quand il existe une solution de contournement aussi simple pour la plupart des cas.
wnoise
Désolé, je n'ai pas lu le dernier paragraphe, et bien que j'aie lu le premier paragraphe, eh bien, je ne sais pas pourquoi j'ai répété cette information.
Aristote Pagaltzis
2
Bien sûr, cette réponse supplémentaire sert à souligner le fait.
Michael Johnson, le
Je suis arrivé ici en regardant un cas où la construction est tombée en panne si le répertoire n'existe pas et par défaut il est vide, mais il n'a pas besoin d'être vide. Créer un .gitignore fait la bonne chose.
Joshua
33

La façon de créer un dossier de journal Ruby on Rails :

mkdir log && touch log/.gitkeep && git add log/.gitkeep

Maintenant, le répertoire des journaux sera inclus dans l'arborescence. Il est super utile lors du déploiement, vous n'aurez donc pas à écrire une routine pour créer des répertoires de journaux.

Les fichiers journaux peuvent être conservés en émettant,

echo log/dev.log >> .gitignore

mais vous le saviez probablement.

Thomas E
la source
23
Qu'est-ce que cela a à voir avec Ruby on Rails?
Questions Quolonel
30

Git ne suit pas les répertoires vides. Voir la FAQ Git pour plus d'explications. La solution de contournement suggérée consiste à.gitignore fichier dans le répertoire vide. Je n'aime pas cette solution, car le.gitignore est "caché" par la convention Unix. De plus, il n'y a aucune explication pour laquelle les répertoires sont vides.

Je suggère de mettre un fichier README dans le répertoire vide expliquant pourquoi le répertoire est vide et pourquoi il doit être suivi dans Git. Avec le fichier README en place, pour Git, le répertoire n'est plus vide.

La vraie question est pourquoi avez-vous besoin du répertoire vide dans git? Habituellement, vous avez une sorte de script de construction qui peut créer le répertoire vide avant de compiler / exécuter. Sinon, faites-en un. C'est une bien meilleure solution que de mettre des répertoires vides dans git.

Vous avez donc une raison pour laquelle vous avez besoin d'un répertoire vide dans git. Mettez cette raison dans le fichier README. De cette façon, les autres développeurs (et à l'avenir vous savez) pourquoi le répertoire vide doit être là. Vous saurez également que vous pouvez supprimer le répertoire vide lorsque le problème nécessitant le répertoire vide a été résolu.


Pour répertorier chaque répertoire vide, utilisez la commande suivante:

find -name .git -prune -o -type d -empty -print

Pour créer des fichiers README d'espace réservé dans chaque répertoire vide:

find -name .git -prune -o -type d -empty -exec sh -c \
  "echo this directory needs to be empty because reasons > {}/README.emptydir" \;

Pour ignorer tout dans le répertoire sauf le fichier README, placez les lignes suivantes dans votre .gitignore:

path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir

Alternativement, vous pouvez simplement exclure chaque fichier README d'être ignoré:

path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir

Pour répertorier chaque fichier README après sa création:

find -name README.emptydir
lesmana
la source
28

AVERTISSEMENT: ce réglage ne fonctionne pas vraiment car il s'avère. Désolé pour le dérangement.

Message d'origine ci-dessous:

J'ai trouvé une solution en jouant avec les internes de Git!

  1. Supposons que vous soyez dans votre référentiel.
  2. Créez votre répertoire vide:

    $ mkdir path/to/empty-folder
    
  3. Ajoutez-le à l'index à l'aide d'une commande de plomberie et de l'arborescence vide SHA-1 :

    $ git update-index --index-info
    040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904    path/to/empty-folder
    

    Tapez la commande, puis entrez la deuxième ligne. Appuyez sur Enterpuis sur Ctrl+ Dpour terminer votre saisie. Remarque: le format est le chemin en mode [ESPACE] type [ESPACE] SHA-1hash [TAB] (l'onglet est important, la mise en forme de la réponse ne le préserve pas).

  4. C'est ça! Votre dossier vide est dans votre index. Tout ce que vous avez à faire est de vous engager.

Cette solution est courte et fonctionne apparemment bien ( voir EDIT! ), Mais ce n'est pas si facile à retenir ...

L'arbre vide SHA-1 peut être trouvé en créant un nouveau référentiel Git vide, cddedans et émis git write-tree, qui génère l'arbre vide SHA-1.

ÉDITER:

J'utilise cette solution depuis que je l'ai trouvée. Il semble fonctionner exactement de la même manière que la création d'un sous-module, sauf qu'aucun module n'est défini nulle part. Cela entraîne des erreurs lors de l'émission git submodule init|update. Le problème est que git update-indexréécrit la 040000 treepièce 160000 commit.

De plus, tout fichier placé sous ce chemin ne sera jamais remarqué par Git, car il pense qu'ils appartiennent à un autre référentiel. C'est méchant car il peut facilement être ignoré!

Cependant, si vous n'utilisez pas (et n'utiliserez pas) de sous-modules Git dans votre référentiel, et que le dossier "vide" restera vide ou si vous voulez que Git connaisse son existence et ignore son contenu, vous pouvez aller avec ce tweak. Suivre la voie habituelle avec les sous-modules nécessite plus d'étapes que ce réglage.

ofavre
la source
Après avoir placé le dossier vide dans l'index et validé, y est-il alors possible git svn dcommitavec le résultat souhaité?
Expiation limitée du
2
Il est peu probable que ce réglage fonctionne avec un autre outil. Comme indiqué dans l'avertissement et l'édition, je déconseille de l'utiliser sauf dans un cas assez restreint.
ofavre
1
Et bien sûr, c'est pourquoi jouer avec les internes de git est contre-indiqué.
Casey
@abhisekp Comment est-ce encore possible?
PyRulez
1
@PyRulez bien, dans le monde du logiciel, rien n'est impossible. : D En fait, j'ai suivi la réponse.
abhisekp
21

Disons que vous avez besoin d'un répertoire vide nommé tmp :

$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp

En d'autres termes, vous devez ajouter le fichier .gitignore à l'index avant de pouvoir dire à Git de l'ignorer (et tout le reste dans le répertoire vide).

m104
la source
12
Deux choses: vous pouvez simplement "echo '*'> tmp / .gitignore" au lieu de toucher, et "git commit -m" ne valide pas les modifications effectuées après avoir ajouté les fichiers à l'index.
Christoffer Hammarström
6
Si vous venez de le faire, echo bla > filevous n'obtiendrez pas file: File existscar >écrasera le fichier s'il est déjà là ou en créera un nouveau s'il n'existe pas.
psyrendust
3
/bin/shhypothèse culturelle! * Si "ici" est cshet la variable noclobberest définie, vous obtiendrez en effet file: File exists. Si quelqu'un dit «je comprends», ne présumez pas qu'il est idiot et répondez «non, vous ne le faites pas». * c2.com/cgi/wiki?AmericanCulturalAssumption
clacke
1
@clacke Si quelqu'un décide d'utiliser un shell différent de tout le monde, il doit l'indiquer expressément s'il rencontre des problèmes. Contrairement à la nationalité, chacun a le libre choix de sa coquille.
SeldomNeedy
2
@SeldomNeedy Peut-être qu'ils recherchent de l'aide parce qu'ils ne savent même pas qu'ils utilisent un shell différent de tout le monde.
clacke
20

Peut-être que l'ajout d'un répertoire vide semble être le chemin de moindre résistance car vous avez des scripts qui s'attendent à ce que ce répertoire existe (peut-être parce qu'il s'agit d'une cible pour les binaires générés). Une autre approche serait de modifier vos scripts pour créer le répertoire selon vos besoins .

mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed

Dans cet exemple, vous pouvez archiver un lien symbolique (rompu) vers le répertoire afin de pouvoir y accéder sans le préfixe ".generated" (mais cela est facultatif).

ln -sf .generated/bin bin
git add bin

Lorsque vous souhaitez nettoyer votre arbre source, vous pouvez simplement:

rm -rf .generated ## this should be in a "clean" script or in a makefile

Si vous adoptez l'approche souvent suggérée consistant à archiver un dossier presque vide, vous avez la complexité mineure de supprimer le contenu sans supprimer également le fichier ".gitignore".

Vous pouvez ignorer tous vos fichiers générés en ajoutant ce qui suit à votre .gitignore racine:

.generated
nobar
la source
1
Remarque: Le lien symbolique que j'ai suggéré est "cassé" dans un checkout propre car le .generatedrépertoire n'existe pas initialement. Il ne sera plus cassé une fois que vous aurez construit.
nobar
2
Je suis d'accord dans certains cas, c'est une très bonne idée, mais dans d'autres (comme la distribution d'un projet où vous avez un squelette autrement vide avec des dossiers tels que des modèles / et des vues /), vous voudriez que l'utilisateur ait ces répertoires à portée de main plutôt que d'avoir à lire manuellement les documents, et il pourrait être difficile de s'attendre à ce qu'ils exécutent une sorte de script d'installation après le clonage du dépôt. Je pense que cette réponse en combinaison avec la réponse README de @ john-mee devrait couvrir la plupart sinon tous les cas.
moopet
14

J'ai également été confronté au problème avec des répertoires vides. Le problème avec l'utilisation des fichiers d'espace réservé est que vous devez les créer et les supprimer s'ils ne sont plus nécessaires (car plus tard, des sous-répertoires ou des fichiers ont été ajoutés. Avec de grandes arborescences de sources, la gestion de ces fichiers d'espace réservé peut être lourde et entraîner des erreurs). enclin.

C'est pourquoi j'ai décidé d'écrire un outil open source qui peut gérer la création / suppression de tels fichiers d'espace réservé automatiquement. Il est écrit pour la plate-forme .NET et fonctionne sous Mono (.NET pour Linux) et Windows.

Jetez un œil à: http://code.google.com/p/markemptydirs


la source
14

J'aime les réponses de @ Artur79 et @mjs, j'ai donc utilisé une combinaison des deux et en ai fait un standard pour nos projets.

find . -type d -empty -exec touch {}/.gitkeep \;

Cependant, seule une poignée de nos développeurs travaillent sur Mac ou Linux. Beaucoup de travail sur Windows et je n'ai pas pu trouver un simple doublure équivalent pour accomplir la même chose là-bas. Certains ont eu la chance d'avoir Cygwin installé pour d'autres raisons, mais prescrire Cygwin juste pour cela semblait exagéré.

Modifier pour une meilleure solution

Donc, comme la plupart de nos développeurs ont déjà installé Ant , la première chose à laquelle j'ai pensé a été de créer un fichier de génération Ant pour accomplir cela indépendamment de la plate-forme. Vous pouvez toujours le trouver ici

Cependant , j'ai pensé plus tard qu'il serait préférable d'en faire une petite commande utilitaire, donc je l'ai recréé en utilisant Python et publié sur PyPI ici . Vous pouvez l'installer en exécutant simplement:

pip3 install gitkeep2

Il vous permettra de créer et de supprimer des .gitkeepfichiers de manière récursive, et il vous permettra également d'y ajouter des messages pour que vos pairs comprennent pourquoi ces répertoires sont importants. Ce dernier morceau est un bonus. J'ai pensé que ce serait bien si les .gitkeepfichiers pouvaient être auto-documentés.

$ gitkeep --help
Usage: gitkeep [OPTIONS] PATH

  Add a .gitkeep file to a directory in order to push them into a Git repo
  even if they're empty.

  Read more about why this is necessary at: https://git.wiki.kernel.org/inde
  x.php/Git_FAQ#Can_I_add_empty_directories.3F

Options:
  -r, --recursive     Add or remove the .gitkeep files recursively for all
                      sub-directories in the specified path.
  -l, --let-go        Remove the .gitkeep files from the specified path.
  -e, --empty         Create empty .gitkeep files. This will ignore any
                      message provided
  -m, --message TEXT  A message to be included in the .gitkeep file, ideally
                      used to explain why it's important to push the specified
                      directory to source control even if it's empty.
  -v, --verbose       Print out everything.
  --help              Show this message and exit.

J'espère que tu trouves cela utile.

Mig82
la source
13

Vous ne pouvez et ne pourrez malheureusement pas le faire. Il s'agit d'une décision prise par Linus Torvald lui-même. Il sait ce qui est bon pour nous.

Il y a une diatribe quelque part que j'ai lu une fois.

J'ai trouvé des répertoires Re: Empty .. , mais il y en a peut-être un autre.

Vous devez vivre avec les solutions de contournement ... malheureusement.

user2334883
la source
1
Je sais que vous avez publié ceci comme exemple d'un mauvais argument, mais j'apprécie le lien car c'est en fait un argument bien raisonné contre le suivi des répertoires. ;-)
clacke
1
Cette réponse semble incohérente, car dans le prochain article sur le thread référencé, Linus Torvald dit qu'il s'attend à ce qu'ils aient besoin d'ajouter le suivi de répertoire: markmail.org/message/libip4vpvvxhyqbl . En fait, il dit qu'il "accueillerait favorablement les correctifs qui [ajouteraient la prise en charge du suivi des répertoires vides]"
Patrick M
Patrick, il y utilise aussi le mot "idiot". Je soupçonne que sa formulation s'adresse aux gens ici dans ce fil et je suppose donc qu'il n'implémentera pas quelque chose d '"idiot" dans Git par lui-même.
user2334883
10

Lorsque vous ajoutez un .gitignorefichier, si vous voulez y mettre une quantité de contenu (que vous voulez que Git ignore), vous voudrez peut-être ajouter une seule ligne avec juste un astérisque *pour vous assurer que vous n'ajoutez pas le contenu ignoré accidentellement .

Michael Johnson
la source
9

Il n'y a aucun moyen d'obtenir Git pour suivre les répertoires, donc la seule solution est d'ajouter un fichier d'espace réservé dans le répertoire que Git doit suivre.

Le fichier peut être nommé et contenir tout ce que vous voulez, mais la plupart des gens utilisent un fichier vide nommé .gitkeep(bien que certaines personnes préfèrent le VCS-agnostic.keep ).

Le préfixe le .marque comme un fichier caché.

Une autre idée serait d'ajouter un READMEfichier expliquant à quoi servira le répertoire.

Zaz
la source
8

Comme mentionné, il n'est pas possible d'ajouter des répertoires vides, mais voici une ligne qui ajoute des fichiers .gitignore vides à tous les répertoires.

ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'

Je l'ai collé dans un rakefile pour un accès facile.

Peter Hoeg
la source
6
Je préfère utiliserfind . -type d -empty -print0 | xargs --null bash -c 'for a; do { echo "*"; echo "!.gitignore"; } >>"$a/.gitignore"; done' --
Tino
8

La solution de Jamie Flournoy fonctionne très bien. Voici une version un peu améliorée pour garder le .htaccess:

# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess

Avec cette solution, vous pouvez valider un dossier vide, par exemple /log, /tmpou /cacheet le dossier restera vide.

romain
la source
2
Il veut garder un répertoire vide et non un fichier.
gvsrepins
2
Et j'ai mentionné qu'il conservera également le .htaccess. Exemple: si un logiciel a un répertoire pour les fichiers journaux (comme oxyde eshop) qui ne devrait pas être accessible via le web, il y a un .htaccess dans le répertoire. Si vous placez le .gitignore mentionné ci-dessus dans le dossier, le .htaccess ne sera pas validé et le dossier sera accessible via le Web.
Roman
Si vous avez un fichier .htaccess sous contrôle de version, vous disposez déjà du répertoire le contenant sous contrôle de version. Ainsi, le problème est déjà résolu - le fichier .gitignore devient hors de propos.
Ponkadoodle
1
@Wallacoloo En rapport avec la question que vous avez raison, néanmoins le fichier est utile, je vais l'utiliser pour un répertoire de téléchargement comme celui où les fichiers doivent être protégés par .htaccess. Contrairement à l'explication des Romains, le fichier .htaccess sera validé car il est exclu par la règle ignore. [vieux fil, je sais]
David
7

Je crée toujours une fonction pour vérifier la structure de dossiers souhaitée et la créer pour moi dans le projet. Cela permet de contourner ce problème car les dossiers vides sont conservés dans Git par proxy.

function check_page_custom_folder_structure () {
    if (!is_dir(TEMPLATEPATH."/page-customs"))
        mkdir(TEMPLATEPATH."/page-customs");    
    if (!is_dir(TEMPLATEPATH."/page-customs/css"))
        mkdir(TEMPLATEPATH."/page-customs/css");
    if (!is_dir(TEMPLATEPATH."/page-customs/js"))
        mkdir(TEMPLATEPATH."/page-customs/js");
}

C'est en PHP, mais je suis sûr que la plupart des langages prennent en charge la même fonctionnalité, et parce que la création des dossiers est prise en charge par l'application, les dossiers seront toujours là.

Doux Fuzz
la source
2
Pour que nous soyons tous sur la même longueur d'onde, je ne fais plus ça. C'est une perte de temps. La .gitkeepconvention est une bien meilleure pratique.
Mild Fuzz
Je ne vois pas comment cela peut être une perte de temps. Lorsque votre TEMPLATEPATH est évidemment dynamique, vous ne pouvez pas utiliser la solution .gitkeep. Et même avec une structure de dossiers non dynamique, vous devriez ajouter d'autres éléments au lieu de supprimer la très bonne solution de vérification des répertoires, par exemple vérifier les autorisations et chmoder les fichiers. Ajouter un moyen de marquer des répertoires dans un .gitignore global serait parfait pour moi. Quelque chose comme #keep / path / to / dir
Jochen Schultz
7

Voici un hack, mais c'est drôle que ça marche (Git 2.2.1). Similaire à ce que @Teka a suggéré, mais plus facile à retenir:

  • Ajouter un sous-module à n'importe quel référentiel ( git submodule add path_to_repo)
  • Cela ajoutera un dossier et un fichier .submodules. Engagez un changement.
  • Supprimez le .submodulesfichier et validez la modification.

Maintenant, vous avez un répertoire qui est créé lorsque la validation est extraite. Une chose intéressante cependant est que si vous regardez le contenu de l'objet arbre de ce fichier, vous obtiendrez:

fatal: nom d'objet non valide b64338b90b4209263b50244d18278c0999867193

Je n'encouragerais pas à l'utiliser, car il pourrait ne plus fonctionner dans les futures versions de Git. Ce qui peut laisser votre référentiel corrompu.

Stanislav Bashkyrtsev
la source
Cela fonctionne réellement mais je pense que confond le diable d'IntelliJ ...: |
rogerdpack
J'ai créé une meilleure solution basée sur cela qui n'a pas ces inconvénients: stackoverflow.com/a/58543445/277882
ntninja
7

Beaucoup ont déjà répondu à cette question. Il suffit d'ajouter une version PowerShell ici.

Trouver tous les dossiers vides dans le répertoire

Ajoutez-y un fichier .gitkeep vide

Get-ChildItem 'Path to your Folder' -Recurse -Directory | Where-Object {[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0} | ForEach-Object { New-Item ($_.FullName + "\.gitkeep") -ItemType file}
Hainan.Z
la source
Nice.‌‌ ༼ ͡☉ ͜ʖ ͡☉ ༽
FiringSquadWitness
6

Si vous souhaitez ajouter un dossier qui contiendra beaucoup de données transitoires dans plusieurs répertoires sémantiques, alors une approche consiste à ajouter quelque chose comme ça à votre racine .gitignore ...

/app/data/**/*.* !/app/data/**/*.md

Ensuite, vous pouvez valider des fichiers README.md descriptifs (ou des fichiers vides, peu importe, tant que vous pouvez les cibler uniquement comme dans le *.mdcas présent) dans chaque répertoire pour vous assurer que les répertoires restent tous partie du référentiel, mais le les fichiers (avec extensions) sont ignorés. LIMITATION:. les ne sont pas autorisés dans les noms de répertoire!

Vous pouvez remplir tous ces répertoires avec des fichiers xml / images ou autre et ajouter plus de répertoires sous /app/data/ fil du temps au fur et à mesure que les besoins de stockage de votre application se développent (avec les fichiers README.md servant à graver dans une description de la fonction de chaque répertoire de stockage exactement).

Il n'est pas nécessaire de modifier davantage votre .gitignoreou de décentraliser en créant un nouveau .gitignorepour chaque nouveau répertoire. Ce n'est probablement pas la solution la plus intelligente, mais elle est sage en termes gitignore et fonctionne toujours pour moi. Agréable et simple! ;)

entrez la description de l'image ici

ajmedway
la source
6

Un moyen simple de le faire consiste à ajouter un .gitkeepfichier dans le répertoire que vous souhaitez (actuellement) conserver vide.

Voir cette réponse SOF pour plus d'informations - ce qui explique également pourquoi certaines personnes trouvent confuse la convention concurrente d'ajouter un fichier .gitignore (comme indiqué dans de nombreuses réponses ici).

arcseldon
la source
4

Ajout d'une option supplémentaire à la mêlée.

En supposant que vous souhaitiez ajouter un répertoire à gitcelui-ci, à toutes les fins liées à git, devrait rester vide et ne jamais avoir son contenu suivi, .gitignorecomme cela a été suggéré à plusieurs reprises ici, fera l'affaire.

Le format, comme mentionné, est:

*
!.gitignore

Maintenant, si vous voulez un moyen de le faire sur la ligne de commande, d'un seul coup, alors que dans le répertoire que vous souhaitez ajouter, vous pouvez exécuter:

$ echo "*" > .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore

Moi-même, j'ai un script shell que j'utilise pour ce faire. Nommez le script comme vous le souhaitez et ajoutez-le quelque part dans votre chemin d'inclusion, ou référencez-le directement:

#!/bin/bash

dir=''

if [ "$1" != "" ]; then
    dir="$1/"
fi

echo "*" > $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore

Avec cela, vous pouvez soit l'exécuter à partir du répertoire que vous souhaitez ajouter, soit référencer le répertoire comme son premier et seul paramètre:

$ ignore_dir ./some/directory

Une autre option (en réponse à un commentaire par @GreenAsJade), si vous voulez suivre un dossier vide MAI contenir des fichiers à l'avenir chenillés, mais sera vide pour l' instant, vous pouvez ommettre le à *partir du .gitignorefichier, et vérifier que dans. Fondamentalement, tout le fichier dit est "ne m'ignore pas ", mais sinon, le répertoire est vide et suivi.

Votre .gitignorefichier ressemblerait à:

!.gitignore

Voilà, vérifiez cela, et vous avez un répertoire vide, mais suivi, dans lequel vous pouvez suivre les fichiers ultérieurement.

La raison pour laquelle je suggère de conserver cette ligne dans le fichier est qu'elle donne le .gitignorebut. Sinon, quelqu'un au bout du fil pourrait penser à le supprimer. Cela peut être utile si vous placez un commentaire au-dessus de la ligne.

Mike
la source
4

Parfois, vous devez gérer de mauvaises bibliothèques ou logiciels écrits, qui nécessitent un "vrai" répertoire vide et existant. Mettre un simple .gitignoreou .keeppourrait les casser et provoquer un bug. Les éléments suivants peuvent aider dans ces cas, mais aucune garantie ...

Créez d'abord le répertoire nécessaire:

mkdir empty

Ensuite, vous ajoutez un lien symbolique cassé vers ce répertoire (mais dans tout autre cas que le cas d'utilisation décrit ci-dessus, veuillez utiliser un READMEavec une explication):

ln -s .this.directory empty/.keep

Pour ignorer les fichiers de ce répertoire, vous pouvez l'ajouter à votre racine .gitignore:

echo "/empty" >> .gitignore

Pour ajouter le fichier ignoré, utilisez un paramètre pour le forcer:

git add -f empty/.keep

Après la validation, vous avez un lien symbolique brisé dans votre index et git crée le répertoire. Le lien rompu présente certains avantages, car il ne s'agit pas d'un fichier normal et ne pointe vers aucun fichier normal. Donc, cela correspond même à la partie de la question "(qui ne contient aucun fichier)", non pas par l'intention mais par le sens, je suppose:

find empty -type f

Cette commande affiche un résultat vide, car aucun fichier n'est présent dans ce répertoire. Ainsi, la plupart des applications, qui obtiennent tous les fichiers d'un répertoire, ne voient généralement pas ce lien, du moins si elles existent, un "fichier existe" ou un "est lisible". Même certains scripts n'y trouveront aucun fichier:

$ php -r "var_export(glob('empty/.*'));"
array (
  0 => 'empty/.',
  1 => 'empty/..',
)

Mais je recommande fortement de n'utiliser cette solution que dans des circonstances spéciales, un bon écrit READMEdans un répertoire vide est généralement une meilleure solution. (Et je ne sais pas si cela fonctionne avec un système de fichiers Windows ...)

Trendfischer
la source
4

Lire @ofavre et @ stanislav-bashkyrtsev utilisant des références de sous-module GIT cassées pour créer les répertoires GIT, je suis surpris que personne n'ait encore suggéré cette simple modification de l'idée pour rendre le tout sain et sûr:

Plutôt que de pirater un faux sous-module dans GIT , ajoutez simplement un vrai vide .

Entrez: https://gitlab.com/empty-repo/empty.git

Un référentiel GIT avec exactement un commit:

commit e84d7b81f0033399e325b8037ed2b801a5c994e0
Author: Nobody <none>
Date: Thu Jan 1 00:00:00 1970 +0000

Aucun message, aucun fichier validé.

Usage

Pour ajouter un répertoire vide à votre référentiel GIT:

git submodule add https://gitlab.com/empty-repo/empty.git path/to/dir

Pour convertir tous les répertoires vides existants en sous-modules:

find . -type d -empty -delete -exec git submodule add -f https://gitlab.com/empty-repo/empty.git \{\} \;

Git stockera le dernier hachage de validation lors de la création de la référence du sous-module, vous n'avez donc pas à vous soucier de moi (ou GitLab) en l'utilisant pour injecter des fichiers malveillants. Malheureusement, je n'ai trouvé aucun moyen de forcer l'ID de validation utilisé lors du paiement, vous devrez donc vérifier manuellement que l'ID de validation de référence e84d7b81f0033399e325b8037ed2b801a5c994e0utilisegit submodule status après l'ajout du dépôt.

Pas encore une solution native, mais le mieux que nous pouvons probablement sans que quelqu'un mettre la main vraiment , vraiment sale dans la base de code GIT.

Annexe: recréation de ce commit

Vous devriez pouvoir recréer ce commit exact en utilisant (dans un répertoire vide):

# Initialize new GIT repository
git init

# Set author data (don't set it as part of the `git commit` command or your default data will be stored as “commit author”)
git config --local user.name "Nobody"
git config --local user.email "none"

# Set both the commit and the author date to the start of the Unix epoch (this cannot be done using `git commit` directly)
export GIT_AUTHOR_DATE="Thu Jan 1 00:00:00 1970 +0000"
export GIT_COMMITTER_DATE="Thu Jan 1 00:00:00 1970 +0000"

# Add root commit
git commit --allow-empty --allow-empty-message --no-edit

Créer des commits GIT reproductibles est étonnamment difficile…

ntninja
la source
3

Tu ne peux pas. Il s'agit d'une décision de conception intentionnelle par les responsables de Git. Fondamentalement, l'objectif d'un système de gestion de code source comme Git est de gérer le code source et les répertoires vides ne sont pas du code source. Git est également souvent décrit comme un tracker de contenu, et encore une fois, les répertoires vides ne sont pas du contenu (bien au contraire, en fait), donc ils ne sont pas suivis.

Jörg W Mittag
la source
60
Je conteste ce point de vue. La structure est du contenu et tout ce que vous nommez contribue au contenu.
ThomasH
20
Un fichier vide n'est pas non plus du code source ou du contenu. C'est juste un nom. Pourtant, Git suivra avec plaisir les fichiers vides. Je ne pense pas que c'était une décision de conception intentionnelle de faire en sorte que Git refuse de suivre les répertoires vides. Je pense que le suivi des répertoires vides est une fonctionnalité qui n'est tout simplement pas nécessaire 99% du temps, donc ils n'ont pas pris la peine de faire le travail supplémentaire nécessaire pour le faire fonctionner correctement. Git peut le faire si quelqu'un veut assez la fonctionnalité pour l'implémenter. Je doute que les mainteneurs de Git soient opposés à un tel patch s'il était fait correctement.
Dan Moulding,
1
@TobyAllen voici le lien FAQ mis à jour . La première réponse est également celle qui est recommandée par la FAQ avec des instructions plus précises.
Daniel Da Cunha
3
C'est une fonctionnalité manquante (et de faible priorité), pas une limitation intentionnelle. De la FAQ Git: Actuellement, la conception de l'index Git (zone de transit) ne permet que la liste des fichiers, et personne suffisamment compétent pour effectuer la modification pour autoriser les répertoires vides ne s'est suffisamment soucié de cette situation pour y remédier.
jbo5112
Je ne suis pas vraiment d'accord. Je peux trouver diverses raisons pour lesquelles je souhaite suivre un dossier vide. Par exemple, je développe un framework PHP MVC très léger pour mes projets. J'ai des dossiers spécifiques pour placer des modèles, des vues, etc. Lorsque je crée un nouveau site basé sur mon framework, ces dossiers sont vides car il n'y a pas de modèles ou de vues par défaut, mais j'ai besoin du dossier pour exister, sinon mon framework a gagné ça marche pas!
Gladen
2

Vous pouvez enregistrer ce code sous create_readme.php et exécuter le code PHP à partir du répertoire racine de votre projet Git.

> php create_readme.php

Il ajoutera des fichiers README à tous les répertoires vides afin que ces répertoires soient ensuite ajoutés à l'index.

<?php
    $path = realpath('.');
    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),       RecursiveIteratorIterator::SELF_FIRST);
    foreach($objects as $name => $object){
        if ( is_dir($name) && ! is_empty_folder($name) ){
            echo "$name\n" ;
            exec("touch ".$name."/"."README");
        }
    }

    function is_empty_folder($folder) {
        $files = opendir($folder);
        while ($file = readdir($files)) {
            if ($file != '.' && $file != '..')
                return true; // Not empty
            }
        }
?>

Alors fais

git commit -m "message"
git push
user665190
la source