Nie ignoruj ​​podkatalogów ignorowanych katalogów w Git

100

Powiedzmy, że zignorowałem katalog, ale chcę zignorować określone w nim podkatalogi. Więc mam konfigurację:

/uploads/
/uploads/rubbish/
/uploads/rubbish/stuff/KEEP_ME/
/uploads/foo/
/uploads/foo/bar/lose/

Chcę zignorować wszystko oprócz KEEP_MEkatalogu. Mam nadzieję, że ignorowanie będzie wyglądało mniej więcej tak:

/uploads/*
!/uploads/rubbish/stuff/KEEP_ME/

Ale to nie działa, podobnie jak kilka permutacji na ten sam temat.

Jeden, który działa, jest

/uploads/**/**/**/
!/uploads/rubbish/stuff/KEEP_ME/

Ale to trochę restrykcyjne i rozwlekłe?

Wil
źródło
1
Kod, który podałeś, nie działał dla mnie (używając git w wersji 1.9.1). Jeden, który działał, to / uploads / *! / Uploads / rubbish / / uploads / rubbish / *! / Uploads / rubbish / stuff / uploads / rubbish / stuff / *! / Uploads / rubbish / stuff / keep (który jest podobny do przykładu w git-scm.com/docs/gitignore ). Struktura mojego folderu; └ README.md └ uploads / foo / bar / lost / lost.txt └ uploads / rubbish / stuff / keep / keep.txt
gihanchanuka

Odpowiedzi:

119

Zgodnie z sekcją dotyczącą formatu wzorca w dokumentacji gitignore :

Opcjonalny przedrostek „!” co neguje wzorzec; każdy pasujący plik wykluczony przez poprzedni wzorzec zostanie ponownie uwzględniony. Nie można ponownie dołączyć pliku, jeśli katalog nadrzędny tego pliku jest wykluczony. Git nie wyświetla wykluczonych katalogów ze względu na wydajność, więc wszelkie wzorce na zawartych plikach nie mają wpływu, bez względu na to, gdzie są zdefiniowane. Umieść ukośnik odwrotny („\”) przed pierwszym znakiem „!” dla wzorców zaczynających się od dosłownego „!”, na przykład „! ważne! .txt”.

Dlatego poprzednio wykluczony /uploads/rubbish/stuff/keep/wzorzec katalogu nadrzędnego musi zostać całkowicie zanegowany przed zanegowaniem jego zawartości:

#ignore everything within /uploads/ 
/uploads/*

#include everything within /uploads/rubbish/stuff/keep
!/uploads/rubbish/stuff/keep/  
!/uploads/rubbish/stuff/keep/*

Aby uwzględnić podkatalogi wewnątrz, /uploads/rubbish/stuff/keep/dodaj trzecią linię:

!/uploads/rubbish/stuff/keep/**/*
Art Shayderov
źródło
1
Jakiej wersji git używasz? Może to coś, co jest dostępne tylko w niektórych wersjach.
Zakłopotany. Zapomniałem, że opublikowałem ten komentarz. Ale udało mi się. FWIW, nie używam początkowych ukośników. Nie pamiętam, czy to był problem. Używam wersji 1.7.2.5.
Mam globalny plik gitignore, w którym zignorowałem cały plik * .zip. Jednak dla konkretnego projektu chcę dołączyć pliki zip. Dodałem tę linię do tego projektu .gitignorei działa świetnie !:!*.zip
Jinghao Shi
Zauważyłem, że konieczne jest jawne określenie dowolnych katalogów zarówno przed, jak i po danym folderze, zarówno podczas wykluczania folderu, jak i podczas włączania podfolderu . ( Pełna odpowiedź ).
Josiah Yoder
Ta metoda nie działa (od gita 2.25 - może coś się zmieniło w git). Jako korektę zamieściłem poniżej stackoverflow.com/a/60288435/295691 .
user295691
34

Nawet jeśli coś dodasz do .gitignore, możesz zmusić git do dodania tego do indeksu

git add --force uploads/rubbish/stuff/KEEP_ME/

Jednak "KEEP_ME" wydaje się być katalogiem, a git zwykle nie lubi pustego folderu, więc możesz zamiast tego dodać plik zastępczy, jeśli folder jest pusty

git add --force uploads/rubbish/stuff/KEEP_ME/.keep_me
KingCrunch
źródło
Jedynym problemem jest to, że ten konkretny przykład odnosi się do globalnego gitignore, o którym powinienem był wspomnieć. Wiem, że mogę wymusić dodanie elementów, ale będę musiał to zrobić, jeśli zostaną dodane nowe elementy, a także początkowo dla każdego nowego repozytorium. Czy .keep zapewnia, że ​​zawartość nie jest ignorowana?
Wil
1
Zrobiłem mały test. Tak, musisz użyć git add --forcedla każdego nowego elementu lub folderu w KEEP_ME. ale potem aktualizacje są po prostu dodawane ( git add -una przykład podczas wykonywania ), tak jakby pliki były „niezignorowane”. .keep_meNic nie robi, jej tylko dlatego, że plik git działa na folderze.
commonpike
1
git add --forcejest złym rozwiązaniem. Jeśli przeniesiesz katalog dookoła lub przeniesiesz plik do innego katalogu, śledzenie git usunie plik, ale nie doda go do nowej lokalizacji i musisz to zrobić git add --forceponownie. usuwając zignorowanie na ogólnym wzorcu, git będzie śledzić ruch pliku w repozytorium.
Merlin
To jedyne rozwiązanie, które u mnie zadziałało. Mój folder NIE został zignorowany, ale w żaden sposób nie mogłem go dodać. W ten sposób rozwiązałem to za mnie.
Akito
6

Próbowałem dowiedzieć się, jak uwzględnić określony folder, wykluczając wszystkie foldery z ogólnym wykluczeniem

**/build

jeśli dodasz na /*końcu wykluczenia ogólnego, nadal będziesz wykluczać wszystkie pliki kompilacji**/build/*

Następnie dodajesz kolejną linię, aby poprawić wygląd ścieżki, którą chcesz dołączyć

!**/folder/build/* 

zostawiając nam gitignore, który brzmi

**/build/* 
!**/folder/build/* 
Jan
źródło
2

Odpowiedzi Buo-Ren Lin i Johna są całkiem pomocne, ale musiałem połączyć obie.

Chcąc wykluczyć inne podfoldery, a także pliki w przesyłanych plikach, stwierdziłem, że konieczne jest jawne określenie dowolnych katalogów przed danym folderem, zarówno podczas wykluczania folderu, jak i podczas włączania podfolderu

**/uploads/*
!**/uploads/rubbish/
!**/uploads/rubbish/*

Zauważyłem również, że konieczne jest wyraźne ponowne uwzględnienie zarówno podfolderu, jak i jego zawartości, aby wyświetlić zarówno elementy w folderze, jak i podfoldery.

Josiah Yoder
źródło
Westchnienie. Zero szczęścia. Teraz już od kilku godzin. Git 2.20.1
RichieHH
@ HörmannHH Przykro mi to słyszeć. Może czas zadać nowe pytanie?
Josiah Yoder
2

Rozwiązanie przedstawiane jako odpowiedź, która uzyskała najwięcej głosów, jest niepoprawne i jako takie łatwe do udowodnienia.

Zacznij od ignorowania wszystkiego w przesyłanych plikach / *:

mkdir -p uploads/rubbish/stuff/KEEP_ME
touch uploads/a uploads/rubbish/a uploads/rubbish/stuff/a uploads/rubbish/stuff/KEEP_ME/a
echo '/uploads/*' >> .gitignore
git init
git add .
git commit -m "Initial commit"

Teraz zignoruj ​​katalog nadrzędny ignorowanych rzeczy, jak powyżej:

echo 'uploads/rubbish/stuff/KEEP_ME/' >> .gitignore
echo 'uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Pokazuje nieśledzone pliki.

Aby to działało, musisz zignorować wszystkie pliki w uploads/drzewie ( uploads/**/*nie tylko najwyższy poziom uploads/*), a następnie dodać wszystkie katalogi nadrzędne drzewa, które chcesz zachować

echo '/uploads/**/*' > .gitignore
echo '!/uploads/rubbish/' >> .gitignore
echo '!/uploads/rubbish/stuff' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Co daje:

On branch master
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        uploads/rubbish/stuff/KEEP_ME/a

Gdybyśmy wykorzystywane uploads/*w .gitignorepowyżej, a następnie wszystkie pliki pośrednie zostałyby uwzględnione, tak więc na przykład uploads/rubbish/aby pokazać się w komendzie stanu powyżej.

user295691
źródło