On Thu, 26 Jan 2017 16:29:12 -0800 (PST)
AD S <a...@radianweb.com.au> wrote:

> I push a file to a remote repo and get a merge conflict error. I know
> my file is totally correct - there's no need to look through the
> code, I just want to overwrite the remote file with mine.
> 
> I've tried:
> 
> 
>    - git merge --strategy-option ours PATH/FILE
>    - git checkout --ours PATH/FILE
>    - git pull --ours PATH/FILE
> 
> but none of these seem to work. It either throws an error or doesnt 
> overwrite the remote file.
> 
> What's the correct way of doing this?

First, some terminological alerts which might indicate you did not yet
fully absorbed how distibuted VC systems work:

* It's impossible to push _a file_ to a remote repo: a minimal chunk of
  information you can share using a DVCS -- that is, push or fetch --
  is a single commit.

* A commit in a DVCS always represents the whole state of the whole
  project maintained in the repository.

* It's impossible to get a merge conflict when pushing in a DVCS: such
  systems never attempt to merge anything with anything else when you
  push; they merely try to *plant* what you sent to update a branch onto
  the tip commit of that branch.

  Now please think of this a little harder.

  As you supposedly know (you should know this), each commit existing
  in a repository has one or more parents.  Commits explicitly refer
  to their parent commits by their SHA-1 names (hashes).
  Such lineages are usually rendered using arrows where parent commits
  "point to" their child commits; so these arrows are oriented along the
  natural progression of the history evolvement:
  So if we draw
   ...->P->C->...
  this means C is a commit which has commit P as its parent.

  Now suppose you're trying to push to a branch named "master",
  and it currently contains this line of commits:

  ...->D->E->F->G->H

  and you're trying to push to that branch a line of history which
  ends in the sequence of commits

  ...->D->E->X->Y->Z

  The remote Git instance would take this history, compare it with
  what's already there and notice that what you sent and what it has
  have E as the last common point, and then they diverge.
  Git can't merely "graft" your commits X->Y->Z onto H because the
  line of history which would result does not exist anywhere in any
  repository, and Git has no way to know whether such line of history
  would even make sense for the project (for instance, your commit X
  could have just deleted all the files in the project).

  Hence such cases require manual resolution by a human.
  There are three possibilities:

  1) You can do a so-called "forced push" (if allowed by the remote
     repository) which would just _throw away_ these commits F->G->H
     and replace them with your X->Y->Z.

     In general, this is a last-resort operation, which is only done
     when you're absolutely positively sure what will the result be.

  2) You can fetch the current state of the branch as seen on the remote
     and _merge_ it into your own state.
     In the indicated state, that would be:

             /->F->G->H-\   # "origin/master"
             |          |
     ...->D->E->X->Y->Z->M  # the resulting merge commit
                      ^ "master" before the merge

     You can then push your

          ...->F->G->H-\
                       |
          ...->X->Y->Z->M

     to the remote "master", and since the "diamond" you'll be pushing
     includes the F->G->H sequence currently at the tip of that branch,
     Git will happily accept your history.

  3) You can fetch the current state of the branch as seen on the remote
     and _rebase_ your commits on top of that new state.

     The result will be

     ...->D->E->F->G->H->X'->Y'->Z'

     that is, all the commits in your rebased sequence will change
     their hashes (and may be even actual contents of the files --
     this depends on how the textual changes introduced by those
     commits were applied) but otherwise the commits will be the same.

     Again, you can safely push the resulting history because it, too,
     will contain the sequence F->G->H currently at the tip at the
     branch want to update with your push.

The first takeaway to do is that conflicts on push only even happen
because what you try to push would not "naturally promote" the branch
you're trying to update.

The second takeaway to do is that Git never merges remotely.
Merging is always a human's undertaking which happens in someone's local
repository.

OK, so how do you resolve a conflict which might occur when you do (2)
or (3) with taking "their" version of a file?

Well, there are indeed two options.

The first one is a _modifier_ to a default merge strategy called (which
is called "recursive").  To use it, you do something like

  git fetch origin
  git checkout master
  git merge -s recursive -Xtheirs origin/master

As soon as Git detects a merge conflict for a file, it will simply take
the remote (being merged) version of the file and call it a day.

The second approach is to do merging without any modifiers and when Git
flags a conflict manually "accept" "their" version of the offending
file.  This requires _two_ steps for each file:

  git checkout --theirs -- path/to/the/file
  git add path/to/the/file

Note that the first command merely replaces the contents of the file
at path/to/the/file in the work tree by the contents of the same
file of "their" version.  The conflict is not resolved after this: you
need to stage the new contents to be recoded in the next commit, and
this is what `git add` does.  (You can also use a simpler `git add -u`
which just adds whatever is changed in the work tree.)

After resolving merge conflicts, you have to record a new commit to
actually record your merge (with conflicts resolved) and re-attempt
your push.

Just in case, also note that the new push can actually result in
another rejection -- simply because someone could have managed to push
their changes first, -- and hence your merged state would again not
promote the remote branch cleanly.  In such case, you'll have to
reattempt reconciling your work with the new remote state.

-- 
You received this message because you are subscribed to the Google Groups "Git 
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to git-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to