2

I've been using Mercurial for a few weeks now and don't understand why when Mercurial comes to merge committed changes from two repositories it does it in the working copy?

Surely the merge could happen without the use of the working copy removing the need to shelf changes etc.

It just doesn't seem necessary to involve the working copy. Am I missing something?

user451126
  • 65
  • 1
  • 5
  • 2
    In general, **ALL** changes happen to the working copy before you commit. Merge is no different. What do you mean by merging "from two repositories" and "need to shelf changes"? Could you give a workflow example? – Geoffrey Zheng Sep 17 '10 at 23:58
  • I've been using the following workflow http://blogs.sun.com/tor/entry/mercurial_tip_checking_in_regularlywhich to me isolates the merging of repositories fro the merging of changes to your – user451126 Sep 18 '10 at 06:33
  • Try again. I've been using the following workflow http://blogs.sun.com/tor/entry/mercurial_tip_checking_in_regularly which to me isolates the merging of repositories from the merging of changes into your working copy (benefit no need to shelve). Unless there are conflicts when I pull into what Tor calls the sync repo, with fetch on the process is automatic. My question is why do I need this extra repository? Couldn't mercurial merge committed changes somewhere other than the working copy? – user451126 Sep 18 '10 at 06:54

3 Answers3

3

I didn't write Mercurial, so I can't say why they did it that way, but here are some of the positive results of that decision:

  • you can look over the results of the merge before you commit it
  • you can edit the results of the merge before you commit it
  • you're encouraged to commit frequently

If you really want to do a merge and have stuff in your working dir that you can't bear to commit don't bother with shelve just do:

cd ..
hg clone myrepo myrepo-mergeclone
hg -R myrepo-mergeclone merge
hg -R myrepo-mergeclone push myrepo

On the same file system clone is near instantaneous and uses hardlinks under the covers so it takes up almost no space past that of the temporary working copy.

Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
  • My only concern: you probably want to test the merge if there's significant conflict, but testing a different repository can require a lot of setup, and if you test in `myrepo` you're back to square 1. – Geoffrey Zheng Sep 19 '10 at 02:52
  • Geoffrey, yeah, keep a symlink named CURRENT that I point to my repo-of-the-moment, which I uses in all my PATH and test configurations, but I recognize that'd easier with some toolchains than with others. – Ry4an Brase Sep 20 '10 at 02:15
3

There is only one working copy per repository, by definition:

The working directory is the top-level directory in a repository, in which the plain versions of files are available to read, edit and build.

Unless your file system descends from Schrödinger's cat, you cannot have two versions of the same file at the same time, thus you cannot have two working copies.

Nevertheless, it's indeed theoretically possible to use something like a ephemeral clone (per @Ry4an) to act as the working copy of a merge, resolve conflicts there, commit, then make it disappear. You'd get a beautiful merge changeset and your intact working copy.

I can think of several ways to achieve this:

  1. Petition hg team to do it in core
  2. Write an extension to implement the ephemeral clone or some other way
  3. Shelve with a temporary changeset
  4. Shelve with MQ

I would strongly recommend #4, as I would for almost all workflow scenarios. It took me a few good days to grok MQ, but once I did I've never had to turn back.

In an MQ workflow, your working copy is always the current patch. So for the merge situation you would do:

  1. hg qrefresh
  2. hg qpop -a
  3. hg update -r<merge first parent>
  4. hg merge [-r<merge second parent>]
  5. hg commit
  6. hg update qparent
  7. hg qgo <working copy patch>

You don't have to pop all patches in #2. I always do that whenever I need to deal with real changesets to avoid mixing them up with patches.

Solution #3 is really the same as #4, since a patch is a temporary changeset by definition (this is really the only thing you need for understanding MQ). It's just different commands:

  1. hg commit -A
  2. hg update -r<merge first parent>
  3. hg merge [-r<merge second parent>]
  4. hg commit
  5. hg update -r<working copy changeset parent>
  6. hg revert -a -r<working copy changeset>
  7. hg strip <working copy changeset>

If you want to keep the working copy changeset and continue to commit, simply update to it in #5.

From your question it seems like you already know #4 but don't like shelving. I think shelving is good because merging is a fundamentally different task than coding (changing working copy), and shelving makes the context switch explicit and safe.

Geoffrey Zheng
  • 6,562
  • 2
  • 38
  • 47
  • "Will I get 1k rep for quoting Joel the Apostle?"... Maybe not. Just a +1 for a complete answer ;) – VonC Sep 19 '10 at 09:15
  • Good answer and you're right I don't like shelving. Shelving was fine until I started using Mercurial in a busy development environment. Since then I've been getting a lot of unshelve aborts as files in the shelve have changed as part of the merge. Meaning what I think is called rebasing of the diff files (read edit of the shelve file in .hg). I assume MQ would have similar problems as its patch based? Think the answer may be to simply clone for individual features. – user451126 Sep 20 '10 at 15:10
  • One-clone-per-feature is a viable workflow with its own problems (see, e.g. my question http://stackoverflow.com/questions/3719019/how-to-manage-concurrent-development-with-mercurial on hg workflows). If you reapply a patch on a new base and there's conflict, MQ saves the conflicting hunk and you'll need to resolve it. I think it's necessary pain because you want to know and resolve this kind of conflict. BTW `hg rebase` can work with applied patches directly and bring up merge tool to resolve conflicts. – Geoffrey Zheng Sep 20 '10 at 15:30
  • At what point do you ask another question in StackOverflow? I've looked very briefly at hg rebase. I've seen a number of people mysteriously mention that it is dangerous but I'm not sure of exactly how. – user451126 Sep 20 '10 at 16:09
  • Feel free to ask another question. People will kill it if they don't like it :) `rebase` is usually considered dangerous because it changes history, but it's totally legit to use with patches since patches are not permanent. – Geoffrey Zheng Sep 20 '10 at 16:17
1

As mentioned in the chapter "Merge" of HgInit:

The merge command, hg merge, took the two heads and combined them.
Then it left the result in my working directory.
It did not commit it. That gives me a chance to check that the merge is correct.

Such check can include conflicts in merge, that the user has to review:

alt text

In KDiff3, you see four panes

  • The top left is the original file.
  • Top center shows Rose her version.
  • Top right shows Rose my version.
  • The bottom pane is an editor where Rose constructs a merged file with the conflicts resolved.

So you need a working directory (a view for the merge) in order to resolve fully a merge.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250