Home > Software engineering >  Git commit but keep current index and working tree?
Git commit but keep current index and working tree?

Time:05-30

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.

  •  Tags:  
  • git
  • Related