Как мне отменить 'git add' перед коммитом? - PullRequest
8168 голосов
/ 08 декабря 2008

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

git add myfile.txt

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

Ответы [ 35 ]

9266 голосов
/ 08 декабря 2008

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

git reset <file>

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

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

git reset

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

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

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

2052 голосов
/ 25 марта 2009

Вы хотите:

git rm --cached <added_file_to_undo>

Рассуждение:

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

git reset .

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

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

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

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

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

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

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

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

  6. git reset .

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

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

И что правильное решение было прямо там, в выводе статуса Git (который, да, я назвал «дерьмом»)

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

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

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

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

Я продолжаю использовать

git rm --cached .

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

git rm -r --cached .

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

git add -n .

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

506 голосов
/ 08 декабря 2008

Если вы введете:

git status

git расскажет вам, что ставится, и т. Д., Включая инструкции по удалению:

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

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

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

(use "git rm --cached <file>..." to unstage)
239 голосов
/ 11 сентября 2010

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

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

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
161 голосов
/ 18 мая 2011

В дополнение к принятому ответу, если ваш ошибочно добавленный файл был огромным, вы, вероятно, заметите, что даже после удаления его из индекса с помощью git reset он все равно занимает место в .git каталог. Об этом не стоит беспокоиться, файл действительно все еще находится в репозитории, но только как «свободный объект», он не будет скопирован в другие репозитории (через клон, push), и пространство в конечном итоге будет освобождено - хотя возможно, не очень скоро. Если вы беспокоитесь, вы можете запустить:

git gc --prune=now

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

Итак, что является настоящим отменить из git add?

git reset HEAD <file>?

или

git rm --cached <file>?

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

git add не может быть отменено - в общем, безопасно.

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

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

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

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

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

Кажется, что сценарий 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 lost irrevocably "version 2"
-version 1
+version 3

Конечно, это не очень важно, если мы просто следуем обычному ленивому рабочему процессу выполнения 'git add' только для добавления новых файлов (случай 1), и мы обновляем новое содержимое с помощью команды commit, git commit -a.


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

92 голосов
/ 10 декабря 2009
git rm --cached . -r

рекурсивно "удалит" все, что вы добавили из текущего каталога

85 голосов
/ 12 октября 2011

Run

git gui

и удалите все файлы вручную или, выбрав их все и нажав кнопку unstage from commit .

83 голосов
/ 28 июня 2017

Отменить файл, который уже добавлен, довольно легко, используя git , для сброса myfile.txt, который уже добавлен, используйте:

git reset HEAD myfile.txt

Объясните:

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

Я создам шаги, изображенные на рисунке ниже, более подробно для вас, включая все шаги, которые могут произойти в следующих случаях:

git reset HEAD file

80 голосов
/ 29 марта 2013

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

Что вы делали раньше:

  • Изменил файл и использовал git add . или git add <file>.

Что вы хотите:

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

    git reset head <file>
    
  • Сброс файла до последнего состояния из HEAD, отмена изменений и удаление их из индекса:

    # Think `svn revert <file>` IIRC.
    git reset HEAD <file>
    git checkout <file>
    
    # If you have a `<branch>` named like `<file>`, use:
    git checkout -- <file>
    

    Это необходимо, поскольку git reset --hard HEAD не будет работать с отдельными файлами.

  • Удалить <file> из индекса и управления версиями, сохранив файл без версии с изменениями в рабочей копии:

    git rm --cached <file>
    
  • Удалите <file> из рабочей копии и полностью версионируйте:

    git rm <file>
    
73 голосов
/ 16 января 2014

Вопрос не четко поставлен. Причина в том, что git add имеет два значения:

  1. добавление нового файла в область подготовки, а затем отмена с git rm --cached file.
  2. добавление измененного файла в область подготовки, затем отмена с git reset HEAD file.

если сомневаетесь, используйте

git reset HEAD file

Потому что это делает ожидаемую вещь в обоих случаях.

Предупреждение: если вы сделаете git rm --cached file для файла, который был изменен (файл, который существовал ранее в хранилище), то этот файл будет удален в git commit ! Он все еще будет существовать в вашей файловой системе, но если кто-нибудь еще извлечет ваш коммит, файл будет удален из их рабочего дерева.

git status сообщит вам, был ли файл новым файлом или изменен :

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   my_new_file.txt
    modified:   my_modified_file.txt
...