-1

Myself and a coworker are working on the same branch (not all the time, but at the moment). He and I both made a commit around the same time and he pushed his changes.

I did my push via Github Desktop and I was surprised to see that there were two commits assigned to myself: My original commit and a "Merge branch 'xyz' of https://github.com/company/repository into xyz", which I didn't expect. It looks like I merged his changes into the branch.

My expectation was that, since I was not doing a force push, I can't set the branch to include my changes without my coworker's changes. From what I can see from the Github Desktop logs, it looks like a pull (and therefore merge) was done prior to the push. However, looking at the history, it appears to me like the branch was set to include my changes first, without my coworkers changes, and then I merged those changes in, exactly what I thought would be impossible without doing a force push.

My preferred 'state' for the history would be to show only my changes merged into the branch, not that I made my coworker's changes. Is the only way to accomplish this to create a new named branch with my changes, commit to that and push, switch back to the original branch, then merge from the newly named branch?

For some reason, I thought that this would essentially happen without going through all these extraneous steps. Was I wrong? Is there a better way to accomplish this?

Thanks!

Regular User
  • 682
  • 7
  • 16
  • “looks like I merged his changes into the branch” You did. Unclear what the issue is. Any time you pull when you have a local commit that the remote does not, you automatically get an additional merge commit. Don’t worry be happy. This normal when two people work on a branch. – matt Feb 19 '21 at 22:06
  • The output of this command might be useful: `git log --graph --oneline --decorate --all`. If the changes made by you and your coworker do not overlap, this can be solved with git rebase/cherry pick. – ejalaa12 Feb 19 '21 at 22:13
  • 1
    The one work around if you are collaborative editing is as follow. After someone commits (say you are also working on changes locally that have not been committed locally), do a `git stash save` to save what you have temporary. Then do a `git pull` to retrieve the latest change from your collaborator. Afterwards, do a `git stash pop` and address any conflicts. Then `git commit` & `git push`. That's the clean way, but never happens – astrochun Feb 20 '21 at 00:44

1 Answers1

4

If two people are working on the same branch, then almost inevitably in the natural course of things each will make commits and one will push before the other. Thus we will have first this situation:

A -- B -- C --|  <-- master     G -- H <-- branch as seen by them     
               \               /
                D -- E -- F -- |
                               \
                                I -- J <-- branch as seen by us

Then, when they push, this situation:

A -- B -- C --|  <-- master      
               \               
                D -- E -- F -- G -- H <-- branch on the remote
                            \
                             I -- J <-- branch as seen by us

If you now pull, you have I and J but the remote has G and H. Unless you take special measures, Git will by default automatically create a merge commit on your local to reconcile this discrepancy:

A -- B -- C --|  <-- master      
               \               
                D -- E -- F -- G -- H
                            \         \
                             I -- J -- M <-- branch as seen by us

... where M is the merge commit.

This is totally normal. Whoever pushes first, the other will be reconciled with a merge commit. That merge commit, of course, gets pushed when you push, and so we get a chain of those parallelograms of divergence and merge, divergence and merge, through the life of the branch.

If you don't like the merge commit, you might be able to say --rebase when you pull. In that case, the incoming new commits get put first and your local new commits get put second:

A -- B -- C --|  <-- master      
               \               
                D -- E -- F -- G -- H -- I' -- J' <-- branch as seen by us
                            \         
                             I -- J

The commits I and J are duplicated to make I' and J' which look like them, but are tacked on to the end of the incoming version of the branch at H.

That rebase approach is a very standard way of making your version of a branch "catch up" even though you have local commits. But that is not always possible, and can result in a confusing situation when Git refuses to do it.

A more standard approach is: don't do that. A common branch should be a place where nobody works directly; there should be no other branches in common. You work on a feature branch, they work on a different feature branch, and now they just remain totally independent and each gets merged in its own time into the main branch (here called master, though there is nothing special about that name). There might well still be a merge commit representing each merge into master (and I would argue that that is good, as it preserves the historical truth) but it doesn't affect your branch in any way; your branch just marches on, alone.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks, Matt. I think I expected the pull to automatically rebase so when the merge happened, it would be my code being added to the other branch rather than the other branch being added on top of my code. However, I don't want to get into potentially damaging or confusing scenarios (I just thought it worked that way be default). Good to know it's just something you have to learn and I will only commit to my own development branches going forward to avoid this situation. – Regular User Feb 22 '21 at 13:46
  • Basically saying plain `git pull` is often ill-advised to begin with, exactly because it is rather unpredictable what it will do (depends on your settings, which you might not know about). It is better to `git fetch` and _look_ at the remote-tracking branch as against your local and decide. And having two people work on one and the same branch is _really_ ill-advised; at the very least one of you should have branched off immediately. Merging / rebasing branches is a controlled, predictable process; just pulling and making Git sync the remote with the local for you, on the other hand, is not. – matt Feb 22 '21 at 20:37