I was working on the main branch, then I decided to create a new branch called test-branch
. I tried git checkout feature
first which warned me to stash
or commit
my changes. I stash
ed them using git stash save latest modification
and then I went to test-branch
using git checkout -b test-branch
. I was trying to add all files (not ignoring any) and commit to the branch. So I deleted everyting from .gitignore
. After running git add .
, I came back to main
without committing to test-branch
. I deleted that branch using git branch -D test-branch
. And then I used git stash apply
in main
. Now my code has gone to the last commit version and all the modifications I did after that commit exist no more. What do I do now ?
Before swtiching branches
PS C:\Users\Administrator\Desktop\projects\songs> git checkout feature
error: Your local changes to the following files would be overwritten by checkout:
.gitignore
app.py
music.db
static/css/styles.css
templates/favorites.html
templates/layout.html
Please commit your changes or stash them before you switch branches.
PS C:\Users\Administrator\Desktop\projects\songs> git stash save "latest modification"
Saved working directory and index state On main: latest modification
Unlink of file 'music.db' failed. Should I try again? (y/n) y
fatal: Could not reset index file to revision 'HEAD'.
After switching branches
PS C:\Users\Administrator\Desktop\projects\songs> git checkout -b test-branch
Switched to a new branch 'test-branch'
PS C:\Users\Administrator\Desktop\projects\songs> git st
M music.db
?? static/scripts/downloader.js
?? test/
PS C:\Users\Administrator\Desktop\projects\songs> git add .
I then came back again to main
PS C:\Users\Administrator\Desktop\projects\songs> git checkout main
Switched to branch 'main'
M .gitignore
M music.db
A static/scripts/downloader.js
A test/a.exe
A test/ipvalidator.exe
A test/nextvalidator.c
A test/nextvalidator.exe
Your branch is up to date with 'origin/main'.
PS C:\Users\Administrator\Desktop\projects\songs> git branch -D "test-branch"
Deleted branch test-branch (was 08f1d8e).
Then I applied the stash
and my changes are gone
PS C:\Users\Administrator\Desktop\projects\songs> git stash apply
error: Your local changes to the following files would be overwritten by merge:
.gitignore
Please commit your changes or stash them before you merge.
Aborting
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: music.db
new file: static/scripts/downloader.js
new file: test/a.exe
new file: test/ipvalidator.exe
new file: test/nextvalidator.c
new file: test/nextvalidator.exe
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: .gitignore
Untracked files:
__pycache__/
flask_session/
improvements.txt
run.ps1
static/downloads/
templates/test.html
test.py
venv/
Edit:
As per @ElderFuthark 's request, I ran git stash show --stat
and got the following:
PS C:\Users\Administrator\Desktop\projects\songs> git stash show --stat
.gitignore | 4 --
app.py | 11 ----
music.db | Bin 69632 -> 86016 bytes
static/css/musicPlayer.css | 1
static/css/styles.css | 4 -
templates/favorites.html | 2
templates/layout.html | 8 --
templates/play.html | 27 --------
8 files changed, 40 insertions( ), 17 deletions(-)
CodePudding user response:
Long: part 2 of 2: what you can do now
(see also part 1)
The short version of this is:
- what you have available through Git itself, to restore files, is whatever's in commits, plus anything you can commit right now from Git's index;
- what you have available on your computer in general includes any untracked files and any backups you made with backup software (e.g., Time Machine on macOS).
These are the places to go to get files back.
Your git stash show --stat
shows a diff from the commit I've been labeling K
to the one in w
:
git stash show --stat .gitignore | 4 -- app.py | 11 ---- music.db | Bin 69632 -> 86016 bytes static/css/musicPlayer.css | 1 static/css/styles.css | 4 - templates/favorites.html | 2 templates/layout.html | 8 -- templates/play.html | 27 --------
You also have, now, in your index, a version of music.db
(probably matching that in the w
commit here), and the A
dded files. You can git commit
this or git stash
again if you like, to make more commits. You still have your existing stash.
You can turn any stash into a branch with git stash branch
. If there is valuable data in the existing stash, that's my general recommendation: once it's a normal everyday branch, you can use all of Git's tools with it.
If there's nothing valuable in Git's index and your working tree right now, you can use git reset --hard HEAD
to reset both of those.
Since there was a problem with music.db
, you should find out why: there's probably a program that had, or still has, it open, preventing you from replacing the file. If you can terminate that program, or convince it to close the file, you can work on / with it again.
So, do each of these things—e.g., make a commit out of what you have now, if necessary and appropriate, fix whatever kept you from working with music.db
, and/or turn the existing stash into a branch with git stash branch
. If there's nothing valuable in the stash, drop the stash.
Using git stash branch
Before you can use git stash branch
, you need to be in a "clean" state—that is, one where git status
does not talk about changes that are to-be-committed and not-staged-for-commit. (Or, one where your git st
short-status alias does not show any M, A, D, etc., files; ??
untracked files are sometimes OK.)
Then you can run:
git stash branch new-branch-for-stash
What this does is:
- check out the parent of the
i
andw
commits (that's commitK
in my drawings here); and - use
git stash apply --index
to restore both the index and working tree states.
This almost always works (the exceptions include cases like "some program holds music.db
open so that we can't patch it"; note that music.db
is different between commit K
and w
here). It leaves you in a state where you can run git commit
, or git add
and git commit
, or git commit
followed by git add
and git commit
. Choose whichever you would like, to commit the changes you'd stashed, and get back to a "clean" git status
(except, perhaps, for untracked files).
Untracked files are the usual problem here, especially when .gitignore
has changed over time, because some files may actually be in some commits, when they shouldn't really be in those commits, and if you successfully check out such a commit, that file will now be in Git's index. Git will now want to remove the file if and when you switch from that commit to another commit that lacks the file.
The solution is usually the obvious trivial one: rename the untracked files out of the way, or entirely out of the working tree (which is also out of the way). That way, you still have the files and they are still not in the index. By using fresh names for them, they won't be clobbered by any commits where they were accidentally (or on purpose but incorrectly) stored.
For any files that aren't in Git, you'll need to restore them using some outside-Git mechanism.
CodePudding user response:
Long, so, part 1 of 2
(see part 2 for what you can do)
There are multiple things to learn here, and also multiple different steps to take to recover everything. There's overlap between the two but they're not exactly the same.
One thing I would suggest as a learning item is "don't use git stash
" because it often makes a big mess.