oz10
oz10

Reputation: 158474

How do I undo 'git add' before commit?

I mistakenly added files to Git using the command:

git add myfile.txt

I have not yet run git commit. How do I undo this so that these changes will not be included in the commit?

Upvotes: 11506

Views: 6021777

Answers (30)

prosoitos
prosoitos

Reputation: 7407

Git 2.23+ (> 2019)

As pointed out by others in related questions (see here, here, here, here, here, here, and here), you can now unstage a single file with:

git restore --staged <file>

and unstage all files (from the root of the repo) with:

git restore --staged .

Notes

git restore was committed in July 2019 and released in version 2.23 (August 2019).
With the --staged flag, it restores the content of the index (what is asked here).

When running git status with staged uncommitted file(s), this is now what Git suggests to use to unstage file(s) (instead of git reset HEAD <file> as it used to prior to v2.23).

Upvotes: 93

chankruze
chankruze

Reputation: 1166

You can use git restore --staged <file>... to unstage. I have accidentally added esp32_client/esp32_client.ino where I just wanted to stage Notes folder.

It's better to do a git status and it will show you how to unstage. Following is a real life example.

PS E:\ArduinoProjects\BlueLink - Cloud> git add .
warning: in the working copy of 'esp32_client/esp32_client.ino', LF will be replaced by CRLF the next time Git touches it

PS E:\ArduinoProjects\BlueLink - Cloud> git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   Notes/Idahowalker.ino
        new file:   Notes/chris700.ino
        new file:   Notes/ldahowalker-pub.ino
        modified:   esp32_client/esp32_client.ino

PS E:\ArduinoProjects\BlueLink - Cloud> git restore --staged .\esp32_client\esp32_client.ino

PS E:\ArduinoProjects\BlueLink - Cloud> git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   Notes/Idahowalker.ino
        new file:   Notes/chris700.ino
        new file:   Notes/ldahowalker-pub.ino

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   esp32_client/esp32_client.ino

Upvotes: 1

Alireza
Alireza

Reputation: 104870

Undo a file which has already been added is quite easy using Git. For resetting myfile.txt, which have already been added, use:

git reset HEAD myfile.txt

Explanation:

After you staged unwanted file(s), to undo, you can do git reset. Head is head of your file in the local and the last parameter is the name of your file which you want to reset.

I have created the steps in the image below in more details for you, including all steps which may happen in these cases:

git reset HEAD file

Upvotes: 195

Sam Macharia
Sam Macharia

Reputation: 1261

The first time I had this problem, I found this post here and from the first answer I learned that I should just do git reset <filename>. It worked fine.

Eventually, I happened to have a few subfolders inside my main git folder. I found it easy to just do git add . to add all files inside the subfolders and then git reset the few files that I did not want to add.

Nowadays I have lots of files and subfolders. It is tedious to git reset one-by-one but still easier to just git add . first, then reset the few heavy/unwanted but useful files and folders.

I've found the following method (which is not recorded here or here) relatively easy. I hope it will be helpful:

Let's say that you have the following situation:

Folder/SubFolder1/file1.txt
Folder/SubFolder2/fig1.png
Folder/SubFolderX/fig.svg
Folder/SubFolder3/<manyfiles>
Folder/SubFolder4/<file1.py, file2.py, ..., file60.py, ...>

You want to add all folders and files but not fig1.png, and not SubFolderX, and not file60.py and the list keeps growing ...

First, make/create a bash shell script and give it a name. Say, git_add.sh:

Then add all the paths to all folders and files you want to git reset preceded by git reset -- . You can easily copy-paste the paths into the script git_add.sh as your list of files grows. The git_add.sh script should look like this:

#!/bin/bash

git add .
git reset -- Folder/SubFolder2/fig1.png
git reset -- Folder/SubFolderX
git reset -- Folder/SubFolder4/file60.py

#!/bin/bash is important. Then do source git_add.sh to run it. After that, you can do git commit -m "some comment", and then git push -u origin master if you have already set up Bitbucket/Github.

Disclaimer: I've only tested this in Linux.


If you have lots of files and folders that you always retain in your local git repository but you don't want git to track changes when you do git add ., say video and data files, you must learn how to use .gitignore. Maybe from here.

Upvotes: 21

Mohideen bin Mohammed
Mohideen bin Mohammed

Reputation: 20196

git add myfile.txt # This will add your file into the to-be-committed list

Quite opposite to this command is,

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

so, you will be in the previous state. Specified will be again in untracked list (previous state).

It will reset your head with that specified file. so, if your head doesn't have it means, it will simply reset it.

Upvotes: 24

electblake
electblake

Reputation: 2185

As per many of the other answers, you can use git reset

BUT:

I found this great little post that actually adds the Git command (well, an alias) for git unadd: see git unadd for details or..

Simply,

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

Now you can

git unadd foo.txt bar.txt

Alternatively / directly:

git reset HEAD foo.txt bar.txt

Upvotes: 110

sjas
sjas

Reputation: 19757

Git has commands for every action imaginable, but it needs extensive knowledge to get things right and because of that it is counter-intuitive at best...

What you did before:

  • Changed a file and used git add ., or git add <file>.

What you want:

  • Remove the file from the index, but keep it versioned and left with uncommitted changes in working copy:

    git reset HEAD <file>
    
  • Reset the file to the last state from HEAD, undoing changes and removing them from the index:

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

    This is needed since git reset --hard HEAD won't work with single files.

  • Remove <file> from index and versioning, keeping the un-versioned file with changes in working copy:

    git rm --cached <file>
    
  • Remove <file> from working copy and versioning completely:

    git rm <file>
    

Upvotes: 130

takeshin
takeshin

Reputation: 50668

To clarify: git add moves changes from the current working directory to the staging area (index).

This process is called staging. So the most natural command to stage the changes (changed files) is the obvious one:

git stage

git add is just an easier-to-type alias for git stage

Pity there is no git unstage nor git unadd commands. The relevant one is harder to guess or remember, but it is pretty obvious:

git reset HEAD --

We can easily create an alias for this:

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

And finally, we have new commands:

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

Personally I use even shorter aliases:

git a # For staging
git u # For unstaging

Upvotes: 317

genehack
genehack

Reputation: 140908

To unstage a specific file

git reset <file>

That will remove the file from the current index (the "about to be committed" list) without changing anything else.

To unstage all files from the current change set:

git reset

In old versions of Git, the above commands are equivalent to git reset HEAD <file> and git reset HEAD respectively, and will fail if HEAD is undefined (because you haven't yet made any commits in your repository) or ambiguous (because you created a branch called HEAD, which is a stupid thing that you shouldn't do). This was changed in Git 1.8.2, though, so in modern versions of Git you can use the commands above even prior to making your first commit:

"git reset" (without options or parameters) used to error out when you do not have any commits in your history, but it now gives you an empty index (to match non-existent commit you are not even on).

Documentation: git reset

Upvotes: 13733

Owen
Owen

Reputation: 123

Adding new information. My git version is 2.32.1, and the recommended way of achieving this is now

git restore --staged <file>...

This is recommended via the output of

git status

Upvotes: 7

akhtarvahid
akhtarvahid

Reputation: 9779

You can unstage or undo using the git command or GUI Git.

Single file

git reset File.txt

Multiple files

git reset File1.txt File2.txt File3.txt

Example

Suppose you have added Home.js, ListItem.js, Update.js by mistake,

Enter image description here

and want to undo/reset =>

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

Enter image description here

The same example using Git GUI

git gui

Opens a window. Uncheck your files from Staged changes (will commit)

Enter image description here

Upvotes: 71

Rahul Sinha
Rahul Sinha

Reputation: 2029

git reset filename.txt

will remove a file named filename.txt from the current index (also called the “staging area”, which is where changes “about to be committed” are saved), without changing anything else (the working directory is not overwritten).

Upvotes: 82

Gerard de Visser
Gerard de Visser

Reputation: 8050

If you want to revert the last commit but still want to keep the changes locally that were made in the commit, use this command:

git reset HEAD~1 --mixed

Upvotes: 10

Supratim Roy
Supratim Roy

Reputation: 882

I would use git restore --staged . or git restore --staged <filename>

You can also use git rm --cached, however, the git rm command should be ideally used for already tracked files.

Upvotes: 10

Rahmat Oktrifianto
Rahmat Oktrifianto

Reputation: 447

You can using this command after git version 2.23 :

git restore --staged <filename>

Or, you can using this command:

git reset HEAD <filename>

Upvotes: 9

user10841478
user10841478

Reputation:

The git reset command helps you to modify either the staging area or the staging area and working tree. Git's ability to craft commits exactly like you want means that you sometimes need to undo changes to the changes you staged with git add.

You can do that by calling git reset HEAD <file to change>. You have two options to get rid of changes completely. git checkout HEAD <file(s) or path(s)> is a quick way to undo changes to your staging area and working tree.

Be careful with this command, however, because it removes all changes to your working tree. Git doesn't know about those changes since they've never been committed. There's no way to get those changes back once you run this command.

Another command at your disposal is git reset --hard. It is equally destructive to your working tree - any uncommitted changes or staged changes are lost after running it. Running git reset -hard HEAD does the same thing as git checkout HEAD. It just does not require a file or path to work.

You can use --soft with git reset. It resets the repository to the commit you specify and stages all of those changes. Any changes you have already staged are not affected, nor are the changes in your working tree.

Finally, you can use --mixed to reset the working tree without staging any changes. This also unstages any changes that are staged.

Upvotes: 7

Marcin Szymczak
Marcin Szymczak

Reputation: 11443

One of the most intuitive solutions is using Sourcetree.

You can just drag and drop files from staged and unstaged

Enter image description here

Upvotes: 9

Vidura Mudalige
Vidura Mudalige

Reputation: 832

Suppose I create a new file, newFile.txt:

Enter image description here

Suppose I add the file accidentally, git add newFile.txt:

Enter image description here

Now I want to undo this add, before commit, git reset newFile.txt:

Enter image description here

Upvotes: 29

Anirudh Sood
Anirudh Sood

Reputation: 1436

To undo git add, use:

git reset filename

Upvotes: 19

miva2
miva2

Reputation: 2151

In Sourcetree you can do this easily via the GUI. You can check which command Sourcetree uses to unstage a file.

I created a new file and added it to Git. Then I unstaged it using the Sourcetree GUI. This is the result:

Unstaging files [08/12/15 10:43] git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree reset -q -- path/to/file/filename.java

Sourcetree uses reset to unstage new files.

Upvotes: 11

Jonathan
Jonathan

Reputation: 369

There is also interactive mode:

git add -i

Choose option 3 to un add files. In my case I often want to add more than one file, and with interactive mode you can use numbers like this to add files. This will take all but 4: 1, 2, 3, and 5

To choose a sequence, just type 1-5 to take all from 1 to 5.

Git staging files

Upvotes: 17

Michael_Scharf
Michael_Scharf

Reputation: 34548

The question is not clearly posed. The reason is that git add has two meanings:

  1. adding a new file to the staging area, then undo with git rm --cached file.
  2. adding a modified file to the staging area, then undo with git reset HEAD file.

If in doubt, use

git reset HEAD file

Because it does the expected thing in both cases.

Warning: if you do git rm --cached file on a file that was modified (a file that existed before in the repository), then the file will be removed on git commit! It will still exist in your file system, but if anybody else pulls your commit, the file will be deleted from their work tree.

git status will tell you if the file was a new file or modified:

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

Upvotes: 106

boulder_ruby
boulder_ruby

Reputation: 39753

Use the * command to handle multiple files at a time:

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

etc.

Upvotes: 30

powlo
powlo

Reputation: 2718

Note that if you fail to specify a revision then you have to include a separator. Example from my console:

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 version 1.7.5.4)

Upvotes: 46

leonbloy
leonbloy

Reputation: 76006

An addition to the accepted answer, if your mistakenly-added file was huge, you'll probably notice that, even after removing it from the index with 'git reset', it still seems to occupy space in the .git directory.

This is nothing to be worried about; the file is indeed still in the repository, but only as a "loose object". It will not be copied to other repositories (via clone, push), and the space will be eventually reclaimed - though perhaps not very soon. If you are anxious, you can run:

git gc --prune=now

Update (what follows is my attempt to clear some confusion that can arise from the most upvoted answers):

So, which is the real undo of git add?

git reset HEAD <file> ?

or

git rm --cached <file>?

Strictly speaking, and if I'm not mistaken: none.

git add cannot be undone - safely, in general.

Let's recall first what git add <file> actually does:

  1. If <file> was not previously tracked, git add adds it to the cache, with its current content.

  2. If <file> was already tracked, git add saves the current content (snapshot, version) to the cache. In Git, this action is still called add, (not mere update it), because two different versions (snapshots) of a file are regarded as two different items: hence, we are indeed adding a new item to the cache, to be eventually committed later.

In light of this, the question is slightly ambiguous:

I mistakenly added files using the command...

The OP's scenario seems to be the first one (untracked file), we want the "undo" to remove the file (not just the current contents) from the tracked items. If this is the case, then it's ok to run git rm --cached <file>.

And we could also run git reset HEAD <file>. This is in general preferable, because it works in both scenarios: it also does the undo when we wrongly added a version of an already tracked item.

But there are two caveats.

First: There is (as pointed out in the answer) only one scenario in which git reset HEAD doesn't work, but git rm --cached does: a new repository (no commits). But, really, this a practically irrelevant case.

Second: Be aware that git reset HEAD can't magically recover the previously cached file contents, it just resynchronises it from the HEAD. If our misguided git add overwrote a previous staged uncommitted version, we can't recover it. That's why, strictly speaking, we cannot undo [*].

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

Of course, this is not very critical if we just follow the usual lazy workflow of doing 'git add' only for adding new files (case 1), and we update new contents via the commit, git commit -a command.


* (Edit: the above is practically correct, but still there can be some slightly hackish/convoluted ways for recovering changes that were staged, but not committed and then overwritten - see the comments by Johannes Matokic and iolsmit)

Upvotes: 228

Paul Beckingham
Paul Beckingham

Reputation: 14925

If you type:

git status

Git will tell you what is staged, etc., including instructions on how to unstage:

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

I find Git does a pretty good job of nudging me to do the right thing in situations like this.

Note: Recent Git versions (1.8.4.x) have changed this message:

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

Upvotes: 640

Ana Betts
Ana Betts

Reputation: 74692

If you're on your initial commit and you can't use git reset, just declare "Git bankruptcy" and delete the .git folder and start over

Upvotes: 77

Hasib Kamal Chowdhury
Hasib Kamal Chowdhury

Reputation: 2660

For a specific file:

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

For all added files:

  • git reset .
  • git checkout .

Note: checkout changes the code in the files and moves to the last updated (committed) state. reset doesn't change the codes; it just resets the header.

Upvotes: 26

Rhubarb
Rhubarb

Reputation: 35863

You want:

git rm --cached <added_file_to_undo>

Reasoning:

When I was new to this, I first tried

git reset .

(to undo my entire initial add), only to get this (not so) helpful message:

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

It turns out that this is because the HEAD ref (branch?) doesn't exist until after the first commit. That is, you'll run into the same beginner's problem as me if your workflow, like mine, was something like:

  1. cd to my great new project directory to try out Git, the new hotness
  2. git init
  3. git add .
  4. git status

    ... lots of crap scrolls by ...

    => Damn, I didn't want to add all of that.

  5. google "undo git add"

    => find Stack Overflow - yay

  6. git reset .

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

It further turns out that there's a bug logged against the unhelpfulness of this in the mailing list.

And that the correct solution was right there in the Git status output (which, yes, I glossed over as 'crap)

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

And the solution indeed is to use git rm --cached FILE.

Note the warnings elsewhere here - git rm deletes your local working copy of the file, but not if you use --cached. Here's the result of git help rm:

--cached Use this option to unstage and remove paths only from the index. Working tree files, whether modified or not, will be left.

I proceed to use

git rm --cached .

to remove everything and start again. Didn't work though, because while add . is recursive, turns out rm needs -r to recurse. Sigh.

git rm -r --cached .

Okay, now I'm back to where I started. Next time I'm going to use -n to do a dry run and see what will be added:

git add -n .

I zipped up everything to a safe place before trusting git help rm about the --cached not destroying anything (and what if I misspelled it).

Upvotes: 2492

Joseph Mathew
Joseph Mathew

Reputation: 1439

git reset filename.txt  

Will remove a file named filename.txt from the current index, the "about to be committed" area, without changing anything else.

Upvotes: 18

Related Questions