Mercurial hooks: How can I detect second head in a particular push? - mercurial

I'm using server-side (remote) hooks to prevent specific kind of pushes.
Among other thing, I want to ban pushes that are creating new heads in mercurial repository even if they were pushed with --force.
I can think only of one way to achieve this: just iterate through ancestors and fail on first ancestor that has two children.
This approach actually works, but I'll be very glad if someone can show me a more elegant way of achieving the same.

OK, so it turns out it's done much easier than I've anticipated. Basically all you need is to check for the number of head in the repo repo object, so:
if repo.heads() > 1:
return True

Related

Is restarting a branch a good idea?

In a software I develop I have a main stable branch (default or prod) from which I develop new ideas.
I believe that usual way to do that is to start a branch, work on it and either abandon it (leave it as it is, close it, delete it) or merge into the default one.
A lot of my development are small tests which I would be glad doing in a dev branch, which I would ultimately merge into default, then restart with new ideas in dev.
Are there major drawbacks with such an approach?
The main one I see is what to do in case of a "bad" idea which I would like to discard. I could leave the existing dev hanging, start a new dev branch and end up with several HEADs for one branch - which does not sound like a good idea (but objectively I dot know why).
In short: is restarting a branch, overall, a good idea and is having potentially multiple HEADs because of that a true problem?
I would describe your proposed course of action as having a non-linear dev branch, i.e., it may have unnamed heads that are never merged into the main line. (Repeatedly merging work from dev into default doesn't necessarily make it non-linear in this sense). Mercurial has no trouble managing configurations like this, so technically speaking it's not problematic.
But if you feel that this would make your history hard to navigate, you might want to use a richer set of branch names. A compromise solution would be to do all your experiments in dev, but use tags to distinguish and identify the different branch heads. I often do that when I put aside an idea (or abandon it for good).
There is no issue with having multiple heads at all. Besides you can close (thus in essence hide) old, abandoned heads, if you think they should vanish from plain sight.
On the contrary, I would start a separate head for each new idea or feature I code, so that I can follow different thoughts in parallel. It also allows to merge them into your main line separately.

Something like VSS labels in Mercurial?

What I would like to do is something like this:
When I deliver my code, I would like to label my part of the source with “delivered”.
If other developers follow the same convention, it should be possible to extract from the scm all the code labelled delivered.
When I deliver code again, it should be possible to move or replace the label delivered on my source.
What is the closest thing you can do in Mercurial, or what is the best convention to follow to keep track of code in specific states as described above?
(I haven’t actually done a lot of this in VSS, I might actually be mistaken about how it works)
Appendix 1:
I would like that we work in one branch as far as possible, commit and pull/push as much as possible. Then we need something like labels to keep track of code in a certain state.
It sounds like you might want named branches. Each developer can work on their own branch and merge their branch to a "delivered" branch when ready. When all the developers have merged their branches, the release can be given a final check and tagged.
If I understand this right, you want to label individual files in more than one revision. E.g. in revision 1 you label all files in /lib1/ as "delivered", and in revision 2 you label all files in /src/ as "delivered". Now if somebody comes along and tells hg to give him all the code that is "delivered", you want in /lib1/ the files from revision 1, and in /src/ the files from revision 2.
If this is what you want, it is not possible in hg (and for a good reason: it is considered bad practice). In such a scenario, you could perhaps split the single repo into 2 subrepos "lib1" and "src", versioning both separately. You can then register a certain combination of these 2 sub-repositories by means of a commit in the super-repository, followed by a tag "delivered" in the super-repository.
If you do not want something like this, I don't understand the purpose of labeling only a subset of files in a revision. In this case standard tagging is sufficient, as you can move public tags in Mercurial, anyway (and with history!).
The closest thing in Mercurial is Tag.

mercurial workflows when collaborating with people who make errors

I need to collaborate on a Mercurial repository (let's call it "foo") with some people who are novices at version control in general, Mercurial in particular.
I am trying to come up with a workflow that will enable us to use Mercurial without a lot of extra effort on either their end (confusion) or my end (cleanup).
My concern is that as novices I need to expect them to make errors, and I need to allow them to do so in a controlled way, otherwise they won't use the tool at all because they're too scared. But I don't want a bad change to pollute the repository unnecessarily.
I do not expect them to be able to merge properly or to use the mq extension. This is not
a matter of underestimating them, instead it is a realistic assessment given past experience with SVN and my own experience with Hg.
Which of the following approaches would make the most sense? Or if there's a better approach, what is it?
We have a repository foo-submit, read/writable by all, and a repository foo-trunk, readable by all but writable by admins. Users pull from foo-trunk, and push changes to foo-submit. Cleanup: If I find a good change, I let it through as is; if I find a bad change, I "bypass" it by merging with the previous version.
We have a repository foo-trunk readable by all, writable by admins. Each user is responsible for maintaining their own clone which is read-accessible to the rest of the team. When someone wants to push a change, they let me know and I pull it from their repository, with proper cleanup as necessary (same as in #1)
We have a repository foo-dev, read/writable by all, and a repository foo-trunk, readable by all but writable by admins. Users pull/push to foo-dev, and work in named branches if they need to do extensive development. I am responsible for performing merges and cleanup. The foo-trunk repository is merely for having a "clean" copy that has branches where the tip is always in a good state.
Good question, and one that I've never seen a great answer to.
That said, I like option 2. This is the "Pull Request" model used by the Linux Kernel and made popular by GitHub. It allows the admins to act as gatekeepers / reviewers, only allowing good change-sets to get past them when they're happy. If they decide a developer hasn't delivered something worthy, then the pull request is rejected (with reasons). Then the developer can go away, fix up their code / repo, and submit another pull request.
Running a server with something like RhodeCode on it can help keep on top of pull requests. As things grow you can have lower level gatekeepers that deal with subsystems, and higher level gatekeepers that deal with the whole project.
The bit I've never quite got my head around is what should happen to change-sets that are rejected, and that the developer decides to abandon rather than fix up and try again. They could be closed, but then could possibly appear by mistake as part of a future pull request. They'd be harmless, but possibly confusing. The alternative is stripping them, but that sounds like giving people tools they'll cut themselves on.
The other 2 options you give deserve a little comment.
1 is similar to 2. You're still doing a "Pull Request" type flow, but now you have server side branches which mirror the developer's clones. There's little difference and this is how a RhodeCode, GitHub, BitBucket server would let you work, except you don't have to go searching for changes. The server would tell you they're waiting for you to look at.
3 has the problem that everyone's changes are all merged together on foo-dev before you get to them. They would start becoming inter-dependent, and cherry-picking is going to be messy. You'd probably end up grafting change-sets on to foo-trunk which means you're creating new change-sets with new hashes. When the developers pull those they'll now have the change in two places; their original foo-dev version and your grafted foo-trunk version. This doesn't sound sustainable to me.
Best way i can think of if you don't want to use mq (understand with the least hassle for you) is to have your dev
create their own branch for the current feature being developped
merge it back to the main dev branch (or graft/transplant) when it's completed and validated
and then close the branch.
In the long term see for them to learn mq, it's not too hard to grasp.
3a - foo-dev has protected default branch (only some admins can push/merge-to this branch), users use named branches

Grouping a set of commits in Mercurial?

I'm working on a new feature branch. It's necessary to keep all the history, but for someone scouring over the history at a later date, much of it is over verbose.
For example I may have 5 commits taking through the steps of adding a new database table, its business logic, its validation and some experiments that I change my mind about etc etc. But for a co-developer all they might need to know is "this fixed bug X".
Is it possible to somehow group a set of commits, so that an overview is shown in the log but still being able to view all the history. Not only only my local repo, but the remote repo as well.
I'm guessing that I could have separate sub-branches and merge them as I go along. But I'll only know that I want to group a set of commit retrospectively. So I don't think that is a good route, as I'll have to keep going back and forth.
I can see that there is a group extension but it's unmaintained. And my experience with unmaintained plugins means that usually I'm going the wrong way about it and that there is a perhaps a better technique.
Is there any best practice around achieving this sort of thing?
For what it's worth, I think you're going down the correct route when you say you want to keep all of your history available. You could use the MQ extension to collapse your changesets into a single commit, but - although this would give you a 'clean' commit - you would lose all that juicy detail.
My way of handling this is to develop on a branch or in a separate clone, and when it's going into Production I describe the whole group of changes in the commit message of the merge, i.e. don't just use "Merge" for the commit message :).
I understand your point about only knowing if you need to group retrospectively, but I think as long as you have some rigour around your dev/test/release process then this shouldn't be too much of a limitation.
You want the collapse extension.

Mercurial: Concrete examples of issues using hg pull --rebase

I'm struggling to find the mercurial workflow that fits the way that we work.
I'm currently favouring a clone per feature but that is quite a change in mindset moving from Subversion. We'll also have issues with the current expense we have in setting up environments.
Using hg pull --rebase seems to give us more of a Subversion-like workflow but from reading around I'm wary of using it.
I think I understand the concepts and I can see that rewriting the history is not ideal but I can't seem to come up with any scenarios which I personally would consider unacceptable.
I'd like to know what are the 'worst' scenarios that hg pull --rebase could create either theoretical or from experience. I'd like concrete examples rather than views on whether you 'should' rewrite history. Not that I'm against people having opinions, just that there already seem to be a lot of them expressed on the internet without many examples to back them up ;)
The first thing new Mercurial converts need to learn is to get comfortable committing incomplete code. Subversion taught us that you shouldn't commit broken code. Now it's time to unlearn that habit. Committing frequently gives you a lot more flexibility in your workflow.
The main problem I see with hg pull --rebase is the ability to break a merge without any way to undo. The DVCS model is based on the idea of tracking history explicitly, and rebasing subverts that idea by saying that all of my changes came after all of your changes, even though we were really working on them at the same time. And because I don't know what your changes are (because I was basing my code off of earlier changesets) it's harder for me to know that my code, on top of yours, won't break something. You also lose the branching capabilities by rebasing, which is really the whole idea behind DVCSs.
Our workflow (which we've built an entire Mercurial hosting system around) is based on keeping multiple clones, or branch repositories, as we call them. Each dev or small team has their own branch repository, which is just a clone of the "central" repository. All of my new features and large bug fixes go into my personal branch repo. I can get that code peer reviewed, and once it's deemed ready, I can merge it into the central repo.
This gives me a few nice benefits. First, I won't be breaking the build, as all of my changes are in their own repo until they're "ready". Second, I can make another branch repo if I need to do a separate feature, or if I have something longer-running, like for the next major version. And third, I can easily get a change into the central repo if there's a bug that needs to be fixed quickly.
That said, there are a couple different ways you can use this workflow. The most simple, and the one I started with, is just keeping separate clones. So I'll have website-central, website-tghw, etc. It works well, especially since you can push and pull between them locally. More recently, I've started keeping multiple heads in the same repo, using the remotebranches extension to help manage them and hg nudge to keep from pushing everything at once.
Of course, some people don't like this workflow as much, usually because their Mercurial server makes it hard to make server-side clones. In that case, you can also look at using named branches to help keep your features straight. Unfortunately, they're not quite as flexible as Git branches (which is why we prefer branch repos) but they work well once you understand how to close branches, and why you can't really get rid of them once you start one.
This is getting a bit long, so I'll wrap it up by encouraging you to embrace the superior branching and merging that Mercurial provides (over SVN). There is definitely a learning curve, but once you get the hang of it, it really does make things easier.
From the question comments, your root issue is that you have developers working on several features/bug fixes/issues at one time and having uncommitted work in their working directory along with some completed work that is ready to be pushed back to the central repository.
There's a really nice exchange that covers the issue well and leads on to a number of ways forward.
http://thread.gmane.org/gmane.comp.version-control.mercurial.general/19704
There are ways you can get around keeping your uncommitted changes, e.g. by having a separate clone to handle merges, but my advice would be to embrace the distributed way of working and commit as often as you like - if you really feel the need you can combine the last few local commits into a single changeset (using MQ, for example) before pushing.