Overwriting branch with default in Mercurial - mercurial

Let say I had a feature branch called feature_x that was worked on, then changesets cherry-picked and transplanted to default, then the branch was closed. Not the best flow, but it's Mercurial, so there is no way of changing the history.
Now I'm going to work again on the feature X, and I feel reusing feature_x branch would be least confusing. However, if I reopen that branch and merge default to it, I've got two problems. First merge conflicts, second changes that were modified in that branch, but never merged into default. So what I'd like to have is clean slate, branch feature_x, but with exact copy of what's currently in the default. Is there a cleaner way of doing that, than creating new branch which will shadow the name?

I think your best bet is to start a new branch off of the current tip of default called feature_x2 or feature_y and leave the past in the past.
But here are some other options:
Is the old feature_x branch confined locally to your repo only or was it pushed? If the former, you could hg strip it and start the branch again at the current default.
If the feature_x name is really, really important, you could do the merge default into it using the internal merge tools and force it to reflect the default branch exactly by doing
hg merge -r default --tool internal:other
Or you could just commit a (file system) copy of default on top of the tip of branch_x. Then you could continue on that branch along your merry way.
I don't know if 2. or 3. will cause strange merge issues down the road. I would test to see if the merge back over to default (or another graft?) could cause issues later.

Related

Split out a branch into a new repo

I have a mercurial repo that now effectively contains two repos.
At some point in the past, a branch was split off from default (let's call it default-other).
Both default and default-other now have a lot of commits and there are no plans to ever merge default-other back to default. Some commits have been grafted from default to default-other.
Now, I want to create a new repo from the default-other branch while retaining the full history. i.e. a repo that contains
all commits from default up to the point where the default-other branch was created
all commits from default-other
all branches that have been branched off from default-other
no commits from default after default-other was branched off
Optimally, I would like to use different strategies for different branches. Some branches are release branches which must be kept, whereas others are feature branches which I would like to fold into the new default.
I tried using the convert extension, but I cannot figure out how to correctly set up the branch map.
I think you can do almost everything you stated using hg strip. Something like this:
Clone the original repo to a new repo
hg up null to remove anything from the working directory (probably quicker to work with it like that)
Identify all branches (named or anonymous) and changesets that you want to remove. To be precise, what you want is the changeset ID of each commit and its descendants that should be removed.
hg strip -r 12345678890 for each of those commits. This removes the commit & all its descendants (potentially including merges).
If needed, you can do this procedure twice, but the second time strip the orthogonal set of changesets (those which pertain to default-other but not to default).
That said, there are a few reasons you might still want to use hg convert:
There are files in the repo that are not relevant. For instance, if default branch had some old stuff which has nothing to do with default-other. You could use convert to eradicate history of such files.
You want default and default-other to look like they were always the same branch. You can use convert to rename one or both of them. (branchmap)
You want to ensure the new repo(s) cannot be pushed/pulled with the original which could mess up all your well-laid plans. By "converting" the entire repo, IIRC all the changeset IDs will be renewed and the repo will not look like a relative of the original.
My advice would be to work in stages:
Clone the original to clone1
Use strip to get as much done as you can
Make clone2 from clone1
Run convert task #1
Make clone3 from clone2
Run convert task #2
etc.
I recommend not batching many different convert things together - run them in small increments. This may seem like it will take longer, but its much easier to get right this way.
Ultimately you can remove all the intermediate clones, but through experience I found this was the most productive & safest way to make big structural changes.
Just use described in wiki format of branchmap. In your case it will be easy plain
default-other default
...
renamed-child1 default
renamed-child2 default
...
Addition
Because Convert extension can't stop conversion of condition "before ", only "after " (see --rev option), you must to prepare repository for conversion before convert process (clone into new intermediate repo only subset or original changesets without default, only default-other and descendants?)

Why do I sometimes but not always end up with two heads on a branch in Mecurial?

I sometimes but not always end up with two heads on my default branch. The sequence of events is something like:
hg pull
hg update -C default
hg branch mybranch
hg merge default //merge in default
hg commit -m"merged mybranch into default"
hg heads -default //shows 2 heads
hg push --branch default //won't let ne. create 2 heads
The 'rival' head appears to be a changeset committed to default earlier in the day.
What I don't understand is why this happens sometimes and not other times.
The explanation I am usually offered is that the other guy pushed a change after I did a pull (my first action in the list above). But I think this happens in other cases e.g. when he pushed his changeset before I started.
I would have thought that when I pull default with his commit I get default with one head. My merge/commit should just create a new head after that. Why does it create a second head?
First of all, this is a totally normal situation. It's not a problem, or an error, or something to be avoided -- it's how a DVCS works.
In brief: you get two heads whenever two people start working from the same commit and do different things. It doesn't matter if they do it in their own (named) branch (as you're doing above) or on default. Once you merge your work back to default and someone else has done work on default you've got two heads and someone has to merge. It's just how things are.
Before you push do a hg pull and then a hg merge and you'll integrate your work with yours, by creating a new merge commit, with two parents -- your work and their work -- and then you push and you'll not see that warning.
Incidentally, you might want to check out the bookmarks feature. It's better suited for per-feature branches like you appear to be doing above than the named branches you're using, but it in no way saves you from having to deal with multiple heads.
check state of repository immediately after pull (pull can bring new head in default for you) with hg heads
hg branch without commit do nothing (you haven't mybranch)
Even if you'll create mybranch and merge it with default's tip (according to your syntax), it will not eliminate 2-nd head in default

Mercurial: abandoning multiple, contiguous commits, on the `default` branch

Requirement
I'd like to abandon a line of development on the default branch, winding back to a revision from about 15 change sets back, and have default proceed from there.
My setup
This is a solo development project with one other guy testing infrequently. I push (frequently) to bitbucket for backups and sharing with the tester. Several of the changes I want to abandon are pushed to BitBucket.
Options
Any of these would be fineā€¦
The abandoned change sets to continue to exist in the repo. It would be nice if they could live on their own branch abandoned-experiment-1, say, that I can close and ignore, but this would need them to move on to a retrospectively created branch (which seems like it would be an awesome feature?).
Some kind of merge to happen where I add a new revision to default that is the rollback to the revision I want to continue from.
The change sets to be destroyed, but I suspect there's no way to achieve that without replacing the BitBucket repo and my tester's repo, which I'm not keen on.
I'm not too sure how to evaluate which options are possible, which is best, or whether there are other, better options. I'm also not sure how to actually proceed with the repo update!
Thank you.
You do have several options (Note that I'm assuming that you are dispensing with all changes in the 15 or so revisions and not trying to keep small bits of them):
Easiest is kinda #2: You can close anonymous branches just like named branches; Tag the tip first with abandoned-development if you wish; hg update to the point you wish to continue from; and continue to code as normal. (You may need to create the new head for new development before you can close the old one. I haven't tested it yet.)
Regarding #3: Based on my cursory read, it does appear that bitbucket has a strip command. If you (both locally and on bitbucket) and your tester strip the offending changesets, you can carry on your merry way and pretend like they never existed.
Achieving #1: If you are definitely set on getting them to a named branch, you could strip them at the remote repos and then hg rebase them onto a new branch locally and then close that branch.
Personally, I try not to mess with history when I can avoid it, so I'd go with the easiest.
Mercurial now has (yet experimental) support for changeset evolution. That is you are able to abandon or rebase already pushed changesets. Internally this works by hiding obsolete changesets (i.e. practically nothing is stripped, only new replacement revisions are added to the history, that is why it works across multiple clones).
To extend #Edward's suggestions, you could also update to the last good revision, continue to commit from there and then merge in the head of the bad changesets using a null-merge:
hg up <good-revision>
... work ... commit ...
hg merge <head-of-bad-revisions>
hg revert --all -r .
hg commit -m 'null-merge of abandoned changesets'
This may be what you thought of as option 2.

How to revert to the future?

I started a named branch several months ago which I then abandoned. Now I want to "restart" it. Specifically, I want to bring it up to the latest version of default and start working on it again.
I tried updating to the branch, and then reverting it to default,
hg revert -a -r default
But when I swap back and forth between this branch and the actual default I see 112 files have changed, so clearly they are not the same.
I ended up closing the branch, updating to default, force-switching back to my named branch again, and then force pushed (because it creates a new head).
Now my named branch is the same as default, but I have this short dead branch in my history now.
My questions are:
What was hg reverting to default doing? Was it reverting to the closest default ancestor rather than the tip of default? Even when I tried reverting to the tip via an explicit changeset, the two branches ended up different.
What is the "proper" way to do this?
What was hg reverting to default doing?
For your (really bad )syntax:
Using the -r/--rev or -d/--date options, revert the given files or directories to their states as of a specific revision
i.e to the state of latest ancestor in default branch for all files in repo
I see 112 files have changed, so clearly they are not the same
Wrong assumption
Because revert does not change the working directory parents, this will cause these files to appear modified.
I.e you must commit this modified Working Directory and diff (for testing) heads of branches after it only
What is the "proper" way to do this?
Proper ways is
If you want to save branch-specific changes and only update with latest changes
Update to the head of abandoned branch
Merge default branch to your branch
Resolve all (if any) conflicts
Commit mergeset
If you want to have empty branch only and remove all changes from it
Backout all changesets from branch
Commit backout-changeset
Merge default to branch

Get a bugfix from default to a feature branch in Mercurial

How do I get a bugfix I made on the default branch into a named branch in mercurial?
I recently started work on a new feature so thought I'd do this work in a branch (which I've not really done before) so I could keep the changes out of the main default branch until I've finished working on them and the feature is ready to deploy. The idea being that I could update to the default branch and apply any bugfixes as needed.
Now I want to get the bugfix into my named branch. The tip (rev 739) has the change I want to incorporate into the BoardSummary branch. I know I could merge but I don't want to bring my BoardSummary changes into the default branch.
I looked at the mercurial: apply a bugfix change from stable named branch to dev branch answer but it didn't make sense to me.
Edit: I'm with it up to "Then you discover that changeset 2 introduced a bug", in my case I went back to 732 fixed the bug and committed (onto the default). The idea being that the fix is in place before I branched. But now how do I get that fix into 738 without merging the 2 branches together? It looks like the bug is actually fixed in 739 - so isn't in the BoardSummary branch yet. This seems to be what the 2nd tree shows in the answer but the 3rd diagram is explained with "you would instead do this" - I don't understand that bit
Evidently, your default branch contains only one changeset not present in the BoardSummary branch. You should merge default into BoardSummary, and not the other way round. This way, BoardSummary will have the fix, and none of the BoardSummary will be in default.
To summarize:
$ hg up BoardSummary
$ hg merge default
$ hg commit -m "Merge the fix for #247"
An explanation
There are a number of kinds of branches which can be employed. The most common are:
stable (production) branches for maintaining the released versions,
default (master, trunk) branch, which contains more or less stable development activity,
feature branches, which are not mature enough to be merged into trunk.
The main idea here is that it is always safe to merge from stable to default, and from default to feature. This means that in terms of changesets, any stable branch is a subset of default, and default is a subset of feature branches.
For instance, you're reworking your data access level in a feature branch new-dal (major feature). At the same time, you've added a couple of new reports in default (minor features), and found and fixed a bug in a 1.0-stable. Well, just merge the branches going from the oldest to the newest (1.0-stable -> default -> new-dal), and that's all.
This is explained very well on the Mercurial wiki: Standard Branching: Release branches.
Your case
In your case, BoardSummary is clearly a feature branch, so you can merge default into it without any hesitation. The opposite should only be done if you're ready to integrate the new feature into default.
At first you should rollback/remove the commit 739 (which is your fix) from the history. Then you commit the fix on r732. This will create a new head and should be the new r739. Your history should look like this:
r329
|
--r232-----default branch
\
\
feature branch
Now you merge your new head (r329) into the default and the feature branch. Now the history should look like the last tree in the linked answer.