1

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.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
codecompleting
  • 9,251
  • 13
  • 61
  • 102

5 Answers5

2

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 <mg@aragost.com>
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 <mg@aragost.com>
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.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
  • I am only referring to merged files that were not actually modified by me and required manual merging of any sort i.e. merged files are not modified at all. – codecompleting Jan 30 '12 at 21:39
  • I was also talking about files that merged cleanly — files that were not touched in the merge commit. There are *still* two possible diffs for such a file (against first or second parent) and Mercurial simply shows the diff against the first parent by default. That way a clean merge can look "big" in Mercurial. That does not mean that Mercurial stores the big patch: the `hg diff` output is *computed* on demand, not stored on disk. I hope that helps a bit? – Martin Geisler Jan 30 '12 at 22:05
1

If you did not touch the files that have been modified on the remote, then git won't show them as conflicts and you won't have to merge them. So no it won't show as if you touched those files if you haven't.

Also, if you don't want that the merge commit show in your history at all, you can use the --rebase option when pulling from a remote (see man git-pull).

Quentin Casasnovas
  • 1,079
  • 5
  • 10
  • Please correct me if I'm wrong, but using `--squash` wont hide the merge commits. It will rewrite your local history so that you don't **have** any merge commits in the first place, right? – Martin Geisler Jan 27 '12 at 21:16
  • You are totally right sorry for the mistake, I meant to talk about `--rebase` like Bill Door. I answered too quickly :) Have edited my answer. – Quentin Casasnovas Jan 28 '12 at 11:30
1

It's smart enough to know. Your commits are separate from merged commits.

smparkes
  • 13,807
  • 4
  • 36
  • 61
1

Git will not show those in a patch view. This means that you merged them because you had to, but your non-merge commits will show no changes to those files. In fact, git log -p which will show the commits and the patches for each, will not show the merge unless there were conflicts.

Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
1

This answer has been substantially revised after a detailed discussion with @LaurensHolst.


You have a choice of including merge commits or not. The default for git is to include merge commits. You can also set pull to use rebase which will create a linear history without merge commits.

Remote branches can be set to rebase rather than merge:

git config branch.<branch-name>.rebase true

git can set this up automatically using

git config [--global] branch.autosetuprebase always

Using rebase for merge commits causes local commits to be placed after remote commits with no extra commit required. This provides a linear version of the history. git allows you to choose which history you prefer.

A similar answer and explanation can be found at Git pull results in extraneous “Merge branch” messages in commit log.

Community
  • 1
  • 1
Bill Door
  • 18,272
  • 3
  • 32
  • 37
  • 1
    -1 because the answer is littered with incorrect statements, particularly “cause the history to be incorrect”, “should be set up” and “the correct logical location”. There is nothing ‘incorrect’ about history with merges, and if it were it wouldn’t be the default git behaviour. – Laurens Holst Jan 23 '12 at 09:55
  • 1
    I did not explain well why the history is incorrect. I've explained this in other posts and should have linked to them. Merge is the git default due to the history of git. Changing defaults such as merging, would be confusing and difficult for existing users of git. It has been the recommendation from many experienced git users that the defaults should be to rebase on pull and no fast-forward on merge. – Bill Door Jan 23 '12 at 16:11
  • For reference: http://stackoverflow.com/questions/8509396/git-pull-results-in-extraneous-merge-branch-messages-in-commit-log/8523117#8523117 – Bill Door Jan 23 '12 at 16:15
  • I fully agree with you Bill, it is much more easier to track changes this way. – Quentin Casasnovas Jan 23 '12 at 20:13
  • 1
    The answer isn’t updated, so I’m not removing the -1. For what it’s worth, your referenced answer isn’t any better. “Using rebase instead of merge on a pull provides the correct history to the shared repository. Using merge provides a false history.” — what? You don’t even provide rationale backing up this rather bold statement. There is no way a history with merges is ‘false’. It is an accurate depiction of the order in which things happened. What you’re doing by rebasing is actually *altering* history, to create a slightly more linear version of it. You sacrifice accuracy for aesthetics. – Laurens Holst Jan 24 '12 at 10:47
  • 2
    I have revised this answer to reflect a better understanding of merge commits. Thank you for pursuing this answer. – Bill Door Jan 26 '12 at 16:49
  • This answer does not really address whether or not Git will show a file as modified when you create a merge where the file was modified on the merged-in branch. Moreover, rebase works the same in Mercurial as in Git — use `hg pull --rebase` if you want to automatically rebase your own changes on top of the incoming changesets. – Martin Geisler Jan 27 '12 at 21:14