Find Mercurial Changes Where Both Parents Are In The Same Named Branch - mercurial

I'd like to list all changes in a Mercurial repo that are merges where both parents are in the same named branch as the change itself.
I.e., merges that are not from one named branch to another.
I know how to list all merges:
hg log -r "merge()"
But I'm having trouble figuring out how to express "both parents are in the same named branch as the change itself".

This is best I've come up with so far, but it only works if you can specify the branch name (default in the example below).
It doesn't seem to include any changes it shouldn't, but I can't say that it's not excluding changes it shouldn't.
hg log -r "children(p2(branch(default)) & branch(default)) & branch(default) & merge()"
Any feedback or better answers are welcome!

Related

Duplicate a branch in Mercurial?

How can I duplicate a branch in Mercurial? I need the new branch to be against head (as the first one is).
The GIT equivalent (if I was in branch-a) would be:
git checkout -b branch-b
A Mercurial branch is a named entity that consists of all the commits contained within the branch. So in order to duplicate some existing branch, you must also duplicate all of its commits to new commits that are in the new branch. We then get into metaphysics arguments about commit identity. It's probably not a good idea to go here at all, but if you do want to go here, use hg graft to copy all the desired commits into the new branch.
A Git branch consists of a name containing a raw commit hash ID. So duplicating a Git branch under a new name is trivial. Note that the set of branches that contain any given commit changes dynamically over time: a branch that was only on feature/tall may now only be on master, even though that commit is still that commit, even via most of these metaphysical arguments. (Only the "no identity over time" argument lets us claim that this is not the same commit.)
Another way to put it is that Mercurial's branches actually mean something, but Git's don't. If you need true branches, you can't use Git in the first place. Don't try to import Git's bizzareness into Mercurial: you'll just make your own life miserable.
Meanwhile, though, Mercurial contains a DAG just like Git. If you use Mercurial bookmarks, those work like Git branches. It's probably wiser, then, to just use bookmarks and be done with it.
If all else fails, see hg graft.
the new branch to be against head
What is this (in usual business-term, not Git-lingua)? While in common (and in details) #torek is totally right, he forgot to write exact command-set, something like
hg up <rev-id>
hg branch <new-branch-name>
hg graft -r "branch(old-branch-name)" --log

Splitting out multiple intermediate changes in Mercurial

We have a very unfortunate situation where a new feature branch was made from a second, unrelated feature branch that had been put on hold rather than from default. There's multiple changesets within both feature branches and while most changed files are unrelated several high level project files that have edits on both branches. Default has also had several updates and merges during this time too. Thankfully the intermediate feature hasn't been updated concurrently with the new feature. I've looked into various commands and options available and lost how to best fix this situation. The tree currently looks roughly like:
Default -- Various edits and merges -- tip
\
\-- Named Branch 1 (15 changes) -- Named Branch 2 (30 edits)
I want to get to a point where default has the changes from Named Branch 2 but none from Named Branch 1. I also want a branch that has the changes from Named Branch 1 available for when we return to this feature.
I suspect there's no nice easy way to do this, and there's going to be some messy parts in the history, however I am at a loss at how to start going about this task.
hg graft can cherry-pick changesets from one branch to another. Update to the destination branch, then graft the revisions you want to copy by running, for example:
hg graft 8 9 10
Conflicts will be handled using the normal merge process.
If you use TortoiseHg, select the changesets to graft to the current selected changeset, then right-click and select Graft Selected to local...:
Result:
Since you want to move the entire branch 2, you could consider using rebase. Make a clone of the repository and try this:
hg rebase --source <first branch2 rev> --dest <new parent in default> --keepbranches
This will in principle transform the history to what it should have been. However:
You may have to resolve conflicts arising when <first branch2 ver> gets moved to a new parent.
Since rebase rewrites history, you'll have to get everyone to cooperate in synchronizing their repositories. Whether that's feasible or worth the trouble in your case I can't say, but it's not that difficult: Assuming everyone has pushed any changes in branch 2, they can pull the new history and then get rid of the obsolete version of branch 2 with hg strip:
hg strip <first branch2 rev>

How to clone from a specific revision to the last one using Mercurial?

In Mercurial , How to clone from a specific revision to the last one using ?
For example repo A have one line history from changeset 0 to changeset 100. and I want to clone A to my local repo from changeset 90 to last one (100).
Looking through the help, I noticed the -r flag but that only clone 1 specific changeset.
And if there is no way to do it can somebody explain why its not implemented ? its considered a bad thing to do ?
Thanks.
You can't.
The current state of the project is all changesets from the beginning of time up until the specific changeset, you cannot prune older changesets without rewriting the history of the repository to permanently get rid of them. This will also make the repository incompatible with the original that contains the old history.
In short, you will have to do one of the following:
Prune the old history, permanently getting rid of it, which will make it impossible to push/pull with original clones that still has that history
Live with the history
The parameters to the clone command that specifies revsets thus only allow you to set an upper limit. This may allow you to avoid whole branches, if they aren't merged into the branch you end up cloning, but the clone command will always clone everything from the beginning of time.
For every changeset you clone, every predecessor will be cloned as well, and this cannot be avoided.

mercurial hg up -C created a branch with the same name as current, how to remove it or merge it

I had a change in my branch and after unseccessfull merge, I tried to revert that unsuccessefull merge with hg up -c but it created a new branch instead. I can merge it into current or discard it or what to do with it?
EDIT:
actually I did the following, I had a branch and committed changes there there. then I wanted to push my changes to server, so I pulled changes, and tried to merge with them, but there were a conflict I couldn't resolve myself and I thought: I'll revert all changes back and merge again - so used hg up -C which I thought, will revert everything I changed during my unfinished merge. But what actually happened, another branch with the same name was created, containing only that changes I committed previously and with the same name as a branch I was working in and I was switched to the branch where I was working, which didn't have my changes. So two questions here: what actually happened and why another branch with the same name was created?
Having multiple heads on the same branch, which I think is what you're saying with "a branch with the same name as current" is a normal situation and, yes, you can use hg merge to consolidate them into one head. Use the hg heads command to find the hashes of the two heads of branch X. Then:
hg update REVISION_ID_OF_ONE_HEAD # changes your working directory to match one of the heads
hg merge REVISION_ID_OF_THE_OTHER_HEAD # merges that head's changes in
hg commit # create a new changeset that is the child of both those heads thus reducing the head count by one
Also #ringding is correct that hg update never creates branches. You either already had them and didn't know or received another head when you pulled.

How do I push specific changesets to a shared library repo in Mercurial?

I have a repo called MySharedLib, and another repo called MyProject. MySharedLib is included in many different repos by force-pulling (like a Jedi), and NOT using subrepos.
If you clone MyProject, you are left with the following structure:
/MyProject
MySharedLib
OtherStuff
Files...
MySharedLib is not a subrepo. Pulling in changes from MySharedLib is as easy as running:
hg pull -f path/to/MySharedLib.
But if changes are made to /MyProject/MySharedLib, what's the most straightforward/standard way to push ONLY those changes to the MySharedLib repo?
MQ? hg export? hg diff? hg transplant? My understanding is that almost all of these options work (some together, some apart), but I'd like some direction.
And then what happens if a dev makes a commit that includes other files than those within MySharedLib? Obviously this is something to avoid, but I'm just curious.
Here are the constraints that govern what you can push:
you can only push whole changesets -- if you commit some changes together it's all or none on the pushing front, you can't break up a changeset after you commit it
you can't push a changeset without pushing all of it ancestor changesets to
So once you've committed a linear history like this:
[0]---[1]----[2]-----[3]
you can push changesets zero and one without pushing two and three, but if you want to push two you also have to push zero and one.
And if changeset one contains changes to both /MyProject/OtherStuff and /MyProject/MySharedLib/ you have to push those together.
Your only flexibility comes before you commit where you can control:
what goes into a changeset
what the parents of a changeset are (which also have to be pushed with it)
So if your history currently looks like this:
[0]---[1]
and hg status is showing something like this:
M MyProject/OtherStuff/file1
M MyProject/OtherStuff/file2
M MyProject/MySharedLib/file3
M MyProject/MySharedLib/file4
Then you want to make a new changeset that has only the changes for MySharedLib that you want to push:
hg commit --include MyProject/MySharedLib
making your history look like:
[0]----[1]-----[2]
and then, before you commit the changes in OtherStuff you don't want to push you do a hg update to change the current parent revision so that your new changeset will have a parent of one instead of two:
hg update 1
Now when you do:
hg commit
your new changeset, three, will have only the non-MySharedLib changes and a parent of one, so you history will look like this:
[0]-----[1]--------[2]
\
--------[3]
Since two and three aren't one another's ancestors you can push either one without pushing the other.
That said, omnifarious is right: your usage isn't just weird, it's out and out wrong. You should look at a subrepo setup. It almost certainly achieves your goals better than what you or I have just described.
Wow, what a bizarre setup. How do you prevent changes to MySharedLib from being pushed to MyProject? How do the files from MySharedLib ever appear unless you do a merge after pulling them? Once you do the merge, the repos are joined and you will need to make advanced used of hg convert (as described in this question about splitting repositories) to pull them apart again.
Do not do this. Use subrepos. This problem is what they exist to solve.