В дополнение к принятому ответу, если ваш ошибочно добавленный файл был огромным, вы, вероятно, заметите, что даже после удаления его из индекса с помощью ' git reset
' он все равно занимает место в.git
каталоге.
Это не о чем беспокоиться; файл действительно все еще находится в хранилище, но только как «свободный объект». Он не будет скопирован в другие репозитории (через клон, push), и пространство будет в конечном итоге восстановлено - хотя, возможно, не очень скоро. Если вы беспокоитесь, вы можете запустить:
git gc --prune=now
Обновить (далее я попытаюсь прояснить некоторую путаницу, которая может возникнуть из-за ответов с наибольшим количеством голосов):
Итак, что реальный откат отgit add
?
git reset HEAD <file>
?
или
git rm --cached <file>
?
Собственно говоря, и если я не ошибаюсь нет .
git add
не может быть отменено - безопасно, в общем.
Давайте вспомним сначала, что git add <file>
самом деле делает:
Если <file>
был ранее не отслеживаются , git add
добавляет его в кэш , с его текущим содержанием.
Если <file>
он уже отслежен , git add
текущий контент (снимок, версия) сохраняется в кеше. В Git это действие по-прежнему называется add , а не просто update его), поскольку две разные версии (снимки) файла рассматриваются как два разных элемента: следовательно, мы действительно добавляем новый элемент в кеш, чтобы в конечном итоге совершено позже.
В свете этого вопрос несколько двусмысленный:
Я по ошибке добавил файлы с помощью команды ...
Похоже, что сценарий OP является первым (неотслеживаемый файл), мы хотим, чтобы «отмена» удаляла файл (а не только текущее содержимое) из отслеживаемых элементов. Если это так, тогда все в порядке git rm --cached <file>
.
И мы могли бы также бежать git reset HEAD <file>
. В целом это предпочтительнее, потому что это работает в обоих сценариях: оно также отменяет действия, когда мы ошибочно добавили версию уже отслеженного элемента.
Но есть две оговорки.
Первый: существует (как указано в ответе) только один сценарий, в котором git reset HEAD
не работает, ноgit rm --cached
работает: новый репозиторий (без коммитов). Но на самом деле это практически неактуальный случай.
Второе: имейте в git reset HEAD
виду, что не может волшебным образом восстановить ранее кэшированное содержимое файла, оно просто ресинхронизирует его из HEAD. Если наши заблужденияgit add
переписал предыдущую подготовленную незафиксированную версию, мы не сможем ее восстановить. Вот почему, строго говоря, мы не можем отменить [*].
Пример:
$ git init
$ echo "version 1" > file.txt
$ git add file.txt # First add of file.txt
$ git commit -m 'first commit'
$ echo "version 2" > file.txt
$ git add file.txt # Stage (don't commit) "version 2" of file.txt
$ git diff --cached file.txt
-version 1
+version 2
$ echo "version 3" > file.txt
$ git diff file.txt
-version 2
+version 3
$ git add file.txt # Oops we didn't mean this
$ git reset HEAD file.txt # Undo?
$ git diff --cached file.txt # No dif, of course. stage == HEAD
$ git diff file.txt # We have irrevocably lost "version 2"
-version 1
+version 3
Конечно, это не очень важно, если мы просто следуем обычному ленивому рабочему процессу выполнения 'git add' только для добавления новых файлов (случай 1), и мы обновляем новое содержимое с помощью команды commit, git commit -a
command.
* (Редактировать: вышеупомянутое практически правильно, но все же могут быть несколько хакерские / запутанные способы восстановления изменений, которые были поставлены, но не зафиксированы, а затем перезаписаны - см. Комментарии Йоханнеса Матокича и iolsmit)
HEAD
илиhead
могут теперь использовать@
вместоHEAD
вместо этого. Посмотрите этот ответ (последний раздел), чтобы узнать, почему вы можете это сделать.