The scenario:
- Stage file changes
- Do some more changes on the file
- Stage file changes
Now I regret I staged the last changes and wish to go back to the way the file was staged at first. In essence, I want to rollback the last stage operation.
Note, that nothing was committed, all the changes were staged only.
Is it possible?
CodePudding user response:
When you stage a file, it is written to the index. When you stage it again, it is written to the index, overwriting the earlier version. That's it. It's gone.
See What's the difference between HEAD, working tree and index, in Git? for an explanation of the index and how it fits in with the rest of the Git world.
CodePudding user response:
It's possible. It's not even hard. Adding something to the repo adds it to the repo, and Git doesn't clean out anything that's been useful recently unless people get very explicit about telling it to do that, and nobody does.
My first attempt would be to see if git reset --patch -- the.file
will do it, though. That lets you reset change hunks in the indexed copy to what they were in the committed copy you checked out; if you're after un-staging something that didn't overwrite lines you staged before and want back now that'll do you just fine.
Also, any good Git plugin, and any half-decent programmer's editor will have one, can do this right in your editor interface, I know of fugitive for vim and magit for emacs, they let you edit and smoosh hunks around in staged content as if they was just another file, and pull stuff out of committed content to wherever you want.
But if your new changes touched what you had in the lines you want back, then the content you want back isn't in your work tree or the indexed or committed content.
For that, and always, there's the option of a little light spelunking in the repo.
Added content stays in .git/objects/??
, type-tagged and compressed some, until Git does a repack, and as I recall Git doesn't by default pack up unreferenced items at all, it leaves them lying around loose until they've been unreferenced for at least several weeks, then cleans them out on the next trash run after that.
find .git/objects/?? -type f -exec ls -t {} | awk -F/ '{print $3$4}'
will list all the loose-object ids in your repo, which will all result from things you did locally, most recent first. To whittle it down to stuff you care about,
find .git/objects/?? -type f -exec ls -t {} \
| awk -F/ '{print $3$4}' | git cat-file --batch-check \
| awk '$2=="blob" && n <50'
will show you the id, type and size of the last 50 blobs you added. Tops on that list will almost certainly be the oops, the next blob about the same size is very likely to be what you added before that, git show
likely-looking ids until you find what you want. Then,
git update-index --cacheinfo 100644,$thatid,that.file
(or 100755 if it's an executable file) to make the index entry point at that content instead of your oops.