Use git stash save or git commit for local changes?

38,807

Solution 1

When pushing, you always push one specific commit (usually the commit at the tip of your currently checked out branch). However, as the commit's hash partly consists of the commits it bases on (its parent commits), you have to push all parent commits also. And by pushing the parent commits you also have to push their parent commits and so on. So, you can only push the whole history of a specific commit.

If you create a commit just to store something but not for pushing, you need to make sure that you never push that commit, nor any commits that base on that commit. To do that, after you have done your work that bases on the temporary commit, you need to squash the temporary commit into the new commit that you create to push it.

In other words, yes it is possible to use a commit for temporary, private storage. However, it is much easier to use the stash feature. In fact, the feature is made for this very use case.

Solution 2

Personally I prefer just going straight to private (local) branches, but stashes work. Be aware of two things about stashes:

  • They are their own commits. Except for the label, there's no fundamental difference between the "stash" commit and a commit tied to a branch or tag label. (A tag label has the form refs/tags/tag-foo; a branch has the form refs/tags/branch-foo; and the—single—labeled stash commit is labeled refs/stash. Of course, branch labels also have the "automatically moves as you add commits" feature, but if you never add more commits there, they never move, so they work just as well to save a single commit.)
  • The stash "stack"1 is implemented using reflogs. Reflogs can expire—by default most do (after 30 or 90 days), and those in refs/stash do not, but you can change this with configuration entries—so stacked stash commits can also "expire" (at the same time the reflog entry expires). (More precisely, they "become collectable", but this distinction is not helpful if they're gone. :-) )

The intent with stashes is to save something short-term. If you've ever come back to a repo late and find a bunch of stashes, all named "WIP on branch", it is no fun trying to figure them out.

The other features/bugs :-) stash provide are:

  • git stash branch lets you change your mind after the fact and turn a stash into a branch. So, if "short term" turns out to be an issue (you were going to fix it this afternoon but now it's been pushed off for at least a month) you can just turn the stash into a branch after all.
  • git stash apply [--index] will do its best to "re-make" the applied change in the current branch. With --index it will try to restore both the staged and unstaged changes independently. (There are cases where this is impossible, though.)
  • git stash pop automatically discards the stash reference for you. Unfortunately it does this even if you meant to use git stash pop --index and left out the --index part. It's easy to lose some of your state (staged vs unstaged) if you use pop. If you use apply, and later drop once you're sure you have everything back the way you wanted, you can avoid this problem.

Note that git stash branch implies --index: the newly created branch will have staged-and-unstaged changes restored to the way they were when you did the git stash. (The branch will branch off from the commit you were on when you did the git stash, too.) Commit the changes (git add-ing more if desired, or as two separate commits, or whatever) and proceed as if you'd made a private branch in the first place.


1The expire-able part of the stack consists of all stashes other than stash@{0}, in git stash list output.

Solution 3

I do things a little bit differently. Stashes to me are more for quick saves, not daily work since they aren't (easily) granular in what you can actually stash. (i.e. If I have 20 changed files and I want to create two stashes of ten each, it's not easy to do.)

That's why I want my daily changes committed to an actual, albeit temporary branch only for my personal usage so I can include notes and such of my work as I go. Daily check-ins, experiments, etc. Basically things I don't want pushed to the final repo.

When I'm in a state where I'm ready to commit back to the main repo, I use the 'soft reset' command on the commit I originally branched from. This puts all of my temp-branch-committed changes back as current changes on that original commit without any of my daily working history.

I then create a new branch for these "new" changes and I can either commit them all at once, or I can break it apart into several commits if it makes sense (i.e. one for the back-end stuff, another for the front-end stuff, another for resources, etc.)

When I'm done, I'm left with a nice, new, clean branch with a history that makes sense to other devs, free of my daily notes, and ready to merge and push back into the main repo. Then I can delete my temp branches and move on to the next task.

So to recap...

  1. Create a working branch
  2. Make as many commits/sub-branches as you need to get your job done
  3. When you're ready to merge back without keeping that history, git-reset back to the original commit where you branched. All your changes are now local changes.
  4. Re-commit and merge as you see fit

Another benefit is I can actually push the temporary branches to the remote repo so I can work from multiple locations which you can't do with a stash. Just remember when you're done, clean things back up off of the server to keep repo browsing clean. (Some may argue that technically the commits are still there, just detached, which is true, but branches are light-weight in GIT, and in a way, it becomes another safety net for not losing work as you can get back a detached commit if really necessary.)

Solution 4

I suggest you to use stashing tool for it. That is why is it here. You can stash your chnges and later add them to your code. There are lots more functionality which you can use with git stash. Here is the link http://git-scm.com/book/en/Git-Tools-Stashing

I would suggest you to once go through the documentation of git here. Also read about the tool. After this you'll become the master of git for sure.

Share:
38,807

Related videos on Youtube

Balthier
Author by

Balthier

Updated on October 10, 2020

Comments

  • Balthier
    Balthier about 3 years

    I changed some files in my repo, but don't want them to be pushed public or create any temporary branch to store them. I just want to save these changes in somewhere. So which command is better:

    git stash save "save message" 
    

    or

    git commit -am "save message"
    

    ?

    If I use git commit, is it true that all of my local commits will be pushed publicly by one git push command? What if I just want to push one specific commit among them?

    • Gauthier
      Gauthier about 10 years
      Why not using a temporary branch? If you use commit you will either create a commit with no HEAD, or use your current HEAD and move it along. Using a branch and not pushing it to the public is what I'd do.
    • Balthier
      Balthier about 10 years
      The reason why I don't want to create any branch is because when I finally decide to public these changed codes, all commit history in this "experimental" branch will be pushed along with it, including some craft commits I made just to save some experimental changes along the process but "not sure they are correct".
  • Balthier
    Balthier about 10 years
    I don't get much about using git in this case. Does that mean that if I make a commit SHA1 for changed works, then do checkout to back to original work, then do git pull to fetch new commits from git, my SHA1 will go to other new branch or simply disappear?
  • functionpointer
    functionpointer about 10 years
    In that case your history isn't linear anymore. You have two commits that base on the same parent commit. One is the commit for the changed work, and the other is the one that you have fetched. You may merge the commits together. You could also just work on the changed work commit and rebase the result on top of the fetched stuff. This wouldn't introduce any danger as you haven't pushed your changed work commit.
  • Balthier
    Balthier about 10 years
    I guess rebase is okay for local commits as it is not as dangerous as for public commits :)
  • Balthier
    Balthier about 10 years
    So git stash does expire, and I'm afraid of not being able to save my changes forever. Also, git stash branch <branchname> does create a new private branch, which is my final choice for saving local works. Thank you. I guess I should modify the question to using git stash, git commit or git branch.
  • functionpointer
    functionpointer about 10 years
    @Balthier yes, that is correct. In fact, i find myself using rebase --interactive multiple times a week because i have found something that i need to change in my history. Examples go from bad commit messages over missing files to incorrect staging.
  • torek
    torek about 10 years
    @Oznerol256: pretty similar to my own work-flow. It might be nice if git kept a "published" flag on commits to make rebasing safer, a la Mercurial's "state". This could be done through a notes-style mechanism, perhaps.
  • functionpointer
    functionpointer about 10 years
    @torek Actually, git does that. Just use origin/<branch> for that. Of course, fetching will change the remote tracking branch, but if you look in the history you can easily spot the lastest pushed commit of you (just by looking at the author field of the fetched commits).
  • torek
    torek about 10 years
    That's not quite the same, but it could be a good safety catch. Mercurial has a three-valued "phase" for each commit: "secret", "draft", and "published". Pushes will "publish" "drafts" and avoid pushing "secret" versions. I mostly prefer git to hg for, well, everything, but this particular 3-phase thing, I think could be nice in git.