2

I have done about 2 months work locally against main branch (without committing or staging anything). This included adding new (untracked) files and modifying existing tracked files.

Then I wanted to check something on the main branch without my changes so did:

git stash -all

Expecting it to stash both my tracked and untracked file changes.

I then did

git stash pop

To get my changes back, and got thousands of errors:

.project already exists, no checkout
all/.project already exists, no checkout
all/.settings/org.eclipse.wst.common.component already exists, no checkout
all/target/vault-work/META-INF/MANIFEST.MF already exists, no checkout
all/target/vault-work/META-INF/vault/config.xml already exists, no checkout
all/target/vault-work/META-INF/vault/filter.xml already exists, no checkout
all/target/vault-work/META-INF/vault/properties.xml already exists, no checkout
all/target/vault-work/META-INF/vault/settings.xml already exists, no checkout
core/.project already exists, no checkout
core/target/classes/META-INF/MANIFEST.MF already exists, no checkout
core/target/classes/OSGI-INF/com.xx.aem.core.filters.CorrelationLoggingFilter.xml already exists, no checkout
core/target/classes/OSGI-INF/com.xx.aem.core.filters.LinkHeaderFilter.xml already exists, no checkout
core/target/classes/OSGI-INF/com.xx.aem.core.filters.LoggingFilter.xml already exists, no checkout

and ending in:

ui.content/target/vault-work/META-INF/vault/settings.xml already exists, no checkout
ui.frontend/.project already exists, no checkout
ui.tests/.project already exists, no checkout
error: could not restore untracked files from stash
The stash entry is kept in case you need it again.

Surprisingly, when looking at the state of the local code, it does seem to have created the new files. But none of the changed files are there. So the error says it could not restore untracked files, but it appears to have, but it has not recovered the changes I made to existing files.

Summary:

  1. I had changed files and new (untracked files) from main.
  2. I did "git stash -all"
  3. This got me back to main without my changes.
  4. I then did "git pop", expecting to be back to 1.
  5. got thousands of errors for no apparent reason.
  6. None of my changes to files are there.
  7. My new, untrack files do see to be there, despite it saying it could not restore them.

How do I get back all the changes I did to existing files?

Any help appreciated.

Note: I have recently noticed that git stash --all (which was recommended on a post in order to stash tracked and untracked files) may also (bizarrely) stash ignored files - this could be the crux of the problem.

If I do

git stash show

I get

bob@MacBook-Pro eyas-web % git stash show
 .../aem/core/filters/xx.java |  25 ++-
 .../models/xxx/response/x.java   |  18 --
 .../xx/aem/core/models/xx/Player.java         |  14 ++
 .../xx/aem/core/services/xx.java       |  31 +++
 .../services/impl/xx.java  |   2 +-
 .../core/services/impl/xx.java |   6 +
 .../aem/core/services/impl/xx.java   | 212 ++++++++++++++++++++-
 pom.xml                                            |  18 --
 8 files changed, 282 insertions(+), 44 deletions(-)

I need to figure out how to get the "8 files changed" back from the stash, along side the new untracked files which do seem to have been restored.

One idea might be to try to remove all the ignored files, then do git stash pop again. However, looking at the man pages for "git clean -xdf", it doesn't say if -x also removes the necessary git files as well as the ignored files we added (such as project config files).

Any ideas how to fix this?

I noticed this post: How do you stash an untracked file?

Which says: "git stash -u Warning, doing this will permanently delete your files if you have any directory/ entries in your gitignore file."

This seems very bad, and may be related to my issue.

John Little
  • 10,707
  • 19
  • 86
  • 158
  • "I have done about 2 months work locally against main branch (without committing anything)" Why? Why would anyone go even a day without committing? It seems to me that _that_ was your mistake. Branches and commits are lightweight and nimble. Commit early and often. – matt Sep 11 '22 at 16:57
  • Good question. My code was not ready yet, and still being on main branch meant I could simply do git pull every morning to be "up to date". If I had checked my code into a feature branch, I could still have regularly pulled from main branch and merged into feature branch, but its more dangerous as its very easy to accidentally commit to the wrong branch, and the difficulty this causes. Now I know how dangerous git stash is, I won't be using it again, I'll go down the always committing to a separate branch route. – John Little Sep 12 '22 at 08:51
  • why man? you must use git stash --include-untracked not git stash -all – Ali Safarpour Sep 12 '22 at 08:59
  • i have crazy idea create new branch then remove all data then git stash apply stash@{0} that stash you use maybe its recovery your data – Ali Safarpour Sep 12 '22 at 09:03
  • Yes, now I know. I had read two posts which recommended using git stash -all, and there are no warnings how dangerous (and un-recoverable) this command is. – John Little Sep 12 '22 at 09:03
  • "but its more dangerous as its very easy to accidentally commit to the wrong branch, and the difficulty this causes" You're wrong. As long as you use commits and branches, every move you make is easily undoable. But what _you_ did is act as if Git didn't exist at all, leaving yourself wide open for issues. Git cares _only about commits_. By never committing, you created a risky situation that is not within the purview of Git at all. Then, without saving your work, you suddenly did commit it using `stash` — and you deleted it from your workspace. – matt Sep 12 '22 at 11:21
  • So now you've no idea what's in that stash, or how to get it back. And whatever did not get into it is gone forever. You did something that is _not_ easily undoable, perhaps not undoable at all. – matt Sep 12 '22 at 11:22

4 Answers4

2

How do I get back all the changes I did to existing files?

I would try git stash branch:

  1. Backup your whole directory (just in case).
  2. git stash branch my-stash-in-a-branch This should bring back everything you've stashed. Even untracked/ignored stuff from git stash --all will be recovered.
  3. Now do something like git rebase -i master to get in sync with your mainline.

PS: I cross my fingers for you that your stash is not already empty. Prefer git stash apply over git stash pop in unclear situations.

jschnasse
  • 8,526
  • 6
  • 32
  • 72
1

I then did a build and deployment,

These steps may have created new untracked files in your working tree. And I think those untracked files are blocking git stash pop.

Check working tree status by git status. If you see unwanted untracked files, use git clean to remove them, then git stash pop.

Yoichi Nakayama
  • 704
  • 6
  • 9
  • Thanks for the suggestion. Interestingly, it has created my untracked files, but hasnt updated the tracked files I edited. I am suspecting that all the "already exists" errors are from ignored files, and I dont know how to get round this. – John Little Sep 11 '22 at 16:20
  • @JohnLittle: You could try clearing the ignored files, also with `git clean`, specifically, using the `-x` or `-X` flags (carefully) – Hasturkun Sep 12 '22 at 09:44
  • In unclear situations like this I would at least recommend to keep the stash as is. **1. do a backup 2. Use `git stash apply` instead of `pop`**. In my answer I recommend using ` git stash branch` which offers much more flexibility. – jschnasse Sep 12 '22 at 10:20
  • The behaviour of **git clean** depends on the global git config. A **git stash --all** performs a `git clean` right away, [see](https://git-scm.com/docs/git-stash), but If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f or -i. [See](https://git-scm.com/docs/git-clean) – jschnasse Sep 13 '22 at 11:49
1

I found a great and simple solution:

  1. duplicate (using macOs duplicate finder option) the entire project directory (5GB) as a backup just in case.
  2. git clean -xfd
  3. git stash apply

Now I seem to be back where I started. The clean -xfd removes the untracked files and folders, which includes all those ignored by git ignore, as well as my work. This was a bit of a gamble as the documentation implies that this command also removes the git control files, but it doesn't seem to.

The "stash apply" then creates all the untracked files, including the ignored files, my work, then updates my modified tracked files.

John Little
  • 10,707
  • 19
  • 86
  • 158
  • Good to know you could recover your work. Now you create a branch and commit *all* of your precious work right away, as half-baked as it happens to be. – j6t Sep 13 '22 at 07:40
1

note : git stash apply first tries to restore your indexed and tracked files, and only then your untracked files. If it reaches the "untracked files" step, it should indicate that the first part was applied without conflicts.


git stash apply can be used with any commit that looks like a stash. So you can create a stash-like commit which contains only the index and the tracked files, and use that one to reapply changes on your tracked files only.

  • with the -u or -a option, git stash will create a 3 legged commit

You can view that by running git log --oneline --graph stash

$ git log --graph --oneline stash
*-.   db814f6 (refs/stash) WIP on master: 06ffba6 create c.txt  # the worktree
|\ \  
| | * 27b820c untracked files on master: 06ffba6 create c.txt   # the untracked files
| * e59f7fb index on master: 06ffba6 create c.txt               # the index
|/  
* 06ffba6 create c.txt                                          # the active commit
* df9858f create b.txt
...
  • you can create a stash-like commit with only 2 legs (e.g : the active commit and the index) :
# create the commit :
git commit-tree stash^{tree} -p stash^ -p stash^2 -m "my stash"

# for convenience : give a name to that commit
git tag mystash <sha output above>
  • you can now run git stash apply --index mystash, and you will have feedback only on your indexed/tracked files (e.g : "it worked / conflicts occurred")

  • you can use git restore or git checkout to get your untracked files back from stash^3 :

# restore selected files from that stash entry :
git restore --overlay -W -s stash^3 -- that/file that/dir/

a word of warning: if you are using git restore for files which are not tracked or not committed, you can accidentally remove data from your disk which isn't stored within git. You would be better off working on a clean worktree.


I wrote all the above command by referring to the stash commit, which is the topmost stash, but if you have to run git stash again to stash away more changes, then the target you want is not the topmost stash anymore.

You can replace stash in all commands above by stash@{1} or stash@{nn}, or by the sha of the stash commit you want to work with.

LeGEC
  • 46,477
  • 5
  • 57
  • 104