I am not aware of any way to retrieve the old origin/master (assuming you do this for master branch) after a git pull. Or better, you could do this using the reflog, but I would look for a cleaner way since you need to script it.
So, the idea is to make a snapshot of the current origin/master before doing a git pull, perhaps tagging the commit pointing to it. git pull is just a shortcut for running git fetch and then git merge, the latter is the one we can intercept using a git hook. The only hook you can enable is the pre-merge-commit, called only after the merge is completed but before creating the commit (I did not forget about ff, see below). This is a possible script:
. git-sh-setup
test $(git rev-parse master) != $(git rev-parse origin/master) && \
git tag -f last_master $(git merge-base master origin/master)
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:
Where the only addition to the default hook is the second command, that compares the current master with the one you have just fetched. If they are different, the tag last_master is created (or forced if already exists) and you can use it inside your script as a replacement for branch_before_pull. git merge-base finds the common ancestor between 2 commits, in your case master and origin/master (remember that it is already updated to the last fetch). Both for a fast forward and a 3-way merge, the found commit is the old origin/master.
There is still one thing to fix: what about fast-forwards? In this mode, no merge commit is created, therefore neither the hook is called. This gets painful: to "force" a merge, you can instruct the pull operation to forbid fast-forwards. There is an option for this:
git pull --no-ff origin master
Next you check if the first child of the new HEAD (the merge commit) references the same commit of last_master, and if it is the case then you perform a hard reset to the new origin/master:
test $(git rev-parse master^1) = $(git rev-parse last_master) && git reset --hard HEAD^2
You could concatenate it with the git pull and create an alias for it, or put it inside the post-merge hook.
Now, a few considerations:
The last_master tag is going to be updated more than necessary, but it is not a real problem since it stays inside your local repository. If it were to be too annoying for whatever reason, just use git pull --no-verify to disable the hook for that command only.
--no-ff is so common that you can make it the default option with
git config pull.ff 'false'
The obvious side effect is that the pull from every branch will follow this behaviour. At the limit, you may want to declare some new aliases.
Do I like all of this? No. Is there any less painful solution? There might be, but (90% sure) forget the simple one-line command, unless you take it from the reflog or exploring the .git folder.