.gitignore виключає папку, але включає конкретну підпапку


964

У мене є папка, application/яку я додаю до .gitignore. Всередині application/папки знаходиться папка application/language/gr. Як я можу включити цю папку?

Я спробував це

application/
!application/language/gr/

без удачі ...


1
Будемо сподіватися, що документація про " .gitignoreформат шаблону" просто з’ясувалася (грудень 2013 року). Дивіться мою відповідь нижче
VonC

Мої улюблені запитання та відповіді, додані до вибраних, а також до закладок браузера.
codekiddy

Відповіді:


1611

Якщо ви виключаєте application/, то все під ним завжди буде виключено (навіть якщо деяка пізніша схема негативного виключення ("unignore") може відповідати чомусь під application/).

Для того, щоб робити те, що ви хочете, ви повинні "знехтувати" кожен батьківський каталог всього, що ви хочете "unignore". Зазвичай ви пишете правила для цієї ситуації парами: ігноруйте все в каталозі, але не якийсь певний підкаталог.

# you can skip this first one if it is not already excluded by prior patterns
!application/

application/*
!application/language/

application/language/*
!application/language/gr/

Примітка.
Оцінка /*важлива:

  • Шаблон dir/виключає каталог з ім'ям dirі (неявно) все, що знаходиться в ньому.
    З dir/, Git ніколи не буде дивитись на що-небудь нижче dir, і, таким чином, ніколи не застосовуватиме будь-який з "не-виключення" шаблонів до чогось під dir.
  • Шаблон dir/*нічого не говорить про dirсебе; це просто виключає все під dir. З dir/*, Git буде обробляти прямий вміст dir, даючи іншим шаблонам шанс "відключити" деякий біт вмісту ( !dir/sub/).

12
Чи значні зірочки в кінці? Якщо так, яка різниця в значенні? Відповідно до алгоритму, описаного в документації на gitignore , що закінчується косою косою рисою, відповідає каталозі та шляхам під цим каталогом. Закінчившись зірочкою, тоді б це траплялося як глобальний зразок. Експерименти показують варіант зірочки для роботи, але не той, який закінчується лише кінцевою косою рисою. Я хотів би зрозуміти, чому це так.
seh

123
@seh: Так, відставання /*є важливим. Якщо каталог виключено, Git ніколи не перегляне вміст цього каталогу. Шаблон dir/виключає каталог з ім'ям dirі (неявно) все, що знаходиться в ньому. Шаблон dir/*нічого не говорить про dirсебе; це просто виключає все під dir. З dir/, Git ніколи не буде дивитись на що-небудь нижче dir, і, таким чином, ніколи не застосовуватиме будь-який з "не-виключення" шаблонів до чогось під dir. З dir/*, Git буде обробляти прямий вміст dir, даючи іншим шаблонам шанс "відключити" деякий біт вмісту ( !dir/sub/).
Кріс Джонсен

7
Ах, це пояснює це. Незалежно від того, скільки разів я читав документацію на gitignore , я ніколи не розумів, коли повернені зразки не працюють. З вашим поясненням тепер зрозуміло. Документація gitignore потребує розділу «рецепт», щоб пояснити, як це зробити.
seh

8
Я не міг змусити це працювати (божевільний .gitignore файл!), Тому замість цього я просто примусив додавати файли після cd'ing до потрібного каталогу. git add -f .
K0D4

2
Зауважте, що ви не можете розраховувати на вихід git status, який просто скаже вам, що буде доданий каталог верхнього рівня. Натомість зробіть git addкаталог верхнього рівня, а потім git status(сподіваємось), перелічіть підмножину файлів, які були узгоджені за шаблоном.
Метью Соломбрідж

136

Коміт 59856de від Karsten Blees (kblees) для Git 1.9 / 2.0 (Q1 2014) уточнює цей випадок:

gitignore.txt: уточнити рекурсивний характер виключених каталогів

Необов’язковий префікс " !", який заперечує шаблон; будь-який відповідний файл, виключений за попереднім шаблоном, знову буде включений.

Неможливо повторно включити файл, якщо батьківський каталог цього файлу виключений. ( *)
( *: якщо певні умови не виконані в git 2.8+, див. нижче)
Git не перераховує виключені каталоги з міркувань продуктивності, тому будь-які шаблони вміщених файлів не мають впливу, незалежно від того, де вони визначені.

Покладіть зворотну косу рису (" \") перед першою " !" для шаблонів, які починаються з прямолінійного " !", наприклад, " \!important!.txt".

Приклад для виключення всього, крім конкретного каталогу foo/bar(зауважте /*- без косої риски підстановка також виключатиме все, що знаходиться в межах foo/bar):

 --------------------------------------------------------------
     $ cat .gitignore
     # exclude everything except directory foo/bar
     /*
     !/foo
     /foo/*
     !/foo/bar
 --------------------------------------------------------------

У вашому випадку:

application/*
!application/**/
application/language/*
!application/language/**/
!application/language/gr/**

Ви повинні білий список папок перше, перш ніж він зможе білий список файлів в цій папці.


Оновлення лютого / березня 2016 року:

Зауважте, що з git 2.9.x / 2.10 (середина 2016?), Можливо, можливо, повторно включити файл, якщо батьківський каталог цього файлу виключений, якщо в шлях повторно не включено підстановку .

Nguyễn Thái Ngọc Duy ( pclouds) намагається додати цю функцію:

Так що з git 2.9+ це могло насправді спрацювати, але в кінцевому підсумку було відмінено:

application/
!application/language/gr/

Я спробував використати оновлений синтаксис для повторного включення, розміщений наприкінці вашої відповіді на git для windows, v2.8.1.windows.1але, здається, він не працює :(
Девід Хенкок,

1
@DavidHancock Вибачте, я відредагував відповідь: ця інформація поки недоступна.
VonC

1
@DavidHancock мене теж: це понад 13 відповідей на переповнення стека, що мені довелося редагувати кілька разів!
VonC

5
Git 2.9 вийшов учора. Підтвердження шаблону application/+, !application/language/gr/зазначеного у відповіді, працює як очікується.
Рей Шен

1
@RayShan Strange: я бачу, що скасування повернення скасовує цю функцію, але я не бачу (і примітка до випуску github.com/git/git/blob/master/Documentation/RelNotes/2.9.0.txt не згадує) будь-які зобов’язання вдосконалювати правила .gitignore.
VonC

52

Відповідь @Chris Johnsen чудова, але в нових версіях Git (1.8.2 або новіших версій) є подвійний візерунок зірочок, на який можна скористатися трохи кращим рішенням:

# assuming the root folder you want to ignore is 'application'
application/**/*

# the subfolder(s) you want to track:
!application/language/gr/

Таким чином, вам не потрібно "унігнорувати" батьківський каталог підпапки, яку ви хочете відстежувати.


З Git 2.17.0 (Не впевнений, як рано до цієї версії. Можливо, повернемось до 1.8.2), використовуючи **шаблон, поєднаний з виключенням для кожного підкаталогу, що веде до вашого файлу (файлів), працює. Наприклад:

# assuming the root folder you want to ignore is 'application'
application/**

# Explicitly track certain content nested in the 'application' folder:
!application/language/
!application/language/gr/
!application/language/gr/** # Example adding all files & folder in the 'gr' folder
!application/language/gr/SomeFile.txt # Example adding specific file in the 'gr' folder

9
На жаль, це не вдається (Git 1.8.4.msysgit.0), оскільки шаблон **може збігатися з нульовими підпапками, і *відповідатиме languageта виключати його, запобігаючи включенню gr. Повний ланцюжок батьків @Chris Johnson рекомендує все ще здається необхідним.
Шон Гуглер

3
Звучить ідеально, але це не працює для мене на git 2.3.7 ... /www/**/* !/www/config.xml !/www/resconfig.xml та довідник res досі ігнорується.
Роб

@Rob також потрібно додати !/www/res/. Ви можете використовувати folder/**/*шаблон, але все одно потрібно додати виключення для кожного доданого підкаталогу. Він все ще коротший і легший для читання, ніж комбо ігнорування / виключення.
Бен Кейн

Я знаю, що це старий коментар, але у випадку, якщо вам цікаво. Я додав редагування у відповідь, що документує такий підхід.
Бен Кейн

21

З цим існує маса подібних питань, тому я опублікую те, що писав раніше:

Єдиний спосіб, коли я змусив це працювати на своїй машині, це зробити це так:

# Ignore all directories, and all sub-directories, and it's contents:
*/*

#Now ignore all files in the current directory 
#(This fails to ignore files without a ".", for example 
#'file.txt' works, but 
#'file' doesn't):
*.*

#Only Include these specific directories and subdirectories:
!wordpress/
!wordpress/*/
!wordpress/*/wp-content/
!wordpress/*/wp-content/themes/
!wordpress/*/wp-content/themes/*
!wordpress/*/wp-content/themes/*/*
!wordpress/*/wp-content/themes/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*/*

Зауважте, як вам явно потрібно дозволити вміст для кожного рівня, який ви хочете включити. Тож якщо у мене є підкаталоги 5 глибоких тем, мені все одно потрібно це прописати.

Це з коментаря @ Yarin тут: https://stackoverflow.com/a/5250314/1696153

Це були корисні теми:

Я також спробував

*
*/*
**/**

і **/wp-content/themes/**

або /wp-content/themes/**/*

Нічого з того не працювало і для мене. Багато спроб та помилок!


1
Примітка. Пам'ятайте, що порядок має значення і у файлі .gitignore, тому обов'язково розмістіть свої !правила внизу.
starbeamrainbowlabs


8

Найпростіший і, мабуть, найкращий спосіб - спробувати додати файли вручну (зазвичай це має перевагу над .gitignoreправилами стилю):

git add /path/to/module

Ви можете навіть хочете -N намір додати прапор, щоб запропонувати вам буде додати їх, але не відразу. Я часто роблю це для нових файлів, які ще не готові ставити.


Це копія відповіді, розміщеної на тому, що легко може бути дублікатом якості. Я відновлюю це тут, щоб підвищити видимість - мені легше не псувати правила gitignore.


2
Дякую за цю відповідь. Мені довелося додати -f, оскільки воно є в моєму .gitignore так, як так: git add -f path / to / file
jasonflaherty

6

Отже, оскільки багато програмістів використовують вузол. випадок використання, який відповідає цьому питанню, полягає у виключенні, node_modulesкрім одного модуля, module-aнаприклад:

!node_modules/

node_modules/*
!node_modules/module-a/

2
Не працює для версії git 2.10.2.windows.1.
Себастьян

1
Для версії git 2.10.2 слідкуйте за цією відповіддю
nalexn

👌 чудово 👋 👋.
Abdennour TOUMI

6

Додати додаткову відповідь:

!/.vs/              <== include this folder to source control, folder only, nothing else
/.vs/*              <== but ignore all files and sub-folder inside this folder
!/.vs/ProjectSettings.json <== but include this file to source control
!/.vs/config/       <== then include this folder to source control, folder only, nothing else
!/.vs/config/*      <== then include all files inside the folder

ось результат:

введіть тут опис зображення


2
Це була найкорисніша відповідь для мене, оскільки візуальні матеріали допомагали. Дякую!
Джоел Мерфі

4

Спеціально для старих версій Git більшість пропозицій не спрацює так добре. Якщо це так, я б помістив окремий .gitignore в каталог, де я хочу, щоб вміст був включений незалежно від інших налаштувань, і дозволити там необхідне.

Наприклад: /.gitignore

# ignore all .dll files
*.dll

/dependency_files/.gitignore

# include everything
!*

Тож все в / залежності_files (навіть файли .dll) включено просто чудово.


4

Тут я знайшов подібний випадок, коли в laravel за замовчуванням .gitignoreігнорує всі, використовуючи asterix, а потім переосмислює публічний каталог.

*
!public
!.gitignore

Цього недостатньо, якщо ви зіткнулися зі сценарієм ОП.

Якщо ви хочете , щоб зробити певні папки public, скажімо, наприклад , у вашій public/productsдиректорії , яку ви хочете включити файли, які один підпапок глибокий , наприклад , для включення public/products/a/b.jpgвони не будуть виявлені правильно, навіть якщо ви додасте їх конкретно , як це !/public/products, !public/products/*і т.д ..

Рішення полягає в тому, щоб переконатися, що ви додаєте запис для кожного рівня шляху, як цей, щоб перекрити їх усіх.

*
!.gitignore
!public/
!public/*/
!public/products/
!public/products/*
!public/products/*/
!public/products/*/
!public/products/*/*

3

Ще один приклад спуску структури каталогів, щоб отримати саме те, що вам потрібно. Примітка: я не виключав, Library/алеLibrary/**/*

# .gitignore file
Library/**/*
!Library/Application Support/
!Library/Application Support/Sublime Text 3/
!Library/Application Support/Sublime Text 3/Packages/
!Library/Application Support/Sublime Text 3/Packages/User/
!Library/Application Support/Sublime Text 3/Packages/User/*macro
!Library/Application Support/Sublime Text 3/Packages/User/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/*settings
!Library/Application Support/Sublime Text 3/Packages/User/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/*theme
!Library/Application Support/Sublime Text 3/Packages/User/**/
!Library/Application Support/Sublime Text 3/Packages/User/**/*macro
!Library/Application Support/Sublime Text 3/Packages/User/**/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/**/*settings
!Library/Application Support/Sublime Text 3/Packages/User/**/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/**/*theme

> git add Library

> git status

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   Library/Application Support/Sublime Text 3/Packages/User/Default (OSX).sublime-keymap
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ElixirSublime.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Package Control.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/RESTer.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/SublimeLinter/Monokai (SL).tmTheme
    new file:   Library/Application Support/Sublime Text 3/Packages/User/TextPastryHistory.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ZenTabs.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/adrian-comment.sublime-macro
    new file:   Library/Application Support/Sublime Text 3/Packages/User/json-pretty-generate.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/raise-exception.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/trailing_spaces.sublime-settings

Саме те, що я хотів зробити теж ;-)
Кітце

3

У WordPress це допомогло мені:

wp-admin/
wp-includes/
/wp-content/*
!wp-content/plugins/
/wp-content/plugins/*
!/wp-content/plugins/plugin-name/
!/wp-content/plugins/plugin-name/*.*
!/wp-content/plugins/plugin-name/**

3

gitignore - Вказує навмисно некрашені файли для ігнорування.

Приклад, щоб виключити все, окрім конкретного каталогу foo / bar (зверніть увагу на / * - без косої риски, підстановка також виключатиме все, що знаходиться у foo / bar ):

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar

Ще один приклад для WordPress :

!/wp-content
wp-content/*
!/wp-content/plugins
wp-content/plugins/*
!wp-content/plugins/my-awesome-plugin

Більше інформації тут: https://git-scm.com/docs/gitignore


2

Я часто використовую це рішення в CLI, коли замість налаштування мого .gitignoreя створюю окремий .includeфайл, де я визначаю (під) каталоги, які я хочу включити, незважаючи на каталоги безпосередньо або рекурсивно ігнорувати .gitignore.

Таким чином, я додатково використовую

git add `cat .include`

під час постановки, перед вчиненням.

Операційній програмі я пропоную використовувати такий, .includeякий має такі рядки:

<parent_folder_path>/application/language/gr/*

ПРИМІТКА: Використання catне дозволяє використовувати псевдоніми (всередині .include) для вказівки $ HOME (або будь-якого іншого конкретного каталогу). Це тому, що рядок homedir/app1/* при переході до git addвищевказаної команди виглядає як git add 'homedir/app1/*', а введення символів в одиничні лапки ('') зберігає буквальне значення кожного символу в лапках, тим самим запобігаючи функціонуванню псевдонімів (наприклад, homedir ) (див. Bash Single Цитати ).

Ось приклад .includeфайлу, який я використовую в репортажі тут .

/home/abhirup/token.txt
/home/abhirup/.include
/home/abhirup/.vim/*
/home/abhirup/.viminfo
/home/abhirup/.bashrc
/home/abhirup/.vimrc
/home/abhirup/.condarc

1

Я хотів відстежувати файли jjs виробництва jquery, і це спрацювало:

node_modules/*
!node_modules/jquery
node_modules/jquery/*
!node_modules/jquery/dist/*

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.