Статьи

Когда Git игнорирует ваш… .gitignore?

Я чувствую, что должен начать этот пост, говоря, что я очень люблю Git . Если вы никогда не слышали об этом, это система контроля версий, такая как CVS или Subversion, но, в отличие от этих двух, это распределенная система контроля версий. Я не буду вдаваться в подробности об истории и возможностях git, но если вам интересно об этом, вы можете перейти на http://git-scm.com/book, который является удивительным ресурсом со всем от вступления до передовые концепции.

Я предполагаю, что к настоящему времени большинство профессиональных разработчиков программного обеспечения используют некоторую форму контроля версий в своей повседневной работе, но вы не должны останавливаться на достигнутом. Я использую git и для личных проектов. Хотя некоторые люди могут подумать, что это может быть излишним , я полностью не согласен. Нет ничего лучше комфорта, зная, что вся история

все ваши файлы в безопасности и готовы быть возвращенными, если они вам когда-нибудь понадобятся. Мы все иногда делаем ошибки. С git это так же просто, как написать 3 простые команды:

1
2
3
mkdir myNewProject
cd myNewProject
git init

Это оно! Каждый файл, который вы создаете или изменяете в «myNewProject», теперь будет отслеживаться git. Очень полезная функция, которую вы получаете с каждым инструментом контроля версий — это возможность игнорировать определенные файлы из отслеживания инструмента. Вообще говоря, вы не хотите помещать в свой репозиторий кода ни один файл, который может быть вычислен в результате другого файла. В типичном проекте Java Maven это может быть, например, каталог «target» или, если вы используете Eclipse, файлы «.metadata», «.project» или «.settings». В git самый простой способ сделать это — иметь специальный файл с именем «.gitignore» в корне вашего проекта со всеми правилами исключения, которые вы хотите установить. Синтаксис этого файла довольно прост. Вы также можете иметь файл «.gitignore» для каждого подкаталога в вашем проекте, но это не так часто.

С правилами git и ignore хитрость заключается в том, что если файл, который вы хотите игнорировать, уже отслеживается git, то добавление его в «.gitignore» не заставит git автоматически забыть о файле. Чтобы проиллюстрировать этот момент, рассмотрим следующий пример. Сначала мы создаем репозиторий с двумя исходными файлами и фиксируем их:

1
2
3
4
5
6
mkdir gitExample
cd gitExample
touch file1 file2
git init
git add .
git commit -m 'Initial commit'

Давайте теперь создадим файл .gitignore, чтобы попытаться игнорировать «file2? и совершить это:

1
2
3
echo file2 > .gitignore
git add .
git commit -m 'Added gitignore for file2'

Теперь давайте изменим «file2? и посмотрим что получится

1
2
echo 'Hello World' >> file2
git status

Мы получаем:

1
2
3
4
5
6
7
8
# On branch master
# Changes not staged for commit:
# (use 'git add ...' to update what will be committed)
# (use 'git checkout -- ...' to discard changes in working directory)
#
# modified: file2
#
no changes added to commit (use 'git add' and/or 'git commit -a')

Git по-прежнему отслеживает file2, хотя уже находится на нашем .gitignore. Как я уже говорил, это происходит потому, что git уже отслеживал файл, когда мы добавляли его в наши игнорирующие файлы. Итак, давайте посмотрим, что произойдет, когда мы добавим «.gitignore» перед добавлением файла в git:

1
2
3
4
5
6
mkdir gitExample
cd gitExample
touch file1 file2
git init
echo 'file2' > .gitignore
git status

И теперь мы получаем:

01
02
03
04
05
06
07
08
09
10
# On branch master
#
# Initial commit
#
# Untracked files:
# (use 'git add ...' to include in what will be committed)
#
# .gitignore
# file1
nothing added to commit but untracked files present (use 'git add' to track)

Здорово! Нет упоминания о file2 в любом месте! Но если в качестве нашего первого примера мы забыли добавить файлы к нашему .gitignore изначально? Как мы можем помешать Git отслеживать их? Хорошая команда, которую мы можем использовать для этих случаев — git rm --cached file . В нашем первом примере:

1
2
git rm --cached file2
git commit -m 'Removed file2'

Если мы теперь изменим файл снова и сделаем git status мы получим:

1
2
echo 'Hello World Again' >> file2
git status
1
2
# On branch master
nothing to commit (working directory clean)

Именно то, что мы хотели!

Обратите внимание, что эта маленькая команда удалит файл из индекса git, но ничего не сделает с вашей рабочей копией. Это означает, что у вас все еще будет файл в вашем каталоге, но файл больше не будет частью репозитория git. Это также означает, что в следующий раз, когда вы отправите файл в удаленный репозиторий, файл не будет передан, и, если он уже существовал в удаленном репозитории, он будет удален.

Это хорошо для типичного случая использования, когда вы добавили файл, который вы никогда не собирались иметь в хранилище. Но рассмотрим этот другой вариант использования. Во многих проектах разработчики загружают в удаленный центральный репозиторий набор файлов конфигурации для своей IDE со значениями по умолчанию для таких вещей, как форматирование кода и проверка стиля. Но в то же время, когда разработчики клонируют репозиторий, они настраивают эти файлы конфигурации в соответствии со своими личными предпочтениями. Тем не менее, те изменения, которые применяются к каждому конкретному разработчику, не должны быть зафиксированы и перенесены обратно в хранилище. Проблема с использованием git rm --cached заключается в том, что, хотя у каждого разработчика все еще будет своя собственная копия, в следующий раз, когда он отправит на сервер, он удалит оттуда конфигурацию по умолчанию. В подобных случаях есть еще одна довольно полезная команда, которая сделает git update-index --assume-unchanged <file> : git update-index --assume-unchanged <file> . Давайте посмотрим, что на примере:

1
2
3
4
5
6
mkdir gitExample
cd gitExample
touch file1 file2
git init
git add .
git commit -m 'Initial commit'

Там у нас есть по умолчанию «file2?». Теперь давайте воспользуемся командой git update-index и внесем некоторые изменения в файл:

1
2
3
git update-index --assume-unchanged file2
echo 'Hello World' >> file2
git status

Результат:

1
2
# On branch master
nothing to commit (working directory clean)

Магия! Git больше не видит изменений в нашем файле, а исходный файл все еще находится в хранилище, чтобы его могли клонировать другие пользователи со значением по умолчанию.

Справка: Когда Git игнорирует ваш… .gitignore? от нашего партнера JCG Хосе Луиса по разработке, как это должно быть в блоге.