I have a repository in which there are two branches MAIN and FEATURE1. Soon after I branched, I needed to make a bug fix and then I tagged MAIN with a version number. These are the only changes on MAIN after the branch. I've been working in FEATURE1 and have added several files.
1--2----4--5
\
3--------6--7--8
3 - Branch created
4 - Bug fix
5 - Tag added
6-8 - Feature changes
Note There is a single conflicting change between the bug fix and the feature.
Now, my feature is complete, and I want to merge FEATURE1 (8) into MAIN (5). But when I perform the merge, it doesn't appear that any of my changes are moved into the MAIN branch.
When I performed the merge without committing, I noticed a few things:
All of the files that were added in the source branch (FEATURE1) are marked to be removed.
There are a lot of .orig files (I have no idea what these are). These are marked ? (unknown action) and are not committed.
Existing files are marked 'M' (modified) as expected, but the changes aren't migrated.
It's almost as if it's taking MAIN as the source and FEATURE1 as the destination, but I'm sure I'm merging into MAIN. I update to MAIN (5), right-click FEATURE1 (8), and select Merge to Local.... The resulting branch appears as part of MAIN as expected.
I've never branched using TortoiseHg or Mercurial before. I'm used to TFS, and I feel like I'm getting the opposite behavior.
Basically, I want the changes I made in FEATURE1 to be present in MAIN.
So apparently, TortoiseHg was working correctly. My frustration was the result of misreading the UI.
Whenever you update to a different revision in TortoiseHg, it gives you a dialog with a checkbox which allows you to discard the uncommitted changes in the current branch.
Discard local changes, no backup (-C/--clean)
When merging, the message is similar but carries a very different meaning.
Discard all changes from merge target (other) revision
While the first means that you want to undo uncommitted changes, the second means that you want to merge the branches without bringing over any of the changes.
On a side note, I can't figure out why that feature is there. Why would you merge branches without migrating the changes? It seems easier to just close the branch.
Related
I just found out that we're not supposed to create named branches in our local Mercurial repos, because they get carried along and pushed to the upstream repo, where they live forever.
Unfortunately, I already have multiple feature branches in my local repo, which I was all set to merge to default and push up to the main repo. So, what I need to do is keep the work in these branches (somehow) but remove the named branches.
Is there a way to do this, short of a lot of horrible manual revert/cut/paste?
Using TortoiseHg:
(Ensure rebase extension is enabled in File -> Settings -> Extensions)
Update to parent of the first change set of the named branch.
Right click on the first change set of the nambed branch and click rebase.
Ensure "Keep orignal branch names (--keepbranches)" is NOT checked.
Ensure "Rebase entire source branch (-b/--base)" is checked.
Click rebase.
Another approach would be to use the hg convert command (a standard extension) and the branchmap option.
For a private repository or at least one with changesets which have not been published this would work fine, even though like a rebase it would modify history.
An advantage as opposed to using rebase is that it could be used to deal with multiple branches (named or unnamed) all at once. That might be quicker / easier if there was a lot of things to move around.
A secondary plus is that since convert will create a NEW repository there is no risk to the original if something doesn't work as expected. (Of course when using rebase you could make a backup first which I think is a reasonable precaution.)
I made some changes to a file and committed it. (In fact there were several commits).
Then I wanted to revert to the earlier version and lose all those changes.
I did something like:
hg update -r nnn where nnn was the reversion number of the changeset I wanted to go back to.
That worked. I was happy.
Then, later, I had to push my local repository to the remote. But when I did hg push I got a message about there being two heads on this branch and one of them not being known to the remote repositiory. It suggested I merge before pushing. (I think).
I googled this and found a page that suggested I do "hg merge". I did that. Now the resultant file is back to where I started. I.e. it contains all the changes I wanted to throw away.
Where did i go wrong?
EDIT:
I have found this post Mercurial — revert back to old version and continue from there
where it says:
If later you commit, you will effectively create a new branch. Then
you might continue working only on this branch or eventually merge the
existing one into it.
That sounds like my case. Something went wrong at the merging stage it seems. Was I on the wrong branch when I did "hg merge"?
You're past this point now but if it happens again, and it's just a single file you want to revert then consider:
hg revert --rev REVISION_YOU_LIKED path/to/just/one/file.txt
That doesn't update you whole repository to a different revision, and it doesn't create any commits. It just takes a single file in your working directory and makes it look like it used to. After doing that you can just commit and you're set.
That's not the way to go if you want to undo all the changes you've made to all files, but for reverting a single file use revert and avoid multiple heads and merging entirely.
No, nothing went wrong at the merge stage – Mercurial did exactly what you asked it to...
What merge means is that you take the changes on your current branch, and the changes on the 'other' branch, and you merge them. Since your original changes were in the 'other' branch, Mercurial carefully merged them back into your current branch.
What you needed to do was to discard the 'other' branch. There are various ways of doing that. The Mercurial help pages discuss the various techniques, but there are pointers in other SO questions: see for example Discard a local branch in Mercurial before it is pushed and Remove experimental branch.
(Edit) Afterthought: the reason you got a warning about there being two heads on the branch is because having two heads is often a temporary situation, so pushing them to a remote repository is something you don't want to do accidentally. Resolutions are (i) you did mean to push them, so use --force to create two heads in the remote repository; (ii) ooops!, you meant to merge them before pushing, so do that; or (iii) ooops!, you'd abandoned the 'other' one, so get rid of it. Your case was (iii).
This question already has answers here:
Mercurial: Merging one file between branches in one repo
(5 answers)
Closed 2 years ago.
Reading up on Mercurial, it seems to always branch and merge the complete repositories.
Is it possible to just merge some files from one branch to another? (For example I may only wish to merge in the files that fix a given bug.)
Likewise can I cherry pick some change sets, but still have a correct merge record, so if a complete merge is done later it is correct?
I am coming from a perforce “mindset” so may be thinking about this the wrong way.
Yes, Mercurial always branches and merges the whole tree. You don't have the "flexibility" that something like perforce gives you to select individual files for a merge. This is a good thing (trust me). Changesets are atomic (you can't split them) and immutable (you can't change them). Hence this needs a little bit of a mindset change.
Changesets should be targetted at one task, and one task only. If you're fixing a bug, nothing else goes in the changeset apart from the bug fix. You've then got a changeset which documents that bug fix, and you haven't got the problem of wanting to split it. It wouldn't make sense to want to. Half a bug fix is often worse than no bug fix.
When it comes to merging that there's a couple of options:
One school of thought says you should go back to where the bug was introduced. Fix it. Commit (making a small anonymous branch), and merge that forward onto whatever head you want it on (dev, stable, release, whatever). This isn't always practical though.
Another method is fixing the bug in the release branch, and then merging to the development branch. This normally works well.
Alternatively you could fix it at the head of your development branch, but then if you merge it onto your release branch you'll bring over all your development changes. This is where graft (new in 2.0) and the older transplant extension come into play. They allow you to "cherry-pick" a single or range of changesets from another branch and place them on another branch.
Reading up on Mercurial, it seems to always branch and merge the
complete repositories.
Yes
Is it possible to just merge some files from one branch to another? (For example I may only wish to merge in the files that fix a given bug.)
Just touch only "some files" in needed changeset and merge branch with this changeset in head with another branch or transplant in any time
Likewise can I cherry pick some change sets, but still have a correct merge record, so if I complete merge is done later it is correct?
Yes, you can transplant| any changesets to another branch, applied state will be remembered and changes will not be duplicated on final merge
I am coming from CVS background.
Currently, I have 2 mercurial repositories developed parallel. hello-world-bugfix and hello-world-feature (This one is being cloned from hello-world-bugfix)
Now, I want to merge the bug fixed code from hello-world-bugfix into hello-world-feature, so that end of the day, I will get a merged file.
[BUG2 BUG2 BUG2]
START
[BUG1 BUG1 BUG1]
[FEATURE2 FEATURE2 FEATURE2]
Here is how all the things looks like before, pulling and merging. The below two files had already been committed.
Now, I perform pull from hello-world-feature, to pull changes from hello-world-bugfix.
Then, I perform update, with always merge options turned on.
Here is my merged file???
[BUG2 BUG2 BUG2]
START
[BUG1 BUG1 BUG1]
It seems that my previous committed [FEATURE2 FEATURE2 FEATURE2] being overwritten.
It seems that I shouldn't perform update step, which will not merge feature with bug, but overwrite feature away with bug. What is the next correct step I should do after pulling? (through TortoiseHg), so that I can get bug fix code, and remain feature code there?
Here is the final repository view of hello-world-feature
The "always merge" option doesn't do what you think it does.
It only merges uncommitted changes.
When you update, committed files are replaced with the new version.
To merge committed changes, ie. merge branches, you need to do an explicit merge.
So, I would select the BUG2 BUG2 BUG2 changeset in the log, then right-click on the FEATURE2 FEATURE2 FEATURE2 changeset and click Merge, and follow the instructions.
Let me expand on what the "Always merge" checkbox does.
Let's say I have two changesets in my repository, I update to the first of them, then I start modifying one of the files.
At some point I decide it would be better to have started from the other changeset instead, so I want to update to it, keeping my modifications.
If I simply do an update, with uncommitted changes, I get this dialog box when I try to update:
However, if I check the "Always merge (when possible)" checkbox, it will simply assume that I clicked on the Merge button in that dialog and not prompt me.
So the "Always merge" does not have any function at all on committed files, it won't introduce merges for you, it will only try to move your local changes along with the update.
I am coming from CVS background.
I try to perform branch by cloning.
The current default tree looks like this from hello project.
I try to clone a project out from 'hello' to 'hello-branch-by-clone'.
I did modification on 'hello-branch-by-clone' and commit.
I did not do any modification on 'hello'.
I perform push from 'hello-branch-by-clone' to 'hello'.
I expect to see a branch but I didn't.
This time, I try another way around.
I did modification on 'hello-branch-by-clone' and commit.
I did modification on 'hello' and commit.
I need to pull from 'hello' to 'hello-branch-by-clone', and merge.
I perform push from 'hello-branch-by-clone' to 'hello'.
This time, then only I can see the branch
By applying cloning technique, is there any way I can have a branch view, without having explicitly modify the default repository (hello)
There's no fork because no two changesets share a parent.
A cloned repository isn't special in any way. It's identical to the original. Commits to it are identical to commits in the original repo. They aren't notionally tagged as being on a branch. A clone is just a nice way of having another work area that you can do some work (including commits) without effecting the original.
A fork occurs when two or more commits have the same parent. Often this happens when using clones, but it may not. If there's only one changeset with the same parent, there is no fork.
After your first sequence you've introduced just one changeset (4) which is which has the old tip (3) as it's parent, so it's still a straight line. Only when you introduce a second changeset parented by (3) will you see a fork.
Now remember, even though you 'push'ed the changeset back, and the original "Hello" repo contains all 4 changesets, it's working directory is still pointing to changeset (3). It will stay that way until you run 'hg update' inside it. This means that if you were to make a commit in "Hello" it will be based upon (3), and then a fork will appear. It doesn't matter when this commit is made.
This is what you did in your second sequence.
Hope that helps.
I've tried to use the term 'fork' in this, because 'branch' has lots of meanings, including the 'hg branch' command which does some slightly different things.