views:

97

answers:

4

That is, in Mercurial, if Peter cloned from me by

hg clone c:\mycode e:\code

into his e:\code

let's say there is a file code.txt and it contains the text the code is 7

Now, when I change it to the code is 11 and hg commit, then he can get my code using hg pull and hg update. Now his version says the code is 11

But if I decide the change was wrong and hg rollback, then my repository should have the 7 version, while the working directory should have the 11 version.

So when Peter does an hg pull and hg update, he should be sync'ed up to my current repository, which is the 7, but I found that it is not the case -- he still gets the 11 version. Why is that? Can he get the rolled back code (the 7)? Does Git behave the same way too?

Update: I thought commit affects the repository the same way that rollback affects the repository -- commit and rollback are both DB transaction words... and now we are saying commit affects the repository but rollback doesn't? What's the rule here?

Update 2: At this point, if Mary does an

hg clone c:\mycode e:\marycode

at this point, she actually gets the 7 version. So, Mary gets 7. Peter gets 11. And they are both "up to date"? What is this?

A: 

Peter won't see any uncommitted changes. Your rollback only affected your working directory. Do a commit and then peter can pull/update to see your rollback.

Patrick Steele
`hg rollback` actually does remove the entire original commit (it works on transactions, not the working directory) - but it only removes it locally.
Amber
please see Update and Update 2 above...
動靜能量
+3  A: 

hg pull pulls down new changesets from a remote repository - but it doesn't delete ones that don't exist remotely. Otherwise, doing a pull would erase any of your own work that hadn't already be pushed to the remote. Thus, pull doesn't get rid of a changeset that was pulled, and then the remote rolled it back, because there's no new changeset to grab.

If you make a new commit which has the rolled-back state, then that commit will get pulled down and Peter will see it.

In other words, what you need to do is first use hg revert -r <previous-rev> to check out an earlier version that you want to change back to, then use hg commit to create a new commit based on the older revision, and then have people pull that commit.

Amber
please see Update and Update 2 above...
動靜能量
how do i do a "commit" which has the rolled back state? my working directory has the "11" version and if i commit, the repo will get the "11" version. If I do a hg revert, then my working directory will get the "7" version. and then if I hg commit, it will say nothing to commit.
動靜能量
What you want to do is create a new commit with the 7 version - generally this means applying a reverse diff of the 7->11 change, so that it becomes a 11->7 change, and then committing the results of applying that. You should be able to do this by using `hg revert` to revert to an earlier commit than the current head, and then you can `hg commit`.
Amber
+1  A: 

I do not use Mercurial, but since you asked how Git behaves in this regard ...

In Git, there are two ways to undo: revert and reset.

The revert command patches the existing code so that it resembles a previous state: the history will record the change from the original "the code is 7" to "the code is 11" and then the patch to "the code is 7".

On the other hand, a reset is an actual "rewinding" of the history. If this command is used, the change to "the code is 11" is removed from the history tree, and the state of the repository is as if the change never happened.

Thus, while revert and reset might both result in your repository being apparently restored to the same state that existed before the change to "the code is 11", they are very different operations conceptually. A revert actually creates new history, while a reset removes existing history.

In practical terms, if a revert operation is carried out on a repository, and Peter pulls from it, then, indeed, his repository, too, will record the change back to "the code is 7". On the other hand, if a reset operation is carried out on a repository, then, from Peter's repo POV, the repository that he is pulling from is actually in an older state than his, and nothing will happen. Which is why with Git, you should only use reset if nobody has pulled your changes (or you have not pushed to a remote). In all other circumstances, you should use revert.

Jeet
Regarding pulling a branch that has been reset: “nothing will happen” is maybe a bit misleading.If non-fast-forward updates are allowed (a `+` refspec, or `-f`/`--force` is used), the local “remote tracking branch” will be reset (made to match the reset remote branch). But, any local branches that track the remote branch will not be reset (even if the update was done with a pull). From a history perspective this leaves the local branch ahead of its upstream branch (even if no commits were ever made locally!).If non-fast-forward updates are not allowed, then the fetch/pull will be rejected.
Chris Johnsen
Chris,Good point. I guess I was focused on the state of the current HEAD and the working tree. But you are absolutely right: with a fast forward pull from a repo that has been <code>reset</code> to a previous state, while the working tree and HEAD of the local repo will not change, the local repo's "view" of the remote repo (i.e., its "remote tracking branch") will be updated to reflect the "reset" operation of the remote repo.
Jeet
A: 

hg pull is not a full sync. All hg pull remote does is copy every changeset in remote that is not in the local repository to the local repository. All rollback does is delete the most recent commit (or more generally, DB operation, but that's almost always a commit) - it does not record any kind of "commit has been deleted" message. The commit is gone, forever, unless there's another repository that has it. To record its reversal, so other repositories get the reversal, you need a reversing commit (this can be created via hg backout). Then you have yet another commit which reverses the effect of the previous one.

So, when you do the rollback and Peter pulls again, you don't have any new changesets for Peter to pull. In fact, you have one less changeset than Peter. So, if Peter pushed to you, you would get the 11 revision again.

In the clone scenario, they are both up to date (as they both contain the 7 revision), but Peter has an additional changeset. It's as if Peter created the 11 change on his own and signed your name to it.

rollback cannot be used safely or meaningfully across cross-repository communication. For that you need backout. For this reason, I always prefer to push to a published location and have people pull from there rather than have them pull directly from my working repository so that I know when rollback is safe and when it isn't (for the few times when I need it).

Michael E