I have a repository in which two revisions (14321 and 14319) share a parent (14318) - both changesets are direct children of 14318. Nevertheless, the revision set query ancestor(14321, 14319) does not return 14318, but instead returns a much older changeset. What's happening?
Screenshot in TortoiseHg:
Background: I encountered odd merge conflicts recently that turned out to be caused by mercurial trying to re-apply changes that had already been merged. I was able to track it down to an odd choice of merge base which caused both heads to include the same changes - but I don't understand why this happened and how I can prevent it in the future (I chose a DVCS partly to avoid these kinds of problems in the first place...)
The picture shows there are not one but two common ancestors. So, it looks like a criss-cross merge case where merge problems arise from chosing one or another common ancestor.
References:
https://bz.mercurial-scm.org/show_bug.cgi?id=1327#c18
http://www.gelato.unsw.edu.au/archives/git/0504/2279.html
http://wiki.vestasys.org/MergingFuture/Food4Thought/TrickyCases
http://revctrl.org/CrissCrossMerge?action=recall&rev=11
There is a proposal for a new merge algorithm (https://www.mercurial-scm.org/wiki/ConsensusMerge). However, since Mercurial's 2.3 sprint this topic is stuck.
To reduce this kind of problem, I suggest you to estabilish a client-server topology, so that developers only merge with the official repository. Maybe rebase could help also.
A criss-cross merge is something like this:
B --- D
/ \ / \
/ \ / \
A X F
\ / \ /
\ / \ /
C --- E
In your case, it was:
B
-----------o---- } stable/production
C \ \ F
------o------o---\------o } default
\ D \ /
-----------o--- } feature
E
A = ?
B = 14318
C = 14294
D = 14319
E = 14321
F = ?
To produce F, there are two possible circuits: B-D-E-F and C-D-E-F. Mercurial has chosen the latter.
You could have avoided the criss-cross if you haven't merged production and feature branches.
The hotfix could have been propagated to the feature branch via the default branch. The log would be:
B
-----------o } stable/production
C \ F
------o------o------o } default
\ D \ /
-------o--- } feature
E
For incorrect base detection in case of common ancestor of mergesets one weak point is known:
it can be wrong if any of mergesets contains unrelated to merge edit
I guess, that the ancestor is 14294. Since both of your new commits are merges, you now have more than one ancestor, which makes the choice ambiguous.
Unfortunately, there is no way to tell mercurial which of the potential ancestors to use.
Related
I have recently encountered the need to generate a Mercurial diff of all changes up to a particular changeset which includes the first changeset of the repo. I realize this kind of stretches the definition of a diff, but this is for uploading a new project to a code review tool.
Let's assume the following changesets:
p83jdps99shjhwop8 - second feature 12:00 PM
hs7783909dnns9097 - first feature - 11:00 AM
a299sdnnas78s9923 - original app setup - 10:00 AM
If I need a "diff" of all changes that have been committed, the only way that I can seem to achieve this is with the following diff command...
diff -r 00:p83jdps99shjhwop8
In this case the first changeset in the argument param (here - 00) takes the regexp form of 0[0]+
This seems to be exactly what we need based on a few tests, but I have had trouble tracking down documentation on this scenario (maybe I just can't devise the right Google query). As a result, I am unsure if this will work universally, or if it happens to be specific to my setup or the repos I have tested by chance.
Is there a suggested way to achieve what I am trying to accomplish? If not, is what I described above documented anywhere?
It appears this actually is documented, but you need to do some digging...
https://www.mercurial-scm.org/wiki/ChangeSetID
https://www.mercurial-scm.org/wiki/Nodeid
So the special nodeid you're referring to is the 'nullid'.
2 digits may not be adequate to identify the nullid as such (as it may be ambiguous if other hashes start with 2 zeros), so you may be better off specifying 4 0's or more.
Eg: hg diff -r 00:<hash of initial add changeset> has resulted in the abort: 00changelog.i#00: ambiguous identifier! error.
I'm a little confused about what you need. The diff between an empty repository and the revision tip is just the content of every file at tip-- in other words, it's the state of your project at tip. In diff format, that'll consist exclusively of + lines.
Anyway, if you want a way to refer to the initial state of the repository, the documented notation for it is null (see hg help revisions). So, to get a diff between the initial (empty) state and the state of your repository at tip, you'd just say
hg diff -r null -r tip
But hg diff gives you a diff between two points in your revision graph. So this will only give you the ancestors of tip: If there are branches (named or unnamed) that have not been merged to an ancestor of tip, you will not see them.
3--6
/
0--1--2--5--7 (tip)
\ /
4
In the above example, the range from null to 7 does not include revisions 3 and 6.
Given
---a----b----c----d----e----f (default)
| | |
---g (1.0) ----h---i---(2.0)
I want to know, for a specific changeset, which named branches (releases in my case) that this changeset is part of (a parent of the head of the named branch).
input -> output
a -> default, 1.0, 2.0
g -> default, 1.0, 2.0
d -> default, 2.0
e -> default
h -> 2.0
How can I do this the easiest way (something with hg log ancestors I guess?)? I would prefer not taking the branch names as input but dynamically using all (open) named branches.
For others having the same question as myself...
I found the extension contains, https://bitbucket.org/resi/hg-contains, which does exactly what I want.
hg headscontaining -b --revno [changesetId] --template {branches}
[revsetalias]
bd($1) = descendants($1) - branch(default)
In use: hg bd(CSET-ID)
Edit: Well, my initial version was better than needed (and not usable) - it returned list of branches immediately, which may be hardly used as revset in final Mercurial commands.
With single operation result is revset for using in templated log
hg log -r "bd(CSET)" --template "{branch}\n"
I have two named branches, SPRINT_009 and SPRINT_010. Some changesets have been committed to SPRINT_009 that I would like to merge into SPRINT_010. I was able to merge the changesets from branch_one back into default without any trouble. I am having problems merging the changesets from branch_one into branch_two.
default A -- B -- C -- G -- H -- I -- J -- K -- L -- N -- O -- P
\ \ /
SPRINT_009 D -- E -- F ----------------- ---------- ----------
\
SPRINT_010 M
Here are the commands I am using:
hg update branch_two
hg merge branch_one
However I get the following message:
abort: merging with a working directory ancestor has no effect
Does anyone know what exactly I am doing wrong?
**EDIT: I've added a picture of the graph. The drawing is conceptual **
The problem was that I hadn't performed an hg pull before attempting the merge. Normally we do our development on a Windows machine using TortoiseHg. We modified the name of one of our resources on the support branch, from fooBAR to fooBar and ran into the mercurial case folding problem. We were trying to get around this by merging the branches on a Linux box. I am so used to using TortoiseHg that I forgot the most basic of commands!
I have a few odd issues with a svn repository I'm trying to convert to hg. Our repository looks more or less like this.
proj_root ___ trunk
\ \___ tags
\_____ branches __A
\ \__B
\_____Q __ C
\___ D
Ideally I could specify --config convert.svn.branches=branches;branches/Q or somesuch nonesense. (Q does not contain a branch in itself, just the two "sub branches".
I just finished converting a repository in which Q only had one subdirectory, and the solution there was easy. rename C/ . in a --filemap option, but that fails rather dramatically for this case (the Q branch interleaves C and D).
Ideally, I could simply ignore Q entirely in one pass, and then do a second conversion with the convert.svn.branches option set to branches/Q, but I cannot get the following syntax in the filemap to work:
exclude "Q C D"
nor
exclude "C D"
My hope was that excluding C and D would prevent any files from being imported on that branch, and since I have a specified filemap, the resulting empty commits would be removed. I can't get the exclude directive to exclude any directories, no matter the various syntax options I've tried.
Edit: The end result I'd like to have is a mercurial repo with trunk as the normal tip, and named branches A, B, C and D... that silly Q thing can just go away during the conversion, if I can figure out how.
For some reason when I tried this yesterday, it wasn't working, but today it works...
a filemap of
exclude "C"
exclude "D"
seems to be working properly now... I'm having an odd issue with the first conversion I'm doing crashing, but that's an issue to take up with the devs (unrelated)
In Mercurial/TortoiseHg, given the following example, what is the easiest way to merge revision "G" into repo A without taking D,E and F (Assume that G has no dependency on D,E or F).
Repo A: A - B - C
Repo B (Clone of A) A - B - C - D - E - F - G
Is a patch the best bet?
Tonfa is right. What you're describing isn't 'merging' (or 'pushing' or 'pulling'); it's 'cherry-picking'. A push or a pull moves all the changesets from one repo to another that aren't already in that repo. A 'merge' takes two 'heads' and merges them down to a new changeset that's the combination of both.
If you really need to move G over but can't possibly abide having D,E,F there you should 'hg export' G from repo A, and then 'hg import' it in repo A. The Transplant extension is a wrapper around export/import with some niceties to help avoid moving the same changeset over multiple times.
However, the drawback to using import/export, transplant, and cherry-picking in general is that you can't really move over G without its ancestors, because in Mercurial a changeset's name is its 'hashid' which includes the hashids of its parents. Different parents (G's new parent would be C and not F) means a different hashid, so it's not G anymore -- it's the work of G but a new changeset by name.
Moving over G as something new, let's call it G' (Gee prime), isn't a big deal for some uses, but for others it's a big pita. When soon repo B get's a new changeset, H, and you want to move it over its parent will be changing from G to G', which have different hashes. That means H will move over as H' -- 100 changesets down the line and you'll have different hashids for everything all because you couldn't stand having D,E,F in repo A.
Things will get even more out of whack if/when you want to move stuff from Repo A into Repo B (the opposite direction of your earlier move). If you try to do a simple 'hg push' from A to B you'll get G' (and H' and by subsequent descendants) which will be duplicates of the changesets you already have in Repo B.
What then, are your options?
Don't care. Your data is still there you just end up with the same changesets with different names and more work on future exchanges between the two repos. It's not wrong, it's just a little clumsy maybe, and some folks don't care.
Move all of D,E, and F over to Repo A. You can move all the changesets over if they're harmless and avoid all the hassle. If they're not so harmless you can move them over and then do a 'hg backout' to undo the effects of D,E and F in a new changeset H.
Give G better parentage to begin with. It's mean for me to mention this because it's too late to go this route (without editing history). What you should have done before working on changeset G was to hg update C. If G doesn't rely on or require changesets D,E, and F then it shouldn't be their kid.
If instead you update to C first you'll have a graph like this:
A - B - C - D - E - F
\
G
then, the whole answer to this question would just be hg push -r G ../repoA and G would move over cleanly, keeping its same hashid, and D, E, and F wouldn't go with it.
UPDATE:
As pointed out in the comments. With modern Mercurials the hg graft command is the perfect way to do this.
Refering to the title, which addresses cherry picking in general, I give the example of working in one repo, as internet search engines might bring people here for cherry picking in general. Working in one repository, it would be done with hg graft:
hg update C
hg graft G
The result is:
G'
/
A - B - C - D - E - F - G
Extra warning: The two changesets will be treated as independent, parallel commits on the same files and might make you run into merge conflicts, which is why cherry picking should be avoided in general for branch management. For example, if G is a bug fix applied to a stable version branch bookmarked as 1.0.1, you should rather merge the freeze branch with it, and from time to time merge the master branch with the freeze branch's bugfixes.
Here's another approach:
hg import =(hg diff -c 7b44cc577701f956f12b029ad54d32fdce0a002d services/webpack/package.json)
This creates a diff for the changeset you want to patch in, then saves it to a temporary file and imports it. The filename(s) are optional.
<(...) also seems to work if you're not using zsh (creates a named pipe instead). Or you can manually save the patch to a file:
hg diff -c xxx > mypatchfile