user784637
user784637

Reputation: 16092

How to tell what files on remote repository changed since last git pull?

I'm trying to push some code using $git push origin master but I get the error

! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

When I did $ git fetch origin master then $ git diff master origin/master I got a list of all the files and changes that were different between the two repos. However I am only interested in the list of files that have changed between the remote repository and the last time I did a $ git pull origin master on my local box.

Is there a way I can do this?

Upvotes: 9

Views: 6883

Answers (3)

torek
torek

Reputation: 487755

michas' answer is the right one for the question as asked.

What if you don't have the old ref, i.e., the a8e5e4e part of a8e5e4e..295bf31 master -> origin/master? Probably you don't actually care: as he suggested, looking at master...origin/master can be even more interesting.1 But, what does this three-dot ... syntax actually mean?

The answer is in the git rev-list documentation:

Another special notation is <commit1>...<commit2> which is useful for merges. The resulting set of commits is the symmetric difference between the two operands. ...

which I suspect is confusing enough wording (and actually git diff uses a quite different meaning). But really, it's not that complicated.

Given some commits that could be drawn like this:

master  origin/master

   E       G
   |       |
   D       F
     \   /
       C
       |
       B
       |
       A

what you have is a divergence at commit C. You started work when master and origin/master both pointed to C. Clearly, you committed D and E, and "they" (whoever they are) committed F and G. Commit C, by the way, is called the merge base.

What master...origin/master means is: find me C, and then give me everything "up from there", on both the left and right sides. That is, all the commits on both master and origin/master, excluding any commits at-and-below the point where they first meet.

If you run gitk master...origin/master you'll see just that:2 all the commits you made, and all the commits they made. But, if you run git diff flags master...origin/master, git diff throws most of this out. Instead, it finds the merge base C,3 and diffs that against the right-hand side name.

Assuming you're on your master branch (i.e., HEAD simply means "master" anyway), you can shorten this even further. To see what files they modified since your and their branches diverged, just run:

$ git diff --stat ...origin/master   # or --name-status, etc

Leaving the name out means HEAD, so this is the same as HEAD...origin/master which is the same as master...origin/master.

If your git is new enough, @{u} refers to "the current branch's upstream branch" (i.e., from master, find origin/master), so you can run:

$ git diff --stat '...@{u}'

(the quotes are to protect the braces from the shell; they may or may not be needed in your particular shell). This works even if you're on develop with origin/develop as its upstream, or featureX with origin/featureX as its upstream, etc.


1If you don't have gitk, try:

$ git log --graph --boundary ...origin/master

(or '...@{u}' as noted above). You need the --boundary to include the merge commit. You might want to add --oneline --decorate as well.

2Actually gitk will show you the merge commit too, just like the command in footnote 1. That is, it uses --boundary to include meeting-point commits (this is not quite the same as merge bases, but close enough).

3This assumes there is exactly one merge base commit. For these cases, that should be true. So, git diff compares the tree for C with the tree for G at the head of the upstream branch. You'll compare "where they were" with "where they ended up", regardless of any intermediate points they visited on perhaps an arbitrarily long drive. :-) For instance, if commit F adds a file this/that and then commit G removes it again, you won't see the file.

Upvotes: 5

michas
michas

Reputation: 26495

git pull is the same as git fetch followed by git merge (or git rebase).

git fetch shows which refs where updated. It will show something like:

a8e5e4e..295bf31  master     -> origin/master

This means the last time you fetched master it was at a8e5e4e now it is at 295bf31. You can see the changed files with something like:

git diff --name-status a8e5e4e..295bf31

But maybe even more interesting is the output of gitk master...origin/master after the fetch. This way you can inspect both the changes on your side and the changes on origin side.

Upvotes: 8

Markus Unterwaditzer
Markus Unterwaditzer

Reputation: 8244

git diff --stat master origin/master

Upvotes: 3

Related Questions