On Thu, Apr 7, 2011 at 9:53 PM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
On Thu, 7 Apr 2011, Dave Martin wrote:
The problem seems to be that when a merge is committed, git references the merged commits in their original context: no information is recorded about how the merge was resolved. The result just appears by magic as the new tree recorded for the merge commit.
you may have a look at the output from "git show <merge_commit_ID>" which would show you a combined diff (Git invention) where you can see the actual merge resolution if there was a conflict.
Hmmm, sounds interesting ... I haven't tried that.
This seems to mean that git format-patch x..y (where x is an ancestor of y) does _not_ necessarily give you a patch series which actually applies on x (indeed, the generated patch series may not be appliable on any commit, in any order). This is certainly my experience.
Indeed. That works well only for a linear set of commits.
As a result, it seems very difficult to pick apart the history of a branch beyond the last merge commit, because the git repo only records the logical ancestry (i.e., which upstream patches got merged) rather than any "physical" history (i.e., what sequence of actual changes would be needed to reconstruct the branch). In fact, it seems to be nonsense to think in terms of a sequence of patches beyond a merge commit.
Well, because a Git history is two-dimentional, you cannot always recreate it only with a linear sequence of changes
I was coming around to that point of view -- it's nice to have my understanding confirmed :)
What I'm actually trying to do is cherry-pick a few omap- and Thumb- specific commits out of the linaro tree to apply on v2.6.39-rc2 -- just the minimum subset so that I can develop Thumb stuff on a tree which is as clean and close to upstream as possible. But I repeatedly run into problems where patch p from branch b depends on cherry-picking some other patch q merged branch b, but the cherry pick fails since the actual delta recorded for q is in the context of someone else's branch (the branch that was merged from).
If anyone knows a straightforward way to achieve this, I'd be interested ...
What I'd do is (assuming there is already a separate branch with v2.6.39-rc2 available):
- Find the latest commit ID you are interested in, and create a
temporary branch with it:
git branch tmp_branch <commit_ID> git checkout tmp_branch
or if you prefer a shortcut:
git checkout -b tmp_branch <commit_ID>
- Find the oldest commit you are interested in, and use it with
interactive rebase:
git rebase -i --onto v2.6.39-rc2 <old_commit_ID>^
Note the ^ here meaning the parent of the commit. Here you should specify the starting point which is always exclusive, hence with ^ you make it inclusive.
I'll try that -- I've not used interactive rebase much, though I guess it can be smarter than just applying patches since git knows about the ancestry.
- In the editor that pops up, discard all the lines corresponding to
those commits you are not interested in bringing forward. If you don't know if a wanted commit is already present in v2.6.39-rc2 then just keep it in the list -- in most cases Git is able to figure it out automatically. Then save the file and watch Git go.
- If patch application problems occur, you then have the option of
manually fixing it, or using 'git mergetool' to help you out. When done just go on with 'git rebase --continue'. Or you may skip a problematic patch with 'git rebase --skip'.
- Rename your tmp_branch into something more meaningful, or simply
discard it if you're not satisfied with the result.
That's it. Of course, if you're looking for only a few commits then it is probably quicker to go with 'git cherry-pick' on each of them instead.
Indeed -- that's worked for me for simpler cases in the past; that's one reason why my understanding of the actual problem here was a bit patchy.
Thanks for the advice ---Dave