views:

730

answers:

5

This question assumes there's a "blessed" central repository that members of a team

  1. clone from
  2. push to when they have contributions that they want other team members to see
  3. pull from when they want to see other people's contributions.
  4. etc.

If so, I would assume hg update is not analogous to svn update (why would there be two commands that do exactly the same thing?). From what I can gather, hg update more like svn revert. Is that correct?

Update:

My understanding of rebase is largely based on the "A common case" section on this page:

http://mercurial.selenic.com/wiki/RebaseProject

+7  A: 

Not exactly.

hg pull grabs the revisions from the other repository and adds them to the locally available revisions in your clone of the repository, but does not update your working copy - only your repository (which, for DCVS like hg/git/etc is not the same thing as a working copy).

hg update updates your actual working copy to the latest revision in your local repository.

This differs from Subversion because in svn, there is no such thing as your "local repository" - the only repository is the one on the server; you only have a working copy locally. Hence why update is only a single command, as opposed to Mercurial's pull and then update.

The equivalent to svn update for Mercurial would be hg pull --update, which is equivalent to doing hg pull and then hg update one after another.

An end-to-end workflow for DCVS with a "central" repo looks something like this:

  1. A does hg commit on some changes.
  2. A does hg push to push them the central repository.
  3. B does hg pull to pull them from the central repository into their own clone.
  4. B does hg update to update their working copy to reflect the changes pulled into their clone.

In systems without a central repo, it would instead look something like this:

  1. A does hg commit on some changes.
  2. B, who has cloned A's repo, wants those changes, and thus does an hg pull directly from A's repo.
  3. B uses hg update to update their working copy to the changes.

Also, the equivalent to svn revert is hg revert. :)

Amber
I know hg pull --rebase is equivalent to hg pull followed by hg rebase. What does rebase do? Will hg pull --update work if I have made commits to a branch that has commits that the hg pull is pulling down? Seems like that's what rebase is for, which is why I think of hg pull --rebase as being analogous to svn update: it takes changes from a central repo, merges them in to my working copy, and changes the parent of my working copy (conflicts may need to be resolved prior to commit).
allyourcode
`rebase` does a little more than just that - it actually reworks the commit history to move your "private" commits that happened before you pulled to be after any "public" commits that were newly pulled in. Thus, instead of having to commit a "merged" changeset, your local repo will appear to have already had all of the newly pulled changesets before you ever made your own private commits (hence the name "rebase" - you change what you were basing your private commits on).
Amber
A graphical representation of what I'm talking about can be seen at http://mercurial.selenic.com/wiki/RebaseProject under the "A common case" heading.
Amber
Essentially, all of this stems from the fact that Subversion only ever has a single unified commit structure, whereas Mercurial and other DCVS systems can have multiple de-synchronized commit structures that can be manipulated relative to one another. Subversion has no concept of rebasing because you can never commit anything except on top of the current HEAD.
Amber
Good answer, but you completely ignored merges, which are also done by `svn update` and need to be done in an extra step in Mercurial.
Konrad Rudolph
Thanks, Dav. I'm starting to get it now. I'm just a little confused about hg update. Suppose I have something like what's pictured in this diagram: http://mercurial.selenic.com/wiki/UnderstandingMercurial#Revisions.2C_Changesets.2C_Heads.2C_and_Tip and only revisions 0-3 exist. I pulled down rev 3. The parent of my working copy is rev 2, and has modifications. If I do hg update at this point, will I be creating rev 4? Am I allowed to have modifications in my working copy (relative to rev 2)?
allyourcode
If you do an `hg update` at that point, Mercurial will not change anything in your working directory - because you're already on a "branch" away from rev 3 (and whoever was working on rev 3 would be on their own "branch" away from your rev 2). To create rev 4, you'd do an `hg merge` to pull that branched off revision back into your commit flow. Essentially, Mercurial *automatically* creates "branches" whenever there are divergent commit paths, and then recombines those branches when you tell it to, either via `merge` or `rebase`.
Amber
Note: it may sound like this is a hassle (having branches created willy-nilly), but in fact, the changeset-oriented nature of DCVS means that most merges are automated and hassle-free, so branching and merging often isn't the kind of problem it is with CVS/SVN.
Amber
+2  A: 
hg pull --update

would be an equivalent of svn update

As described in this SO question

The hg command push and pull move changes between repositories and update and commit moves changes between your working copy and your local repository.

So in a DVCS, you have 2 notions instead of one:

  • local repo (pull/push)
  • working directory (which is the only local representation of the "tip" of a repo with SVN)
VonC
Does hg pull --update handle when I've made commits to a branch that has commits in the remote repo that I'm pulling down with hg pull? More details in my comment to Dav.
allyourcode
+1  A: 

Here's a great beginners guide to mercurial http://hginit.com/. Should explain most things clearly. Starting off with "Do not try and apply svn knowledge to distributed vcs's"!

Decado
This answer does not answer my specific question. Even if not every hg command must have an svn analog, you can still explain what hg pull --rebase and hg update are about.
allyourcode
Okay, Assume you've made some local changes to your repository. L1' and L2' in your referenced document.Rather than thinking of it as hg pull --rebase, you may be better to think of it as the two steps hg pull and hg rebase.When you do a hg pull from the repository you "sort off" branch the code. It's still applied initially against the revision you checked out originally. The rebase itself then applies your two local change sets after the last of the changesets that came from the pull.Does that help?
Decado
The things is though, that you don't normally need to do this with dvcs's. Hence the initial comment (sorry if it came across as being flipent).If you read through and understand the initially linked document you will realise you don't need to do the rebase. You can, in most circumstances, check in as long as you've resolved any conflicts without rebasing.Dav's comment above gives a pretty good summary.
Decado
+2  A: 

The command hg pull --rebase isn't exactly analogous to svn update, but the result can be the same.

In Subversion, if you update your working copy you get the latest changes in the repository merged in with any local changes. So the files in your repository are up to date but you might still have uncommitted changes.

In Mercurial, hg pull --rebase, will get the latest changes from the 'central repository' (or whatever repository you're pulling from) to update your repository then shuffle along your local commits. You'll still need an hg update to make your working copy the same as your local repository.

Nick Pierpoint
Thanks, Nick. Most of what you said makes sense to me. The only part I didn't really follow was your last sentence. Suppose you're in the situation pictured in the second diagram in the "A common case" section on this page: http://mercurial.selenic.com/wiki/RebaseProject . At that point, the parent of your working copy is L2. Are you saying that the parent of my working copy will still be L2, even after doing hg rebase? Are you saying I need to do hg update to a) merge changes in R1 and R2 into my working copy, and b) make L2' the parent of my working copy?
allyourcode
I'm just saying that there's a distinction between your working copy and your local repository. After the pull the "local repository" (everything in the hidden .hg directory) has been updated but your working copy (the actual files you're working with) is unaffected. The final "update" will change your working copy to reflect your local repository.
Nick Pierpoint
Note that the "rebase" is working on changes committed to your local repository - it isn't working on uncommitted files in your working copy (which is different to svn which doesn't have a local repository).
Nick Pierpoint
The more I write the less clear I become. Sorry about that. :)
Nick Pierpoint
+5  A: 

As others have indicated, almost but not quite. In order of decreasing similarity to svn update (and increasing compliance with general DVCS, and specifically Mercurial, best practices[1]):

  1. hg pull -u (or hg pull followed by hg update) with your changes uncommitted and no committed changes since your last pull. This is as close to svn update as you can get, but is pretty bad DVCS practice. One of the niceties of DVCS is that you can commit your changes before trying to merge them with others, and thus have a backup version to rollback and retry a failed merge, and this practice gives that up. Don't do it.

  2. hg pull --rebase after committing your changes. This pulls the upstream changes, re-applies your changes on top of them, and lets you push your changes back as a linear history. The end result will look very similar to a Subversion revision history, but you get the DVCS benefit of committing before merging. I do not know how the safety of this mode of operation compares between Mercurial and Git, though; in Git, pre-rebase versions of your changes will still be there until you do a git gc, but Mercurial doesn't have an explicit gc safety net.

  3. hg pull followed by hg merge with your changes already committed to your local copy. This is the traditional Mercurial practice for doing the functional analog of svn update, notwithstanding footnote 1 below. This results in a nonlinear version history, but all changes are tracked and inspectable.

That said, there is much wisdom in thinking of Mercurial (and other DVCSes) on their own terms, and not trying to translate from Subversion/CVS-style thinking.

  1. If you are not of the rewrite-history-to-keep-it-linear school of thought. If you are, then rebase is probably preferable to update. The Mercurial community tends to favor update.
Michael E
This is a great answer. It doesn't just try to explain hg. It really tries to explain it in comparison to svn, which I specifically asked for in my question. It not only explains the differences, which others strongly emphasized, it explains the similarities. This answer also tries to cover all the related hg commands that I'm confused about and doesn't narrowly focus on hg pull --rebase.
allyourcode
The one follow up question I had was this: it seems like hg update would only be useful if you've never made any commits (as in case 1), because after that, you'll be working off a branch that no one else knows about. Again, this assumes a work flow involving a blessed central repo that members of a team push to and pull from.
allyourcode
@allyourcode If you have local changes, yes, you need merge rather than update. However, update is also how you switch revisions or named branches, and is useful once your changes are pushed upstream. If you need to merge and try to update, update will fail, so I usually use update first and merge if it fails.
Michael E
I see. Seems weird that hg update can be used to switch branches, but I guess a branch is just another rev, right?
allyourcode
@allyourcode Mercurial named branches seem slightly more complicated than that, but in the update context, they are just another way to identify what revision to update (switch/checkout) to.
Michael E
I disagree. #2 `hg pull --rebase` is much more like `svn update`, in that it does the merge in the background instead of as its own distinct step. That means that some of your commit(s) will not actually be your code; some of your commit(s) will be you merging the changes you just pulled. In terms of safety, #1 is much safer, as it does not require rewriting history, and makes the merge explicit. That way, if anything breaks in the merge, you can just revert and try it again.
tghw
Also, I'm curious why you think #1 is bad practice? That's the way DVCSs are intended to work. Rebasing is just a hack that people use to reduce anonymous branching and merging, but it subverts the intended workflow and benefits of a DVCS. If anything, I would say rebasing is bad practice, since you can lose code and it is not representative of what actually happened.
tghw
@tghw #1 is a bad practice because your changes are not yet committed when you try to merge - the "merge" is done against uncommitted changes in the working copy, and if something goes wrong you can quickly be hosed. 'hg merge' (#3) is the safest and is Mercurial best-practice, because of the history rewriting that you mention with rebase. I think Mercurial saves a backup on rebase, so it's safer than updating with uncommitted changes. Also, if you rebase properly, you only rebase your changes, not others'.
Michael E