With Mercurial, if you try and push and there were commits made to the main repo, you are forced to pull and merge.
The problem is, when you go to commit your changes, the changeset you push contains files that you were forced to merge.
You didn't touch these files, yet the history shows you modifying them.
Does git have this same behaviour? Or is it smart enough to know you didn't modify those files so there is no point in having it your history.
With Mercurial, if you try and push and there were commits made to the main repo, you are forced to pull and merge.
Both Git and Mercurial work essentially the same here. When new commits have been made in the remote repo, git push
will abort with:
$ git push
To /home/mg/tmp/git/repo-1
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to '/home/mg/tmp/git/repo-1'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again. See the
'Note about fast-forwards' section of 'git push --help' for details.
Mercurial also aborts in this situation:
$ hg push
pushing to /home/mg/tmp/hg/repo-1
searching for changes
abort: push creates new remote head 436b0ce25d42!
(you should pull and merge or use push -f to force)
So far so good. In Git, you'll now run git pull
and in Mercurial you can run hg fetch
. This will retrieve and merge the new changesets and works the same in both systems.
The problem is, when you go to commit your changes, the changeset you push contains files that you were forced to merge.
You didn't touch these files, yet the history shows you modifying them.
I think you're misunderstanding what Mercurial is showing you. Both systems work on snapshots of the full repository so both systems will force you to push changes to files you didn't touch in the merge. A Git merge commit will also "contain" all the files that wasn't changed — they're referenced through the tree object referenced by the commit.
Because both systems use snapshots, the question of "who modified what?" only makes sense when you compare two snapshots. For a merge changeset, there are two interesting comparisons: against the first parent and against the second parent.
The difference between Mercurial and Git is that no patch is shown for a merge changeset:
$ git log -p -1
commit 8cdbbef1b6f0fc8e01997f6842b7f249d066a30c
Merge: b77058e e99e303
Author: Martin Geisler <[email protected]>
Date: Mon Jan 23 14:09:09 2012 +0100
Merge branch 'master' of /home/mg/tmp/git/repo-1
whereas Mercurial always shows a patch against the first parent:
$ hg log -p -l 1
changeset: 3:94060588f0a5
tag: tip
parent: 2:06d00ad5063b
parent: 1:436b0ce25d42
user: Martin Geisler <[email protected]>
date: Mon Jan 23 14:01:25 2012 +0100
summary: Automated merge with file:///home/mg/tmp/hg/repo-1
diff --git a/b b/b
new file mode 100644
--- /dev/null
+++ b/b
@@ -0,0 +1,1 @@
+b
This is shows that the file b
was not present in the first parent of the merge. In other words: it probably came from the second parent. Use hg diff -r "p2(3):3"
or hg diff -r "3^2:3"
to check this. In Git you'll use git diff "8cdbbef^2" 8cdbbef
to compare with the second parent.
Notice that both systems show the same for git log b
and hg log b
: the merge changeset is not in the log for the file unless the file was actually modified as part of the merge changeset. Files are typically modified in merge changesets because conflicts need to be resolved before the merge is committed.