How to restrict "-f" option while making hg push - mercurial

Is there any option to restrict a user to use hg push -f? Because it will remove intermediate commits by other users.

First of all, doing hg push -f cannot remove intermediate commits. Mercurial is built around an append-only history model and you cannot delete stuff from a server by pushing to it.
When a user does hg push -f, then he tells Mercurial to go ahead with the push even though it creates new remote heads. To prevent this, you need a hook on the server that forbids more than a single head. There are listed several such hooks here.
With Mercurial 1.6, it is no longer necessary to use -f when you push a new named branch. You should instead use hg push --new-branch. This is safer since it only allows the creation of new branches, not the creation of multiple remote heads.

Related

Mercurial: enforce "hg pull -u" before "hg commit"

I have in some cases a need to enforce that Mercurial-users have run hg pull -u before any hg commit can be allowed, i.e., hg pull will mean that the incoming queue is empty — and furthermore I also want that the person is using the head version of the branch.
How can I set up such a restriction?
(I am fully aware that this goes against parts of the DVCS design core)
You could ask your developers to install
[hooks]
pre-commit = hg pull -u
in their config files (it should probably be installed in the per-repository .hg/hgrc file since this workflow is repository specific).
This makes Mercurial a little Subversion-like: your developers will only have one outstanding changeset. But note as soon as someone pushes to the server, hg pull -u cannot update to the new branch tip since it will cross branches (topological branches) to do so. So a proper merge will be needed at that point (or a rebase, see hg pull --rebase).
Normally mercurial will NOT let you push an open head to the server without using the -f flag (force). You can write a hook to pull automatically but that can not be enforced server side due to the server not knowing what you have. There is an article on mercurial's website about this scenario:
https://www.mercurial-scm.org/wiki/TipsAndTricks?highlight=%28heads%29#Prevent_a_push_that_would_create_multiple_heads
As Adam says, perhaps what you really need to do is prevent multiple heads (per branch). This is what we do, using the 'forbid_2head' hook from Netbeans (linked from here https://www.mercurial-scm.org/wiki/TipsAndTricks#Prevent_a_push_that_would_create_multiple_heads)
The result is that the hook prevents any push that creates multiple heads on a branch (so one on the anonymous/default branch plus one each on named branches). This effectively forces a pull before commit because you have to pull, get the two heads locally, then merge or rebase to remove it.
note, the hook is on the server/master repo

Allow pushing multiple heads without -f?

For our project, we have two repositories: Main and Automated Testing. In the Testing repository, we allow multiple heads, so one commonly used "hg push -f" when pushing to the Testing repository. But using "push -f" is a bad habit, as one may accidentally use this for other repositories, too.
So I am looking for some configuration option, preferably on the repository side, which allows pushing multiple heads without using -f -- does Mercurial provide such an option?
(I know that I can install a hook to an repository to prevent it being the target of a forced push, but I would like to get rid of the need to use -f altogether.)
A simple solution (unfortunately needed per-client) is to setup an alias in your ~/.hgrc as follows:
[alias]
testboardpush = push -f ssh://example.com/testboard
You can then use hg testboardpush to push your commits to the automated testing repository, instead of getting into the bad habbit of using push -f.
If you have multiple repositories with multiple testboard locations, you can instead setup your alias inside your ~/.hgrc file as follows:
[alias]
testboardpush = push -f testboard
And then for each HG repository's .hg/hgrc file, have the lines:
[paths]
testboard = ssh://example.com/testboard
With this setup, typing hg testboardpush will always push to the correct place for the particular HG repository you are currently working in (or fail with an error if the path hasn't been setup).
Unfortunately, it does not appear you can do this from the server side without a custom version of HG; in particular, my reading of the push implementation in the localrepo.py file of the HG sources indicates it unconditionally checks for new heads using discovery.checkheads (and aborts) unless the force argument is set.

Can I mark a branch as 'not going to push'?

I use named branches in Mercurial.
In doing so I have created one branch called playground where I can try out various wacky experiments. I never intend to merge this branch into any others and I never want to push it to our main repository.
Since creating it, every time I do a push I am told I have added a new branch and I have to use the --new-branch flag. At this point hg push -b default (or whatever branch I'm pushing) works fine but it's annoying. Is there any way to suppress that message by letting Hg know that I am not interested in pushing that branch ever?
Starting with Mercurial 2.1 (released in February 2012), you can mark your changesets secret to keep them from being pushed to another repository. You use the new hg phase command to do this:
$ hg phase --force --secret .
This mark the current working directory parent revision (.) as being in the secret phase. Secret changesets are local to your repository: they wont be pushed or pulled. Pushing now looks like this:
$ hg push
pushing to /home/mg/tmp/repo
searching for changes
no changes to push but 2 secret changesets
There is no equivalent mechanism in older versions of Mercurial. There your best bet is to create a local clone for the changesets you don't want to push.
Update:
Mercurial 2.1 introduced the hg phase command which allows users to control what change sets are exchanged with remote repositories. #MartinGeisler answer to this question details this method.
Original Answer:
If you want to create a local branch of your code you have a couple options. You can hg clone the repository which will locally create a branch of the entire repository in your filesystem. The other alternative is you can try to use a Mercurial extension like LocalbranchExtension.
There are many ways to branch in Mercurial without using a named branch. Just find a method that suits your needs.
Further reading: http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
In addition to the excellent answer above concerning phases, you can also specify 'default-path' (in the [paths] section of your .hgrc) to refer to the local repository:
[paths]
default = ...
default-push = .
This will cause all outgoing changesets to be compared to the specified repository. In this case, comparing outgoing changesets in your local repository TO your local repository results in nothing to push.
You can still pull/update/merge from the main repository, but no push will ever send anything back to that main repository.
If you work on multiple machines/repositories, you can set one up as described above, and configure the others to specify the 'default' path to point to the server that pushes to itself. In this way, the other machines can push/pull to your local central repository, and these changesets will never escape your carefully configured collection of repositories.

creating a new branch in mercurial: "abort: push creates new remote head"

I am trying to do something very simple: create a new branch. But I messed up. Where did I make the mistake, and how do I fix it?
I am the only user of Mercurial. I had revision 54 committed and pushed to remote repository. I wanted to create a branch based on revision 53, so I updated my local copy to revision 53, made changes, and committed (ignoring the warning about "it's not the head"). Then when I am trying to push to remote repository, it says
abort: push creates new remote head
Maybe I needed to tell Mercurial that I want to create a new branch? If so, how and at what point?
Thanks!
You tell Mercurial that it can go ahead with
$ hg push --force
You need to force it since multiple (unnamed) heads are normally discouraged. The problem with them is that people that clone the repository wont know which one to use. But since you're the only user you can just go ahead and push.
The alternative is to use a named branch (with hg branch) and then you'll use
$ hg push --new-branch
to allow the creation of a new branch on the remote. Named branches have the advantage that they make it easy to distinguish the two branches. They have the disadvantage that they are permanent. Permanent means that you cannot remove the branch name from the changesets on the branch — the name is literally baked directly into the changeset.
Bookmarks provide a way to have non-permanent branch names, see hg help bookmarks.
Another reason for this error: probably there are some UNMERGED changes form the central repo in your default branch.
hg up default
hg merge
hg ci -m "Merge"
hg pus
I did this. Using TortoiseHg ... this is how I fixed it:
In settings, I enabled the Strip extension then right clicked the branch i did not want, Modified History - strip. If you have pushed, then it needs to be stripped from all other repositories, including workmates who have pulled your unwanted branch.
An alternative is to merge the unwanted branch into your main branch, but do not take any of the changes from that branch - I am unsure of how that mechanism works.

Why is a --new-branch flag needed?

Isn't this a normal workflow?
[default] $ hg branch foo
[foo] $ [... some commits ...]
[foo] $ hg update default
[default] $ hg merge foo
[default] $ hg commit -m "merged foo"
[default] $ hg push
abort: push creates new remote branches: foo!
(use 'hg push --new-branch' to create new remote branches)
What is the otherwise ideal way to do branching → merging → pushing?
The mercurial philosophy is that you should not be pushing things which make it harder for other users of the repository. Relevant to this question is that multiple heads make it harder for other developers, since they would then need to merge your changes. Hence by default pushing new heads is rejected by the server. The -f option was used to allow pushing new heads.
However, the case of pushing a new named branch is quite different conceptually to pushing a new head on the same branch. Many workflows (including mine) do each task on a separate named branch. The --new-branch option allows you to push up a new branch, whilst rejecting new heads on existing branches. It's also different (as you've seen) because it's needed even if the new branch does not create a new head (due to merging).
My personal feeling is that new branches should be allowed by default, but the mercurial developers prefer otherwise.
This is a one-time thing. Just use --new-branch the first time you push a (new) branch. It's normal.
Every other push can remain as hg push, no --new-branch flag.
That depends on what the branch is used for.
Is it used internally in your own repository clone it would be appropriate to commit your changes to your branch as long as you develop on your feature decoupled from the others.
After you finished you'll have to invest some work to keep track on the efforts of other people who may have done changes on the default branch
Then you should update in their changes, resolve the conflicts commit your part.
Switch over to default and make your feature part of the default branch by merging in your changes. Now you can close your branch, commit the stuff and push it!