Is there any way to force merge branch A in branch B where all possible conflicts will be resolved in favor of branch B?
In any words how to push last branch B revision in branch A without vanity around conflicts?
You can decide to take all of one branch over another by using hg merge --tool internal:other or hg merge --tool internal:local
I'm not sure which way you want to merge but if you want to merge A into B taking all changes from B then you would do the following:
> hg update B
> hg merge A --tool internal:local
> hg commit -m "Merge"
The internal:local merge tool will take the changes in the current revision (which is B because of the hg update B) over the changes in the other revision, internal:other would take all changes from A.
For more info use the following commands: hg help merge and hg help merge-tools
Related
In How do I do a pristine checkout with mercurial? Martin Geisler discuss how to remove already Mercurial commit'ed files using:
hg strip "outgoing()"
But what if I I want to keep my added files which went into "outgoing()" - example:
Two users a and b — starting on the same changeset
User a:
echo "A" > A.txt; hg ci -M -m ""; hg push
User b (forgets to run hg pull -u):
echo "B" > B.txt; hg ci -M -m "" B.txt;
echo "C" > C.txt; hg ci -M -m "" C.txt;
If user b run hg strip "outgoing()" then B.txt and C.txt are lost. hg rollback is not an option since there are two commits.
Can user b revert his files as "locally added - nontracked", then do hg pull -u, which gets A.txt, then handle the add/commit/push for B.txt and C.txt later?
Martin Geisler answered this earlier in the mentioned thread (a comment which I deleted and moved here:
hg update "p1(min(outgoing()))"
hg revert --all --rev tip
hg strip "outgoing()"
hg pull -u
Now user c can finalize his work in the new files B.txt and C.txt and commit+push those.
Other ways to do this?
You could but, by doing so, you are working against one of the biggest features of a DVCS like mercurial, that is, to easily and reliably handle the merging of multiple lines of development as in your case. If user b's goal is to have a line of development with all three changes applied, then the standard way to do that in hg would be to just go ahead and do an hg pull -u which will create a new head containing the change(s) from user a (and any other changes pushed to repo used for pulling) and then use hg merge to merge the two heads, the head containing user b's two change sets and the other containing user a's change set (as pulled). In a simple case like this one with no overlapping changes, hg should do all the right things by default.
$ hg pull -u
[...]
added 1 changesets with 1 changes to 1 files (+1 heads)
not updating: crosses branches (merge branches or update --check to force update)
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "merge"
If there were conflicts between the two heads (i.e. both users committed changes to the same files), there might need to be conflict resolution editing as part of the merge; hg will tell you if that is the case.
Another option is the rebase extension. With your scenario:
A and B start with the same history.
A commits and pushs a change.
B commits two changes, but can't push because of A's commit.
B pulls A's change.
B runs hg rebase and pushes.
Before rebase:
Common ---------------------------- A (tip)
\
B1 - B2 (working parent)
After:
Common - A - B1 - B2 (tip, working parent)
Let's say that I have a named branch 'B1' which I'm doing feature development on.
I am at a good stopping point before a demo though not done with the feature so I:
hg up default
hg merge B1
hg ci -m "merged in feature drop"
hg push
Now I continue working for a half an hour or so and go to commit only to realize that I forgot to update back to B1 and that my current working directory is on default - uhoh. In theory I should be able to just mark my working directory parent as the tip of B1 - is there an easy way to do this?
I could of course commit, update back to B1, and merge my changes back, but then there's an unstable changeset in default and this happens often enough to me that I would like a real solution.
Two ways. First, the obvious way:
hg diff > foo
hg up -C b1
hg import --no-commit foo
rm foo
Second, the magical way:
hg up -r 'ancestor(., b1)' # take working dir back to the fork point
hg up b1 # take it forward to the branch head
This way involves merges. Depending on how much your branches have diverged, this may be painless. Or it may be complicated, and you may make a mess of your changes that you haven't saved anywhere. Which is why even magicians like myself prefer to do it the first way.
I would use the shelve extension. I think it’s distributed along with TortoiseHg, you can also use it from the UI:
hg shelve --all
hg up B1
hg unshelve
Rebase extension allow you to change parent for any commit for wrongly commited changeset.
If you want just change branch for future commit - MQ (as mentioned) or Shelve
Typically for this sort of dynamic approach, I favor mercurial queues.
In your situation, what I would do would be to create a patch on default with the changes, pop the patch off, switch over to B1, and apply the patch.
It goes something like:
hg qnew OOPSPATCH
hg qrefresh
hg qpop
hg up B1
hg qpush
<hack hack>
hg qrefresh
hg qfinish
All you need is simple hg up -m B1
From hg up --help:
options:
…
-m --merge merge uncommitted changes
…
I am working with a repository with stable and experimental branches. Sometimes I add a file on the experimental branch that is not yet ready for the stable branch. When I merge, I want to merge the changes in the files that are common to both branches, but ignore the files that don't exist on one of the branches.
Here's a simple example:
hg init
hg branch stable
(create file A)
hg add A
hg commit -m "Added A"
hg branch exp
(create file B)
hg add B
hg commit -m "Added B, which is really experimental"
(modify file A)
hg commit -m "Some changes to A"
hg update stable
hg merge exp
However I change the merge tool configuration, Mercurial always seems to take B along with the merge. Since it doesn't exist on the stable branch, it's never a conflict.
I could do the following:
hg update stable
hg merge exp
hg commit -m "Merged"
hg revert -r 0 B
but that requires me to know which files need reverting.
Any thoughts on the simplest way to make the merge ignore files that don't exist on one branch, and preferably do it automatically?
You cannot ask Mercurial to do what you want.
You do not merge individual files, you merge the entire branch, which means that all the files that are part of the branch becomes part of the merge. This is how Mercurial is designed and how it operates.
Now, you could revert/forget/delete the files you don't want before you commit, but then you're just setting yourself up for disaster later.
I recommend you separate things you want to keep from things you don't know if you want to keep so that you can merge one branch and let the other be separate for now.
I just merged branch A into B, and for some reason the merge did not go well. I want to revert B back to where it was before the merge and try again like it never happened before. I was thinking of just doing
hg clone myrepo newrepo -r A -r 12345
where 12345 is the revision number before B's bad merge commit
I think this works, but I have a lot of other branches (most of which are closed using commit --close-branch) and this puts those branches back to an inactive state.
Is there a way to clone everything except revision 123456 or something? (where 123456 is the bad commit on B)
Assuming you have not pushed the merge changeset to any public location, the easiest solution is to use the hg strip command that comes with the Mercurial Queues (i.e. mq) extension.
From the wiki:
hg strip rev removes the rev revision
and all its descendants from a
repository. To remove an unwanted
branch, you would specify the first
revision specific to that branch. By
default, hg strip will place a backup
in the .hg/strip-backup/ directory. If
strip turned out to be a bad idea, you
can restore with hg unbundle
.hg/strip-backup/filename.
It might not be as nice as hg rollback, but usually what I do is update to head A, merge in previous head B, check that I got it right this time, and then dummy-merge away the bad merge.
I hope I'm understanding your situation correctly. If I am you should be able to update to the revision of B before the merge, give that revision a new branch name, merge A in to it, and continue on. You'll probably want to mark the original B branch as closed.
$ hg up 12345 #12345 is the revision of B prior to the merge
$ hg branch B-take2
$ hg merge A
$ hg commit -m 'merge A in to B-take2'
$ hg up B
$ hg commit --close-branch -m 'mark original B branch as closed'
Is it too late to use the hg rollback command? If so, try the hg backout command.
I'm trying to figure out how to merge branches from a separate repo into the current.
I have the following:
PJT1
- contains branches default and foodog
PJT2
- contains branch default
from PJT2, I do the following:
$ hg fetch -y ../PJT1 -r foodog -m "this is a test"
Now, if I look in PJT2, I see the correct files and changes. However, I if I do hg branches, I get the following:
[someone#myhome pjt2]$ hg branches
foodog 1:c1e14fde816b
default 0:7b1adb938f71 (inactive)
and hg branch reveals the following:
[someone#myhome pjt2]$ hg branch
foodog
How do I get the contents from PJT1's foodog branch into PJT2's default branch?
You need to merge, but keep in mind changes on branch foodog will always be on foodog -- branches never go away but they can be hidden. This sequence of commands is as close as you'll get to what you're asking:
cd PJT2
hg update default # just in case you were somewhere else
hg pull ../PJT1 -r foodog # that gets you foodog
hg merge foodog # that merges the changes into default
hg commit # commit the merge
hg update foodog # go to the most recent change in foodog (note: it is not a 'head')
hg commit --close-branch
After the merge hg branches will still show foodog unless you do hg branches --active which only shows branches that have heads on them. After the commit --close-branch you won't see foodog unless you do hg branches --closed.
It's because branches in Mercurial never go away entirely (a design feature) that they're often reserved only for life-long things like release-1.0 or stable. For short-lived efforts like bugs and features consider using bookmarks instead. Here's a great comparison of the two: http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial
You could also try using the rebase extension. It would look something like this:
hg fetch -y ../PJT1 -r foodog -m "this is a test"
hg rebase --source <sRev> --dest <dRev>
The rebase action will detatch changeset sRev and all descendents and apply the group of changes to changeset dRev. By default, the changes will be applied on the default branch. So, in your case, sRev would be the first changeset on branch foodog and dRev would be the default changeset you want to apply them to.
Finally, If you want to override this and preserve the source branch name you can use rebase option --keepbranches. Your questions indicates that this is exactly what you do not want to do, but it should still be noted.