Почему есть 2 способа удалить файл из git?

Иногда мерзавец предлагает git rm --cached иногда удалять файл git reset HEAD file, Когда я должен использовать что?

РЕДАКТИРОВАТЬ:

D:\code\gt2>git init
Initialized empty Git repository in D:/code/gt2/.git/
D:\code\gt2>touch a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a
#
D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a

D:\code\gt2>touch b

D:\code\gt2>git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       b
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add b

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

16 ответов

Решение

git rm --cached <filePath> не удаляет файл, он фактически удаляет файл (ы) из репозитория (при условии, что он уже был зафиксирован ранее), но оставляет файл в рабочем дереве (оставляя файл без отслеживания).

git reset -- <filePath> будет отменять любые поэтапные изменения для данного файла (ов).

Тем не менее, если вы использовали git rm --cached для нового файла, который находится в стадии подготовки, он будет выглядеть так, как будто вы только что установили его, поскольку он никогда не был зафиксирован ранее.

git rm --cached используется для удаления файла из индекса. В случае, если файл уже находится в репо, git rm --cached удалит файл из индекса, оставив его в рабочем каталоге, а коммит теперь также удалит его из репозитория. По сути, после коммита вы бы развернули файл и сохранили локальную копию.

git reset HEAD file (который по умолчанию использует --mixed Параметр flag) отличается тем, что в случае, когда файл уже находится в репо, он заменяет индексную версию файла версией из репо (HEAD), фактически не внося изменений в него.

В случае неверсионного файла он собирается удалить весь файл, так как его не было в HEAD. В этом аспекте git reset HEAD file а также git rm --cached одинаковы, но не совпадают (как описано в случае файлов, уже находящихся в репо)

К вопросу о Why are there 2 ways to unstage a file in git? - в git никогда не бывает только одного способа что-либо сделать. в этом вся прелесть:)

Довольно просто:

  • git rm --cached <file> заставляет git полностью прекратить отслеживание файла (оставляя его в файловой системе, в отличие от простого git rm *)
  • git reset HEAD <file> unstages любые изменения, сделанные в файле с момента последнего коммита (но не возвращает их в файловой системе, в отличие от того, что может указывать имя команды **). Файл остается под контролем ревизии.

Если файл ранее не контролировался ревизиями (т. Е. Вы удаляете файл, который у вас был git add в первый раз), затем эти две команды имеют одинаковый эффект, следовательно, они выглядят как "два способа сделать что-то".

* Имейте в виду, предостережение, которое @DrewT упоминает в своем ответе относительно git rm --cached файла, который был ранее зафиксирован в хранилище. В контексте этого вопроса о файле, который был только что добавлен и еще не зафиксирован, не о чем беспокоиться.

** Мне было страшно долгое время использовать команду git reset из-за ее названия - и до сих пор я часто просматриваю синтаксис, чтобы убедиться, что я не облажался. (обновление: я наконец нашел время, чтобы подвести итоги использования git reset на странице tldr, так что теперь у меня есть лучшая ментальная модель того, как это работает, и краткий справочник, когда я забываю некоторые детали.)

Этот поток немного староват, но я все же хочу добавить небольшую демонстрацию, так как это все еще не интуитивная проблема:

me$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   to-be-added
#   modified:   to-be-modified
#   deleted:    to-be-removed
#

me$ git reset -q HEAD to-be-added

    # ok

me$ git reset -q HEAD to-be-modified

    # ok

me$ git reset -q HEAD to-be-removed

    # ok

# or alternatively:

me$ git reset -q HEAD to-be-added to-be-removed to-be-modified

    # ok

me$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   to-be-modified
#   deleted:    to-be-removed
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   to-be-added
no changes added to commit (use "git add" and/or "git commit -a")

git reset HEAD (без -q) выдает предупреждение об измененном файле и его код выхода равен 1, что будет считаться ошибкой в ​​скрипте.

Редактировать: git checkout HEAD to-be-modified to-be-removed также работает для unstaging, но полностью удаляет изменения из рабочей области

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

git stash
git stash pop

это выполнит сброс в HEAD и повторно применяет ваши изменения, позволяя вам повторно подготовить отдельные файлы для фиксации. это также полезно, если вы забыли создать функциональную ветвь для запросов извлечения (git stash ; git checkout -b <feature> ; git stash pop).

В более новой версии > 2.2 вы можете использовать git restore --staged <file_name>. Примечание. Если вы хотите отменить (перейти к изменениям) ваши файлы по одному, вы используете приведенную выше команду с именем вашего файла. например

      git restore --staged abc.html

Теперь, если вы хотите отключить весь файл сразу, вы можете сделать что-то вроде этого

      git restore --staged .

Обратите внимание на пробел и точку (.), что означает считать все файлы подготовленными.

Эти 2 команды имеют несколько тонких отличий, если рассматриваемый файл уже находится в репозитории и находится под контролем версий (ранее зафиксирован и т. Д.):

  • git reset HEAD <file> unstages файл в текущем коммите.
  • git rm --cached <file> также разархивирует файл для будущих коммитов. Это unstaged, пока это не будет добавлено снова с git add <file>,

И есть еще одно важное отличие:

  • После запуска git rm --cached <file> и перенесите вашу ветку на удаленный, любой, кто вытаскивает вашу ветку с удаленного, получит файл, фактически удаленный из их папки, даже если в вашем локальном рабочем наборе файл просто не будет отслежен (то есть физически не удален из папки).

Это последнее различие важно для проектов, которые включают в себя конфигурационный файл, в котором каждый разработчик в команде имеет разный конфиг (т. Е. Разные базовые url, ip или настройки порта), поэтому, если вы используете git rm --cached <file> любой, кто тянет вашу ветку, должен будет заново создать конфигурацию вручную, или вы можете отправить им свою собственную, и они могут повторно отредактировать ее обратно в свои настройки ip (и т. д.), потому что удаление только влияет на людей, тянущих вашу ветку с удаленного,

Скажем вам stage весь каталог через git add <folder>, но вы хотите исключить файл из поэтапного списка (то есть списка, который генерируется при запуске git status) и сохраните изменения в исключенном файле (вы работали над чем-то, и он не готов к коммиту, но вы не хотите терять свою работу...). Вы можете просто использовать:

git reset <file>

Когда ты бежишь git status, вы увидите, что любой файл (ы) вы reset являются unstaged а остальные файлы вы added все еще в staged список.

1.

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a

(используйте "git rm --cached ..." для удаления)

  • Git это система указателей

  • у вас еще нет коммита, чтобы изменить указатель на

  • Единственный способ "извлечь файлы из корзины, на которую указывают", - это удалить файлы, которые вы сказали git, чтобы следить за изменениями.

2.

D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 a

git commit -ma

  • вы совершили "спас"

3.

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

(используйте "git reset HEAD ..." для удаления)

  • вы сделали коммит в своем коде в это время
  • Теперь вы можете сбросить указатель на ваш коммит "вернуться к последнему сохранению"

Просто используйте:

git reset HEAD <filename>

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

Только для версий 2.23 и выше,

Вместо этих предложений вы можете использоватьgit restore --staged <file> чтобы unstage файлы).

Unstaging файлы (отмена git add)

git restore --staged file.js # Копирует последнюю версию file.js из репозитория в индекс

отбрасывание локальных изменений

git restore file.js # Копирует file.js из индекса в рабочий каталог

git restore file1.js file2.js # Восстанавливает несколько файлов в рабочем каталоге

гит восстановить. # Отбрасывает все локальные изменения (кроме неотслеживаемых файлов)

git clean -fd # Удаляет все неотслеживаемые файлы

Я удивлен, что никто не упомянул git reflog ( http://git-scm.com/docs/git-reflog):

# git reflog
<find the place before your staged anything>
# git reset HEAD@{1}

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

Это похоже на git reset HEAD <file> но в некоторых случаях может быть более гранулированным.

Извините - на самом деле не отвечаю на ваш вопрос, а просто указываю еще один способ нестандартных файлов, которые я использую довольно часто (например, мне очень нравятся ответы Райана Стюарта и Вальдириуса.);) Надеюсь, это поможет.

Мне кажется, что git rm --cached <file> удаляет файл из индекса, не удаляя его из каталога, в котором находится простой git rm <file> будет делать как, так и ОС rm <file> удалит файл из каталога, не удаляя его версии.

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

Я выполнил приведенные выше команды, но команда, которая сработала, похожа на то, когда вы находитесь в корне проекта, просто добавляя снимок экрана для большей ясности.

      git rm --cached 'ios/AppName/Info.plist'

ИЛИ

      git reset HEAD 'ios/AppName/Info.plist'

Другие вопросы по тегам