Git: Как удалить файл из индекса, не удаляя файлы из любого хранилища - PullRequest
152 голосов
/ 09 апреля 2010

Когда вы используете

git rm --cached myfile

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

Есть ли способ просто удалить файл из версий, не удаляя его из какой-либо файловой системы?

Редактировать: Я уточнил, я надеюсь.

Ответы [ 7 ]

110 голосов
/ 10 апреля 2010

Я не думаю, что коммит Git может записать намерение типа «прекратить отслеживание этого файла, но не удаляйте его».

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


Сохранить копию, применить удаление, восстановить

Вероятно, самое простое, что нужно сделать, - это попросить своих нижестоящих пользователей сохранить копию файла, вытащить удаление, а затем восстановить файл. Если они вытягивают через rebase и «переносят» изменения в файл, они получат конфликты. Чтобы разрешить такие конфликты, используйте 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

Если они предприняли другие действия после извлечения вашего удаления (или они вытаскивают с ребазой в отдельную ГОЛОВКУ), им может понадобиться что-то, кроме @{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 …. Это равносильно переписыванию истории, что потребует ручного вмешательства для каждой ветви / репозитория (см. Раздел «Восстановление из исходной перебазировки» в git rebase manpage ). Специальная обработка, требуемая для вашего файла конфигурации, будет просто еще одним шагом, который необходимо выполнить при восстановлении после перезаписи:

  1. Сохраните копию файла конфигурации.
  2. Восстановить после перезаписи.
  3. Восстановить файл конфигурации.

Игнорировать это, чтобы предотвратить повторение

Какой бы метод вы ни использовали, вы, вероятно, захотите включить имя файла конфигурации в файл .gitignore в хранилище, чтобы никто не мог случайно git add foo.conf снова (это возможно, но требует -f / --force ). Если у вас есть больше, чемодин файл конфигурации, вы можете подумать о «перемещении» их всех в один каталог и игнорировании всего этого (под «перемещением» я имею в виду изменение того, где программа ожидает найти свои файлы конфигурации, и получение пользователей (или механизм запуска / развертывания) ) скопировать / переместить файлы в их новое расположение; очевидно, вы не захотите git mv файл в каталог, который вы будете игнорировать).

86 голосов
/ 27 мая 2012

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

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

отлично сработал и пока не упоминается.

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

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

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

Если вы когда-нибудь хотели вернуть его обратно.

Редактировать: смотрите комментарии Криса Джонсена и KPM, это работает только локально, и файл остается под контролем версий для других пользователей, если они этого не делают. Принятый ответ дает более полные / правильные методы борьбы с этим. Также некоторые примечания по ссылке при использовании этого метода:

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

30 голосов
/ 09 апреля 2010

Чтобы удалить файл из индекса, используйте:

git reset myfile

Это не должно повлиять на вашу локальную или чужую копию.

15 голосов
/ 09 апреля 2010

После выполнения команды git rm --cached попробуйте добавить myfile в файл .gitignore (создайте его, если он не существует). Это должно сказать git игнорировать myfile.

Файл .gitignore имеет версию, поэтому вам необходимо зафиксировать его и отправить в удаленный репозиторий.

12 голосов
/ 09 февраля 2017
  1. git rm --cached remove_file
  2. добавить файл в gitignore
  3. git add .gitignore
  4. git commit -m "Excluding"
  5. Веселиться;)
1 голос
/ 05 января 2012

Мое решение - вытащить другую рабочую копию и затем выполнить:

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

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

0 голосов
/ 11 декабря 2015

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

Вот решение, которое удаляет все следы файла из всей истории фиксации, как будто его никогда не существовало, но сохраняет файл на месте в вашей системе.

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

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

Чтобы увидеть ваши изменения, вам может потребоваться перейти в корень GitHub вашего репозитория и обновить страницу. Затем перейдите по ссылкам, чтобы добраться до старого коммита, в котором когда-то был файл, чтобы увидеть, что он теперь удален. Для меня простое обновление старой страницы фиксации не показало изменения.

Сначала это выглядело пугающе, но на самом деле было легко и сработало как шарм! : -)

...