Как отменить 'git add' перед коммитом?

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

git add myfile.txt

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


На данный момент есть 48 ответов (некоторые удалены). Пожалуйста, не добавляйте новый, если у вас нет новой информации.

47 ответов

Решение

Вы можете отменить 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 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 add"

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

  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 ничего не разрушая (а что если я ошибся в этом).

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

git status

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

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

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

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

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

Чтобы уточнить: 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

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

git gc --prune=now

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

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

git reset HEAD <file>?

или же

git rm --cached <file>?

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

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

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

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

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

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

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

Кажется, что сценарий 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), и мы обновляем новое содержимое с помощью коммита, git commit -a команда.


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

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

git reset HEAD myfile.txt

Объясните:

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

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

git reset HEAD

У 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>
    
git rm --cached . -r

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

Бежать

git gui

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

Вопрос не четко поставлен. Причина в том, что 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

По многим другим ответам вы можете использовать git reset

НО:

Я нашел этот замечательный небольшой пост, который на самом деле добавляет команду Git (ну, алиас) для git unadd: смотрите git unadd для деталей или..

Просто,

git config --global alias.unadd "reset HEAD"

Теперь вы можете

git unadd foo.txt bar.txt
git reset filename.txt

Удалит файл с именем filename.txt из текущего индекса, области "собирается быть зафиксирован", без изменения чего-либо еще.

Если вы находитесь на начальном коммите и не можете использовать git resetПросто объявите "Git банкротство" и удалите .git папка и начать все сначала

Обновление 2019

Как указывали другие здесь, здесь, здесь, здесь, здесь, здесь и здесь, теперь вы можете сделать это с помощьюgit restore --staged <file>.

git restoreбыл представлен в июле 2019 года и выпущен в версии 2.23 Git. С--staged flag, он восстанавливает содержимое индекса (о чем здесь спрашивают).

При беге git status с поэтапными незафиксированными файлами Git теперь предлагает использовать git restore --staged <file> убрать сцену (вместо git reset HEAD <file> как это было до v2.23).

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

git restore --staged <file>

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

git restore --staged .

Вы можете отключить / отменить с помощью команды git или графического интерфейса git.

Отдельный файл

       git reset File.txt 

Несколько файлов

       git reset File1.txt File2.txt File3.txt

Пример. Предположим, вы по ошибке добавили Home.js, ListItem.js, Update.js и хотите отменить / сбросить =>

       git reset src/components/home/Home.js src/components/listItem/ListItem.js src/components/update/Update.js

Тот же пример с использованием git GUI

       git gui

открывает окно => Снимите отметку с ваших файлов с поэтапных изменений (будет зафиксировано)

Использование git add -i удалить только что добавленные файлы из вашего предстоящего коммита. Пример:

Добавление файла, который вы не хотели:

$ git add foo
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   foo
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]#

Переход к интерактивному добавлению для отмены добавления (команды, набранные здесь в git: "r" (возврат), "1" (первая запись в списке показывает возврат), "возврат", чтобы выйти из режима возврата, и "q" (уволиться):

$ git add -i
           staged     unstaged path
  1:        +1/-0      nothing foo

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> r
           staged     unstaged path
  1:        +1/-0      nothing [f]oo
Revert>> 1
           staged     unstaged path
* 1:        +1/-0      nothing [f]oo
Revert>> 
note: foo is untracked now.
reverted one path

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> q
Bye.
$

Это оно! Вот ваше доказательство, показывающее, что "foo" снова в списке неотслеживаемых:

$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]
#       foo
nothing added to commit but untracked files present (use "git add" to track)
$

git remove или же git rm может быть использован для этого, с --cached флаг. Пытаться:

git help rm

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

  • Создайте основной каталог для вашего нового проекта.
  • Бежать git init,
  • Теперь создайте файл.gitignore (даже если он пустой).
  • Зафиксируйте свой файл.gitignore.

Git делает это действительно трудно сделать git reset если у вас нет никаких коммитов. Если вы создаете крошечный начальный коммит только ради одного, после этого вы можете git add -A а также git reset столько раз, сколько вы хотите, чтобы все было правильно.

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

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

Обратите внимание, что если вы не указали ревизию, вам необходимо включить разделитель. Пример из моей консоли:

git reset <path_to_file>
fatal: ambiguous argument '<path_to_file>': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

git reset -- <path_to_file>
Unstaged changes after reset:
M   <path_to_file>

(git версия 1.7.5.4)

Возможно, Git эволюционировал с тех пор, как вы опубликовали свой вопрос.

$> git --version
git version 1.6.2.1

Теперь вы можете попробовать:

git reset HEAD .

Это должно быть то, что вы ищете.

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

git rm --cached FILE

Используйте rm --cached только для случайно добавленных новых файлов.

Чтобы сбросить каждый файл в определенной папке (и ее подпапках), вы можете использовать следующую команду:

git reset *

Использовать * команда для обработки нескольких файлов одновременно

git reset HEAD *.prj
git reset HEAD *.bmp
git reset HEAD *gdb*

так далее

Просто введите git reset он вернется назад и как будто ты никогда не печатал git add . с вашего последнего коммита. Убедитесь, что вы совершили раньше.

Предположим, я создаю новый файл newFile.txt,

Предположим, я случайно добавил файл, git add newFile.txt

Теперь я хочу отменить это добавление перед коммитом, git reset newFile.txt

Для конкретного файла:

  • git reset my_file.txt
  • git checkout my_file.txt

Для всех добавленных файлов:

  • git reset
  • Git Checkout .

Примечание: checkout изменяет код в файлах и переходит в последнее обновленное (подтвержденное) состояние. сброс не меняет коды; он просто сбрасывает заголовок.

Чтобы отменить git добавить использование

git reset filename

Я удивлен, что никто не упоминает интерактивный режим:

git add -i

выберите опцию 3, чтобы удалить файлы. В моем случае я часто хочу добавить более одного файла, в интерактивном режиме вы можете использовать такие номера, чтобы добавить файлы. Это займет все, кроме 4: 1,2,3,5

Чтобы выбрать последовательность, просто наберите 1-5, чтобы взять все от 1 до 5.

Git промежуточные файлы

Эта команда отменяет ваши изменения:

git reset HEAD filename.txt

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

git add -p 

добавить части файлов.

git add myfile.txt # это добавит ваш файл в список фиксации

Совершенно противоположно этой команде,

git reset HEAD myfile.txt  # this will undo it. 

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

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

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