1

I read from https://github.com/blog/2019-how-to-undo-almost-anything-with-git this :

If you want to restore the project's history as it was at that moment in time use git reset --hard If you want to replay exactly one of those commits into your repository use git cherry-pick .

I am a beginner and have not gone into branching yet. To me , the usage of cherry-pick here seems identical to of git reset. I want to know what actually git cherry-pick does different from git reset , given I am working in one branch only.

Chirag
  • 618
  • 6
  • 21

2 Answers2

2

Cherry-picking is done to merge a particular (and even a sequence of) commit, which belongs to another branch, to currently checked-out branch.

git checkout foo
#you are in branch foo. you make some EDITS on this branch.
git commit -am "my changes to foo branch"
git push 
#The commit, say sha1, is pushed to foo branch.

### several other commits are pushed randomly by different users to this branch ###

Lets say, another user wants to take this commit, sha1, from the branch foo to branch bar of same repository. Note that in this case, branch foo could be ahead of several commits by sha1 commit state.

foo : ORIG_HEAD -- sha1 -- sha2 -- sha3 -- .... shaN
                    ^~~~user want to cherry-pick 
                        only this commit

To cherry-pick commit sha1 to branch bar:

git checkout bar
git cherry-pick sha1 
# The commit `sha1` is merged to your branch `bar` and is ahead by 1 commit

Git reset is mostly used to undo the local commits or failed git pull/merge. It is also used to clear the mess from the dirtly working tree.

For example:

$ git pull    
  Automatic merge failed; fix conflicts and then commit the result.
$ git reset --hard   # clears the mess from the index file and the working tree.

So, both cherry-picking and git-resetting affect the HEAD position, but they are very different in terms of their use-cases.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
1

The git reset --hard means git reset --hard HEAD where HEAD is a ref (reference) to the currently checked out commit or the last commit in your current branch, i.e. don't change the branch but get rid of all local changes so it will remove all the staged and unstaged changes. The git reset command provides a lot of options which is explained here very well:

Can you explain what "git reset" does in plain english?

Whereas Cherry picking means to choose a commit from one branch and apply it onto another. It can be done if you eg. made a mistake and committed a change into wrong branch, but do not want to merge the whole branch. You can just eg. revert the commit and cherry-pick it on another branch.

If in case you push to a wrong branch or you have issues with your branch which is showing a lot of commits from other users (when multiple users are working) due to old git history on your system you can delete the current branch keeping your commit hashes safe and then cherry-pick the commits to a new branch which will be updated from master. (This case happens sometimes and cherry-pick is an option when rebase or merge is not solving the issue)

The quote taken from this answer:

Source: https://stackoverflow.com/a/30218784/4207394

Using git cherry-pick The command git cherry-pick commit applies the changes introduced by the named commit on the current branch. It will introduce a new, distinct commit. Strictly speaking, using git cherry-pick doesn’t alter the existing history within a repository; instead, it adds to the history. As with other Git operations that introduce changes via the process of applying a diff, you may need to resolve conflicts to fully apply the changes from the given commit . The command git cherry-pick is typically used to introduce particular commits from one branch within a repository onto a different branch. A common use is to forward- or back-port commits from a maintenance branch to a development branch.

So whenever you want to reset a commit or your changes you can use git reset and event if you want to reset the commit and keep the changes safe of that commit you can use git reset with --soft option. And if you want to copy a commit from some other branch to some other then you can use git cherry-pick. The git reset has many options available for example:

To reset to the current HEAD:

git reset --hard HEAD

To reset one commit down and removing the changes:

git reset --hard HEAD~1

this 1 can be n to remove any number of commits. And also to preserve the changes of the commits you can use --soft instead of --hard.

For cherry-pick the syntax is:

git cherry-pick <commit-hash>
Community
  • 1
  • 1
Deepesh
  • 6,138
  • 1
  • 24
  • 41
  • "So I delete the current branch keeping my commit hashes safe and then cherry-pick the commits to my new branch." Does rebasing master into your feature branch would be useful here? (I mean `git rebase master` when you're on the feature branch). – Oleg Arkhipov Jan 12 '17 at 08:15
  • @Construct Yes it can be useful but it get difficult when 6-7 developers are working and you are completely rebuilding the site of many new feature has been added that time the `rebase` will cause a lot of conflicts. – Deepesh Jan 12 '17 at 08:17
  • Wouldn't all of these conflicts appear if you cherry-pick too? You still have to somehow solve conflicts between your code and changes in diverged master, if they are present. – Oleg Arkhipov Jan 12 '17 at 08:19
  • 1
    @Construct I have updated my statement because I understood your concern and I was not clear in explaining that issue. This problem comes when you have an older git history and you have not updated it from a long time. Then sometimes in your feature branch it starts showing the commits of other users but no extra changes in the files. In this case you can do this. – Deepesh Jan 12 '17 at 08:23
  • 1
    @Construct: yes, they will. In fact `git rebase` is merely an automated series of cherry-pick operations, followed at the end by moving the rebased branch to point to the last such cherry-picked commit. – torek Jan 12 '17 at 08:24
  • Thank you both for explanation. @Deep, I have just never met such situation. – Oleg Arkhipov Jan 12 '17 at 08:31
  • @torek So there would be a difference in rebasing and cherry pick right? The cherry pick you will do will be upon your commits and rebase will play your commit upon the master branch commits? – Deepesh Jan 12 '17 at 08:35
  • 1
    @Deep: `git cherry-pick` means "copy one commit". You pick the commit, it gets added as a new commit wherever you are now. (You can copy more than one but the default is just one.) On the other hand, `git rebase` means: "copy *as many commits* as are appropriate, *from* the current branch, where I am now, *to* where I tell you to move to; and then move my current branch to the *last* copied commit." The last step—moving the branch—effectively *drops* the original (now-copied) commits from that branch. (Which is good, because they're *copied*.) So these are *very* different. – torek Jan 12 '17 at 08:46
  • 1
    @Deep: the "copy as many commits as needed" part literally *uses* cherry-pick, if you use `git rebase -i` (it may use an alternative mechanism for a non-interactive rebase). That's why you get an editor with a bunch of "pick" commands: those are the commits to be cherry-picked. However, the "drop" step is new—and the main point of all the copying is so that the new *copies* occur at a different point in the commit graph. You might want to look at, e.g., http://stackoverflow.com/q/39154794/1256452 here. – torek Jan 12 '17 at 08:51
  • @torek Thanks for the explanation, I know the difference between `cherry-pick` and `rebase` but as you mentioned the `rebase` uses `cherry-pick` internally so was just clarifying that both will be different. Suppose take a case that there only one commit in the branch you want to rebase so you can `cherry-pick` or `rebase` so both will be different in this case (the difference would be in rare case when the git automerge merges the files). Hope I am clear what I am trying to say. – Deepesh Jan 12 '17 at 08:54
  • 1
    Well, this gets deep into the weeds, because as I mentioned, rebase *may* actually run `git cherry-pick`, or it may run `git format-patch ... | git am ...`. Both will try to do the same thing in cases that require merging, but the cherry-pick form is more suitable in the case of renames. This is why modern `git rebase` has the `-m` flag argument, to force it to use `git cherry-pick` rather than `git format-patch`. But in general, yes: if there's just one commit to copy, you can do that with three Git commands `git checkout; git cherry-pick; git branch -f` instead of 1 `git rebase`. – torek Jan 12 '17 at 09:02
  • @torek Okay thanks for the explanation. Frankly speaking I don't know what `git rebase` does internally but will have a read of that and the link of your answer you have provided above. There are some issues which can't be exactly explained or reproduced as it completely depends on your usage of `git` and `git` being so vast it is hard to know each and every thing. But comments like this and users like you are helping me learning those things. :-) – Deepesh Jan 12 '17 at 09:16