Given that I have created a branch in Mercurial how can I push the resulting merge of that branch to a remote repository without the history of how I got to that merged branch result. For example.
[a] - [b] -----------------[k]
\ /
[g] - [h] - [i] - [j]
[a], [b] and [k] being the 'default' branch, [g] through [j] being the feature branch. Once I merge the feature branch into the default branch how can I have just [a] - [b] - [k] change sets in the remote repository when I push? I don't want to simply not see the branch, I do not want those change sets pushed to the remote repository at all. I don't care how I got to [k], I do care what the [k] end result is though.
I am currently leaning toward the branch by cloning method but how can I accomplish this with cloning? Would there also be a way to make this work with named branches?
I have been looking for an answer to this but there is so much documentation out there it's difficult to find this needle in a haystack.
Instead of merging, you want to use hg rebase with the --collapse option.
hg rebase --collapse --source [g] --dest [b]
The rebase extension is shipped with Mercurial, you just need to enable it in your settings file.
p.s. If you have already committed the merge [k], you should rollback (or strip) it first before rebasing.
how can I push the resulting merge of that branch to a remote repository without the history of how I got to that merged branch result
No ways to get stripped history for merged branches
Related
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>
I'm not sure why this is so hard to figure out or google, but I am trying to take changes I made to a private branch and push them to the default branch.
In other words:
I pulled from the default branch a few weeks back and made major changes
Since then, I have finished my work
I then merged the code from the original default branch (just the code, the HG is still set to the "NewBranch"
Now that the code works, I want to commit and push these changes back to the default branch and continue my development from there.
But I can't find any information on how to do that. If I switch branches, I lose all my changesets since I am still in the NewBranch. I can't figure out what rebase or transplant do and can't find guides that explain scenarios on what they could be used for... So hopefully someone here knows what to do!
I am specifically using Mercurial on Eclipse but I am fine doing this on command line if its easier.
merge is the way to get changes from one branch into another. I know you merged default into feature, but now you go the other way. Here's an example where numbered changesets come from other people and lettered changesets comes from you:
Before you do anything you clone and have this:
[1]---[2]---[3]---[4] (default branch)
then you create your branch named 'feature' and do two commits on it, yielding:
[1]---[2]---[3]---[4] (default branch)
\
[A]---[B] ('feature' branch)
then you hg pull to get changes to default since you diverged down in your local repository:
[1]---[2]---[3]---[4]---[5]---[6] (default branch)
\
[A]---[B] ('feature' branch)
now you want their changes (5 and 6) integrated into your branch so you do:
hg checkout feature # make sure you're looking at the he head of your branch
hg merge default # merge default into your branch
which yields:
[1]---[2]---[3]---[4]---[5]---[6] (default branch)
\ \
[A]---[B]---[C] ('feature' branch)
If I'm understanding correctly, you've already done all that, so now you just need to bring your branch, including the new merge commit, C, into default, which again is done via a merge:
hg checkout default # hop back to default, files look like [6] and [A] and [B] are missing
hg merge feature # merge feature into default brining [A] and [B] in
that yields:
[1]---[2]---[3]---[4]---[5]---[6]---[7] (default branch)
\ \ /
[A]---[B]---[C] ('feature' branch)
That looks like a lot of work drawn out that way, but in practice it's usually just:
hg branch feature
....work....
hg commit
hg pull
hg merge default
hg checkout default
hg merge feature
and if the pull didn't bring down any new work from other you can skip the merging of default into yours.
That does create two new merge changesets. They're easily hidden on hg log if you find them unhelpful (some people love having a record of which direction each merge went), but if you want to avoid them entirely you can use bookmarks (very similar to git branches) instead of "named branches" for your features -- then you'll avoid a merge changeset when coming back since it would be the spiritual equivalent of what git calls a "fast forward" merge.
I have merged two repositories together with the mqextension, giving me a repository that looks like this:
.. [a] --- [b] --- [c] --- [d]<- default branch
/
[x] --- [y] <- feature branch
The problem is that when I try to push this I get:
hg push --new-branch
abort: push creates new remote head x!
(did you forget to merge? use push -f to force)
How can I fix this? I assume I need to merge [a] with [x] so that I have a common ancestor. Is this possible? would I cause issues if I just forced the push?
EDIT - After a little more research I found I was trying to simplify the repository a little too much.. the repository looks like this:
.. [a] --- [b] --- [c] --- [d]<- default branch
\
[f] --- [g] --- [z] <- integration branch
/
[x] --- [y] <- feature branch
/
[w] <- default branch from old repository.
I think what is happening is that I have two heads for the default branch and hg doesn't want to push both of them to master.
Should I merge the two defaults together?
There's no reason why merging two unrelated repositories should cause this problem. I have just tried it and it pushed with no issue at all.
If time flows from left to right in your graph then you only have the one head [d]. That graph looks as I would expect it to after the merging of two repos.
The error message looks like someone else has pushed changes to the central repository and so you'd need to do hg pull and hg merge to merge their changes into your branch.
EDIT - After your edit adding more info it seems like you do actually have two heads on the default branch and, yes, you should merge them with hg merge.
I have a repository and am using mq patch queue for unfinished changes. The patch queue is also under version control.
Let's say I have 2 patches p1 and p2 (applied in that order). Now I make a change on p1:
hg qnew p1
...
hg qnew p2
...
hg qref
hg com --mq -m"(Commit before reject)"
hg qpop p1
{make change}
hg qref
hg qpush -a
... and p2 fails to apply.
The standard way would now be to apply the rejected hunks manually. I
want to use something like MqMergePatch which is nice and uses the merge of
mercurial—but it is based on the deprecated feature:
hg qsave // deprecated: use "hg rebase" instead
My question is: how to do it with hg rebase?
EDIT
After having seen the log of the repository, I do not like at all what MqMergePatch does to it. My main goal in using patches is to have the repository's history clean, and not scattered with useless details.
The suggestion to use hg rebase is misleading, I think. The MqMergePatch page says it is a modification of MqMerge, which was a technique for rebasing a series of patches on top of new changesets pulled from elsewhere.
However, it involves saving a copy of the patch queue already applied (that's really all hg qsave does) and using the saved copy as part of the reference for a 3-way merge that effects a patch queue rebase. I used to do that myself before I enabled the rebase extension. Then it was simply a matter of rebasing the first patch on top of the tip changeset I wanted to be its new parent.
That's not what you want though, because what you want is to basically rebase a patch on top of a patch that you changed. The patch queue is linear, though, and you can only rebase a patch if the changeset onto which it has been applied has other children parallel to the patch queue:
--- A -------- patch1 --- patch2
\
\-- B
In the above situation, the patch queue could be rebased on B with hg rebase easily enough (thus the suggestion to use hg rebase), but that has nothing to do with your situation.
An approach to your situation
Here's an applied patch with unsaved local changes that will conflict with an unapplied patch:
--- A --- patch1 <patch2>
\
\-- [changes]
Usually I bite the bullet and handle rejections manually since they are usually few. I find that if I have a situation where there are too many rejections to handle manually, I was probably not organizing them properly in the first place.
If the technique using qsave and qpush -m and so on is preferable to the following to you, it is unlikely that qsave will be removed any time soon, even though it is deprecated.
Here is how I would handle the above situation if I really wanted to take advantage of 3-way merge tools:
(TortoisHg 2.x doesn't let us rebase patch queues yet, so this is a variant of the finish-rebase-import that I sometimes do.)
Instead of qrefresh, use qnew to make the unsaved changes a new patch:
--- A --- patch1 --- patch1b <patch2>
Finish these patches into regular changesets:
--- A --- B --- C <patch2>
Update to the changeset to which patch will apply cleanly (B), and apply the patch:
--- A --- B --- patch2
\
\-- C
Rebase patch2 atop C so that 3-way merge is used to resolve conflicts between local patch2 and other C using base B:
(I would have to do this in TortoiseHg 2.x by finishing patch2 before rebasing, then importing it back into the queue.)
--- A --- B --- C --- patch2
Import B and C into the queue as patches again:
--- A --- patch1 --- patch1b --- patch2
Pop patch2 and patch1b and then fold patch1b into patch1 (renamed as patch1new):
--- A --- patch1new <patch2>
Now patch2 will apply cleanly to patch1new.
I recently have been working on an extension to do this, as I've been using a lot of MQ patches. The extension is called qsmooth (since you "smooth out" your patches).
You can have a look here: https://bitbucket.org/jwdevel/qsmooth
It uses a procedure very similar to that in Joel's answer.
I haven't used it in production a whole lot yet, but it has a decent number of tests, and I'm happy to receive bug reports.
I tried to merge two heads in Mercurial. After merging, I didn't commit and did some more changes. Then I tried to commit and got the following message:
abort: cannot partially commit a merge (do not specify files or patterns)
I'm using TortoiseHG as visual shell, and Beyond Compare for comparing and merging. And I'm relatively new to all of them.
What should I do to finish commit successfully?
Mercurial/TortoiseHg is correct in telling you that you should not partially commit a merge. Partial means that you do not commit all files at once.
The underlying reason for this message is that is gives you the wrong results. When you merge two changesets in Mercurial, you are creating a new changeset with two parent changesets. This merge changeset shows others how you want everybody else to combine the two changesets.
Let us imagine that you start with changesets A and B and want to merge them. This creates a graph like this:
... --- [A]
\
[M]
/
... --- [B]
Pretend that we added the line A! to a.txt in the A changeset and that we added B! to b.txt in the B changeset. Just two independent changes that does not conflict. If Mercurial allowed you to do a partial commit, then you could do this:
hg merge
hg commit -m 'Added A!' a.txt # creates M
hg commit -m 'Added B!' b.txt # creates M'
and the result is this graph:
... --- [A]
\
[M] --- [M']
/
... --- [B]
If you look at b.txt along the path B, M, M', then you will see that the line with B! was introduced in B, removed in M and reintroduced in M'!
This is not what you want from a merge changeset: a partial merge throws away changes from one branch just to introduce them again in a followup commit. Mercurial trusts you when you create M: it really believes that M contains the correct mix of A and B. In particular, if the B! line is removed in M, then it will remain gone when you merge M with other changesets.
So Mercurial is trying to protect you from creating a bad history by not allowing partial merges.
I think you have aliases in hgrc file. Try to remove [alias] section and commit again.
What should I do to finish commit
successfully?
One of the benefits of Mercurial (or git or any other DVCS) is that you can perform a commit at any point in your development process and it will be both fast and private. It will be fast because you should be committing to a local copy of the repository residing on your hard drive, and it will be private because no-one will see your change set until you push them to the server (or other master repository).
Therefore, to partially answer your question, the appropriate thing to do would have been to commit the merge without your addition changes, and then apply and commit your next wave of changes. If you are using TortoiseHG to peform the merge it will actually prompt you to commit the merge before leaving the GUI because this is the intended HG workflow.
That being said, I made some changes on a named branch (ie: new head), merged it back into the default branch, exited the TortoiseHG GUI without committing, made some more changes, and then committed with no problem. I will ask some clarifying questions below your original inquiry.
I had this problem because I had deleted some files. I reverted the files to restore them, then was able to commit. I then deleted the files and did a second commit.
I had the same problem and I was NOT specifying any files and using command-line.
The problem was the [default] section in my .hgrc
[defaults]
commit = -X project/web.config
So it added specific files to every commit-operation by default.
Review your defaults section for potential problems.
I had the same problem and the command I gave was
hg commit -m Merge with 1234
I figured it out after sometime that the commit message "Merge with 1234" has to be given in quotes as the command takes "with" and "1234" as file name params.
please check it in your case.