Git - різниця між "припустити-незмінним" та "пропустити робоче дерево"


450

У мене є місцеві зміни до файлу, які я не хочу вносити до свого сховища. Це файл конфігурації для побудови програми на сервері, але я хочу створити локально з різними налаштуваннями. Звичайно, файл завжди відображається, коли я роблю 'git status' як щось, що потрібно ставити. Я хотів би приховати цю конкретну зміну, а не вчиняти її. Я не вношу жодних інших змін у файл.

Після деякого копання я бачу два варіанти: 'припустити-змінити' та 'пропустити робоче дерево'. Попереднє питання тут говорить про них, але насправді не пояснює їх відмінності. Моє запитання таке: чим дві команди відрізняються? Чому хтось використовував би те чи інше?


1
Зазвичай я використовую .gitignoreдля подібних цілей. Чи допоможе це рішення вам?
самуїл

45
samuil, .gitignore ігнорує додавання, не змінюючи. Коли файл уже в git, його буде відслідковувати подія, якщо воно вказане у .gitignore
Григорій

але не можна видалити все та додати все так, щоб "оновити", як пояснено тут? stackoverflow.com/questions/7075923 / ... @Grigory
Daniel Springer

2
Файл не слід ігнорувати, якщо я правильно отримав намір ОП. Файл повинен бути у сховищі, але ці дуже конкретні зміни, які він вніс, не повинні здійснюватися - принаймні зараз, принаймні.
Симона

Відповіді:


666

Ти хочеш 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це саме те, що ви хочете.

3
Що має сенс. skip-worktree справді, здається, шлях. Дякую!
ckb

100
Невелика примітка, щоб заощадити кілька секунд на пошуку та читанні. Для скасування --skip-worktreeефектів та зняття прапора є --no-skip-worktreeопція. Працює точно так само. Це корисно в тому випадку, якщо в руці зісковзли і помилилися файли, або якщо обставини змінилися і раніше пропущені файли більше не слід ігнорувати.
drdaeman

18
Щоб відповісти на моє власне запитання вище, різниця між використанням --skip-worktreeта .git/info/excludeфайлом полягає в тому, що перший працюватиме навіть для файлів, які зараз відстежуються. .git/info/exclude, наприклад .gitignore, запобігає лише випадковому додаванню неіндексованих файлів до індексу, але не вносить змін до файлів, які вже відстежуються.
ЛінусР

13
Чи можна це відсунути на віддалений і зберегти всі клони?
CMCDragonkai

4
Просто використання , пані:git update-index --skip-worktree <file_name>
ruffin

108

Примітка: 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-worktree файлу і відображає реальність (файл, обіцяний фактично незмінним, був змінений) для assume-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 р.) Від Брайана m. Карлсон ( bk2204) .
(Об'єднав Хуніо С Хамано - gitster- у комітеті 53a8329 , 30 січня 2020 р.)
(Список Git Mailing )

doc: відверніть користувачів від спроби ігнорувати відстежені файли

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

Користувачі досить часто хочуть ігнорувати зміни у файлі, який відстежує Git.

Загальні сценарії для цього випадку - це параметри IDE та конфігураційні файли, які, як правило, не слід відслідковувати та, можливо, генерувати з відстежуваних файлів за допомогою механізму шаблонів.

Однак користувачі дізнаються про біти, що не змінюються, і пропускають робочі дерева, і намагаються використовувати їх для будь-якого.

Це проблематично, оскільки коли ці біти встановлені, багато операцій ведуть себе так, як очікує користувач, але вони зазвичай не допомагають, коли git checkoutпотрібно замінити файл.

У цій справі немає розумної поведінки, оскільки іноді дані є дорогоцінними, наприклад, певні файли конфігурації, а іноді це нерелевантні дані, які користувач із задоволенням відкине.

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

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

Сторінка git update-indexman тепер включає:

Користувачі часто намагаються використовувати assume-unchangedі skip-worktreeбіти, щоб сказати Git ігнорувати зміни у файлах, які відслідковуються. Це не працює, як очікувалося, оскільки Git все ще може перевіряти робочі файли дерев на предмет індексу під час виконання певних операцій. Загалом, Git не пропонує способу ігнорувати зміни відсліджених файлів, тому рекомендуються альтернативні рішення.

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

Останньою частиною є те, що я описую типовий драйвер фільтру вмісту на основі сценаріїв розмиття / очищення .


8
Якщо у вас є файл skip-worktree для файлу, і зміни вгору потоку ви отримуєте "будь ласка, скопіюйте або приховайте", коли ви намагаєтеся витягнути, навіть якщо статус git не повідомляє про файл як про змінений. Як ви можете цього уникнути, щоб локальні зміни могли тривати, поки люди обмінюються з виробничими налаштуваннями щодо походження?
GreenAsJade

3
Так, я можу підтвердити, що ви це робите. Це означає, що все ще дуже важко мати локальний файл, який ви просто хочете підтримувати по-іншому до джерела.
GreenAsJade

1
@GreenAsJade здається древнім. Будь-який шанс ви можете протестувати за допомогою 2.2.x?
VonC

1
@VonC, Посилання на "коментар Хуніо" не знаходиться в історії ревізій. Є чи це те , що ви мали в виду?
Майкл - Де Клей Ширкий

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