Pregunta

This SO question perfectly describes our situation: What is the right way to commit/push when there are conflicts in Git or TortoiseGit?

There is no answer (atleast not one that is accepted) on the above question.

This seems to be one of the solutions: https://stackoverflow.com/a/12171221/172396

However I think that's an overkill. I just lost a commit to my colleagues. Git being a distributed VCS, I thought it would be okay if we advise colleagues to make local commits and then push to a central repo once or twice a day. Most of the time, they are working on separate modules, and won't cause a conflict. On occasional conflicts, I thought we can always resolve locally and then make another local commit and remote push.

Now a colleague committed locally and was trying to push resulting in a conflict. She pulled, resolved conflicts and then ONLY pushed her changed files. The remote repo had another commit saying merge branch with some files that is effectively undoing my commits earlier.

Is this expected? How are we supposed to work locally and then re-sync once in a while. If I have committed locally, and a subsequent pull results in a conflict, how do I ensure I merge correctly so I don't undo previous commits on the remote repo.

¿Fue útil?

Solución

I'm going to address your questions line by line:

On occasional conflicts, I thought we can always resolve locally and then make another local commit and remote push.

Yes, that's correct.

Now a colleague committed locally and was trying to push resulting in a conflict. She pulled, resolved conflicts and then ONLY pushed her changed files. The remote repo had another commit saying merge branch with some files that is effectively undoing my commits earlier. Is this expected?

Yes, it's expected (i.e. I'm not surprised), though that doesn't mean that what your coworker did was correct. Your coworker basically threw away all the work you did previously with that mege commit. I shall explain.

When git detects conflicts that it can't figure out how to auto-resolve during an attempted merge, it aborts the merge midway, leaving un-conflicted files added to your staging area, and leaving conflicted files with conflict markers un-staged in your working copy.

For example, this is what a merge that results in conflicts looks like from the command line:

git status

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Changes to be committed:

        modified:   hello.txt

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:      foo.txt

Notice that git has automatically staged hello.txt to be committed, because it doesn't have any conflicts. I haven't used TortoiseGit in over 1.5+ years, but if my memory serves me correctly, staged files are represented in TortoiseGit with checked-checkboxes, which means you want to commit those files.

Un-checking those automatically-staged checkboxes is incorrect, in this case. It basically means that you don't want to commit those file changes that you've just merged in from the other branch (or in your case, from the upstream remote/origin). It's essentially throwing away the work that was done on those files.

The correct way to merge, in this case, would be to resolve the conflicted files, and then add them to the staging area to be committed, along with all the other file changes that are already there, even if you were not originally responsible for those changes.

How are we supposed to work locally and then re-sync once in a while.

That's up to how you and your team want to organize your workflow.

If I have committed locally, and a subsequent pull results in a conflict, how do I ensure I merge correctly so I don't undo previous commits on the remote repo.

Unless you have a good reason not to, as I've already said, you usually want to commit all the files, even if you weren't originally reponsible for the changes to them. Not doing so essentially means that you don't actually want to keep those changes.

Otros consejos

For everyone's benefit, this is the strategy that I have resorted to that seems to work well for us.

  1. If a Git pull, results in a conflict, resolve the conflict locally.
  2. Ensure there are no remaining files that are conflicted.
  3. Do a Git pull again.
  4. Goto Step 2 if you again get a conflict.

Basically you try to resove conflicts and do a Git pull and keep on doing this until a Git pull completes successfully with no conflicts (effectively meaning your commit head now is updated to the remote commit head).

A change of mindset is needed when addressing conflicts if you are coming from a SVN background. In SVN, a merge conflict during an update does not abort the SVN update process. SVN client would still update your local copy to the latest remote revision. Only individual files would be left in conflicted state that you can resolve (and commit back if needed).

So a conflict still means all local files that were not conflicted are up--to-date with the remote repo after an update.

In Git, a conflict during pull simply terminates/aborts the update process. So if the remote repo had 10 commits that need to be pulled, and you get a conflict when Git was pulling (and merging) the 3rd of these commits, effectively the process is aborted. 8 of the remote commits are NOT in your local repo (note the remote commit that caused a conflict also isn't merged successfully, so its 8 commits that are not synced locally and not 7).

You resolve conflicts and keep doing a git pull until successful thus preventing you from overwriting other commits. To provide a bit more details from what I have understood about git, a push without resolving the conflict would cause the remote branch's commit head to be relocated incorrectly. e.g. suppose you need to pull 4 revisions from a Git repo:

A - B - C - D
            |- commit head

Now suppose you get a conflict while pulling and merging Revision B. If you do a push now to remote (without resolving the conflicts and doing a git pull until successful), the remote repo now looks like this:

A - B - C - D
    |- E - commit head

So effectively although commits C/D exist remotely, they won't be a part of your build based on the branch's commit head. If you follow @CupCake's advice and push the remaining files, commits C/D become a part of commit E sort of. So that doesn't impact your correctness of the build. But if you don't push those files after conflict which you don't changed but Git was showing as modified (because you did not resolve the conflict and completed a successful git pull), then effectievly you are leading to lost commits.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top