Often I'm in the following situation: I'm in the middle of a complicated maneuver and I want to try out two or more ways of proceeding from here. So I might add-and-commit and now I can try out my various strategies from this point, on one or more branches.
But here's the problem: I don't want to lose track of what I've changed so far on this branch with respect to HEAD
. Why? Well, in the IDE where I'm coding, there are really helpful "change bars" in the margin of the code editor that mark all the staged and unstaged changes. I don't want to lose those change bars. And what they are responding to, in effect, is the diff
between the working tree and HEAD
.
So you see, I'd like to save all my work so as to have a stable point to return to later, if needed, but I don't want this to affect the state of HEAD
, the index, and the working tree. I want, in effect, to make a commit that is "just a copy", without altering anything else about the universe.
Here's a diagram. I've got this:
A -- B -- C -- (mybranch) [and I've edited files X, Y, and Z with respect to C]
I want this:
D? something that preserves the state of files X, Y, and Z
/
A -- B -- C -- (mybranch) [and X, Y, and Z are still _modified_ with respect to C]
Basically what I'm trying to do is copy the state of things into a commit, without effectively checking out that commit. Is there a command that does this?
What I've found so far is this sort of thing:
git switch -c temp
git commit -m 'hold my place just in case'
git switch -
git restore --source temp --worktree --staged -- .
But I don't honestly like it; it feels risky, somehow. What I'd prefer, I think, is some form of git stash push
that doesn't alter the state of the index and working tree.
CodePudding user response:
git commit
keeps the current index and working tree, the only other thing it does is update HEAD to point at the new commit.
git stash -k
makes a couple of new commits from your current index and work tree, but you don't need the interim-work-tree snapshot, skip it by either doing an ordinary commit and re-hanging the HEAD
label,
git commit
git tag snap
git reset --soft @^
or just do it directly,
git tag snap $(git commit-tree -p @ -m snap `git write-tree`)
and then you can cherry-pick and discard the snapshot whenever you want.
CodePudding user response:
git stash
actually has subcommands that allow to "stash without clearing the changes" :
git stash create # creates the same commits as 'git stash push",
# but don't store them
git stash store <sha> # adds commit <sha> in the stash list
You can create an alias :
git config --global alias.snap '! git stash store $(git stash create)'
Check git help stash
for more details (for example: you can add git stash store -m "..."
to add a custom message ...)
The upside with respect to git commit-tree $(git write-tree)
is : git stash create
also saves the unstaged content on modified files.
Also note that git stash store
basically does git update-ref refs/stash
with a few standardized options, and that the list of stashes is just the reflog for refs/stash
.
If you want to store these kind of snapshots under another name, you can use :
git update-ref -m "spapshot while working on '$commitmsg'" --create-reflog \
refs/snap $(git stash create)
and inspect git reflog snap
to have a list of your "snaps".
CodePudding user response:
Indeed, it appears that there is such a form of git stash push
— namely, --keep-index
(or -k
). I was able to achieve what I was looking for by saying
git stash push -k -m 'hold my place while working on the progress bar'
So now I can just go right on working, and if I need to return to the current state of things, I can presumably reset hard and apply that stash.
(It was difficult to discover this because the effect of --keep-index
is described in rather a murky way in the docs, so it took me a while, and a great deal of preparation, to work up the nerve to try it.)
CodePudding user response:
You could also execute the plumbing commands git write-tree
and git commit-tree
directly:
git branch rememberme $(git commit-tree $(git write-tree) -p HEAD)
Can be easily wrapped in an alias to make the branch name a user input or use push
instead to create a history of intermediate steps.