Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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

like image 717
Antonio Notarangelo Avatar asked Dec 19 '16 15:12

Antonio Notarangelo


1 Answers

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.

like image 104
torek Avatar answered Sep 28 '22 01:09

torek