Stashing only staged changes in git - is it possible?

我的未来我决定 提交于 2020-01-10 06:13:31

问题


Is there a way I can stash just my staged changes? The scenario I'm having issues with is when I've worked on several bugs at a given time, and have several unstaged changes. I'd like to be able to stage these files individually, create my .patch files, and stash them away until the code is approved. This way, when it's approved I can stash my entire (current) session, pop that bug and push the code.

Am I going about this the wrong way? Am I misunderstanding how git can work in other ways to simplify my process?


回答1:


Yes, It's possible with DOUBLE STASH

  1. Stage all your files that you need to stash.
  2. Run git stash --keep-index. This command will create a stash with ALL of your changes (staged and unstaged), but will leave the staged changes in your working directory (still in state staged).
  3. Run git stash push -m "good stash"
  4. Now your "good stash" has ONLY staged files.

Now if you need unstaged files before stash, simply apply first stash (the one created with --keep-index) and now you can remove files you stashed to "good stash".

Enjoy




回答2:


With latest git you may use --patch option

git stash push --patch

And git will ask you for each change in your files to add or not into stash. You just answer y or n




回答3:


I made a script that stashes only what is currently staged and leaves everything else. This is awesome when I start making too many unrelated changes. Simply stage what isn't related to the desired commit and stash just that.

(Thanks to Bartłomiej for the starting point)

#!/bin/bash

#Stash everything temporarily.  Keep staged files, discard everything else after stashing.
git stash --keep-index

#Stash everything that remains (only the staged files should remain)  This is the stash we want to keep, so give it a name.
git stash save "$1"

#Apply the original stash to get us back to where we started.
git stash apply stash@{1}

#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R

#Delete the temporary stash
git stash drop stash@{1}



回答4:


In this scenario, I prefer to create new branches for each issue. I use a prefix temp/ so I know that I can delete these branches later.

git checkout -b temp/bug1

Stage the files that fix bug1 and commit them.

git checkout -b temp/bug2

You can then cherry pick the commits from the respective branches as require and submit a pull request.




回答5:


Why don't you commit the change for a certain bug and create a patch from that commit and its predecessor?

# hackhackhack, fix two unrelated bugs
git add -p                   # add hunks of first bug
git commit -m 'fix bug #123' # create commit #1
git add -p                   # add hunks of second bug
git commit -m 'fix bug #321' # create commit #2

Then, to create the appropriate patches, use git format-patch:

git format-patch HEAD^^

This will create two files: 0001-fix-bug-123.patch and 0002-fix-bug-321.patch

Or you can create separate branches for each bug, so you can merge or rebase bug fixes individually, or even delete them, if they don't work out.




回答6:


To accomplish the same thing...

  1. Stage just the files you want to work on.
  2. git commit -m 'temp'
  3. git add .
  4. git stash
  5. git reset HEAD~1

Boom. The files you don't want are stashed. The files you want are all ready for you.




回答7:


Is it absolutely necessary to work on several bugs at once? And by "at once," I mean "having files edited for multiple bugs at the same time." Because unless you absolutely need that, I'd only work on one bug at a time in your environment. That way you can use local branches & rebase, which I find far easier than managing a complex stash/stage.

Let's say master is at commit B. Now work on bug #1.

git checkout -b bug1

Now you're on branch bug1. Make some changes, commit, wait for code review. This is local, so you're not affecting anyone else, and it should be easy enough to make a patch from git diffs.

A-B < master
   \
    C < bug1

Now you're working on bug2. Go back to master with git checkout master. Make a new branch, git checkout -b bug2. Make changes, commit, wait for code review.

    D < bug2
   /
A-B < master
   \
    C < bug1

Let's pretend that someone else commits E & F on master while you're waiting on review.

    D < bug2
   /
A-B-E-F < master
   \
    C < bug1

When your code has been approved, you can rebase it on to master with the following steps:

git checkout bug1
git rebase master
git checkout master
git merge bug1

This will result in the following:

    D < bug2
   /
A-B-E-F-C' < master, bug1

Then you can push, delete your local bug1 branch, and off you go. One bug at a time in your workspace, but with using local branches your repository can handle multiple bugs. And this avoids a complicated stage/stash dance.

Answer to ctote's question in the comments:

Well, you can go back to stashing for each bug, and only work with one bug at a time. Atleast that saves you the staging issue. But having tried this, I personally find it troublesome. Stashes are a bit messy in a git log graph. And more importantly, if you screw something up you can't revert. If you have a dirty working directory and you pop a stash, you can't "undo" that pop. It's much harder to screw up already existing commits.

So git rebase -i.

When you rebase one branch onto another, you can do it interactively (the -i flag). When you do this, you have the option to pick what you want to do with each commit. Pro Git is an awesome book which is also online in HTML format, and has a nice section on rebasing & squashing:

http://git-scm.com/book/ch6-4.html

I'll steal their example verbatim for convenience. Pretend you have the following commit history, and you want to rebase & squash bug1 onto master:

    F < bug2
   /
A-B-G-H < master
   \
    C-D-E < bug1

Here's what you will see when you type git rebase -i master bug1

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

To squash all commits of a branch down into a single commit, keep the first commit as "pick" and replace all subsequent "pick" entries with "squash" or simply "s". You will get the opportunity to change the commit message, too.

pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

So yeah, squashing is a bit of a pain, but I would still recommend it over heavy use of stashes.




回答8:


git stash --keep-index is a good solution... except it did not work correctly on paths that have been removed, which has been fixed in Git 2.23 (Q3 2019)

See commit b932f6a (16 Jul 2019) by Thomas Gummerer (tgummerer).
(Merged by Junio C Hamano -- gitster -- in commit f8aee85, 25 Jul 2019)

stash: fix handling removed files with --keep-index

git stash push --keep-index is supposed to keep all changes that have been added to the index, both in the index and on disk.

Currently this doesn't behave correctly when a file is removed from the index.
Instead of keeping it deleted on disk, **--keep-index currently restores the file.**

Fix that behaviour by using 'git checkout' in no-overlay mode which can faithfully restore the index and working tree.
This also simplifies the code.

Note that this will overwrite untracked files if the untracked file has the same name as a file that has been deleted in the index.




回答9:


Out of your comments to Mike Monkiewicz answer I suggest to use a simpler model: Use regular development branches, but use the squash option of the merge to get a single commit in your master branch:

git checkout -b bug1    # create the development branch
* hack hack hack *      # do some work
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
git checkout master     # go back to the master branch
git merge --squash bug1 # merge the work back
git commit              # commit the merge (don't forget
                        #    to change the default commit message)
git branch -D bug1      # remove the development branch

The advantage of this procedure is that you can use the normal git work flow.




回答10:


To prune an accidental change, especially the deletion of multiple files, do the following:

git add <stuff to keep> && git stash --keep-index && git stash drop

in other words, stash the crap and throw it away with the stash altogether.

Tested in git version 2.17.1



来源:https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!