245

After a Git rebase, and in other circumstances, you can find some files marked as deleted by us in the git status report. Who is us according to Git and why?

Is it referring to me sitting on this branch and it working for me? Or is it referring to itself and the folks working on the branch I am rebasing against?

danza
  • 11,511
  • 8
  • 40
  • 47
  • 8
    Strangely enough, it seems "deleted by them" means that you deleted the file on the branch that you're rebasing, while "deleted by us" means the other folks deleted it. `git merge` gives the opposite message. – Fred Foo Jan 09 '14 at 16:23
  • Possible duplicate of [git rebase, keeping track of 'local' and 'remote'](https://stackoverflow.com/questions/3051461/git-rebase-keeping-track-of-local-and-remote) –  May 13 '18 at 21:56
  • Related: [What is the precise meaning of “ours” and “theirs” in git?](https://stackoverflow.com/q/25576415/4561887) – Gabriel Staples Mar 05 '21 at 17:39

2 Answers2

228

When you merge, us refers to the branch you're merging into, as opposed to them, the branch to be merged.

When you rebase, us refers the upstream branch, and them is the branch you're moving about. It's a bit counter-intuitive in case of a rebase.

The reason is that Git uses the same merge-engine for rebase, and it's actually cherry-picking your stuff into the upstream branch. us = into, them = from.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SzG
  • 12,333
  • 4
  • 28
  • 41
  • 66
    It makes sense from the *implementation*'s point of view, as rebase uses the merge machinery with the "ours" branch being the upstream branch and the "theirs" branch being the one being rebased. But I agree it's, well, "extremely unhelpful" seems like a polite way to put it. I'd much rather have the branches labeled by some other words than "us/ours" and "them/theirs", perhaps by branch-name for instance: "deleted in master, modified in feature". – torek Jan 09 '14 at 21:43
  • 4
    I always tend to confuse `--theirs` with `--ours` when doing a checkout during a rebase, it's so counter-intuitive. I hope they will fix this some day. – iosdude Apr 19 '16 at 12:04
  • 1
    What about when only one branch is involved, such as when re-ordering or squashing commits during a `rebase`? – Justin Johnson Sep 10 '16 at 00:55
  • `us`: the new rewritten branch (into), `them`: the original branch (from). – SzG Sep 13 '16 at 19:35
  • 25
    It may help to just think of `us` as a mnemonic for "[u]p[s]tream" instead of the normal English word "us". – kojiro May 15 '17 at 20:19
  • 1
    Can you clarify for the `git revert` case too please? I've added this question here: https://stackoverflow.com/q/63908012/4561887. – Gabriel Staples Sep 15 '20 at 18:41
  • After doing some research, testing, and looking at some other answers, I've just added my answer here to cover all 4 cases: merge, rebase, cherry-pick, and revert: https://stackoverflow.com/a/63911630/4561887 – Gabriel Staples Sep 16 '20 at 00:54
  • And when you're [reordering commits](https://gist.github.com/x-yuri/c45fc590e1080e4c4d36f24f8163e151)? :) – x-yuri Aug 05 '22 at 02:25
82

Who is "us"/"ours" and "them"/"theirs" according to Git?

(This also answers the question: "How does a git rebase work and what exactly is happening with it?")

When you have conflicts in the middle of a git merge, cherry-pick, rebase, or revert, you may need to pick a side to choose to keep conflicting content from just the --ours or --theirs side (and to keep non-conflicting content from both sides otherwise), leading to the question: who is "us" vs "them" in each of those cases?

Conflict resolution might involve the following, for instance:

git checkout master
git merge feature_branch
git checkout --theirs -- path/to/some/dir
git add path/to/some/dir 
git status 
git merge --continue 

But, what does the git checkout --theirs line do, and what other options do we have? Here are some options:

# ------------------------------------------------------------------------------
# Do this:
# - Generally, one of these might be useful during conflict resolution:
# ------------------------------------------------------------------------------

# Integrate changes from both sides, but in the lines which conflict, keep the
# `--theirs` changes for all conflicts within files inside this directory.
git checkout --theirs -- path/to/some/dir

# OR: Integrate changes from both sides, but in the lines which conflict, keep
# the `--ours` changes for all conflicts within files inside this directory.
git checkout --ours -- path/to/some/dir

# ------------------------------------------------------------------------------
# Do *not* do this:
# - Generally, do *not* do this during conflict resolution:
# ------------------------------------------------------------------------------

# Discard all changes from both sides by hard resetting all the contents inside of
# this directory back to their state at the `some_branch` commit. 
# - But, oddly enough, this does *not* do deletions of files inside this directory
#   which don't exist at this `some_branch` commit but are there now. So, this
#   isn't even a proper hard reset of this directory. It's a mishmash. 
git checkout some_branch -- path/to/some/dir

See the "best conflict resolution example" below, as well as all examples within the "Example uses-cases" section, for details. See also the "WARNING WARNING WARNING!" section though. In most cases, you do not want to do git checkout some_branch -- path/to/some/dir in an attempt to resolve conflicts, as that discards the entire merge, cherry-pick, rebase or revert, undoing all changes from one side rather than keeping changes from both sides but favoring the one side in the lines which conflict. So, using --ours or --theirs, as shown above, is generally the right course of action instead of using some_branch.

Study those sections at the bottom of my answer for details.

Now on to the main answer:

In all cases:

In rough layman's terms (thank you, @user20358):

"us" is the code already in the repo, and "them" is the code [you are] trying to merge in

In more-complete terms:

  1. "us" (or "ours") = the currently-checked out commit (HEAD) at the moment git does the action which causes the conflict (more on this later), and:
  2. "them" (or "theirs") = the other commit, NOT checked-out by git at the moment git does the action which causes the conflict (more on this later).

IMPORTANT: HEAD at the moment it does the action which causes the conflict is NOT necessarily the HEAD at the moment you type the git command. This is essential to understand. Git may do some checkouts and change the HEAD (which commit is checked-out) before running the action which causes the conflict, thereby causing "us" and "them" to appear swapped or backwards to the untrained eye.

The 4 cases, in detail: merge, cherry-pick, rebase, revert:

  1. git merge (intuitive):
    1. Sample command:
      git checkout master
      git merge feature_branch  # merge feature_branch into master
      
    2. "us"/"ours" = HEAD, which is master, because you were on branch master at the time you ran git merge feature_branch.
    3. "them"/"theirs" = feature_branch, which is the branch you're merging into master.
  2. git cherry-pick (intuitive):
    1. Sample command:
      git checkout feature_branch
      git cherry-pick some_commit  # apply some_commit to feature_branch
      
    2. "us"/"ours" = HEAD, which is feature_branch, because you were on branch feature_branch at the time you ran git cherry-pick some_commit.
    3. "them"/"theirs" = some_commit, which is the commit you're cherry-picking onto feature_branch.
  3. git rebase (counter-intuitive, but totally makes sense once you understand the mechanics of how it works):
    1. Sample command:
      git checkout feature_branch
      git rebase master  # rebase feature_branch onto latest master
      
    2. Diagram of this (drawn at https://asciiflow.com), with the latest or newest commits on top and/or to the right:
      #             Prior to rebase: feature_branch
      #             received new commits while
      #             master did too
      # 
      #                           master
      #                           x
      #                           |          feature_branch
      #                           x          y
      #                           |          |
      #                           x          y
      #                           |         /
      # git merge-base      ────► x--y--y--y
      # master feature_branch     |
      #                           x
      # 
      # 
      #             After rebase: feature_branch has
      #             been completely cherry-picked onto
      #             the end of master
      # 
      #                                   feature_branch
      #                                   y'
      #                                   |
      #                                   y'
      #                                  /
      #                         y'--y'--y'
      #                         |
      #                  master x
      #                         |
      #                         x
      #                         |
      #                         x
      #                         |
      #                         x
      #                         |
      #                         x
      
    3. "us"/"ours" = HEAD, which is the upstream branch: initially the last x commit on master, and then thereafter, some NEW commit, y', cherry-picked on top of that (this one's tricky!). This is because when you typed git rebase master, git first checks out master as the starting point to start cherry-picking your feature_branch commits onto, then it determines which commits from feature_branch to cherry-pick (ie: which of your feature_branch commits are not already on master). It does this by finding the merge-base (the commit which is common to both feature_branch and master and which can be found with git merge-base master feature_branch), and THEN it starts cherry-picking commits from the first one after this merge-base and onward, working one-at-a-time, towards the last commit on feature_branch, onto the tip of master, thereby "rebasing" all "new" y commits you added to feature_branch onto the latest master, as new y' commits. Therefore, "us"/"ours" = HEAD, but since git did a new checkout behind-the-scenes to perform this rebase, HEAD is NOT the branch you were on when you typed git rebase master. Instead, us, or HEAD, is either the last x commit on master if the conflict occurs during the first cherry-pick, or it is whatever NEW commit, y', was last successfully cherry-picked onto master if the conflict occurs during any later cherry-pick. Them is therefore the other commit, which is some y commit from feature_branch which is being applied to this new HEAD via a cherry-pick, in order, FROM the first y commit on feature_branch which is immediately after git merge-base master feature_branch all the way TO the last y commit on feature_branch. See explanation for "them" also, just below.
    4. "them"/"theirs" = some y commit from feature_branch which is being applied to a newly-checked-out HEAD, where HEAD is either the last x commit on master for the first cherry-pick operation during the rebase, OR one of these newly-created y' commits on top of master as feature_branch is "rebased", or cherry-picked one-commit-at-a-time (along your string of new commits from git merge-base master feature_branch to the last commit on feature_branch) onto master. See explanation for "us" also, just above.
  4. git revert (sort of intuitive):
    1. Sample command:
      git checkout feature_branch
      # create a new commit to undo the changes from some_previous_commit
      # within feature_branch
      git revert some_previous_commit  
      
    2. For some of the detailed, low-level mechanics of this one, see my "Results and Conclusions" section at the bottom of my other answer here, as well as this very long and detailed answer by @torek here.
    3. "us"/"ours" = HEAD, which is feature_branch, because you were on branch feature_branch at the time you ran git revert some_previous_commit. More specifically, "us"/"ours" contains the changes expressed by git diff some_previous_commit..HEAD, which are the changes from the point at which the commit being reverted (some_previous_commit) was committed to the commit we are on now.
    4. "them"/"theirs" = (the inverse or opposite of) some_previous_commit, which is the commit whose changes you're reverting (undoing, by creating a new commit on top of feature_branch). In other words, "them"/"theirs" contains the changes expressed by git diff some_previous_commit..some_previous_commit~, where some_previous_commit~ is the parent commit of some_previous_commit. This means that "them"/"theirs" is the opposite of some_previous_commit, as it contains the opposite of its changes, in order to undo some_previous_commit's changes.

Example use-cases:

Merge conflict resolution examples:

# 1. Merge `feature_branch` into `master`, accepting ALL of 
# `master`'s (`ours`) changes in the event of 
# any merge conflicts! 
git checkout master
git merge -X ours feature_branch

# 2. Merge `feature_branch` into `master`, accepting ALL of 
# `feature_branch`'s (`theirs`) changes in the event of 
# any merge conflicts! 
git checkout master
git merge -X theirs feature_branch

Here are some more. These are my most-commonly-used techniques, rather than the 2 examples just above.

# 3. Assuming this merge attempt results in merge conflicts in
# these 3 files, but we know all of the changes on the `master`
# branch side are the ones we wish to keep, check out these 3 
# files from `master` (`--ours`) to overwrite the conflicted
# files. Then, add these now-fixed files to stage them for 
# committing, and continue (finish) the merge. 
git checkout master
git merge feature_branch
git checkout --ours -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git add path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git status 
git merge --continue

# 4. Assuming this merge attempt results in merge conflicts in
# these 3 files, but we know all of the changes on the `feature_branch`
# side are the ones we wish to keep, check out these 3 
# files from `feature_branch` (`--theirs`) to overwrite the conflicted
# files. Then, add these now-fixed files to stage them for 
# committing, and continue (finish) the merge. 
git checkout master
git merge feature_branch
git checkout --theirs -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git add path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git status 
git merge --continue

VERY USEFUL: If an entire folder of conflicts exists, you can also specify to accept all conflicting changes from the --ours or --theirs branch for the entire folder at once, like this!:

**BEST MERGE CONFLICT RESOLUTION EXAMPLE:**

# 5. [BEST EXAMPLE] Assuming this merge attempt results in merge conflicts in
# a bunch of files, some of which are inside `path/to/some/dir`, I can
# choose to accept the changes from one side or the other **for 
# all conflicts within files inside this directory**, like this!:
git checkout master
git merge feature_branch

# Keep `--theirs` for all conflicts within files inside this dir
git checkout --theirs -- path/to/some/dir
# OR: keep `--ours` for all conflicts within files inside this dir
git checkout --ours -- path/to/some/dir

# Add (stage for committing) all changes within files inside this dir 
# all at once
git add path/to/some/dir 
git status 
git merge --continue 

DEALING WITH path does not have our version or path does not have their version ERRORS:

If you ever run something like this:

git checkout --ours -- path/to/some/dir

...and it didn't work! It didn't do anything. Instead, it output these errors:

error: path 'path/to/some/dir/file1.cpp' does not have our version
error: path 'path/to/some/dir/file2.cpp' does not have our version
error: path 'path/to/some/dir/file3.cpp' does not have our version

The problem is that these errored files are deleted files on the our side, so we must git rm each of them manually BEFORE running git checkout --ours -- path/to/some/dir.

git rm path/to/some/dir/file1.cpp path/to/some/dir/file2.cpp \
path/to/some/dir/file3.cpp

# then try again
git checkout --ours -- path/to/some/dir

You can also just do this instead to automate the process:

git checkout --ours -- path/to/some/dir \
|& gawk '{ print $3 }' | xargs git rm

git checkout --ours -- path/to/some/dir

See my answer here for a detailed explanation of the commands above: git checkout --ours when file spec includes deleted file.

WARNING WARNING WARNING!

For a more-detailed example of the problem described below, see my other answer here.

Do NOT do git checkout -- path/to/some/dir, nor git checkout some_branch -- path/to/some/dir in the middle of a conflict resolution (such as during a merge conflict like in the examples above), UNLESS YOU INTEND TO CHECK OUT ALL FILES FROM HEAD, or from some_branch, respectively, in directory path/to/some/dir, AND OVERWRITE THE LOCAL FILES WITH THOSE FILES, thereby not just accepting the conflicted changes from one side or the other.

In other words, during the middle of a conflict resolution, this:

GOOD:

# GOOD :)
# Accept all conflicts from one side or the other (while still 
# merging changes from both sides into one, in the event of being
# in the middle of a `git merge`).

git checkout --ours -- path/to/some/dir
# OR
git checkout --ours -- path/to/some/file

will accept just the changes from side --ours, which is always good and safe if that's what we want, whereas this:

BAD:

# BAD :(
# OVERWRITE all files with these files from `some_branch` instead,
# thereby _losing_ any changes and/or files contained in the other
# side but which are not in `some_branch`.

git checkout some_branch -- path/to/some/dir 
# OR
git checkout some_branch -- path/to/some/file

will fully check out and overwrite the ENTIRE DIRECTORY or ENTIRE FILE, as specified, rather than only the conflicting changes themselves. This means you may be inadvertently deleting changes from one side or the other by doing a full checkout with git checkout some_branch rather than a conflict resolution with git checkout --ours or git checkout --theirs. FOR THIS REASON, IT IS RECOMMENDED TO USE git checkout --ours -- file_or_dir_paths or git checkout --theirs -- file_or_dir_paths, NOT git checkout some_branch -- file_or_dir_paths whenever you are in the middle of a conflict resolution such as for git merge, git cherry-pick, git rebase, or git revert.

HOWEVER, if you DO run git checkout some_branch -- file_or_dir_paths because you understand this behavior and that's what you want, then you need to be aware of this too: checking out an entire directory like that does NOT delete local files in that dir which do not exist at some_branch, like you'd expect it would. Instead, it leaves them alone in your local file system if they exist locally but not at some_branch. So, you must MANUALLY remove all of those files instead. Keep that in mind or else it will leave you very very confused in the end. Read more about this in my other answers here (this answer has a good solution to that too) and here.

Going further / additional notes and tips:

  1. The above examples of file conflict resolution can apply in the event of conflicts in any of the various types of operations (git merge, git cherry-pick, git rebase, git revert, etc.), except you need to keep in mind what theirs and ours means for each type of conflict resolution, as explained above.
  2. You can also just use branch names such as master or feature_branch in place of -X ours/-X theirs and --ours and --theirs. WARNING: Passing branch names may seem easier and clearer, but CAN BE DANGEROUS to your changes, as doing it this way does a FULL FILE OR DIRECTORY REPLACEMENT, RATHER THAN A CONFLICT RESOLUTION FOR JUST THE CONFLICTS WITHIN THE FILES. See the "WARNING WARNING WARNING" section above. If you DO want to do a full file replacement, however, rather than just accepting conflicting changes from one side or the other, here's how:
    # See "WARNING WARNING WARNING" section above.
    git checkout feature_branch -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
    
  3. You can also check out entire directories rather than specifying files individually! See this answer here and my answer here and my other answer here. I just tested it. This works too. Again, however, pay attention to the "WARNING WARNING WARNING" section above. This does a full directory replacement, rather than just accepting conflicting changes from one side or the other for an entire folder:
    # Check out ALL files from feature_branch which are in
    # directory "path/to/dir". See "WARNING WARNING WARNING"
    # section above.
    git checkout feature_branch -- path/to/dir
    
  4. Remember, if you do intentionally use git checkout feature_branch -- path/to/dir, expecting/hoping it will delete local files in directory path/to/dir which do NOT exist at feature_branch, it will NOT. You must remove those files manually in your local file system before or after running the checkout command. Read more in my answers here:
    1. All about checking out files or directories in git
    2. How to do a --soft or --hard git reset by path

References:

  1. [my answer, which I reference all the time!] "All about checking out files or directories in git": How to get just one file from another branch
  2. [my answer] Why git can't do hard/soft resets by path? --> see especially the git terminology and definitions in the "Background knowledge" section at the end!
  3. [my own answer on what "them" and "us" mean during git revert] Who is `them` and `us` in a `git revert`?
  4. [@LeGEC's answer which points out that "ours/us" is always HEAD, and "them/theirs" is always the other branch or commit] Who is `them` and `us` in a `git revert`?
  5. [the pre-existing answer which I cross-checked against regarding my understandings of git merge and git rebase] Who is "us" and who is "them" according to Git?
  6. From man git checkout: "Note that during git rebase and git pull --rebase, ours and theirs may appear swapped":
    --ours, --theirs
        When checking out paths from the index, check out stage #2 (ours) or #3 (theirs) for
        unmerged paths.
    
        Note that during git rebase and git pull --rebase, ours and theirs may appear swapped;
        --ours gives the version from the branch the changes are rebased onto, while --theirs
        gives the version from the branch that holds your work that is being rebased.
    
        This is because rebase is used in a workflow that treats the history at the remote as
        the shared canonical one, and treats the work done on the branch you are rebasing as the
        third-party work to be integrated, and you are temporarily assuming the role of the
        keeper of the canonical history during the rebase. As the keeper of the canonical
        history, you need to view the history from the remote as ours (i.e. "our shared
        canonical history"), while what you did on your side branch as theirs (i.e. "one
        contributor’s work on top of it").
    
  7. [answer to my question]: you can pass directory paths to git too to check out all files from entire directories, rather than having to specify files individually: How do I accept git merge conflicts from "their" branch for only a certain directory?
  8. [my answer] git checkout --ours when file spec includes deleted file
  9. For drawing pretty ASCII pictures or diagrams to place in code: https://asciiflow.com/.

Additional Study:

  1. [I NEED TO STUDY THIS ANSWER MYSELF STILL!--done; I've figured it out and updated my answer here now as of 7 Jan. 2020] Who is `them` and `us` in a `git revert`?
  2. [I NEED TO STUDY AND READ THIS STILL] git checkout --ours does not remove files from unmerged files list

See also:

  1. Quick links to my answers I reference frequently and consider to be "git fundamentals":
    1. Various ways to create a branch in git from another branch
    2. All about checking out files or directories in git
    3. Who is "us" and who is "them" according to Git?
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • 1
    The fault, it seems to me, is in the curious syntax of the verb `rebase`. When you say `git merge feature` you are saying to merge the feature branch into me (whoever I am), but when you say `git rebase master` you are saying to rebase me (whoever I am) onto the master branch. Thus the direct object and the indirect object, as it were, are swapped. The reversal of ours and theirs follows directly from that. – matt Feb 26 '21 at 18:44
  • What about `git rebase -m`? The manpage seems to imply that "us" and "them" are reversed in that case. – imz -- Ivan Zakharyaschev Mar 10 '21 at 16:54
  • @imz--IvanZakharyaschev, the way I'm reading the `-m` description in `man git rebase`, and looking at my `git rebase` diagram I just added to the answer, no, `git rebase upstream` and `git rebase -m upstream` have identical definitions for `us` and `them` or `ours` and `theirs`. When they say, "In other words, the sides are swapped", what I think they are saying is that, as I explain in my answer already, the sides appear to be swapped in regards to a `git rebase` in general as opposed to a `git merge` in general, but the sides are the same for a `git rebase` as they are for a `git rebase -m`. – Gabriel Staples Mar 10 '21 at 18:04
  • 2
    Can this be made simpler by saying "us" is the code already in the repo and "them" is the code I am trying to merge in? Is that correct? – user20358 Feb 25 '23 at 02:14
  • @user20358, yes. Good observation. That is essentially correct as far as I can tell. – Gabriel Staples Feb 25 '23 at 05:37
  • @slhck, can you please post the full command where you used `ours` and `theirs` for `git revert`. This is in regards to your edit. I need to see your full command in context. – Gabriel Staples Jul 24 '23 at 06:52
  • 1
    @GabrielStaples Sorry if I made something *more* ambiguous. I was in a situation where I wanted to make sure I completely reverted a change introduced earlier, and in the end I chose `git revert fed8934 --strategy-option=theirs`. So it was the opposite of what I wrote. I rolled back the edit. I believe your answer could be more straightforward with respect to `revert` but I have troubles wording it properly. – slhck Jul 24 '23 at 06:56
  • @slhck, thanks. It is difficult to word things for sure. This is complicated stuff, and much of it rarely comes up too. If I use the revert command again and reference my answer to use `ours` or `theirs`, I'll be sure to try to improve the wording. – Gabriel Staples Jul 24 '23 at 07:09
  • Maybe something like: "If you want to make sure you entirely undo the changes from the commit you are trying to revert, falling back to the version before it, use `theirs`." – slhck Jul 24 '23 at 09:37