Managing long lived named branches in Mercurial - mercurial

So I'm using mercurial for a project of mine, I'm the only developer.
I usually use the default branch for actual developing, I use some short lived branches for new-features, and that's fine: I create them, write the new feature and if it works good enough, I merge that branch in the default branch and never use it again.
But I'd like to write documentation in a different branch, since I don't really want to "pollute" the default branch with docs commits.
After I have written enough documentation for the stuff I have in the default branch I merge the docs branch in the main one. BUT after a while I'd like to use the docs branch again, and I have to pull the changes from the main one, or create another new branch.
What's the best workflow to deal with this? Is my approach entirely wrong?

Placing documents in source control is a little bit strange. If the documents are binary (.doc/.docx/.xlsx), Hg will not be able to merge them. If you're storing .html, .xml, or some plain text format then it will do a slightly better job. There are a few open source systems that will allow you to use Hg and provide separate document management (Redmine, for one)
Assuming you've just merged docs into default you can continue using the docs branch by doing this:
> hg update docs # update to the docs branch
> hg merge default # merge default into docs branch
(do some work)
> hg commit -m "adding new things to docs branch"
(merge into default when ready)
By merging default into docs, you're making sure that docs has all changes that existed on default. Performing a subsequent commit on docs will effectively allow you to continue working on that branch. Another way to say this is that merging is directional in Hg - if you want docs to be up to date with default, you've got to perform that merge explicitly.

To start using the docs branch again from a child of your merge with the original docs branch, simply change your working copy to the branch and commit to it.
If you have changes on the docs branch then you need to merge before you can commit.

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?)

Remove branches in Mercurial but keep changes?

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.)

Overwriting branch with default in 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.

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.

Can I checkout & commit to several Mercurial hg branches at once?

I've forked a project from the internet, and I want to write some new features. I want to write several orthogonal features at the same time, (eg. debug helpers, new feature X, new feature Y), and have the code for all of them in my current directory, but when I commit, I want to be able to say "these files go to branch 'debug'", "those files go to branch 'feature X'", etc. Where these are branches in the 'hg branches' sense.
The reason for this is the project upstream may not want to merge my debug helpers or hacked bug fixes, but I certainly want to use them whilst developing my features.
Effectively, I just want to apply the changes in those files to the branch, but keep several branches checked out & merged to my current working directory.
Is this possible? Perhaps there's some hg extension to do this?
Thanks!
Look at mercurial queues (MQ) for things like debug helpers or local hacks. Very useful for patches that you only want locally and may want to apply to any revision/branch.
Doing the same thing with branches becomes tedious IMHO as you have to be very careful to do the changes for debug and features on different branches, and then merge them in to a local, throwaway branch in order to run anything. You can end up with lots of changesets on the feature branch that leave the tree in a broken state because you can only test after you commit.
I don't fully understand why you'd you would want to do things that way. If your features are orthogonal, you can work on them independently until they are ready to be merged. That is exactly what branches are for after all!
But to answer your question: you could commit on a branch and then, as a matter of workflow, always up to default and merge it in. That would keep the default branch as the sum of the other features. You would need to update to the feature branch before you commit, though and that could get tedious.
The other option for post-facto determining which branch you want to commit to is to use the rebase extension. In this case, you'd commit your changes and then do hg rebase -d targetBranch.
I don't recommend using history revisions as part of your standard workflow, though. That smells to me.