سؤال

This is not a duplicate of git pull from clean directory has merge conflicts - In that question the user was trying to pull from a remote which had commits which were not in the local branch. In my case there are NO commits on the remote which are not also in my local branch.

For starters, here's my git status:

asj@asj] git fetch
asj@asj] git status
# On branch project
# Your branch is ahead of 'origin/project' by 17 commits.
#   (use "git push" to publish your local commits)
#
nothing to commit, working directory clean

As you can see I'm on my own project branch which is 17 commits ahead of origin/project. When I run git log as a diff it lists the 17 commits in project which aren't in origin/project:

asj@asj] git log project ^origin/project
<shows all 17 commits>

So far so good, now I check for commits in origin/project which are not yet in project:

asj@asj] git log origin/project ^project
<shows nothing>

As expected, there is nothing on the remote which is missing from my local project branch. The local branch is fully merged. Now I run git pull as a best practice before pushing my 17 commits. I expect this to tell me I'm already up to date:

asj@asj] git pull
First, rewinding head to replay your work on top of it...
Applying: SomeEarlierChange
Using index info to reconstruct a base tree...
M       SomeFile
Falling back to patching base and 3-way merge...
Auto-merging SomeFile
CONFLICT (content): Merge conflict in SomeFile
Failed to merge in the changes.
Patch failed at 0001 SomeEarlierChange
The copy of the patch that failed is found in:
   SomeDirectory/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

This is not what I expected. When I play along and resolve the conflicts in SomeFile then git rebase --continue it comes up with more conflicts in more files. I've continued down this rabbit hole through a few iterations, but I didn't recognize any of the changes I was seeing or where they might be coming from. I've gone through the whole process a couple of times, and always end up running git rebase --abort and returning to the situation described at the beginning of this post.

I'd like to simply push the changes from those 17 new commits to the remote, since they're urgently needed for the project. However, I'm quite afraid that this would result in more mysterious conflicts and that I'd end up spending all day fixing the remote branch instead of my local one. I'd like to address the difficulties I'm having with pull before I get to push.

The only relevant thing I can think of is that some of the commits on the local branch were merged in from a third branch. Could these commits be conflicting with the history between project and origin/project? My fear is that git now thinks origin/project's history is new and different and needs to be merged into project when pulling (even though it contains no new commits). Might this be the case? How would I remedy this?

Any other ideas as to what could be going on here?

هل كانت مفيدة؟

المحلول

You have git pull set to do an automatic rebase (rather than an automatic merge), so this is doing the rough equivalent of git fetch; git rebase project origin/project.

If all your commits were linear, the rebase would be a no-op after git fetch brings in no new commits, and you would get the Current branch project is up to date. message. But, as you said, your commits include a merge-commit of another branch. This is where things are going awry, as the rebase attempts to flatten away the merge. (If you were to rebase with --preserve-merges it would probably be OK.)

The main thing to recognize here is that there is no need to run git pull here. Pull is just fetch-then-merge (or fetch-then-rebase if configured to rebase, as yours is). The idea here is to make sure that you have all the commits from the remote. Once you do, you can then git push them back to the remote and the result will be a fast-forward operation for the remote.

The only time it's not a fast-forward is when someone else sneaks in before you can git push and gets their commits added to the remote repository.1 In this case, you must git fetch their commits, then combine them with yours in some fashion (typically a rebase or a merge—i.e., what git pull does!), then retry your push. If this happens to take you ten seconds while a third group gets their new commits pushed in nine seconds or less, you will again get a "non fast forward" error, and have to repeat the process (potentially forever, if you're slower than everyone else, but in practice this converges quickly).

Using git pull does not guarantee that you'll be the fastest and "win" the "push race", it's just a convenient way to do the "fetch, then merge-or-rebase" step needed after observing the error. You can simply try the push and see if you get the error ... and if so, use git fetch rather than git pull, then decide for yourself how to deal with "losing" the "push race".


1Well, there are one or two other cases, when someone does a force-push to "rewind" or "reset" a branch name, or deletes and recreates a branch, or renames it, or in general causes the whole branch-name-to-commit-ID mapping to change in some unusual / unexpected fashion. But those are not normal cases, except when negotiated ahead of time (some projects have specific "resettable" branches that you're not supposed to depend on behaving "properly", in git terms).

نصائح أخرى

Have you tried creating a new tracking branch and merging your commits there?

Basically my suggestions:

git checkout -b project_1 origin/project
git merge project

You can use --squash option while merging to club all 17 commits also.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top