Git - Разница между «предположим, без изменений» и «пропустить рабочее дерево»

454

У меня есть локальные изменения в файле, которые я не хочу фиксировать в своем хранилище. Это файл конфигурации для сборки приложения на сервере, но я хочу собрать локально с другими настройками. Естественно, файл всегда отображается, когда я делаю «git status», как что-то, что нужно поставить. Я хотел бы скрыть это конкретное изменение, а не совершать его. Я не буду вносить другие изменения в файл.

После нескольких копаний я вижу 2 варианта: «предположить, без изменений» и «пропустить рабочее дерево». Предыдущий вопрос здесь говорит о них, но на самом деле не объясняет их различия. У меня такой вопрос: чем отличаются две команды? Зачем кому-то использовать один или другой?

ЦКБ
источник
1
Обычно я использую .gitignoreдля подобных целей. Будет ли это решение работать на вас?
Самуил
45
samuil, .gitignore игнорирует добавление, а не изменение. Когда файл уже находится в git, он будет отслеживаться, если он указан в .gitignore
Григорий
но нельзя ли удалить все и добавить все, чтобы «освежить», как описано здесь? stackoverflow.com/questions/7075923/… @Grigory
Даниэль Спрингер
2
Файл не следует игнорировать, если я правильно понял намерение ОП. Файл должен находиться в репозитории, но эти очень конкретные изменения, которые он сделал, не должны быть зафиксированы - по крайней мере, не сейчас.
Симона

Ответы:

668

Вы хотите skip-worktree.

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

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

Хорошее резюме последствий этой разницы и типичных случаев использования здесь: http://fallengamer.livejournal.com/93321.html .

Из этой статьи:

  • --assume-unchangedПредполагается, что разработчик не должен изменять файл. Этот флаг предназначен для повышения производительности для неизменяемых папок, таких как SDK.
  • --skip-worktreeполезно, когда вы указываете git не трогать определенный файл, потому что разработчики должны изменить его. Например, если основной основной репозиторий содержит несколько готовых файлов конфигурации и вы не хотите случайно вносить изменения в эти файлы, --skip-worktreeэто именно то, что вам нужно.
Borealid
источник
100
Небольшая заметка, чтобы сэкономить несколько секунд поиска и чтения. Для отмены --skip-worktreeэффектов и снятия флажка есть --no-skip-worktreeопция. Работает точно так же. Это полезно, если рука поскользнулась и были помечены неправильные файлы, или если обстоятельства изменились и ранее пропущенные файлы больше не должны игнорироваться.
drdaeman
18
Чтобы ответить на мой собственный вопрос выше, разница между использованием --skip-worktreeи .git/info/excludeфайлом заключается в том, что первый будет работать даже для файлов, которые в настоящее время отслеживаются. Точно .git/info/excludeтак же .gitignoreбудет предотвращать только случайное добавление неотслеживаемых файлов в индекс, но не вносить изменения в файлы, которые уже отслеживаются.
LinusR
13
Может ли это быть перенесено на пульт и быть сохранено всеми клонами?
CMCDragonkai
4
К сожалению оба: --skip-worktreeи --assume-unchangedне позволяют переключиться на другую ветку. Я получаю ошибку: Your local changes to the following files would be overwritten by checkout. Подробности здесь
Евгений Коньков
4
Только использование , мэм:git update-index --skip-worktree <file_name>
ruffin
109

Примечание: fallengamer провел несколько тестов в 2011 году (поэтому они могут быть устаревшими), и вот его выводы :

операции

  • Файл изменяется как в локальном репозитории, так и в апстриме
    git pull:
    Git сохраняет локальные изменения в любом случае.
    Таким образом, вы случайно не потеряете данные, помеченные любым из флагов.
    • Файл с assume-unchangedфлагом: Git не будет перезаписывать локальный файл. Вместо этого он будет выводить конфликты и советы, как их разрешать
    • Файл с skip-worktreeфлагом: Git не будет перезаписывать локальный файл. Вместо этого он будет выводить конфликты и советы, как их разрешать

  • Файл изменяется как в локальном репозитории, так и в восходящем потоке, все равно пытаясь извлечь. Используя результаты в некоторой дополнительной ручной работе, но, по крайней мере, вы не потеряете данные, если у вас будут локальные изменения.
    git stash
    git pull
    skip-worktree
    • Файл с assume-unchangedфлагом: Отменяет все локальные изменения без возможности их восстановления. Эффект похож на ' git reset --hard'. ' git pull' вызов будет успешным
    • Файл с skip-worktreeфлагом: Stash не будет работать с skip-worktreeфайлами. ' git pull' потерпит неудачу с той же ошибкой, что и выше. Разработчик вынужден вручную сбросить skip-worktreeфлаг, чтобы иметь возможность скрыть и завершить сбой pull.

  • Локальных изменений нет, файл исходных данных изменен Оба флага не помешают вам получить входящие изменения. Git обнаруживает, что вы нарушили обещание, и пытается отразить реальность, сбросив флаг.
    git pull
    assume-unchanged
    • Файл с assume-unchangedфлагом: содержимое обновлено, флаг утерян.
      ' git ls-files -v' показывает, что флаг изменен на Hh).
    • Файл с skip-worktreeфлагом: содержимое обновлено, флаг сохранен.
      ' git ls-files -v' будет показывать тот же Sфлаг, что и до pull.

  • При изменении локального файла Git не трогает файл и отражает реальность (файл, обещанный неизменным, фактически был изменен) для файла.
    git reset --hard
    skip-worktreeassume-unchanged
    • Файл с assume-unchangedфлагом: содержимое файла обращено. Флаг сбрасывается на Hh).
    • Файл с skip-worktreeфлагом: содержимое файла не повреждено. Флаг остается прежним.

Он добавляет следующий анализ:

  • Похоже , что skip-worktreeэто очень старается сохранить свои локальные данные . Но это не мешает вам вносить изменения, если это безопасно. Плюс git не сбрасывает флаг pull.
    Но игнорирование команды ' reset --hard' может стать неприятным сюрпризом для разработчика.

  • Assume-unchangedфлаг может быть утерян во время pullоперации, и локальные изменения внутри таких файлов не кажутся важными для git.

Видеть:

Он делает вывод:

На самом деле ни один из флагов не является достаточно интуитивным .

  • assume-unchangedПредполагается, что разработчик не должен изменять файл. Если файл был изменен - ​​тогда это изменение не важно. Этот флаг предназначен для повышения производительности для неизменяемых папок, таких как SDK.
    Но если обещание нарушено и файл фактически изменен, git возвращает флаг, чтобы отразить реальность. Вероятно, все-таки есть несколько несовместимых флагов в папках, которые обычно не предназначены для изменения.

  • С другой стороны skip-worktree, полезно, когда вы указываете git не трогать определенный файл. Это полезно для уже отслеженного файла конфигурации.
    Основной основной репозиторий содержит несколько готовых конфигураций, но вы хотели бы изменить некоторые параметры в конфигурации, чтобы иметь возможность проводить локальное тестирование. И вы не хотите случайно проверять изменения в таком файле, чтобы повлиять на производственный конфиг. В таком случае skip-worktreeделает идеальную сцену.


С Git 2.25.1 (февраль 2020 г.), «фактически ни один из флагов не является достаточно интуитивным», упомянутое выше, дополнительно разъясняется:

См. Коммит 7a2dc95 , коммит 1b13e90 (22 января 2020 г.) от Брайана М. Карлсон ( bk2204) .
(Слиты Junio C Hamano - gitster- в фиксации 53a8329 , 30 Jan 2020)
( Git список рассылки )

doc: отговорить пользователей от попыток игнорировать отслеживаемые файлы

Подписано: Джефф Кинг
Подписано: Брайан М. Карлсон

Пользователи часто хотят игнорировать изменения в файле, который отслеживает Git.

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

Тем не менее, пользователи узнают о предполагаемых неизменяемых битах и ​​битах пропуска рабочего дерева и в любом случае пытаются использовать их для этого.

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

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

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

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

Страница git update-indexman теперь включает в себя:

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

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

Эта последняя часть - то, что я описываю типичный драйвер фильтра контента, основанный на нечетких / чистых скриптах .

VonC
источник
8
Если у вас есть skip-worktree для файла и изменения в верхнем потоке, вы получите «пожалуйста, подтвердите или скопируйте», когда вы пытаетесь извлечь, даже если git status не сообщает об этом файле как об измененном. Как вы можете избежать этого, чтобы локальные изменения могли сохраняться, пока люди возятся с производственными настройками на источнике?
GreenAsJade
3
Да, я могу подтвердить, что вы делаете. Это означает, что все еще очень трудно иметь локальный файл, который вы просто хотите сохранить в отличии от источника.
GreenAsJade
1
@GreenAsJade, чем кажется древним. Есть ли шанс, что вы сможете протестировать его с 2.2.x?
VonC
1
@VonC, ссылка на «комментарий Junio» отсутствует в истории изменений. Является ли это то , что вы имели в виду?
Майкл - Где Клэй Ширки
1
@ Майкл Отлично, спасибо. Я поставил эту ссылку обратно в ответ.
VonC