Почему есть два способа удалить файл из Git? - PullRequest
1033 голосов
/ 03 августа 2011

Иногда 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
#

Ответы [ 10 ]

1709 голосов
/ 03 августа 2011

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

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

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

324 голосов
/ 03 августа 2011

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

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

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

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

114 голосов
/ 18 октября 2014

Проще говоря:

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

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

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

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

44 голосов
/ 16 апреля 2013

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

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, что в скрипте будет рассматриваться как ошибка.

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

34 голосов
/ 10 февраля 2015

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

git stash
git stash pop

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

15 голосов
/ 11 августа 2014

Эти 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 (и т. д.), потому что удаление только влияет на людей, тянущих вашу ветку с пульта.

9 голосов
/ 08 сентября 2016

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 -m a

  • Вы подтвердили, ' сохранено '

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 ...» для отключения)

  • вы сделали коммит в своем коде в это время
  • теперь вы можете сбросить указатель на ваш коммит ' вернуться к последнему сохранению '
8 голосов
/ 28 августа 2015

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

git reset <file>

Когда вы запустите git status, вы увидите, что все файлы, которые вы reset * unstaged, а остальные файлы, которые вы added, все еще находятся в списке staged.

5 голосов
/ 10 февраля 2015

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

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

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

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

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

3 голосов
/ 06 июня 2013

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

...