Как мне отменить "git add" перед коммитом.

git version-control git-commit git-stage


Я ошибочно добавил файлы в Git с помощью команды:

git add myfile.txt

Я еще не запускал git commit . Есть ли способ отменить это, чтобы эти файлы не были включены в коммит?




Answer 1 genehack


Вы можете отменить git add перед фиксацией с помощью

git reset <file>

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

Вы можете использовать

git reset

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

В старых версиях Git вышеприведенные команды эквивалентны git reset HEAD <file> и git reset HEAD соответственно и завершатся неудачно, если HEAD не определен (потому что вы еще не сделали никаких коммитов в своем хранилище) или неоднозначными (потому что вы создал ветку под названием HEAD , а это глупость, которую вы не должны делать). Однако это изменилось в Git 1.8.2 , поэтому в современных версиях Git вы можете использовать приведенные выше команды даже перед тем, как сделать первый коммит:

«git reset» (без опций или параметров) используется для вывода ошибок, когда у вас нет никаких коммитов в вашей истории, но теперь он дает пустой индекс (для соответствия несуществующему коммиту вы даже не используете).

Документация: git reset




Answer 2 Rhubarb


Ты хочешь:

git rm --cached <added_file_to_undo>

Reasoning:

Когда я был новичком в этом деле,я впервые попробовал

git reset .

(чтобы отменить все мои начальные добавления), только чтобы получить это (не очень) полезное сообщение:

fatal: Failed to resolve 'HEAD' as a valid ref.

Оказывается,это потому,что ссылка на HEAD (ветка?)существует только после первого коммита.То есть,вы столкнётесь с той же проблемой новичка,что и я,если ваш рабочий процесс,как и мой:

  1. cd к моему большому новому каталогу проекта,чтобы попробовать Git,новую горячую штучку.
  2. git init
  3. git add .
  4. git status

    ... много дерьмовых свитков ...

    => Черт, я не хотел добавлять все это.

  5. Google "отменить git-добавление"

    => найти переполнение стека - ууу

  6. git reset .

    => fatal: Не удалось разрешить 'HEAD' в качестве действительного ссылки.

Кроме того, выясняется, что в списке рассылки зафиксирована ошибка против этой бесполезности.

И что правильное решение было прямо там,в выводе состояния Git'а (которое,да,я проглядел как 'дерьмо').

...
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
...

И решение действительно заключается в использовании git rm --cached FILE .

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

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

Я приступаю к использованию

git rm --cached .

удалить все и начать заново. Не сработало, потому что, хотя add . является рекурсивным, оказывается, rm нуждается в -r для рекурсии. Вздох.

git rm -r --cached .

Хорошо, теперь я вернулся к тому, с чего начал. В следующий раз я собираюсь использовать -n , чтобы выполнить пробный прогон и посмотреть, что будет добавлено:

git add -n .

Я заархивировал все в безопасное место, прежде чем доверять git help rm о том, что --cached ничего не уничтожает (и что, если я его неправильно написал).




Answer 3 Paul Beckingham


Если ты набираешь:

git status

Git расскажет вам,что такое инсценировка и т.д.,включая инструкции по нестабильности:

use "git reset HEAD <file>..." to unstage

Я нахожу,что Гит делает довольно хорошую работу,подталкивая меня делать правильные вещи в таких ситуациях,как эта.

Примечание: последние версии Git (1.8.4.x) изменили это сообщение:

(use "git rm --cached <file>..." to unstage)



Answer 4 takeshin


Для пояснения: git add перемещает изменения из текущего рабочего каталога в область подготовки (индекс).

Этот процесс называется постановкой . Таким образом, наиболее естественная команда этапа изменения (измененные файлы) является очевидным:

git stage

git add - простой псевдоним для git stage

Жаль, что нет git unstage и git unadd . Соответствующий труднее угадать или вспомнить, но он довольно очевиден:

git reset HEAD --

Мы легко можем создать для этого псевдоним:

git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'

И,наконец,у нас появились новые команды:

git add file1
git stage file2
git unadd file2
git unstage file1

Лично я использую еще более короткие псевдонимы:

git a # For staging
git u # For unstaging



Answer 5 leonbloy


В дополнение к принятому ответу, если ваш ошибочно добавленный файл был огромным, вы, вероятно, заметите, что даже после удаления его из индекса с помощью « git reset » он все равно занимает место в каталоге .git .

Беспокоиться не о чем;файл действительно все еще находится в репозитории,но только как "свободный объект".Он не будет скопирован в другие репозитории (через клон,push),и место в конечном итоге будет восстановлено-хотя,возможно,не очень скоро.Если вы беспокоитесь,то можете бежать:

git gc --prune=now

Обновление (далее я попытаюсь прояснить некоторую путаницу, которая может возникнуть из-за ответов с наибольшим количеством голосов)

Итак, что реальный откат от git add ?

git reset HEAD <file> ?

or

git rm --cached <file> ?

Строго говоря, и если я не ошибаюсь: нет .

git add нельзя отменить - безопасно, в общем.

Давайте сначала вспомним, что на самом деле делает git add <file> :

  1. Если <file> был ранее не отслеживаются , git add добавляет его в кэш , с его текущим содержанием.

  2. Если <file> был уже отслеживаются , git add сохраняет текущее содержимое (снимок, версия) в кэш. В Git это действие по-прежнему называется add (а не просто обновляет его), потому что две разные версии (снимки) файла рассматриваются как два разных элемента: следовательно, мы действительно добавляем новый элемент в кеш, чтобы в конечном итоге совершено позже.

В свете этого вопрос несколько двусмысленен:

Я ошибочно добавил файлы с помощью команды...

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

И мы также можем запустить git reset HEAD <file> . В целом это предпочтительнее, потому что он работает в обоих сценариях: он также отменяет действия, когда мы ошибочно добавили версию уже отслеженного элемента.

Но есть два предостережения.

Первый: существует (как указано в ответе) только один сценарий, в котором git reset HEAD не работает, но git rm --cached делает: новый репозиторий (без коммитов). Но, на самом деле, это практически неактуальный случай.

Второе: помните, что git reset HEAD не может волшебным образом восстановить ранее кэшированное содержимое файла, он просто ресинхронизирует его из HEAD. Если наш неверный git add перезаписал предыдущую готовую незафиксированную версию, мы не сможем ее восстановить. Вот почему, строго говоря, мы не можем отменить [*].

Example:

$ 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 .


* (Редактировать: вышеупомянутое практически правильно, но все же могут быть несколько хакерские / запутанные способы восстановления изменений, которые были поставлены, но не зафиксированы, а затем перезаписаны - см. Комментарии Йоханнеса Матокича и iolsmit)