0

Just curious to know. Say I have one file named test, I add Hello World\n to the file and git add it.

Now in the staging area, there should be a file named test with content Hello World\n.

Now I add another line Hello World 2\n and then git add it.

Now my staging area would be file test with its content as "Hello World\nHello World2\n".

Now is there any way that I undo my second git-add to make the staging area back to file test with content "Hello World\n".

Assumptions: There may or may not be any commits at this time. Please consider two conditions.

Additions: What if there are multiple git-add and I want to undo the last n times of them.

2
  • 1
    As far as I’m aware, nothing keeps track of git add’s history. (Which makes sense – commits are for keeping track of history.) You’ll probably have to do it manually, which isn’t really an undo. (That is, unstage and git add -p, then split or edit as necessary.)
    – Ry-
    Commented Apr 6, 2016 at 21:10
  • .git/objects records all the changes you made. Every time you git add sth, git will create a corresponding blob object and you can "git cat-file -p" to view the change. What I need is a way to manage staging index more straight forward instead of using interactive modes. Hope there is one :)
    – lazybug
    Commented Apr 7, 2016 at 2:22

2 Answers 2

3

Once you do a git add, Git starts to track the file and creates a SHA-1 every time you add a file to the staging area.

You can recover and restore any of the versions you had in the staging area as long as git gc did not compact and clean your repository.

Assuming you didn’t run git gc, you simply need to know the SHA-1 of your file.

What happens when I add the same file to the staging area again?

Once you add the same file to stash with new contents, Git calculates the new SHA-1 for the file and updates the tree with the new SHA-1. The old SHA-1 is still stored under .git/objects.

How do I restore the “old” staged file?

First you need to find the SHA-1 of the desired file.

# print the list of all the dangling files in the repo
git fsck

# now you need to manually search the files to find the desired 
# "old file" and then restore it using git cat-file -p

Screenshot


A complete example:

cd tmp
mkdir repo1
cd repo1
git init
echo 'line1' > a.txt
git add .
echo 'line2' >> a.txt
git add .
git fsck
git cat-file -p a29bdeb434d874c9b1d8969c40c42161b03fafdc
git cat-file -p c0d0fb45c382919737f8d0c20aaf57cf89b74af8

Screenshot

2
  • Thanks for the answer. I can find the SHA-1 of an "older" version, but "git cat-file" just provide content/type/size info for repository objects, which means it doesn't change or unstage anything. What kind of command could I use to manipulate content in the staging area? I know "git reset -i" will let me manually manage which part to unstage. Is there any more efficient way to make the work more straight forward, like change the file to a specific "older" SHA-1 with a few commands?
    – lazybug
    Commented Apr 7, 2016 at 1:38
  • Thanks. Your answer answered something I should have known before answering a question incorrectly. I can't find that question from yesterday, but it had to do with a file being re-edited, and before the commit. Commented Apr 7, 2016 at 12:55
1

The stage doesn't save individual actions, it just keeps the state of the files. Therefore, if you do multiple adds, you just see the result in the stage, not a series of actions.

Git itself tells you how to revert the staged changes:

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

        new file:   blah.txt

Not the answer you're looking for? Browse other questions tagged or ask your own question.