Git: Як видалити файл з індексу без видалення файлів із будь-якого сховища


163

Коли ви використовуєте

git rm --cached myfile

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

Чи є спосіб просто видалити файл з версії, не видаляючи його з жодної файлової системи?

Редагувати: Пояснено, сподіваюся.


Можливо, ви могли б розширити свій приклад використання. Індекс - це область постановки для наступної фіксації, тому чому ви хочете видалити файл з індексу, якщо ви не хочете видалити його з поточної гілки?
CB Bailey

1
Мені шкода. Я мав на увазі сказати, що мій файл чомусь був зроблений і розповсюджений давно. Тепер мета - вилучити його з версії, не видаляючи її з людей. Причина цього з’явилася в тому, що я випадково перетворив конфігураційний файл. Конфігураційний файл необхідний, тому я не хочу його видаляти із сторонніх систем.
Флетчер Мур

Я відредагував питання, щоб бути більш зрозумілим.
Флетчер Мур

3
git rm --cached не видалить файл з іншого робочого каталогу. Файл буде видалений лише у тому випадку, якщо хтось, що працює в цьому каталозі, здійснив витяг. Файл можна легко відновити за допомогою "git checkout HEAD @ {1} foo" (якщо виконується відразу після витягування)
William Pursell

Відповіді:


119

Я не думаю, що фіксація Git може записати намір, наприклад "припинити відстежувати цей файл, але не видаляти його".

Якщо ввести такий намір, зажадає втручання поза Git в будь-які сховища, які об'єднують (або перезавантажують) комісію, яка видаляє файл.


Збережіть копію, застосуйте видалення, відновлення

Напевно, найпростіше зробити це сказати своїм нижчим користувачам зберегти копію файлу, витягнути видалення та відновити файл. Якщо вони перетягуються через ребазу та вносять зміни до файлу, у них виникнуть конфлікти. Щоб вирішити такі конфлікти, використовуйте git rm foo.conf && git rebase --continue(якщо суперечлива комісія має зміни, крім змін у вилученому файлі), або git rebase --skip(якщо суперечлива фіксація змінилася лише на видалений файл).

Відновіть файл як невиправлений після витягування комітету, який його видаляє

Якщо вони вже зняли вашу команду видалення, вони все одно можуть відновити попередню версію файлу за допомогою git show :

git show @{1}:foo.conf >foo.conf

Або з git checkout (за коментарем Вільяма Перселя; але не забудьте знову видалити його з індексу!):

git checkout @{1} -- foo.conf && git rm --cached foo.conf

Якщо вони виконали інші дії з моменту вилучення вашого видалення (або вони перетягуються з базою даних у відокремлену HEAD), їм може знадобитися щось інше, ніж @{1}. Їх можна було git log -gб знайти, перш ніж вони видалили ваше видалення.


У коментарі ви згадуєте, що файл, який ви хочете "відстежувати, але зберігати", - це якийсь файл конфігурації, необхідний для запуску програмного забезпечення (безпосередньо з сховища).

Зберігайте файл як "за замовчуванням" і вручну / автоматично його активуйте

Якщо продовжувати зберігати вміст файлу конфігурації у сховищі не зовсім неприйнятно, можливо, ви зможете перейменувати відстежений файл з (наприклад) foo.confна, foo.conf.defaultа потім доручити вашим користувачам cp foo.conf.default foo.confпісля застосування перейменування. Або якщо користувачі вже використовують деяку існуючу частину репозиторію (наприклад, скрипт або якусь іншу програму, налаштовану вмістом у сховищі (наприклад, Makefileчи подібне)) для запуску / розгортання вашого програмного забезпечення, ви можете включити механізм дефолту в запуск / процес розгортання:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

За наявності такого механізму дефолту користувачі повинні мати можливість взяти на себе зобов’язання, яке перейменовано foo.confнаfoo.conf.default без необхідності робити будь - які додаткові роботи. Крім того, вам не доведеться копіювати файл конфігурації вручну, якщо ви зробите додаткові установки / сховища в майбутньому.

Переписування історії вимагає ручного втручання в будь-якому випадку ...

Якщо неприпустимо підтримувати вміст у сховищі, ви, ймовірно, захочете повністю викорінити його з історії чимось подібним git filter-branch --index-filter …. Це означає історію перезапису, що вимагатиме вручну втручання для кожної гілки / сховища (див. Розділ «Відновлення з upstream Rebase» на сторінці сторінки git rebase ). Спеціальна обробка, потрібна для вашого конфігураційного файлу, - це ще один крок, який потрібно виконати під час відновлення з перезапису:

  1. Збережіть копію файлу конфігурації.
  2. Відновлення після перезапису.
  3. Відновіть файл конфігурації.

Ігноруйте це, щоб запобігти рецидиву

Який би метод ви не використовували, ви, ймовірно, захочете включити ім’я файлу конфігурації у .gitignoreфайл у сховищі, щоб ніхто не міг ненароком git add foo.confзнову (це можливо, але вимагає -f/ --force). Якщо у вас є декілька файлів конфігурації, ви можете розглянути можливість "переміщення" їх усіх в єдиний каталог і ігнорування всього цього (маючи на увазі "переміщення", я маю на увазі зміну там, де програма розраховує знайти свої конфігураційні файли, та отримати користувачів (або механізм запуску / розгортання) для копіювання / переміщення файлів на їх нове місце; ви, очевидно, не хочете збирати файл mv у каталог, який ви будете ігнорувати).


5
Неймовірно ретельна відповідь. Дякую!
Флетчер Мур

Відповідь Тома Пауера нижче, здається, суперечить вашому першому реченню.
Майк S

1
@MikeS: Ефект --{,no-}assume-unchangedсуто локальний: його стан безпосередньо не фіксується у комітах. Це може запобігти репозиторію внесення нових змін до файлу, але не видаляє його з контролю версій. Якщо ви можете встановити його для всіх ваших відповідних, пов'язаних, неоголених сховищ, то це може допомогти вашій ситуації, але це не те, що ви могли б безпосередньо натиснути + потягнути / перезавантажити в інші пов'язані, неоголені сховища (особливо ті, що Ви не контролюєте, згідно з роз'яснювальними коментарями первинного запитувача до питання: див. "народні системи" / "закордонні системи").
Кріс Джонсен

1
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”.- тепер може,git rm --cached foo.conf
Нік Волинкін

1
@ NickVolynkin: Хіба це питання вже не вказує на те, що це недостатньо для цілі запитувача: (автоматично) зберігати файл навколо, коли отриманий комітет переноситься в інший сховище?
Кріс Джонсен

86

У цьому ж тижні, коли я випадково зробив це, я намагався видалити файл збірки із спільного сховища, і це:

http://gitready.com/intermediate/2009/02/18/temporary-ignoring-files.html

добре працював для мене і досі не згадується.

git update-index --assume-unchanged <file>

Щоб видалити файл, який вас цікавить, з контролю версій, тоді використовуйте всі інші команди як звичайні.

git update-index --no-assume-unchanged <file>

Якщо ви коли-небудь хотіли повернути його назад.

Редагувати: дивіться коментарі від Chris Johnsen та KPM. Це працює лише локально, і файл залишається під контролем версій для інших користувачів, якщо вони також не роблять цього. Прийнята відповідь дає більш повні / правильні методи боротьби з цим. Також деякі примітки від посилання, якщо використовується цей метод:

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


7
Це не відповідь на конкретну проблему. Він працюватиме лише для вашого власного локального сховища, тому кожен користувач повинен зробити це сам. Це біль.
КПМ

28

Щоб видалити файл з індексу, використовуйте:

git reset myfile

Це не повинно впливати на вашу місцеву копію чи будь-кого іншого.


1
resetвидаляє файл з індексу лише в тому випадку, якщо файл не знаходиться в поточній версії HEAD, інакше він просто повертає версію індексу до поточної версії HEAD.
CB Bailey

1
Можливо, я неправильно зрозумів це питання, але, схоже, це стосується видалення файлу з індексу, не впливаючи на жодні коміти.
Арман

Як сказав Чарльз, скидання не "видаляє файл". Для отримання додаткової інформації введіть програму git reset.
Саймон Б.

4
Це відповідає на питання під назвою "Як видалити файл з індексу без видалення файлів із будь-якого сховища". Незважаючи на те, що ОП насправді запитував "Як я відстежую файл із видаленням локальної копії".
hewsonism

@hewsonism OP сказав "будь-яку файлову систему" (навіть перед будь-якими правками).
jbobbins


15

Виконавши git rm --cachedкоманду, спробуйте додати myfileдо .gitignoreфайлу (створіть його, якщо його не існує). Це повинно сказати git ігнорувати myfile.

.gitignoreФайл версірован, так що ви повинні будете зробити його і штовхати його в віддалений репозиторій.


1

Моє рішення - натягнути на іншу робочу копію, а потім зробити:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

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


0

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

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

https://help.github.com/articles/remove-sensitive-data/

Насправді ви можете перейти до кроку 3, якщо ви перебуваєте у вашому локальному сховищі git, і вам не потрібно виконувати суху роботу. У моєму випадку мені знадобилися лише кроки 3 та 6, оскільки я вже створив свій файл .gitignore і знаходився у сховищі, над яким я хотів працювати.

Щоб побачити зміни, можливо, вам доведеться перейти до кореня GitHub вашого сховища та оновити сторінку. Потім перейдіть по посиланнях, щоб перейти до старої комісії, у якої колись був файл, і побачити, що його тепер видалено. Для мене просто оновлення старої сторінки фіксації не показало змін.

Спочатку це виглядало залякано, але насправді було легко і працювало як принадність! :-)

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