How to "push" manually?

Martin Geisler mg at daimi.au.dk
Mon Apr 6 07:47:25 CDT 2009


skip at pobox.com writes:

>     Martin> If you have SSH access to the machine you can install
>     Martin> Mercurial yourself. I'll use the 'make local' Makefile
>     Martin> target and then simply symlink the hg executable to a
>     Martin> directory in your PATH on the server.
>
>     Martin> Then push to ssh://webserver.net/path/to/your/clone.
>
> I do have ssh access and mercurial is installed there (it's an Ubuntu
> machine with /usr/bin/hg).

Great!

>  I think I might have originally created the repo using ssh://... I
> just tried the following push commands:
>
>     hg push ssh://www.smontanaro.net/public_html/python/lockfile
>     hg push ssh://www.smontanaro.net/home/skip/public_html/python/lockfile
>     hg push ssh://www.smontanaro.net//home/skip/public_html/python/lockfile
>
> The first and last failed with
>
>     pushing to ssh://...whatever...
>     searching for changes
>     abort: push creates new remote heads!
>     (did you forget to merge? use push -f to force)
>
> The second failed with
>
>     remote: abort: There is no Mercurial repository here (.hg not
>     found)! abort: no suitable response from remote hg!

Right -- after "ssh://www.smontanaro.net/" comes a path *relative to
your home directory* to the repository. But I think you figured that
out.

> It seems either the first or third one should work but doesn't for
> some mystifying reason. What is a "remote head"? I don't think I
> forgot to merge. Was I supposed to merge something?

Others have already given lots of good advice, but let me try to make
some of the basic concepts clear:

* Like in Subversion, history consists of a number of commits. They're
  called changesets in Mercurial.

* Subversion requires a strict linear ordering of the commits and
  gives nice linear revision numbers to them. So revision N has only
  one child revision, rN+1.

  This is simple, but it requires a central server to make sure that
  everybody agrees on the revision numbers.

* Mercurial generalizes this by letting each changeset have multiple
  children. If I work alone and make commits I'll make

    C1 --> C2 --> C3

  by making three commits. The commit C3 with no children is a "head".
  It is also the newest changeset in the repository -- called "tip".

  If I shared C1 with you and you started your work from that, your
  commits will build a repository like this:

    C1 --> C2' --> C3'

  Here C3' is a head in your repository and I don't know anything
  about C2' and C3' yet.

* If I pull from you, or you push to me, the two repositories are
  compared. By default, all missing changesets are transferred. This
  is all there is to push/pull: compare two graphs of changesets and
  transfer the missing ones.

  After a pull from you my repository will look like this:

         /-> C2 --> C3
    C1 -<
         \-> C2' --> C3'

  Here C1 has two child changesets, and the repository has two heads
  since the development has diverged.

  The changeset C3' will be the new tip since it is the newest
  changeset in the repository. Note that tip is always a head, but a
  head need not be the tip.

* Having two heads suggest that someone should merge them -- otherwise
  the changes from one will never be combined with the changed made in
  the other head.

  When merging with 'hg merge' the task is to figure out the canonical
  way to combine the changesets. If the changes do not overlap this is
  usually trivial, otherwise you have to do a three-way merge. The
  merge must be committed and this creates a changeset which explains
  to the world how you think the two heads should be combined:

         /-> C2 --> C3   -\
    C1 -<                  >-> M
         \-> C2' --> C3' -/

  Note that the merge changeset M has two parents.

  If you do not merge C3 and C3' and try to push you get the 'new
  remote head' message and push aborts. It aborts since it is a little
  "impolite" to leave the job of merging to someone else -- he who
  created the two heads by pulling in some code should also normally
  do the merging.

> That seems to have worked (I see changes to lockfile.py which I
> checked in earlier today). While that might be a workaround, I'm
> still left not understanding how to sync the web server's repo with
> the repo on my laptop. This seems like it ought to be a one-liner,
> but it's obviously not.

When you've merged any heads you should be able to do 'hg push' to
transport the new changesets to your server.

> In general I still find myself overwhelmed by all the possible ways
> to shoot myself in the foot (ummm... make that "all the possible
> workflows"). This is made more complicated by the fact that there
> are several different dVCS's competing for mind share and they all
> seem to do things differently. If you're not immersed in the
> technology all the time (I definitely am not) it seems impossible to
> figure out what to do in any given situation. CVS and Subversion are
> *so* much easier to do simple things with: checkout, update, commit,
> diff, all quite predictable in their behavior. More limited to be
> sure, but certainly more straightforward for many common cases.

It helped me a lot to think in terms of the changeset graph. Remember
that:

  * "hg commit" adds a new node. The parent changesets of the new node
    is given by "hg parents"

  * "hg push" and "hg pull" transfer nodes in the graph between two
    repositories.

  * "hg update" updates the working copy to reflect a given node in
    the history graph. This also changes the parent changeset of the
    next commit, see "hg parents".

> Is there not a simple Mercurial cheat sheet somewhere?

There are some here:

http://www.selenic.com/mercurial/wiki/index.cgi/QuickReferenceCardsAndCheatSheets

-- 
Martin Geisler

VIFF (Virtual Ideal Functionality Framework) brings easy and efficient
SMPC (Secure Multiparty Computation) to Python. See: http://viff.dk/.


More information about the Mercurial mailing list