This is a little bit difficult for several reasons:
git pull
means run git fetch
, then run a second Git command to incorporate whatever got fetched.
- Git does not record here which second command is used. The second command is chosen by whoever ran
git pull
, so you would have to make sure that whoever ran it, remembers which command they chose. (The choice is based on both command line options and Git configuration settings.)
- The command you need to use to obtain the right answer depends on both what came in and what second command was used.
Practical example: a deployment script ...
Deployment scripts should never use git pull
, so this gives you an easy way out of the problem: just don't use git pull
in the deployment script. Run git fetch
, then run your own second Git command. Now you know for sure which second command was used, because your script, not the user running your script, chose that second command.
Now, let's assume the second command, the one that you choose in your script, is git merge
. There is still a problem here because git merge
can do a fast-forward merge, but it can do a real merge. If it does a real merge, the merge can fail. If you tell it do only a fast-forward merge (using git merge --ff-only
), that also can fail, if a real merge is required.
There is no single correct action for all cases here. You must decide what you want to have happen based on your situations. But let's assume, for the moment, that git merge --ff-only
along with a test of the form "if the merge fails, abort the deployment entirely" is sufficient. Then your script would contain these lines:
git fetch origin || die ...
starthash=$(git rev-parse HEAD) || die ...
git merge --ff-only || die ...
where die
is a shell function that you write, that aborts this deployment. In other words, we will:
Use git fetch origin
to update our local Git repository with new commits from origin
, updating origin/master
, origin/develop
, and so on.
This is what the first line, git fetch origin || die ...
does. Again, you must write the die
function.
Save the current hash ID so that we know which commit was current before we ran git merge --ff-only
.
Run git merge --ff-only
so that we get a fast-forward merge, or a failure if fast-forward merging is not possible (if a real merge is required).
(Note: if you want to try a real merge for this case, this complicates deployment! You'll need to decide what to do if the real merge stops to get help from the user.)
If all of the above go well, you're now ready to compare what was in the HEAD
commit before the git merge --ff-only
to what is in the HEAD
commit after the git merge --ff-only
. You do this with a simple git diff
, or for reliability in a script, git diff-tree
. (The git diff-tree
command is a little bit harder to use in general, but is not affected by per-user configurations, so it's wise to use git diff-tree
in any script that is not user-oriented.) So now you can run:
git diff --name-only $starthash HEAD
or:
git diff-tree --name-only $starthash HEAD
In this case, both produce the same output except that git diff-tree
has the rename detector turned off, regardless of the user's git diff
configuration. This will only make a visible difference if the rename detector is on and finds a rename, and even then it will be non-obvious unless you were to switch from --name-only
to --name-status
: you'll see that one add-file and one delete-file are replaced with one rename-file-from-old-name-to-new-name operation.