Git merge/cherry-pick avoiding staging
Asked Answered
A

3

20

I am trying to make a cherry-pick with some changes, but I do not want to commit them in this branch, I just want to have them locally.

For this purpose, I am using

git cherry-pick <hash> --no-commit

However, this adds them automatically to the stage, and then, I have to manually reset them using

git reset HEAD <files>

Is there no option with git to make cherry pick not commit, and not add to index?

something like:

git cherry-pick <hash> --no-commit --no-stage

I know this trick would do what I want, but I would have to specify all the files in the commit:

Edit

Tried also this, but it is also added to the index.

git checkout hash -- <list of files>

And this files, might not share the same common path. I am trying to automate it

Angloamerican answered 24/4, 2018 at 7:35 Comment(2)
How about letting git make the cherry-pick commit and then resetting that one git reset HEAD~?Amaurosis
"I am trying to make a cherry-pick with some changes, but I do not want to commit them in this branch, I just want to have them locally... I am trying to automate it." This is something that should happen very rarely. Wanting pieces of other branches often enough that unstaging is a hassle indicates something is wrong with the process. I believe this is an XY Problem. I suspect they're trying to use Git as a configuration manager.Stavanger
N
9

An alternative would be to use apply instead of cherry-pick:

git show <commit> | git apply

This will apply the changes made in <commit> but will not add them to staging or create a commit.

Nuts answered 13/4, 2021 at 19:32 Comment(1)
Works like a charm, however, there seems a small bug in Git itself. <stdin>:74: trailing whitespace. I opened the commit in editor, and there was extra space after +Borghese
C
6

Cherry-pick is, behind the scenes, a merge operation. Git performs merges in the index—so no, there is no way to do this other than using the index / staging-area. (But see below.)

If you don't want to commit the result in the current branch, just use some other branch (git checkout -b <newbranch>) or a detached HEAD (no branch at all: git checkout --detach HEAD). You can also use a mixed reset, as lucas-reineke suggested in a comment, to make the commit in the current branch and then move the current branch back one commit. This has the side effect of resetting the index to match the adjusted (post-cherry-pick) HEAD, leaving you with the state you originally asked for.

You can use git cherry-pick -n HEAD followed by git reset --mixed HEAD (with no path names listed) to get the same result: the cherry-pick takes place in the index, updating the work-tree as a side effect, without committing, and then the reset copies the files from the HEAD commit back into the index, leaving the work-tree undisturbed. Note that --mixed is the default, so git reset without --soft or --hard does --mixed even if you don't include an explicit --mixed (it's useful to make sure you did not make any typos in the command, though).

These are the two ways you would normally do this. There is one more possibility, though: while Git has the index—the one distinguished index that goes with the primary work-tree for the repository—you can redirect Git to your own alternative index, using the GIT_INDEX_FILE variable. You could set this to the name of a temporary file that does not yet exist, run git reset to create that temporary index file and fill it in, then run git cherry-pick -n <commit> to update the temporary index. You can then unset GIT_INDEX_FILE and remove the temporary file. The result is a cherry-pick that uses your temporary index, instead of the normal index, that alters the work-tree files as a side effect. Note that this is the same amount of work as doing the cherry-pick in the normal index and then resetting the normal index. It may be useful for some sort of scripted work-flow, however. Beware of cherry-picks that fail and therefore leave merge conflicts in the index!

Cleric answered 24/4, 2018 at 9:27 Comment(3)
Wouldn't git reset --mixed HEAD also remove from my index files that I had staged previously? since I am not specifying pathAngloamerican
Yes: the --mixed reset (without pathspec) will set your index back to the commit from which you are resetting. Remember, the index / staging-area contains all the files that are in the commit; git add copies a replacement into the index when (a different version of) the file was already in the index. Note also that a plain (non--n) cherry-pick requires that the index be "clean", i.e., match the current commit, when you start.Cleric
@scaly: given that the answer literally is "you can't do it" (because the merge happens in the index), it doesn't really matter whether you like the answer or not. You can get close, but you can't do it without creating a temporary index or using the main index.Cleric
B
2

I was able to achieve this by

  1. Cherry-pick the commit into your branch
  2. git reset --soft
Boilermaker answered 11/6, 2021 at 14:6 Comment(1)
It will unstage all staged commits that were staged before CPBorghese

© 2022 - 2024 — McMap. All rights reserved.