Merge on push?
Jesse Glick
jesse.glick at sun.com
Thu Jun 12 19:28:49 CDT 2008
Roman Kennke wrote:
> I'd like to propose an extension to the push command. I imagine an
> option --merge [...] which makes push try a merge on the remote side
> if necessary [...and] then try to perform a non-interactive merge and
> commit on the remote repository, when the push would create an
> additional head. This should fail when the changes touch files that
> have been touched by other changesets since their 'branch-point'.
Something like this would be really, really valuable. I can concur that
the need to explicitly pull and merge before pushing, even when your
changes are unrelated to anything else that has been done remotely, is
the single biggest reason for annoyance with Mercurial (compared to CVS)
in the team I work on.
I think your proposal is sensible. Its main drawback that I can see is
that it would require support on the server as well as the client (i.e.
a wire protocol change).
I have also been thinking about an extension command which would
essentially do
loop:
hg push
if success:
exit 0
else:
hg fetch
if files merged (even w/o conflict) or anything else unusual:
exit 1
This would I think be relatively easy to implement. Call it 'hg synch'
perhaps: when successful it means your local and remote repos should be
identical. You could imagine some refinements to let you push and fetch
only the active named branch, etc. Unlike using CVS/SVN, you still have
a full record of what the developer originally committed vs. what was
merged.
'hg synch' would force you to pull and update remote changes even if you
would rather not do so just yet, unlike push --merge, although you could
always use 'hg up <older>' to go back if you wanted to. In my experience
it is unusual to not want to get the latest upstream stuff anyway; if
nothing else, your chance of future merge conflicts goes down the newer
your local repo is. (Under CVS I would occasionally hear a developer
working on a small corner of the product pipe up out of the blue and ask
about a broken source tree. Further questioning would reveal that the
developer had not updated other parts of the source tree in months!)
'hg push --merge' could be significantly faster than 'hg synch' because
doing a merge forces inodes for the whole working copy and parts of the
repository to be loaded into memory caches. A server processing --merge
requests would be doing automated merges constantly and keeping
everything in cache, whereas a developer running synch would likely do
so infrequently and interspersed with other operations (builds, email,
...) which would flush the Hg working copy out of the cache. This is an
especially important consideration for a big repository that most people
only work on small portions of at a time, since a developer can 'hg di'
and 'hg ci' just one subdir fairly quickly but repository-wide
operations may be many times slower.
'hg push --merge' would make it possible to push some changes while
there will still uncommitted modifications elsewhere in the tree, which
could be valuable, whereas it is hard to see how synch could relax
fetch's requirement that the working copy be a clean checkout of tip.
> there is a chance that this results in a broken tree even when there
> are no overlapping changes, but experience with more traditional
> RCSes [...] shows that such cases are very rare in a reasonable
> structured project.
I would second this. At least on the project I work on - with something
on the order of 1 MLOC over 80k files and >100 developers - "hard" merge
conflicts (<<< === >>>) are unusual, nonconflicting merges are in many
cases fine straight from diff3's output without additional fixups, and
build breakages caused by merging nonoverlapping changesets are
definitely rare.
Locally validating every merge is out of the question: just a clean
build and basic smoke test can take upwards of an hour, not to mention
more advanced tests, some of which require a special environment to be
set up. Even an unusually patient developer doing such validation of a
merge would almost certainly find that a new merge was needed
afterwards, since you can expect a new changeset to be arriving in the
central repository every few minutes on average during peak hours. It is
much more practical on such a project to let a continuous builder find
the occasional problem for you.
The best setup is (arguably) a branch per developer which gets
independently tested and incrementally merged with other stuff by an
automated server process. This puts a lot of burden of complexity and
performance on a server, however, and may be overkill for many projects.
More information about the Mercurial
mailing list