How can I discard remote changes and mark a file as "resolved"?

111,148

Solution 1

git checkout has the --ours option to check out the version of the file that you had locally (as opposed to --theirs, which is the version that you pulled in). You can pass . to git checkout to tell it to check out everything in the tree. Then you need to mark the conflicts as resolved, which you can do with git add, and commit your work once done:

git checkout --ours .  # checkout our local version of all files
git add -u             # mark all conflicted files as merged
git commit             # commit the merge

Note the . in the git checkout command. That's very important, and easy to miss. git checkout has two modes; one in which it switches branches, and one in which it checks files out of the index into the working copy (sometimes pulling them into the index from another revision first). The way it distinguishes is by whether you've passed a filename in; if you haven't passed in a filename, it tries switching branches (though if you don't pass in a branch either, it will just try checking out the current branch again), but it refuses to do so if there are modified files that that would effect. So, if you want a behavior that will overwrite existing files, you need to pass in . or a filename in order to get the second behavior from git checkout.

It's also a good habit to have, when passing in a filename, to offset it with --, such as git checkout --ours -- <filename>. If you don't do this, and the filename happens to match the name of a branch or tag, Git will think that you want to check that revision out, instead of checking that filename out, and so use the first form of the checkout command.

I'll expand a bit on how conflicts and merging work in Git. When you merge in someone else's code (which also happens during a pull; a pull is essentially a fetch followed by a merge), there are few possible situations.

The simplest is that you're on the same revision. In this case, you're "already up to date", and nothing happens.

Another possibility is that their revision is simply a descendent of yours, in which case you will by default have a "fast-forward merge", in which your HEAD is just updated to their commit, with no merging happening (this can be disabled if you really want to record a merge, using --no-ff).

Then you get into the situations in which you actually need to merge two revisions. In this case, there are two possible outcomes. One is that the merge happens cleanly; all of the changes are in different files, or are in the same files but far enough apart that both sets of changes can be applied without problems. By default, when a clean merge happens, it is automatically committed, though you can disable this with --no-commit if you need to edit it beforehand (for instance, if you rename function foo to bar, and someone else adds new code that calls foo, it will merge cleanly, but produce a broken tree, so you may want to clean that up as part of the merge commit in order to avoid having any broken commits).

The final possibility is that there's a real merge, and there are conflicts. In this case, Git will do as much of the merge as it can, and produce files with conflict markers (<<<<<<<, =======, and >>>>>>>) in your working copy. In the index (also known as the "staging area"; the place where files are stored by git add before committing them), you will have 3 versions of each file with conflicts; there is the original version of the file from the ancestor of the two branches you are merging, the version from HEAD (your side of the merge), and the version from the remote branch.

In order to resolve the conflict, you can either edit the file that is in your working copy, removing the conflict markers and fixing the code up so that it works. Or, you can check out the version from one or the other sides of the merge, using git checkout --ours or git checkout --theirs. Once you have put the file into the state you want it, you indicate that you are done merging the file and it is ready to commit using git add, and then you can commit the merge with git commit.

Solution 2

Make sure of the conflict origin: if it is the result of a git merge, see Brian Campbell's answer.

But if is the result of a git rebase, in order to discard remote (their) changes and use local changes, you would have to do a:

git checkout --theirs -- .

See "Why is the meaning of “ours” and “theirs” reversed"" to see how ours and theirs are swapped during a rebase (because the upstream branch is checked out).

Share:
111,148

Related videos on Youtube

Tom DeMille
Author by

Tom DeMille

Current: Engineering Lead for OTTO Health, a Telehealth startup based in Boulder CO Previous: Director of Technology for BoomTown Real Estate Web Platform, one of the fastest growing companies in the US! Our technology stack includes CSharp.Net, Sql Server, MongoDB, Memcached, Lucene, CouchBase, Wordpress, PHP

Updated on April 30, 2020

Comments

  • Tom DeMille
    Tom DeMille about 4 years

    I have some local files, I pull from remote branch and there are conflicts. I know that I would like to keep my local changes and ignore the remote changes causing conflicts. Is there a command I can use to in effect say "mark all conflicts as resolved, use local"?

    • Tom DeMille
      Tom DeMille over 14 years
      The answer below has been super illuminating to me. There are a couple of subtle points made that really clear things up for me, I recommend any non-expert GIT users to read all of the comments below the post below, and thanks Brian!
  • CB Bailey
    CB Bailey over 14 years
    You should probably note that git add --all adds all files to the repository so this may add more files than intended unless your .gitignore patterns are in a perfect state. git add -u is probably more suitable for this situation, you're less likely to have edits to tracked files which you don't want to add while resolving a merge.
  • Brian Campbell
    Brian Campbell over 14 years
    Oops, sorry. That's what I meant. Corrected it now.
  • Tom DeMille
    Tom DeMille over 14 years
    thanks for your detailed answer. I actually tried git checkout --ours and received an error message (which I don't recall now). The files in question are dll (we have a few that we DO stash, 3rd party references mostly) and I wanted to just say 'ok my copy are the ones I want but the error was something like 'can't checkout while merging'..... I'll keep this article as a reference and the next time it happens try it again and see if it works or if I can post that message. Thanks again
  • Tom DeMille
    Tom DeMille over 14 years
    but your explanation clears up a lot for me about the process, thanks again... Follow up question: Any way to get git to delete the .orig files once I have the merge cleared up?
  • Brian Campbell
    Brian Campbell over 14 years
    You need to do git checkout --ours .. The . is important; passing in a file name (in this case, the whole directory) selects between two different modes of operation of checkout, one which switches branches and one which moves files from the index to the working copy. I agree, it's very confusing. You could also do git checkout --ours -- <filename> to check out an individual file at a time.
  • Brian Campbell
    Brian Campbell over 14 years
    The general way to get git to clean up extra files in the working tree is with git clean -f kernel.org/pub/software/scm/git/docs/git-clean.html (beware, that's a dangerous command). git clean will clean out any files that git doesn't know about; -f is necessary because git clean is dangerous, so you need a "force" option to tell it that you really mean it. If you have files in your .gitignore that you want to clean out too (like .o files), you can use git clean -xf. And if you want to get directories too, git clean -fd or git clean -xfd.
  • Brian Campbell
    Brian Campbell over 14 years
    (by the way, for a followup question, it's usually better to post a new question; it can be hard to fit an answer in the comments, and the answer will be hidden by default so other people won't be able to find it as easily)
  • Tom DeMille
    Tom DeMille over 14 years
    Dude, you should be a 'git consultant' my company would hire you :) Thanks again, your explanation of the . after checkout is very illuminating
  • Brian Campbell
    Brian Campbell over 14 years
    @Tom Actually, I am available as a Git consultant if you are still interested. I have fairly substantial experience with working with Git and Subversion in several different workflows, along with build automation experience and continuous integration using BuildBot. If you would like to get in touch with me, my email is lambda (at) continuation (dot) org
  • Martin Klosi
    Martin Klosi almost 11 years
    Great answer. However the asker said: "I have some local files, I pull from remote branch and there are conflicts." That means rebase, right? which means that in the end it is sufficient to add the resolved files and just --continue. We dont commit here.
  • James Webster
    James Webster almost 11 years
    That's very important, and easy to miss <- Yep. I did miss it
  • ErikE
    ErikE over 8 years
    You may want to note that for rebases, ours and theirs are reversed from what you might think.
  • Gabrielius
    Gabrielius over 8 years
    Is there a way to deal with files that were deleted by us? When trying to do a git commit --ours ., I get error: path 'file.ext' does not have our version, which is understandable, but is there any way to commit and delete file.ext without using git rm?
  • machine yearning
    machine yearning over 6 years
    Eww, I ran git checkout --ours . and it overwrote all my uncommitted local changes without warning. Totally different behavior than git checkout branchname. Had to recover the changes with some difficulty. Can I please suggest that you put a warning as to this behavior? See also : Here's a crazy idea: If you have an innocuous action and a dangerous action, do not label them with the same command.
  • maaartinus
    maaartinus about 6 years
    @machineyearning Agreed. Some time ago, a similar problem burned me, too, but I found a simple solution: I just always commit everything non-trivial (i.e., more than a few minutes of work). Then there's git reflog having everything there. Before pushing I have to clean up my commits, but I review all changes anyway, so it's hardly any overhead.
  • user3753693
    user3753693 about 4 years
    @BrianCampbell my sir made my day with this