codecompleting
codecompleting

Reputation: 9611

mercurial and git, how do they handle a check-in when the file was modified

Imagine user#1 modifies file1, and user#2 also modifies file1. The changes do not require any manually merging.

User#1 has already checked in his changes and pushed them to a central repository. Now user#2 wants to push their changes in.

From what I have heard, Mercurial will force you to update your local copy before you push in the changes. And because of this, the changeset that you push makes it seems as though you modified the files of user#1 when in fact you didn't.

Is this correct?

Does Git do this differently?

Upvotes: 0

Views: 121

Answers (3)

Neil
Neil

Reputation: 55402

When working with a master repository in Mercurial, you have two options.

The typical workflow is to merge. This means that you commit your changes locally, then you pull the second person's change(s) into your clone, then you merge all of the changes into a merge changeset. You can then push both commits to the master repository.

EDITED as per Martin:

The other workflow is to rebase. There are three options here:

  1. Don't actually commit your work. Just pull the other user's changes into your tree, update (which will merge where necessary), then commit and push. Obviously this only works if you have one commit to push at a time.
  2. Mercurial queues. This is equivalent to temporarily unapplying your patches, pulling the latest work into your clone, then reapplying your patches and committing. However the patches are not applied intelligently and you may run into merge conflicts.
  3. Rebase extension. This is newer, and therefore smarter. For a single changeset it resembles a merge commit, but then it deletes your original commit, leaving the changeset with just the other user's changes as its parent. The rebase extension can even rebase your Mercurial queue for you.

Upvotes: 3

Bill Door
Bill Door

Reputation: 18926

The answer for git depends on your settings for git pull.

When user #2 goes to push, the push will fail because the shared repo has changed. User #2 will be required to pull before pushing.

By default git pull is a combination of git fetch and git merge. However, git pull can also be configured to be git fetch followed by git rebase.

git fetch updates the local representation of the remote repo. Git maintains this area for you automatically.

In the default mode, using git merge, git will merge the changes from the remote repo into to local repo. This makes it appear as if the changes for user #1 occurred after the changes for user #2. This may also create a so called merge commit.

In the rebase mode, any local changes to the branch are saved, the branch is updated from the remote representation, then the local changes are replayed on top of the branch. In this way, the changes for user #1 occur before the changes to user #2.

All of the information from @Kyralessa is correct concerning merge conflicts. Merge conflicts can occur with merge or with rebase.

Editorial

We prefer to use git rebase with git pull. This more correctly represents the history of the remote repo. In this example, user #1 pushed changes to the remote before user #2 and the history should reflect that. git pull with rebase also avoids the unfortunate side affect of merge commits.

Upvotes: 0

Ryan Lundy
Ryan Lundy

Reputation: 210190

I can't speak for Mercurial, but in Git, merges are handled automatically except when two people modify the same location in the same file.

If that happens, the second person to check in has to merge the changes. The file will look something like this:

<<<<<<<<<<
void SomeMethod()
{
    // do something
}
==========
void SomeMethod()
{
    // do something else
}
>>>>>>>>>>

The basic idea is that you, as a human who understands code, figure out how to put the changes together in the two sections, and then delete the marker characters. I can do that by combining the two, if appropriate:

void SomeMethod()
{
    // do something
    // do something else
}

Or I could just use one if it supersedes the other:

void SomeMethod()
{
    // do something else
}

Then I add the merged file and finish the commit. Or, if I'm not sure whether the changes make sense, I can do as much testing as I want prior to finishing the commit.

In addition to merging, you can also rebase. This changes the nature of the history, so that rather than you and the other person making simultaneous changes, your history is placed after his. But while rebasing changes the way the history looks, it doesn't change the fact that if the two of you changed the same part of a file, you'll have to merge the changes together. Rebase (and any other potentially merge-y operation like applying/popping a stash or cherry-picking a commit) will present conflicts in the same way as described above.

Upvotes: 2

Related Questions