Using Git how do I find changes between local and remote
Asked Answered
T

11

161

Here are two different questions but I think they are related.

  1. When using Git, how do I find which changes I have committed locally, but haven't yet pushed to a remote branch? I'm looking for something similar to the Mercurial command hg outgoing.

  2. When using Git, how do I find what changes a remote branch has prior to doing a pull? I'm looking for something similar to the Mercurial command hg incoming.

For the second: is there a way to see what is available and then cherry-pick the changes I want to pull?

Turpin answered 23/10, 2008 at 19:52 Comment(1)
Looking at the answers, there seems to be some confusion as to what hg incoming and hg outgoing actually do. The nearest Git equivalent I found is the --dry-run option. Just git pull --dry-run and you'll see a list of all the things that need to happen.Pull
S
100

Git can't send that kind of information over the network, like Hg can. But you can run git fetch (which is more like hg pull than hg fetch) to fetch new commits from your remote servers.

So, if you have a branch called master and a remote called origin, after running git fetch, you should also have a branch called origin/master. You can then get the git log of all commits that master needs to be a superset of origin/master by doing git log master..origin/master. Invert those two to get the opposite.

A friend of mine, David Dollar, has created a couple of git shell scripts to simulate hg incoming/outgoing. You can find them at http://github.com/ddollar/git-utils.

Singlefoot answered 23/10, 2008 at 20:31 Comment(0)
M
119

Starting with Git 1.7.0, there is a special syntax that allows you to generically refer to the upstream branch: @{u} or @{upstream}.

To mimic hg incoming:

git log ..@{u}

To mimic hg outgoing:

git log @{u}..

I use the following incoming and outgoing aliases to make the above easier to use:

git config --global alias.incoming '!git remote update -p; git log ..@{u}'
git config --global alias.outgoing 'log @{u}..'
Moldau answered 17/6, 2011 at 17:18 Comment(10)
git log ..@{u} gives me these errors. (I have both origin and an upstream repository in my git config). error: No upstream branch found for '' error: No upstream branch found for '..' error: No upstream branch found for '..' fatal: ambiguous argument '..@{u}': unknown revision or path not in the working tree. Use '--' to separate paths from revisionsCupped
You'll get those errors if your local branch isn't configured with an upstream. To fix, run git branch --set-upstream foo origin/foo.Moldau
git log @{u}.. lists every single change in the repo for me. There's no way they don't exist yet.Pull
@romkyns: It's possible your local branch has the wrong remote branch configured as the upstream. Make sure git rev-parse --symbolic-full-name @{u} prints the appropriate remote reference. Also, git log @{u}.. shows the commits that aren't reachable by the upstream branch, which can include commits that are already in the remote repository (if they are reachable by a different reference). This will happen right after you merge in an already-pushed branch.Moldau
@RichardHansen I'm afraid I'm too noob to know what would be appropriate for a remote reference, however this was a freshly cloned repo on which I did only a checkout <somebranch> and merge <otherbranch>. At this point, I did the log @{u}.. and saw every change listed.Pull
@romkyns: If by "saw every change" you mean that you saw all of the commits from <otherbranch>, then this is expected. Because you just did the merge, the commits on <otherbranch> are now reachable from your local <somebranch> but aren't yet reachable from the remote origin/<somebranch>. Thus, these commits are "outgoing" to the remote origin/<somebranch> branch. Even though they won't be new to the remote repository, they'll be new to that remote branch.Moldau
@romkyns: I realize this is confusing; Git is inherently hard to understand. I highly recommend reading Pro Git -- it'll help you understand this stuff.Moldau
I see, your comment makes it clear. My confusion stems from the fact that hg outgoing does not do that. It just lists commits that need to be sent to the remote repo. I think git push --dry-run is much closer in spirit to hg outgoing.Pull
You still need to git fetch all changes before executing git log ..@{u} for this to work.Forrest
@anatolytechtonik Indeed. The suggested incoming alias includes a git remote update -p, which fetches changes. But I'd rather git fetch instead, to only fetch changes for the current branch's upstream: git config --global alias.incoming '!git fetch && git log ..@{u}'Phaedra
S
100

Git can't send that kind of information over the network, like Hg can. But you can run git fetch (which is more like hg pull than hg fetch) to fetch new commits from your remote servers.

So, if you have a branch called master and a remote called origin, after running git fetch, you should also have a branch called origin/master. You can then get the git log of all commits that master needs to be a superset of origin/master by doing git log master..origin/master. Invert those two to get the opposite.

A friend of mine, David Dollar, has created a couple of git shell scripts to simulate hg incoming/outgoing. You can find them at http://github.com/ddollar/git-utils.

Singlefoot answered 23/10, 2008 at 20:31 Comment(0)
H
44

Not a full answer but git fetch will pull the remote repo and not do a merge. You can then do a

git diff master origin/master
Harbin answered 23/10, 2008 at 20:7 Comment(1)
Worked for me (but other way around) - git diff origin/master masterSpock
S
35
  1. Use "git log origin..HEAD"

  2. Use "git fetch" followed by "git log HEAD..origin". You can cherry-pick individual commits using the listed commit ids.

The above assumes, of course, that "origin" is the name of your remote tracking branch (which it is if you've used clone with default options).

Scrap answered 23/10, 2008 at 19:55 Comment(2)
(And if you’re not tracking the remote branch, it’s “git log origin/master..HEAD”.)Hammel
"origin" is not the name of the remote tracking branch, it's the name of the remote. And just specifying the remote name doesn't work, you have to specify the remote tracking branch, which would be origin/master.Vasoinhibitor
V
22

There's also this, for comparing all branches:

git log --branches --not --remotes=origin

This is what the git log man page says about this:

Shows all commits that are in any of local branches but not in any of remote tracking branches for origin (what you have that origin doesn’t).

The above is for outgoing. For incoming, just swap:

git log --remotes=origin --not --branches
Vasoinhibitor answered 25/5, 2011 at 9:57 Comment(0)
R
9

I would do

$ git fetch --dry-run

for hg incoming and

$ git push --dry-run

for hg outgoing.

Ralfston answered 21/1, 2014 at 14:30 Comment(1)
Sorry, I overlooked that this was already said as a comment to the OP.Ralfston
T
1

git-out is a script that emulates hg outgoing quite accurately. It parses on "push -n" output, so it produces accurate output if you need to specify additional arguments to push.

Timothytimour answered 5/11, 2011 at 0:33 Comment(0)
W
1

git incoming

$ git fetch && git log ..origin/master --stat
OR
$ git fetch && git log ..origin/master --patch

git outgoing

$ git fetch && git log origin/master.. --stat
OR
$ git fetch && git log origin/master.. --patch
Whack answered 9/12, 2013 at 12:45 Comment(0)
D
0

When the "git log" and @{u} answers initially gave me "unknown revision" errors, I tried out Chris/romkyns suggestion of git push --dry-run.

You will get an output such as "5905..4878 master->master". 5905 is the latest commit that the remote has and commits through (and including) 4878 will be applied to the remote.

You can then use 5905..4878 as arguments to several other git commands to get more details:

git diff 5905..4878 # Gives full code changes in diff style

git log --online 5905..4878 # Displays each commit's comment
Dolly answered 7/7, 2014 at 16:32 Comment(0)
H
0

Incoming commits across all branches can be shown with the following approach.

The command git fetch-diff becomes available by adding an executable called git-fetch-diff to your PATH, containing:

#!/bin/bash

set -e

# get hashes before fetch
old_hashes=$(git log --all --no-color --pretty=format:"%H")

# perform the fetch
git fetch

# get hashes after fetch
new_hashes=$(git log --all --no-color --pretty=format:"%H")

# get the difference
added_hashes=$(comm -1 -3 <(echo "$old_hashes") <(echo "$new_hashes"))

# print added hashes
[ ! -z "$added_hashes" ] && echo "$added_hashes" | git log --stdin --no-walk --oneline

Commit hashes are compared before and after the fetch. The difference is piped back to git log for pretty printing. The appearance of the printed log can be further tuned to your liking with arguments such as --pretty=<format> and --graph.

Note: You might want to cap how far git log will go back in time depending on how much a bash variable can hold on your system, or for performance reasons. This can be done by adding the argument --max-count=<count>.

Hydrotherapy answered 8/10, 2020 at 9:37 Comment(0)
E
-1

When you do git fetch, all the contents including branches,tags ( refs) are stored temporarily in .git/FETCH_HEAD whose content can be viewed with command: git log FETCH_HEAD If you don't use suffix -a with git fetch then by default, FETCH_HEAD's content's will be overwritten by new contents. From these contents, you can view and decide to which branch you want to merge them if you do or you can simple cherry-pick if you want only a few commits from what has been brought by fetch.

Elainaelaine answered 21/10, 2015 at 21:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.