For those of you that use Mercurial with the MQ extension:
This is the second time I accidentally submit changes to the central repository (hg push) instead of applying a patch to my working directory (hg qpush).
I think this is very unfortunate, because it is a very simple error to make and has very severe consequences (the least having to do a hg backout and an extra hg push for each submitted change in order to generate a new commit that "undoes" the las one to the central repository, but the history becomes convoluted and unpleasant.
My goal is to configure some alias or something in my environment in orden to make hg push harder to do by accident.
Do you have any suggestions? I was thinking something like:
[alias]
push= <-- how to NOP the push command??
pushtoserver=push
As this is a completely subjective question, this goes as community wiki.
thanks!
some vague ideas:
you could remove the default push location from your repo
you could write a "did you mean qpush? yes, no" pre-push hook
This hook (bash command line) asks for confirmation before pushing changes to the remote (tested with mercurial 1.4):
[hooks]
preoutgoing.confirm = read -p 'Are you sure you want to push to remote? (y/n): '; echo $REPLY | grep -q 'y'
you could alias push to qpush and alias pushtoserver to push (i think this works but can't try it now)
Put the following in your .hgrc:
[alias]
pushtoserver = push
push = 'Did you mean qpush or pushtoserver?'
Works like this:
$ hg push
alias 'push' resolves to unknown command 'Did you mean qpush or pushtoserver?'
$ hg pushtoserver
abort: repository default-push not found!
See also the alias section of the hgrc manpage.
Related
I'm using TortoiseHg with an SVN repository using the hgsubversion extension.
I like to use hg pull --rebase when I pull, to mirror what SVN does on svn update. Because I'm using hgsubversion, I will need to rebase anyway before I push, so I may as well do it in one step.
Additionally, hg push will automatically do a rebase internally, there is no way around that.
My difficulty is that hg rebase will refuse to work if I have any uncommitted changes. So to push or pull from SVN I always need to hg shelve first and then remember to do hg unshelve after. This can get really annoying and I always forget.
Ideally I'd like to tell TortoiseHg to do this for me automatically, but I'd settle for a command-line alias. I tried putting an alias like svnpull = !hg shelve && hg pull --rebase && hg unshelve in my config as suggested here but I get an error "user: abort: response expected" instead of being asked for my password. What can I do to avoid manually shelve/unshelve steps every time I interact with the central repository?
I can't actually commit my changes locally and just avoid pushing the local change, because hgsubversion doesn't respect the secret phase and hgsubversion doesn't support designating a revision to push. So unfortunately none of the answers to this similar question will work for me. And anyway I'd need manual steps to arrange for my "local only" changeset to always be on the tip.
The solution was to use repository hooks. I added this to my .hg/hgrc config file:
[hooks]
pre-pull = hg shelve
post-pull = hg unshelve
pre-push = hg shelve
post-push = hg unshelve
Don't enter password manually, automate it with keyring (questionable on Windows) or using [auth] section of in project's .hgrc
Sample from my local hg-repo for remote SVN-backend
[auth]
assembla.prefix = https://subversion.assembla.com
assembla.username = USER
assembla.password = PASSWORD
and entering password not needed anymore
Another idea: you haven't push immediatelly your WIP, yes? You have only to have it on top of "other" work, true? You can in this case commit, rebase, and continue to work with the same tip, modifying it with commit --amend
I'm looking for the Mercurial equivalent of git commit --allow-empty for testing purposes.
Can't be done. There doesn't have to be a change to a source file, but you have to have changes something, be it file permissions, branch name, tag, or something.
You say "for testing purposes". If that's the case I usually just use
echo another line >> README ; hg commit -m 'added another line'
I can hit up-arrow enter on that plenty fast.
I think the best solution I've found is:
touch foo
hg add foo
hg commit -m 'Empty commit'
hg rm foo
hg commit --amend
Works with MQ. Make a MQ changeset with some dummy change, then revert the change and refresh (hg qref) the patch. Voila.
I think I "get" most of Mecurial, but one thing that bothers me is, when I do a pull to grab changes made by others, in other files, how does it make any sense for me to have to supply a commit message? Those users already had an opportunity to supply a commit message when they pushed the corresponding changeset to "the" server.
As far as I know, there's no way to push just the part of the tree where I made my changes, so when others make a change to unrelated files in an unrelated part of the tree, and I have a changeset that needs to be pushed, I have to "pull", "merge", and then "commit", where I supply a message describing THEIR changes, changes that have already in theory been described by their commit message(s).
I'm probably not understanding something. Is there a better way to handle the situation where I:
~$ ## Make some changes
~$ hg ci -m 'blah'
~$ ## Attempt to "push" and get "abort: push creates new remote head"
~$ hg pull
~$ hg merge # <- totally unrelated files updated here
~$ hg ci -m "SOMEONE ELSE'S FILES CHANGED....!"
~$ hg push
??
You must to understand value of merge and your actions on merge better
Commit message of changeset (conventionally) is "Short description of what is done by this changeset". For mergeset "done" is "Merge changes from ..." and commit messages from second parent's branch of this mergeset will inform, that really (which changes) was merged
The merge is the change you're commenting on, not the changesets you pulled. So in your example:
~$ ## Make some changes
~$ hg ci -m 'blah'
~$ ## Attempt to "push" and get "abort: push creates new remote head"
~$ hg pull
~$ hg merge
~$ hg ci -m "Merged with changes on the Flibble-floo server"
~$ hg push
Remember you could be pulling directly from other developers or from different branches. The message should describe the merge you've done.
~$ hg pull bob
~$ hg merge
~$ hg ci -m "Merged with Bob's changes"
It is important to understand what a merge is. Your commit is merging the two divergent branches, not committing that user's code, and thus a more suitable commit message will involve the word "merge".
Now I will show you a still better way.
In this case, where you have never pushed the code that you are trying to push, it is probably more suitable to rebase. Your case is exactly covered inside that document, in A common case.
~$ ## Make some changes
~$ hg ci -m 'blah'
~$ ## Attempt to "push" and get "abort: push creates new remote head"
~$ hg pull --rebase # Or alternately, `hg pull; hg rebase`
~$ hg push
Then you end up with linear history, which is typically nicer to work with (when feasible).
Remember that, as noted, the extension needs to be enabled first in your configuration:
[extensions]
rebase =
I'm trying to get the hg-git extension working under Windows and after hours of fiddling, I finally seem to have it working. However, nothing shows up in my git repository even though the output of hg push reads:
importing Hg objects into Git
creating and sending data
github::refs/heads/master => GIT:8d946209
[command completed successfully Wed Oct 20 15:26:47 2010]
Try issuing the command hg bookmark -f master
(use -f to force an existing bookmark to move)
Then try pushing again.
This works because Hg-Git pushes your bookmarks up to the Git server as branches and will pull Git branches down and set them up as bookmarks. (from the official README.md)
And it seems that just after I asked this, I made a trivial change. This was picked up and pushed. So it seems that you have to wait until you've made a new commit in order for hg-git to pick it up.
I had chosen to 'Initialize this repository with a README'. This meant I ended up with two heads, which I couldn't hg merge because one had a bookmark.
To get pushing working, I had to:
configure hg-git and github remote as per https://blog.glyphobet.net/essay/2029
pull from github and update
force the merge (checking which id to use with hg heads),
commit the merge
add a trivial change to a file (add a space char to the end),
commit, then
move the bookmark to the tip
push to my configured github remote
This ended up with commands as follows (substituting in <x> sections)
hg pull github
hg update
hg merge <revision-id-of-incoming-git-version>
hg addremove
hg commit -m 'merged with github'
# make some trivial change to a file - eg add a space where it doesn't cause harm
hg add <changed-file>
hg commit -m 'trivial change'
hg bookmark -f master
hg push github
make sure you pick the remote revision for the merge above - if you don't it doesn't work!
Being very familiar with the subversion workflow and that fact that 99.9% of the time my computer is connected to the internet, I don't like doing 'hg ci' and 'hg push' separately.
I remember bzr had a 'checkout' command that would bind subsequent 'commit' commands to automatically commit directly to the server ('push').
Does mercurial have something similar to this?
PS: Writing a shell script or alias that runs 'hg ci $* && hg push' would be the last thing I'd do.
You could add a hook to run push after a successful commit.
EDIT: I just tried it out and it seems to work fine. I added the following to the .hg/hgrc file of the repository I wanted to activate automatic pushing for:
[hooks]
commit.autopush = hg push
EDIT 2: Also, you don't have to worry about something like this:
You're in a repository that you don't want to automatically push.
You use hg -R ~/another-repo-that-autopushes commit to commit in a different repo that does automatically push.
Will the hg push hook end up pushing the changes in the current directory instead of the one you're committing in?
No, it won't. According to the page I linked:
An executable hook is always run with its current directory set to a repository's root directory.
It's an edge case, but Mercurial handles it correctly.