6

I did the following:

git fetch upstream
git cherry-pick xyz

The picked commit had been applied cleanly except that in one of the files it had exactly the same changes I had already done in a previous commit so these changes were not reapplied.

Everything in terms of code is fine but I'd like to have the commit hash in my history. In my history it appears with a new name. Is this even possible? As far as I'm reading the git merge "ours" strategy it seems to be generally possible but how to do it for a single commit?

I want this so it is easier to identify later what commits does upstream has that I don't have. At the moment in github network view I see the cherry-picked commit as being something separate that I don't have.

Additional information: What @CharlesB says makes sense to me. But how does merge -s ours do the magic then? In this case it was not important for me to cherry-pick. Because the change I wanted to take is only one and at the tip of the upstream/master. So just to try it out I did: git merge -s ours upstream/master

Now doing git log --graph --pretty=oneline --abbrev-commit I see something like:

*   9e8108b Merge remote-tracking branch 'mgencur/master' for better github netw
|\  
| * aa7117d Fix displaying watchers/watching for incorrect user // this commit magically appeared after merge -s ours
* | ff05f8c Fix displaying watchers/watching for incorrect user // this is commit from cherry-pick of aa7117d
* | b7ca8ec older commit in my fork
* | <more commits in my fork>
|/  
* 94d6870 Fix obtaining available users for testing purposes
* <older commits of upstream/master>

The same command before git merge -s ours was looking like:

* ff05f8c Fix displaying watchers/watching for incorrect user // this is commit from cherry-pick of aa7117d
* b7ca8ec older commit in my fork
* <more commits in my fork>
* 94d6870 Fix obtaining available users for testing purposes
* <older commits of upstream/master>

As you can see after cherry-picking of commit aa7117d, there was no indication that aa7117d is already applied to my fork repo. But after a merge it is indicated it is in there although nothing in my files changed.

That makes me think that it is indeed possible to declare a number of commits included in a branch although they are not applied exactly as they were applied upstream.

update2: I see question How to merge a specific commit in Git and its best answer. So an explanation why it is not possible or it is not implemented would also be appreciated.

Community
  • 1
  • 1
akostadinov
  • 15,093
  • 5
  • 64
  • 79
  • You seem to be confused over what a cherry-pick and a merge is. The former applies the specified commit to your current branch. It's like a short-cut for exporting a patch-file and then applying it. Nothing more. The latter also creates a new commit, but that one has **two parent commits**. So no commit gets *patched* on top of another branch, it's more like bringing to development strands together into one. That's why you see the original hash strings in the history, but that is only because they really are still there, unmodified from their original state. – Michael Wild Mar 05 '13 at 15:09
  • @Michael-Wild, yeah,I'd like some sort of merge/cherry-pick combination. – akostadinov Mar 05 '13 at 15:26
  • 1
    that won't ever work. It's just not how Git works. The hashes uniquely identify a commit, and if you change it's parent commit, the hash must change. That's why commit hashes are said to be *cryptographically secure* in Git. If you can verify the hash of the the branch head, you have effectively verified its whole history. Any operation that modifies that history, will change the hashes. Period. – Michael Wild Mar 05 '13 at 15:35
  • @Michael-Wild, thanks, with your comment I think I all pieces come to their places. If you care to write an answer, I'll give you the credit. – akostadinov Mar 05 '13 at 16:05

2 Answers2

4

Commit hashes are unique to each commit, by definition.

When cherry-picking, you're creating a new commit, even if you apply the same modifications, because it has a different parent commit.

However you can add ask git to put a message in the cherry-picked commit message :

cherry-picked from commit <original-sha1>

From the documentation:

-x

When recording the commit, append a line that says "(cherry picked from commit ...)" to the original commit message in order to indicate which commit this change was cherry-picked from. This is done only for cherry picks without conflicts. Do not use this option if you are cherry-picking from your private branch because the information is useless to the recipient. If on the other hand you are cherry-picking between two publicly visible branches (e.g. backporting a fix to a maintenance branch for an older release from a development branch), adding this information can be useful.

CharlesB
  • 75,315
  • 26
  • 174
  • 199
  • Please see "Additional information" in my question. It seems to me possible to declare certain commits as applied to current branch although they are not really the same. Perhaps not the cherry-pick command? – akostadinov Mar 05 '13 at 14:46
  • I can't understand what you mean by "declare commits to be applied to current branch". Do you mean that you want to select commits you want to include/exclude at merge operation? – CharlesB Mar 05 '13 at 15:05
  • See the `ours` merge strategy explanation. I want them to appear as been applied like a merge operation does. I guess that can be achieved by some branching and merging operation. But it would have been cool if `cherry-pick` command did it automagically. – akostadinov Mar 05 '13 at 15:16
3

Git doesn't allow you to do that. Git hashes uniquely identify a commit and all of its history. That means, that when you cherry-pick a commit you apply a patch to another history, and hence there is no way (except in some freak occasion where the hashes collide) that the hashes will be the same.

The reason that you still see the original hash numbers when you perform a merge is that here the situation is quite different. A merge is not a normal commit with a single parent commit. Instead it has two (or even more) parent commits, bringing together separate development strands. Thus the original history of the merged heads is preserved.

Michael Wild
  • 21,851
  • 3
  • 36
  • 40