How do I save work in progress without using git-stash?
I have a git directory with this situation:
ProgSoul@PROGSOUL-LENOVO:~/esercizio3_2$ git status Sul branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: A Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: A Untracked files: (use "git add <file>..." to include in what will be committed) B
In this situation I have:
- Git: Create a branch from unstaged/uncommited changes on master
- How to recover from “git stash save --all”?
- Git - switching between branches in the middle of work
- What is a stash?
- Git: see what's in a stash without applying stash
- What are those 'WIP' and 'index' commits that appear after stashing?
- there is a file named A in the index with a string “AA” inside it
- I modified the file A with “AAA” inside it but I didn’t add this change on the stage. So in the working directory I have A with a string “AAA” inside it
- an untracked empty file B
My teacher wants me to temporarily suspend my work, create a BUGFIX file, commit it and restore my previous situation.
I achieved it through these commands:
git stash --include-untracked touch BUGFIX git add BUGFIX git commit -m "Aggiunto file BUGFIX" git stash pop --index
With these commands I saved my initial situation and restored it once my fix has been commited.
My teacher also asked me to reach this goal without using git-stash.
I followed the help in the stash documentation:
git checkout -b WIP git commit -a -m "WIP" git checkout master touch BUGFIX git add BUGFIX git commit -a -m "BUGFIX" git checkout WIP git reset --soft HEAD^
With git reset –soft I restored the index but the changes not staged for commit have been lost.
With git reset –mixed I restored the changes not staged for commit but the index has been lost.
How can I restore the same initial situation once I commit the fix without using git stash?
3 Solutions collect form web for “How do I save work in progress without using git-stash?”
Let’s try it this way:
Q: How can you save something in Git?
A: Commit it.
Q: What about
git stash, it seems to save things, how does it manage that?
A: It commits.
Q: But it doesn’t put any commits on my branch.1
A: They’re on the special “stash” thing, which is not a branch. But they’re still commits.
1This is, technically, not a question. 🙂
If you want to save something in Git, commit it
This is the Git bottom line, as it were: a commit saves things. Otherwise all you have is stuff in your work-tree, and stuff in your index (staging-area). The staging-area stuff becomes permanent when you run
git commit. The work-tree stuff is never permanent: you have to copy it to the staging area and then commit it.
This is what
git stash does. It actually makes two commits, one for the current index, and one for the work-tree.2 It just makes them both on something other than a branch, using the name
stash to find them instead.
There’s nothing stopping you from making your own commits, though. It’s just a bit of a pain to make two or more commits and then have to undo them, which is why
git stash exists.
2When you use
--include-untracked as you did, it actually makes three commits: one for the index, a second for the work-tree, and a third one for the untracked files. That third commit is extra-tricky, both to make and to restore. The stash script uses a temporary index rather than trying to do the work in the main index.
You can always use another clone
Each Git repository is, in general, independent of all other Git repositories, but can peer with any related Git repository. So you can clone one repository to another, and thereby get another work-tree where you can do work. This work-tree also comes with its own (separate) index / staging-area.
If you make the clone locally, on your local file system, Git is often able to avoid a lot of repository-file copying. So while this might seem expensive, it’s usually not that bad. The main problem is that you now have two repositories to remember to commit-to, and you must fetch and/or push between them and/or whatever upstream you originally cloned from.
For quick side work,
git worktree add (2.5 and newer only)
Before Git 2.5 there was a “contributed” script to make alternate work-trees. As of 2.5 it became officially supported, though there were some important bug fixes since then (and even now it has some rough edges). You can now run
git worktree add to create a new worktree that will use a different branch, but share the underlying repository.
No two work-trees that share one underlying repository may use the same branch. (This is because of the way Git stores its idea of the “current branch” and “current commit”, and the way Git advances the current branch when you make a new commit.) If your goal, however, is to make a fix in some other branch than the one you are working on now, this is just what you need anyway.
Git’s got a little-known feature just for this, built in.
echo fix fix >> BUGFIX git add BUGFIX git commit BUGFIX
… and if
BUGFIX were already tracked, you wouldn’t even need the
git add, it’d do that for you. See point 3 of the
git commit description:
listing files as arguments to the commit command (without –interactive or –patch switch), in which case the commit will ignore changes staged in the index, and instead record the current content of the listed files (which must already be known to Git);
and although the description doesn’t say it, the current contents are added to the index as well as the commit.
Thanks to every answer I received. I achieved two possible solutions:
git worktree add -b BUGFIX ../bugfix_temp master pushd ../bugfix_temp touch BUGFIX git add BUGFIX git commit -a -m "emergency BUGFIX" popd rm -rf ../bugfix_temp git worktree prune
touch BUGFIX git add BUGFIX git commit --only BUGFIX -m "emergency BUGFIX"