gitignore bez plików binarnych

141

Jak można ignorować pliki binarne podczas gitkorzystania z .gitignorepliku?

Przykład:

$ g++ hello.c -o hello

Plik „hello” jest plikiem binarnym. Czy można gitzignorować ten plik?

JuanPablo
źródło
2
Jestem bardzo zaskoczony, że na tak stare i ważne pytanie nie ma właściwej odpowiedzi. Jeszcze bardziej dziwi mnie, że odpowiedź jest prosta [^\.]*.
TamaMcGlinn
to nie działa
timotheecour

Odpowiedzi:

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
źródło
1
To rozwiązanie działa jak marzenie! Nie rozumiem, dlaczego przez unignore all dirs "! * /", Może również anulować ignorowanie plików subdir z rozszerzeniem? (np. aaa / bbb.c), ale nadal ignoruj ​​plik subdir bez rozszerzeń. (np. aaa / ccc)
dragonxlwang
4
Wygląda na to, że ta metoda nie działa zgodnie z oczekiwaniami po tym, jak odkryłem, że gdy istnieje wiele warstw katalogu ...
dragonxlwang
@dragonxlwang Jestem ciekawy, gdzie to nie zadziała? Przyjęte tutaj rozwiązanie stackoverflow.com/a/19023985/1426932 jest nieco inne i używa !/**/zamiast !*/; który jest prawidłowy? / cc @VonC
timotheecour
W kulturze uniksowej dość powszechne jest nazywanie skryptów powłoki, a także binarnych plików wykonywalnych bez rozszerzeń. W takim przypadku to rozwiązanie spowoduje ignorowanie skryptów. Lepszym pomysłem jest ręczne dodawanie binarnych plików wykonywalnych do .gitignore za każdym razem, gdy są one dodawane do projektu - zazwyczaj nie zdarza się to zbyt często. Jeśli jest to zbyt kłopotliwe, lepsze jest rozwiązanie makefile sugerowane przez vedantk.
Peter Helfer
Spowoduje to zignorowanie pliku makefile
VMatrix1900
42

Dodaj coś takiego jak

*.o

w pliku .gitignore i umieść go w katalogu głównym repozytorium (lub możesz umieścić go w dowolnym podkatalogu - będzie obowiązywał od tego poziomu) i zaewidencjonuj.

Edytować:

W przypadku plików binarnych bez rozszerzenia lepiej umieścić je w bin/lub innym folderze. W końcu nie ma ignorowania w oparciu o typ zawartości.

Możesz spróbować

*
!*.*

ale to nie jest niezawodne.

manojlds
źródło
1
Dodano edycję. Czy jest jakiś powód, dla którego nie chcesz, aby Twój plik binarny miał rozszerzenie
manojlds
10
Pliki wykonywalne często nie mają rozszerzeń. Próbuję zrobić to samo tutaj dla plików utworzonych przez gccprzekazanie -o $@.
Nathan Lilienthal,
29

Aby dołączyć wszystkie pliki wykonywalne do swojego .gitignore(co prawdopodobnie rozumiesz przez „plik binarny”, sądząc po pytaniu), możesz użyć

find . -executable -type f >>.gitignore

Jeśli nie zależy Ci na kolejności wierszy w Twoim .gitignore, możesz również zaktualizować swój .gitignoreza pomocą następującego polecenia, które również usuwa duplikaty i zachowuje nienaruszoną kolejność alfabetyczną.

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

Zauważ, że nie możesz potokować wyjścia bezpośrednio do .gitignore, ponieważ spowodowałoby to obcięcie pliku przed catotwarciem go do odczytu. Możesz również dodać \! -regex '.*/.*/.*'jako opcję, aby znaleźć, jeśli nie chcesz umieszczać plików wykonywalnych w podkatalogach.

icks
źródło
23

Najlepszym rozwiązaniem w przypadku plików binarnych jest albo nadanie im rozszerzenia, które można łatwo odfiltrować za pomocą standardowego wzorca, albo umieszczenie ich w katalogach, które można odfiltrować na poziomie katalogu.

Sugestia rozszerzenia jest bardziej odpowiednia w systemie Windows, ponieważ rozszerzenia są standardowe i zasadniczo wymagane, ale w systemie Unix możesz lub nie używać rozszerzeń w plikach wykonywalnych. W takim przypadku możesz umieścić je w koszu / folderze i dodać bin/do swojego .gitignore.

W swoim bardzo szczegółowym przykładzie o małym zakresie możesz po prostu wstawić helloplik .gitignore.

Andy White
źródło
15

Możesz spróbować w .gitignore:

*
!*.c

Takie podejście ma wiele wad, ale jest akceptowalne w przypadku małych projektów.

Andrei Beliankou
źródło
3
Byłoby miło, gdybyś przynajmniej
wymienił
Oczywistą wadą jest kolejność reguł zezwalaj-odmawiaj. Właściwym sposobem jest ignorowanie tylko niepożądanych plików, nie blokowanie wszystkich, a następnie włączanie tylko żądanych plików.
Andrei Beliankou
13

Jeśli używasz pliku makefile, możesz spróbować zmodyfikować reguły make, aby dodać nazwy nowych plików binarnych do pliku .gitignore.

Oto przykład Makefile dla małego projektu Haskell;

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

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

Ten plik makefile definiuje regułę tworzenia plików wykonywalnych z kodu Haskell. Po wywołaniu ghc sprawdzamy plik .gitignore, aby zobaczyć, czy plik binarny już się w nim znajduje. Jeśli tak nie jest, dodajemy nazwę pliku binarnego do pliku.

vedantk
źródło
To jest trochę inne podejście.
René Nyffenegger
5

Oto inne rozwiązanie wykorzystujące plik. W ten sposób wykonywalne skrypty nie trafią do gitignore. Być może będziesz musiał zmienić sposób interpretacji danych wyjściowych z pliku, aby pasował do twojego systemu. Można wtedy ustawić hak przed zatwierdzeniem, aby wywoływać ten skrypt za każdym razem, gdy zatwierdzasz.

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
źródło
Zrobiłem podobny skrypt i zamieściłem na zduplikowanym pytaniu: stackoverflow.com/a/28258619/218294 Twój kod jest ładniejszy :) mój prawdopodobnie działa szybciej bo "file" uruchamia tylko raz lub kilka razy (używając xargs).
Sam Watkins
4

Sposób na ignorowanie w jakimś podkatalogu, nie tylko w katalogu głównym:

# 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/**/*.*

Lub, jeśli chcesz uwzględnić tylko określone typy plików:

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

Wygląda na to, że może nawet działać tak, jak dla każdego nowego podkatalogu, jeśli chcesz !:

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

Ukośniki wiodące są ważne tylko w pierwszych dwóch wierszach i opcjonalne w pozostałych. Tailing slash in !/*/i !/subdir/jest również opcjonalny, ale tylko w tej linii.

szaman.sir
źródło
3

Jeśli wykonasz te polecenia w pliku .gitignore, a pliki nadal wydają się pojawiać, możesz spróbować:

git rm --cached FILENAME

Następnie dodaj swój .gitignore, zatwierdź i wciśnij. Zrozumienie tego zajęło mi 40 minut, mam nadzieję, że pomoże to nowicjuszom takim jak ja

Shaun Peretz
źródło
2

Stary wątek, ale nadal aktualny. Zmieniłem plik makefile, więc wynikowy plik binarny po dowiązaniu ma nazwę [nazwa pliku]. bin zamiast tylko [nazwa pliku]. Następnie dodałem pliki * .bin w gitignore.
Ta rutyna spełnia moje potrzeby.

Nalle Haddock
źródło
1

Nie znam innego rozwiązania, ale dodam je pojedynczo do .gitignore.

Prostym sposobem testowania jest grepowanie danych wyjściowych polecenia pliku:

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

EDYTOWAĆ

Dlaczego po prostu nie nazwiesz swojego pliku wykonywalnego hello.bin?

muhuk
źródło
Ponieważ nazywanie plików wykonywalnych z rozszerzeniem pliku .binjest złą praktyką.
MD XF
1

Po prostu dodaj hellolub /hellodo swojego .gitignore. Albo działa.

Travis Reeder
źródło
Spowoduje to również zignorowanie folderu o nazwie hello.
Patrick D'appollonio,
0

Utworzyłem plik .gitignore z dwoma wpisami w katalogu GOPATH.

/bin
/pkg

Obecnie ignoruje wszystkie skompilowane zmiany.

gszecsenyi
źródło
0

.gitignore używa programowania globalnego do filtrowania plików, przynajmniej w Linuksie.

Mam zamiar wygłosić wykład na temat kodowania na Meetupie i w ramach przygotowań stworzyłem katalog zawierający kilka podkatalogów, które są nazwane zgodnie z kolejnością, w jakiej chcę je przedstawić: 01_subject1, 02_subject2, 03_subject3. Każdy podkatalog zawiera plik źródłowy z rozszerzeniem zależnym od języka, który zgodnie z powszechną praktyką kompiluje się do pliku wykonywalnego, którego nazwa jest zgodna z nazwą pliku źródłowego bez rozszerzenia.

Wykluczam skompilowane pliki w katalogach z prefiksem liczbowym z następującą linią .gitignore:

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

Zgodnie z moim rozumieniem dokumentacji to nie powinno działać. Gwiazdka na końcu powinna zakończyć się niepowodzeniem, ponieważ powinna pasować do dowolnej liczby nieokreślonych znaków, w tym „.” + rozszerzenie. Pominięcie końcowej gwiazdki powinno zakończyć się niepowodzeniem (i nie działa), ponieważ [!\.]dopasowuje tylko jeden znak bez kropki. Jednak dodałem końcową gwiazdkę, tak jak w przypadku wyrażenia regularnego i to działa. Przez pracę rozumiem, że git zauważa zmiany w pliku źródłowym, ale nie zauważa istnienia lub zmian w skompilowanych plikach.

chuckj
źródło
0

Opierając się na odpowiedzi VenomVendors

# Ignore all
*

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

# Unignore Makefiles recursively
!**/Makefile

# other .gitignore rules...
Eero Aaltonen
źródło
0

Dodaj do swojego pliku .gitignore:

[^\.]*

Wyjaśnienie:

[] 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
źródło
0

.gitignoreMechanizm działa w oparciu jedynie o plikach nazw , a nie w aktach treści . Bycie plikiem binarnym jest właściwością zawartości, dlatego nie możesz bezpośrednio poprosić git o ignorowanie plików binarnych, ale tylko po to, aby zignorować je po nazwie (i jak sugerowano inne, możesz dodać wszystkie nazwy plików binarnych do swojego .gitignorelub użyć odpowiedniego Konwencja nazewnictwa).

Fakt, że .gitignoredziała na nazwach plików, jest ważny z punktu widzenia wydajności: Git musi tylko wyświetlać listę plików, ale nie musi ich otwierać i czytać, aby wiedzieć, które pliki zignorować. Innymi słowy, Git byłby strasznie wolny, gdybyś mógł poprosić go o ignorowanie plików na podstawie ich zawartości.

Matthieu Moy
źródło