OK, based on comments, let's note:
- The
pull
script is basically the same as1 git fetch
followed by either git merge
or git rebase
, depending on which one you ask for (in your config setup or with --rebase
).
- Using
gitrevisions
syntax, we can find "the commit some branch name, like master
, pointed to before the rebase ran" with master@{1}
. (The reflog syntax is described in more detail in the git reflog
documentation.)
Thus, you can see what the rebase did to your code with git diff branch@{1} branch
(note: in some shells, not including bash but including csh/tcsh, you have to quote the braces to get this to work: git diff 'branch@{1}' branch
or git diff branch@\{1} branch
, for instance).
(You can get even fancier: gitrevisions
syntax can be used pretty much anywhere, so you can use these as arguments to git merge-base
, for instance.)
Long illustration follows, feel free to skip.
Before fetch-and-rebase, you might have something like this:
o--o--o <-- master
/
c--c--c <-- origin/master
The c
commit-nodes are "common" (shared between you and everyone else), while the o
commit-nodes are "ours" (or "original"), i.e., your own work, not yet shared with anyone.
When you fetch
this brings in new work, let's call them C
for also-common-but-new:
o--o--o <-- master
/
c--c--c--C--C <-- origin/master
(see footnote 1 for minor caveat). At this point nothing has happened to master
, but then the pull does a git rebase
, as you instructed it to. This copies your o
commits to new, somewhat different commits (they now include stuff that was changed in the C
commits):
o--o--o <-- master@{1}
/
c--c--c--C--C <-- origin/master
\
*--*--* <-- master
The three original commits (o
) are still in there. Normally they're invisible: I label them "abandoned" in similar drawings in other StackOverflow answers, as they have no branch-name pointing to them. The reflog, though, keeps "previous references" alive for a while (default = 30 days), and the @{1}
or @{yesterday}
or other similar syntax can be used to dig them out.
So git diff master@{1} master
compares the last o
commit with the last *
commit, which shows you how "what they did" affects "what you did".
(Note that origin/master
also has a reflog. If you do a regular fetch
, so that origin/master
is updated, you can git diff origin/master@{1} origin/master
to compare the last c
commit against the second C
commit. If you use git pull
, however, this needs git 1.8.4 or newer to get origin/master
updated; see footnote 1.)
1When you git pull origin master
this really does run git fetch origin master
, i.e., it really does invoke git fetch
directly. The thing here is that it gives fetch
two arguments: the remote, and a branch name. In git versions older than 1.8.4, this changes the way fetch
operates, so that fetch does not update origin/master
. In 1.8.4 and newer, fetch
updates the remote-branch origin/master
, which makes more sense: now that "our git" knows that "their git" has new commits, we really should just update our idea of where master
is over there. (That's all a "remote branch" is: a copy, locally, of where "their" branch was, the last time we checked.)
The fetch
command always writes the fetched-branch information to the file FETCH_HEAD
in the top level git directory. It does this no matter how it's invoked. While FETCH_HEAD
looks a lot like a regular reference a la HEAD
, MERGE_HEAD
, ORIG_HEAD
, and so on, it has some extra information on each line, left there specifically for the pull
script.
In all cases, after fetch
brings in new commits and maybe-updates-remote-branches, the pull
script then extracts the SHA-1 ID of the newest commit from FETCH_HEAD
. It supplies this raw SHA-1 ID to either merge
or rebase
.
There's one more special case though: when git pull
is going to rebase, it has some fancy logic for detecting and recovering from a rebase on the remote. Normally this should not happen (it's not a good idea to retract published/shared commits), but git pull --rebase
can handle it, while regular git rebase
needs extra help from the user. (There is a new feature in git 1.9/2.0 to make this work better.)
I think it's worth looking through /usr/local/libexec/git-core/git-pull
(if this is where your git-core
directory lives: sometimes it's /usr/libexec
instead, or somewhere else) to see how this works.