Can't cherry pick one commit to a branch (bad object error)
Asked Answered
R

3

5

OK, so our general git structure is that we have a master branch, one or more release branches and then feature branches. All the primary development happens in the feature branches but bug-fixes will sometimes get committed directly to the release branches.

While merging some features into a release branch, there was a bad merge but we didn't notice it until a couple bugfixes were committed afterwards. Some of the feature branches were deleted after merging (something we will alter our workflow to only do after an actual release has occurred in the future). If they hadn't been deleted, we would just scrap the release branch and redo it.

I'm now trying to eliminate this bad merge. I created a new release branch from the release branch prior to the merge.

git checkout <hash prior to merge>
git checkout -b new_release_branch
git merge feature_branch_which_resulted_in_bad_merge_before

This branch is now the way we want it but I still need to bring in the few (less than 5) commits that were made to release_branch after the bad merge. But I can't figure out how to do it. I thought that cherry-pick was the way to go but when I try I get:

$ git cherry-pick fa4a761
error: fa4a761: can't cherry-pick a blob
fatal: cherry-pick failed

$ git cherry-pick 44923992349dae68d982dd305a289ba63f8f6d0b
fatal: bad object 44923992349dae68d982dd305a289ba63f8f6d0b

Note that the above hash is copy/pasted out of gitk but it doesn't show up in any git log for any of my branches.

I also went back and checked and all of the commits I'm trying to fix right now and they are all the same. I'm not sure what that means or why they would show up in gitk but not in git log (where is gitk getting the information?).


OK, Update time. Here is the rest of the story that I left out. When I discovered the broken merge, I created a new clone of the repo to "play with" from our central repo.

Turns out all of the problem commits were never pushed from the original copy of the repo to the central repo. Once I pushed those commits, I was able to fix everything up just fine.

Rhenium answered 26/4, 2018 at 12:51 Comment(4)
You can only cherry-pick commits, not blobs. Where did you get that id from? Are you sure you typed in the id correctly, and didn't misplace a digit or something?Fateful
From git log. At least I think so. I'll have to verifyRhenium
Apparently I didn't get the hash from git log, I got it from gitk and it is indeed a blob. Unfortunately, the actual hash of the commit gives me a different error. Updating the OP now.Rhenium
Run git fsck to perform an integrity check of your repository.Fateful
R
1

Turns out that I'm just an idiot.

It isn't working because the un-pushed commits don't exist in the cloned repo.

I had made a clone repo from a central repository into another directory before starting to "fixup" the branch". The missing commits were actually never pushed to the central repo so of course the hashes don't exist in the cloned repo.

Rhenium answered 26/4, 2018 at 16:57 Comment(0)
E
10

you need to do git fetch to get the latest commits in sync with local

git fetch

then do

git cherry-pick

Eraser answered 27/6, 2019 at 17:6 Comment(0)
E
2

It seems git thinks fa4a761 is an abbreviated ID for a BLOB (content of a file) rather than for a COMMIT.

I'm assuming you got the commit ID in a reliable way, and that you didn't just mistype it.

It would be a staggering coincidence, but I wonder if the first 7 characters of your target commit's ID match the first 7 characters of a BLOB ID? (I would've guessed if this happened git would throw an error saying the abbreviation were ambiguous, but I'm not sure and don't have an easy way to test it...)

So you could try using, say, the first 10 digits of the commit ID instead. Or you could use an expression like old_release_branch~2 to identify the 3rd-to-last commit on the release branch, so as to not have to correctly copy commit ID values.

Another option that might suit your case, and would also avoid having to do so much dealing with commit ID in the first place, is to use rebase instead of cherry-pick. This is a good option if you want a range of commits that are not merges. For example, it sounds like you have a series of non-merge "bugfix" commits between the bad merge (which you've recreated) and the old branch tip.

git rebase --onto new_release_branch <bad_merge> old_release_branch

In this command <bad_merge> could be the ID of the old merge commit, or any expression that resolves to the merge commit. For example, if you had 3 bugfix commits after the merge, you could say old_release_branch~3.

As an aside, you mention that you'd do something different if the feature branches hand't been deleted. I'm not entirely sure I see what you'd do differently, because eventually you'd still need to pull the directly-committed bugfixes from the old release branch I think. But if it really makes a difference, you can always recreate the feature branches. When you delete a merged branch, nothing important is lost really.

For example, if you have

           ... x -- M -- x -- x <--(release)
                   /
   ... A -- B -- O

you see that something was merged into release 3 commits ago, but I guess the feature branch was deleted. You could probably retrieve its name from the merge commit message (assuming you keep the default message or replace it with something equally sensible), but if not you could still make up a name.

git checkout release~2^2
git branch replacement_feature_branch_name
Ennoble answered 26/4, 2018 at 13:19 Comment(2)
I thought git had code in place to ensure id's it reports in logs and so on are in fact unique, in the sense that it ups the number of digits to output if it detects that the id could refer to multiple objects. Perhaps I was wrong.Fateful
@LasseVågsætherKarlsen - I think it does. But that doesn't necessarily mean that kinar copied every digit that the command reported.Ennoble
R
1

Turns out that I'm just an idiot.

It isn't working because the un-pushed commits don't exist in the cloned repo.

I had made a clone repo from a central repository into another directory before starting to "fixup" the branch". The missing commits were actually never pushed to the central repo so of course the hashes don't exist in the cloned repo.

Rhenium answered 26/4, 2018 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.