gitignore sans fichiers binaires

141

Comment les fichiers binaires peuvent-ils être ignorés lors de l' gitutilisation du .gitignorefichier?

Exemple:

$ g++ hello.c -o hello

Le fichier "bonjour" est un fichier binaire. Peut gitignorer ce fichier?

Juan Pablo
la source
2
Je suis très surpris qu'une question aussi ancienne et importante n'ait pas de réponse appropriée. Je suis encore plus surpris que la réponse soit simple [^\.]*.
TamaMcGlinn
ça ne marche pas
timotheecour

Réponses:

136
# Ignore all
*

# Unignore all with extensions
!*.*

# Unignore all dirs
!*/

### Above combination will ignore all files without extension ###

# Ignore files with extension `.class` & `.sm`
*.class
*.sm

# Ignore `bin` dir
bin/
# or
*/bin/*

# Unignore all `.jar` in `bin` dir
!*/bin/*.jar

# Ignore all `library.jar` in `bin` dir
*/bin/library.jar

# Ignore a file with extension
relative/path/to/dir/filename.extension

# Ignore a file without extension
relative/path/to/dir/anotherfile
VenomVendor
la source
1
Cette solution fonctionne comme un charme! Je ne comprends pas pourquoi en annulant tous les répertoires "! * /", Il peut également annuler les fichiers de sous-répertoire avec une extension? (par exemple aaa / bbb.c) mais ignore toujours le fichier de sous-répertoire sans extensions. (par exemple aaa / ccc)
dragonxlwang
4
Il semble que cette méthode ne fonctionne pas comme prévu après avoir constaté que lorsqu'il y a plusieurs couches de répertoire ...
dragonxlwang
@dragonxlwang Je suis curieux de savoir où cela ne fonctionnerait pas? La solution acceptée ici stackoverflow.com/a/19023985/1426932 est légèrement différente et utilise à la !/**/place de !*/; laquelle est correcte? / cc @VonC
timotheecour
Il est assez courant dans la culture Unix de nommer des scripts shell ainsi que des exécutables binaires sans extensions, auquel cas cette solution entraînera l'ignorance des scripts. Une meilleure idée est d'ajouter simplement des exécutables binaires à .gitignore manuellement chaque fois qu'ils sont ajoutés au projet - cela ne se produit généralement pas si souvent. Si cela est trop compliqué, alors la solution makefile suggérée par vedantk est meilleure.
Peter Helfer
Cela ignorera makefile
VMatrix1900
42

Ajoutez quelque chose comme

*.o

dans le fichier .gitignore et placez-le à la racine de votre dépôt (ou vous pouvez le placer dans n'importe quel sous-répertoire de votre choix - il s'appliquera à partir de ce niveau) et archivez-le.

Éditer:

Pour les binaires sans extension, il vaut mieux les placer dans bin/ou dans un autre dossier. Après tout, il n'y a pas d'ignorer basé sur le type de contenu.

Tu peux essayer

*
!*.*

mais ce n'est pas infaillible.

manojlds
la source
1
Modification ajoutée. Y a-t-il une raison pour laquelle vous ne voulez pas que votre binaire ait une extension
manojlds
10
Les exécutables n'ont souvent pas d'extensions. J'essaye de faire la même chose ici pour les fichiers créés en gccpassant -o $@.
Nathan Lilienthal
29

Pour ajouter tous les exécutables à votre .gitignore(ce que vous entendez probablement par «fichier binaire» d'après votre question), vous pouvez utiliser

find . -executable -type f >>.gitignore

Si vous ne vous souciez pas de l'ordre des lignes dans votre .gitignore, vous pouvez également mettre à jour votre .gitignoreavec la commande suivante qui supprime également les doublons et maintient l'ordre alphabétique intact.

T=$(mktemp); (cat .gitignore; find . -executable -type f | sed -e 's%^\./%%') | sort | uniq >$T; mv $T .gitignore

Notez que vous ne pouvez pas diriger la sortie directement vers .gitignore, car cela tronquerait le fichier avant de l' catouvrir pour la lecture. En outre, vous souhaiterez peut-être ajouter \! -regex '.*/.*/.*'une option pour rechercher si vous ne souhaitez pas inclure de fichiers exécutables dans les sous-répertoires.

icks
la source
23

Votre meilleur pari avec les binaires est de leur donner une extension que vous pouvez facilement filtrer avec un modèle standard, ou de les placer dans des répertoires que vous pouvez filtrer au niveau du répertoire.

La suggestion d'extension est plus applicable dans Windows, car les extensions sont standard et fondamentalement requises, mais sous Unix, vous pouvez ou non utiliser des extensions sur vos binaires exécutables. Dans ce cas, vous pouvez les mettre dans un dossier bin / et les ajouter bin/à votre .gitignore.

Dans votre exemple très spécifique, à petite portée, vous pouvez simplement mettre hellovotre .gitignore.

Andy White
la source
15

Vous pouvez essayer dans votre .gitignore:

*
!*.c

Cette approche présente de nombreux inconvénients, mais elle est acceptable pour les petits projets.

Andrei Beliankou
la source
3
Ce serait bien si vous
énumérez au
L'inconvénient évident est l'ordre des règles autoriser-refuser, la bonne façon est d'ignorer uniquement les fichiers indésirables, de ne pas tout interdire et ensuite d'inclure uniquement les fichiers souhaités.
Andrei Beliankou
13

Si vous utilisez un makefile, vous pouvez essayer de modifier vos règles de make pour ajouter les noms des nouveaux binaires à votre fichier .gitignore.

Voici un exemple de Makefile pour un petit projet Haskell;

all: $(patsubst %.hs, %, $(wildcard *.hs))

%: %.hs
    ghc $^
    grep -xq "$@" .gitignore || echo $@ >> .gitignore

Ce makefile définit une règle pour créer des exécutables à partir de code Haskell. Une fois que ghc est appelé, nous vérifions le .gitignore pour voir si le binaire y est déjà. Si ce n'est pas le cas, nous ajoutons le nom du binaire au fichier.

vedantk
la source
Maintenant, c'est une sorte d'approche différente.
René Nyffenegger
5

Voici une autre solution utilisant file. De cette façon, les scripts exécutables ne finiront pas dans gitignore. Vous devrez peut-être modifier la façon dont la sortie du fichier est interprétée pour correspondre à votre système. On pourrait alors configurer un hook pré-commit pour appeler ce script à chaque fois que vous vous engagez.

import subprocess, os

git_root = subprocess.check_output(['git', 'root']).decode("UTF-8").strip()
exes = []
cut = len(git_root)

for root, dirnames, filenames in os.walk(git_root+"/src/"):
  for fname in filenames:
    f = os.path.join(root,fname)
    if not os.access(f,os.X_OK):
      continue

    ft = subprocess.check_output(['file', f]).decode("UTF-8")

    if 'ELF' in ft and 'executable' in ft:
      exes.append(f[cut:])

gifiles = [ str.strip(a) for a in open(git_root + "/.gitignore").readlines() ]
gitignore=frozenset(exes+gifiles)

with open(git_root+"/.gitignore", "w") as g:
  for a in sorted(gitignore):
    print(a, file=g)
Tyler Earnest
la source
J'ai fait un script similaire, et posté sur une question en double: stackoverflow.com/a/28258619/218294 Votre code est plus agréable :) le mien tourne probablement plus vite car il exécute "file" une seule fois, ou plusieurs fois (en utilisant xargs).
Sam Watkins
4

Un moyen d'ignorer également dans certains sous-répertoires, pas seulement dans une racine:

# Ignore everything in a root
/*
# But not files with extension located in a root
!/*.*
# And not my subdir (by name)
!/subdir/
# Ignore everything inside my subdir on any level below
/subdir/**/*
# A bit of magic, removing last slash or changing combination with previous line
# fails everything. Though very possibly it just says not to ignore sub-sub-dirs.
!/subdir/**/
# ...Also excluding (grand-)children files having extension on any level
# below subdir
!/subdir/**/*.*

Ou, si vous souhaitez inclure uniquement certains types de fichiers spécifiques:

/*
!/*.c
!/*.h
!/subdir/
/subdir/**/*
!/subdir/**/
!/subdir/**/*.c
!/subdir/**/*.h

Il semble que cela puisse même fonctionner comme pour chaque nouveau sous-répertoire si vous le souhaitez!:

/*
!/*.c
!/*.h
!/*/
/*/**/*
!/*/**/
!/*/**/*.c
!/*/**/*.h

Les barres obliques de début ne sont importantes que dans les deux premières lignes et facultatives dans les autres. Tailing slash in !/*/et !/subdir/est également facultatif, mais uniquement dans cette ligne.

shaman.sir
la source
3

Si vous suivez ces commandes sur votre fichier .gitignore et que les fichiers semblent toujours apparaître, vous pouvez essayer:

git rm --cached FILENAME

Après cela, ajoutez votre .gitignore, validez et poussez. Il m'a fallu 40 minutes pour comprendre cela, j'espère que cela aidera les débutants comme moi

Shaun Peretz
la source
2

Vieux fil, mais toujours d'actualité. J'ai changé le makefile pour que le fichier binaire résultant après la liaison porte le nom [filname]. bin au lieu de seulement [filname]. Ensuite, j'ai ajouté des fichiers * .bin dans le gitignore.
Cette routine répond à mes besoins.

Nalle Haddock
la source
1

Je ne connais pas d'autre solution que de les ajouter une par une à .gitignore.

Une manière rudimentaire de tester est de grep la sortie de la commande de fichier:

find . \( ! -regex '.*/\..*' \) -type f | xargs -n 1 file | egrep "ASCII|text"

ÉDITER

Pourquoi ne vous nommez-vous pas simplement exécutable hello.bin?

muhuk
la source
Parce que nommer les exécutables avec l'extension de fichier .binest une mauvaise pratique.
MD XF
1

Ajoutez simplement helloou /helloà votre .gitignore. L'un ou l'autre fonctionne.

Travis Reeder
la source
Cela ignorera également un dossier appelé hello.
Patrick D'appollonio
0

J'ai créé un fichier .gitignore avec deux entrées dans le répertoire GOPATH.

/bin
/pkg

Il ignore tous les développements compilés, actuellement.

gszecsenyi
la source
0

.gitignore utilise la programmation glob pour filtrer les fichiers, au moins sous Linux.

Je suis sur le point de donner une conférence sur le codage lors d'un Meetup et, en préparation, j'ai créé un répertoire avec plusieurs sous-répertoires qui sont nommés selon l'ordre dans lequel je veux les présenter: 01_subject1, 02_subject2, 03_subject3. Chaque sous-répertoire contient un fichier source avec une extension dépendante de la langue qui se compile en un fichier exécutable dont le nom correspond au nom du fichier source sans l'extension selon la pratique courante.

J'exclus les fichiers compilés dans les répertoires à préfixe numérique avec la ligne .gitignore suivante:

[0-9][0-9]_*/[!\.]*

D'après ma compréhension de la documentation, cela ne devrait pas fonctionner. L'astérisque de fin doit échouer car il doit correspondre à n'importe quel nombre de caractères non spécifiés, y compris le «.» + extension. Omettre l'astérisque de fin doit échouer (et le fait) car il [!\.]ne correspond qu'à un seul caractère non point. Cependant, j'ai ajouté l'astérisque de fin, comme je le ferais pour une expression régulière, et cela fonctionne. Par travail, je veux dire que git remarque les modifications apportées au fichier source, mais pas l'existence ou les modifications des fichiers compilés.

chuckj
la source
0

S'appuyer sur la réponse de VenomVendors

# Ignore all
*

# Unignore all files with extensions recursively
!**/*.*

# Unignore Makefiles recursively
!**/Makefile

# other .gitignore rules...
Eero Aaltonen
la source
0

Ajoutez ce qui suit à votre fichier .gitignore:

[^\.]*

Explication:

[] encloses a character class, e.g. [a-zA-Z] means "any letter".
^  means "not"
\. means a literal dot - without the backslash . means "any character"
*  means "any number of these characters"
TamaMcGlinn
la source
0

Le .gitignoremécanisme fonctionne uniquement sur la base des noms de fichiers , pas sur le contenu des fichiers . Être un fichier binaire est une propriété du contenu, par conséquent vous ne pouvez pas demander directement à git d'ignorer les fichiers binaires, mais uniquement de les ignorer par leur nom (et comme cela est suggéré, vous pouvez soit ajouter tous les noms de fichiers binaires à votre, .gitignoresoit utiliser un convention de dénomination).

Le fait que cela .gitignorefonctionne sur les noms de fichiers est une propriété importante en termes de performances: Git n'a besoin que de lister les fichiers, mais pas de les ouvrir et de les lire pour savoir quels fichiers ignorer. En d'autres termes, Git serait terriblement lent si vous pouviez lui demander d'ignorer les fichiers en fonction de leur contenu.

Matthieu Moy
la source