Могу ли я 'git commit' файл и игнорировать изменения его содержимого?

355

Каждый разработчик в моей команде имеет свою локальную конфигурацию. Эта информация о конфигурации хранится в файле с именем, devtargets.rbкоторый используется в наших задачах сборки rake. Однако я не хочу, чтобы разработчики блокировали файл devtargets друг друга.

Моей первой мыслью было поместить этот файл в .gitignoreсписок, чтобы он не использовался в git.

Тогда я начал задаваться вопросом: можно ли зафиксировать файл, но игнорировать изменения в файле? Таким образом, я фиксирую версию файла по умолчанию, а затем, когда разработчик изменяет ее на своем локальном компьютере, git игнорирует эти изменения и не отображается в списке измененных файлов, когда вы выполняете состояние git или фиксируете git ,

Это возможно? Это, безусловно, было бы хорошей особенностью ...

Дерик Бэйли
источник

Ответы:

459

Конечно, я делаю это время от времени, используя

git update-index --assume-unchanged [<file> ...]

Чтобы отменить и снова начать отслеживание (если вы забыли, какие файлы не были отслежены, посмотрите этот вопрос ):

git update-index --no-assume-unchanged [<file> ...]

Соответствующая документация :

- [no-] предположить-без изменений
Когда указан этот флаг, имена объектов, записанные для путей, не обновляются. Вместо этого, эта опция устанавливает / отменяет бит «предположить неизменным» для путей. Когда бит «предположить, что без изменений» включен, пользователь обещает не изменять файл и позволяет Git предполагать, что файл рабочего дерева соответствует тому, что записано в индексе. Если вы хотите изменить файл рабочего дерева, вам нужно сбросить бит, чтобы сообщить Git. Это иногда полезно при работе с большим проектом в файловой системе с очень медленным lstat(2)системным вызовом (например, cifs).

Git потерпит неудачу (изящно), если ему нужно изменить этот файл в индексе, например, при слиянии в коммите; таким образом, в случае, если предполагаемый неотслеживаемый файл будет изменен в восходящем направлении, вам нужно будет обработать ситуацию вручную.

Изящный сбой в этом случае означает, что если есть какие-либо изменения перед этим файлом (допустимые изменения и т. Д.), Когда вы выполняете извлечение, он скажет:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

и откажется слиться.

На этом этапе вы можете преодолеть это путем отмены локальных изменений, вот один из способов:

 $ git checkout filename.ext

затем снова потяните и повторно измените свой локальный файл, или можете установить, –no-assume-unchangedи вы можете сделать обычное копирование и слияние и т. д. в этот момент.

Роб Уилкерсон
источник
10
эта команда делает свою вещь локально в папке .git? Я имею в виду, если я выполню эту команду для файла config.php, распространится ли это на других пользователей, которые используют репо?
Волхв
16
@Magus: Нет. Это будет работать только для вас.
Роб Уилкерсон
3
И вскоре позже вы захотите узнать, как определить, что файл считается неизменным: stackoverflow.com/questions/2363197/…
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
10
Изменения в файлах, игнорируемые таким образом, теряются при использовании «git stash». Есть ли способ обойти это?
Алексис
5
Это не то, что git update-index --assume-unchangedдля. public-inbox.org/git/…
jsageryd
97

Предпочтительный способ сделать это - использовать git update-index --skip-worktree <file>, как описано в этом ответе :

assume-unchangedпредназначен для случаев, когда стоит проверить, была ли изменена группа файлов; когда вы устанавливаете бит, git (конечно) предполагает, что файлы, соответствующие этой части индекса, не были изменены в рабочей копии. Таким образом, это позволяет избежать беспорядка статистических звонков. Этот бит теряется всякий раз, когда изменяется запись файла в индексе (то есть, когда файл изменяется в восходящем направлении).

skip-worktreeэто нечто большее: даже если git знает, что файл был изменен (или его нужно изменить с помощью reset --hard или подобного), он будет делать вид, что это не так, вместо этого используя версию из индекса. Это сохраняется до тех пор, пока индекс не будет отброшен.

Чтобы отменить это, используйте git update-index --no-skip-worktree <file>

Начиная с git версии 2.25.1, это больше не рекомендуемый способ, цитируя:

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

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

1615903
источник
Работает ли это на всех пользователях, которые проверяют хранилище? Получат ли они определенные файлы, но больше не смогут добавлять изменения по ошибке, если это явно не указано?
ммм
2
@momomo флаг хранится в индексе, поэтому нет, он только для одного пользователя. См . Ответ erjiang о том, что работает для всех пользователей.
1615903
Я пытаюсь выяснить, каким должно быть содержимое файла. Я прокомментировал ответ, на который вы ссылались, но ответа не получил. Где он должен быть расположен и каково его содержимое? Ты знаешь?
ммм
Я не следую. Команда используется для игнорирования одного конкретного файла, который вы указываете в команде. Содержимое этого файла не имеет значения.
1615903
1
В документации Git конкретно сказано, что не использовать git update-index --skip-worktreeдля этой цели.
bk2204
43

Похоже, что обычной практикой является создание devtargets.default.rbи принятие его, а затем указание каждому пользователю скопировать этот файл devtargets.rb(который находится в списке .gitignore). Например, CakePHP делает то же самое для своего файла конфигурации базы данных, который естественным образом изменяется от компьютера к компьютеру.

erjiang
источник
6
Вы не можете .gitignore файл, который отслеживается. .gitignore влияет только на файлы, которых нет в индексе.
CB Bailey
1
Я пытался избежать этого, хотя у меня действительно нет веской причины. мы делаем это сейчас, и я думаю, мне больно вспоминать, что мне нужно создать собственную версию без имени «.default».
Дерик Бейли
11
@DerickBailey Но, если честно, проще не забыть скопировать файл, чем использовать эту --assume-unchangedопцию для всех, кто клонирует репозиторий.
Дан
1
@DerickBailey, вы также можете настроить сборку рейка по умолчанию, devtargets.default.rbесли devtargets.rbона не существует.
Люк
@erjang, что в этом файле devtargets.default.rb? Пример?
ммм
2

Для пользователей IntelliJ IDEA: если вы хотите игнорировать изменения для файла (или файлов), вы можете переместить его в другой файл Change Set.

  • Направляйтесь к Local Changes( Cmd + 9)
  • Выберите файл (ы), которые вы хотите игнорировать
  • F6 переместить их в другой Change Set
Евгений
источник