How do I save work in progress without using git-stash?

4.2k views Asked by At

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:

  • 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?

4

There are 4 answers

0
Antonio Notarangelo On BEST ANSWER

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

OR

touch BUGFIX
git add BUGFIX
git commit --only BUGFIX -m "emergency BUGFIX"
1
torek On

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.

5
jthill On

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.

0
Mika Hänninen On

If you have bunch of changes in a file which you would like to save but not yet commit, then one option would be taking a diff of your changes and save that diff to a file and store diff in some other location.

git diff changedfile > ~/diff_of_an_idea.diff
git restore changedfile # back to original

then sometime later when you want to include diff

git apply ~/diff_of_an_idea.diff
git add & git commit