Can mercurial rebase delete a branch? - mercurial

This is the summary of a hg session:
> hg branch dev
marked working directory as branch dev
(branches are permanent and global, did you want a bookmark?)
> hg branch
dev
> hg ci -m 'test'
> hg update default
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
> hg pull --rebase
pulling from ssh://hg#bitbucket.org/user/repo
searching for changes
adding changesets
adding manifests
adding file changes
added 3 changesets with 44 changes to 44 files (+1 heads)
saved backup bundle to C:\repo\.hg\strip-backup\edc5f75b39d1-backup.hg
The problem is that after all of this, there is no trace whatsoever of the 'dev' branch. I can't make any sense of it. I committed a changeset when in the dev branch so it must have been saved. How is it possible to disappear? Could rebase delete it somehow?
EDIT: just to clarify the 'test' commit is there, but it's in the 'default' branch

Finally able to reproduce it!
Your named branch branches off of a local changeset on the default branch.
When you run pull --rebase it inserts the pulled changesets into the tree and then rebases your local change sets from the default branch onto the pulled default changesets.
Since your branch dev branches off of that local change set, it is rebased as well. Furthermore, since you can't pass --keepbranches to pull --rebase, you lose the branch name.
To prevent that from happening, branch dev off of a public changeset or run rebase manually with --keepbranches.

Related

How can I move a changeset from a remotely deleted branch to another branch?

So someone deleted a remote branch, but a changeset was lost when he deleted the branch.
I have the changeset on my local repository and tried to merge the changeset to my default branch, then I pushed, but I got an error "abort: push creates new remote head 650367cd0ff4 on branch 'rc'!"
There are few options, depending on the situation you have:
If the whole branch was stripped and you have that branch locally then you can push it again:
hg push --new-branch
This is recommended, because Mercurial will anyway send your local commits to remote repo every time you will do push (until you strip these commits locally). You can then close unwanted branch with --close-branch (this will leave all commits in repo, but just mark branch as closed/unused).
hg ci --close-branch
Graft the wanted commit locally from some branch to other:
hg graft -r 123
hg push
Create new remote head ("abort: push creates new remote head 650367cd0ff4 on branch 'rc'!"). It's nothing wrong, it just means that one of your branches will have two separate top commits. These commits can be merged together later.
hg push -f

How to merge a feature branch to default with subrepositories with Mercurial

I have numerous projects with subrepositories:
/project <- Main repository
/project/src <- Source code subrepository (subrepository to /project)
/project/src/module <- Module subrepository (subrepository to /project/src repository)
I've now worked on a feature branch (feature1) which has had a few revisions, which I'd now like to merge back into the default branch. The default branch hasn't had any changes since the feature1 branch was created.
I've tried merging the branch to default however end up with some strange things happening in the subrepositories.
I've followed the instructions in this other post, and get the following results:
$ hg checkout default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge feature1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg status -S
M .hgsubstate
$ hg commit -S -m "branch merge test"
nothing changed
$ hg branches
default 19:c2398dc23428
feature1 17:98dc0efbad90 (inactive)
What's strange is that even though many files were changed in the module subrepository, the merge only stated that 1 file was updated. I'm assuming that this happens to be the .hgsubstate.
When I explicitly update the subrepository, then I get the following:
$ cd src/module
$ hg update
39 files updated, 0 files merged, 23 files removed, 0 files unresolved
$ cd ../..
$ hg commit -S -m "feature1 merge"
committing subrepository src
$ hg status -S
M .hgsubstate
So after doing a hg update to bring all the changes into the working directory, I see the changes in the module subrepository that I need to commit. However, .hgsubstate always remains in the modified state. I've tried hg remove. I've tried hg forget. But no matter what I do, it still is marked when I do a hg status.
So my questions are:
Was the process I took to merge the branch in correct (considering subrepositories are present)?
Is it necessary to do a hg update in the subrepositories to make the main repository recognize the changes?
Why is .hgsubstate misbehaving?
You don't say which version of hg you are using - subrepo support has changed a certain amount over time. I've just tried something like your test with 3 subrepo levels in hg v2.8 and it works for me.
When you got a dirty .hgsubstate at the top level, that is normal when you commit a subrepo. [If only a subrepo has been committed independently, only the .hgsubstate will be dirty at the top level.] If you then go up to the top level and commit at that level the .hgsubstate will be committed, and everything is fine. Remember, the top level repo tracks subrepos in a similar fashion to files - it commits a particular changeset from the subrepo at each top level commit.
FWIW. The recommended practice is to commit subrepos separately, i.e. avoid committing at the top level if the subrepos are dirty. The reason is that the subrepos often require a different commit message - they are subrepos for a reason after all; but you can commit at the top level if you wish. In your case with 3 levels the sequence would be:
cd src/module
hg commit -m "src/module commit reason"
cd ..
hg commit -m "src commit reason"
cd ..
hg commit -m "top level reason"
It was intended that subrepos would change infrequently, e.g. third party libraries. If your subrepos are going to change frequently, you and your team will have to be vigilant to avoid mistakes, especially when merging with other peoples work. [But given the date of the question you've probably worked that out yourself by now.]

ignore non-existant files when merging in Mercurial

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.

How to prevent a file from automatically merging when switching branches in Mercurial?

Let's say I have two branches named default and newfeature. I have a file called readme.txt in both branches. I'm working on the newfeature branch and I make a change to readme.txt. If I run hg up default without committing the change, Mercurial automatically merges the version of readme.txt in newfeature directly into default.
How can I change this behavior? What I'm worried about is developers forgetting to commit before they switch branches, thus merging whatever they've been working on.
This is what the process looks like:
C:\source\BranchTest\Main>hg branch
Exams
C:\source\BranchTest\Main>hg status
M readme.txt
C:\source\BranchTest\Main>hg up default
merging readme.txt
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
C:\source\BranchTest\Main>
Notice the automatic merge because I didn't commit the change to readme.txt. Mercurial doesn't warn me that this will happen.
Any suggestions?
Use hg up -c (lower-case 'c'). This will check your working directory before updating.
You can make this the default in your hgrc file.

Named previously unnamed branch

It seems naming a previously unnamed branch doesn't really work out. It creates a nasty multiple heads problem that I can't find a solution for.
Here is the workflow...
UserA starts working on feature that they expect to be small, so they just start working(off the default branch). The change turns out to be a large project and will need multiple contributors. So UserA issues... hg branch "Feature1" and continues working, committing locally s needed.
UserA then pulls down the changes from the central repo so he can push.
At this point, why does hg heads return 3 heads? It shows 2 for default and 1 for Feature1. The first head for default is the latest change by another user on the branch(irrelevant). The second default head is the commit prior to the hg branch "Feature1" commit.
The central repository has rules enforced so that only 1 head per branch is allowed, so forcing a push isn't an option. The repo doesn't want multiple heads on the default branch.
UserA should be able to push these changes so that other users can see the Feature1 branch and help out. I can't seem to find a way to "correct" this. I don't think I can re-write the branch of the initial commits for the feature, before it was a named branch.
I know the initial changes before the named branch are technically on the default branch, but does that mean they will be heads until that Feature1 branch is merged?
I have found a solution without have to re-clone and merge changes in. I prefer this method mainly for historical purposes as I think it's valuable information on what happened with the feature (aka it started small and then was re-thought to be larger etc..)
In my example, UserA should update to the unwanted head on default and close that branch of default, as it is unwanted. This will leave 2 heads one for default and one for Feature1 as expected.
hg update -r X // X is the rev of the unwanted head.
hg commit --close-branch -m "Moved to Named Branch Feature1, cleaning up initial work"
Then update to the Feature1 branch, push and continue working.
Another workflow is almost the same except the UserA decided to push Feature1 for others to help and default has not been moved forward by anyone else. The local repo only has 2 heads and the user could push, but UserA does NOT want to just push as the tip of default would now be the changeset that really "belongs" to Feature1.
UserA should update to the latest, unwanted changeset of default. Then revert the default back to the revision before UserA starting working.
hg update default
hg revert -r Y // Y is the changeset before UserA started working on the feature
hg commit -m "Reverting changes that now exist in Feature1 branch"
Then update to the Feature1 branch, push and continue working.
The reason you're seeing two heads on the default branch in the local repo is because, after the most recent common ancestor, the changesets in the central repo have nothing in common with the changesets in the local repo.
To solve your problem:
Create a new local clone of the central repo at whatever revision you want (it will probably be easier if you use the most recent common ancestor).
hg clone -r common_ancestor central local2
Export the changes from the first local repo. Note the colon after first_local_change to get all the changes in that repo.
cd local1
hg export -r first_local_change: > ../local1.patch
Go to the new local repository, create the feature branch to import the changes into, then import them:
cd ../local2
hg branch feature
hg import ../local1.patch
hg import has an option to use the branch information in the patch file, but it's disabled by default.
At this point, you can continue using the new local repo in the original one's place. Also, I would double check to make sure that everything is as it should be in the new repo.
We found this to be a very big problem with our team (doing branch-per-feature) and ultimately stopped the hgweb.cgi script working (HTTP 414 Request too Long).
from hg help heads: hg heads with no args will show branch heads, which by definition are changesets that have no children on the same branch. hg heads --topo should give you result you need in this case.
Don't go via the central repository. Just have your developers pull from each other.