我不知道有什么方法可以在git pull 之后检索旧的origin/master(假设您为master 分支执行此操作)。或者更好的是,您可以使用reflog 来执行此操作,但我会寻找一种更简洁的方法,因为您需要编写脚本。
因此,我们的想法是在执行git pull 之前对当前的origin/master 进行快照,也许标记指向它的提交。 git pull 只是运行git fetch 然后git merge 的快捷方式,后者是我们可以使用 git 挂钩拦截的快捷方式。您可以启用的唯一钩子是pre-merge-commit,仅在合并完成后但在创建提交之前调用(我没有忘记ff,见下文)。这是一个可能的脚本:
. 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"
:
默认挂钩的唯一补充是第二个命令,它将当前的master 与您刚刚获得的fetched 进行比较。如果它们不同,则会创建标签last_master(如果已经存在,则强制使用),您可以在脚本中使用它来替代branch_before_pull。 git merge-base 找到 2 个提交之间的共同祖先,在您的情况下是 master 和 origin/master(请记住,它已经更新到最后一个 fetch)。对于快进和 3 路合并,找到的提交都是旧的 origin/master。
还有一件事需要解决:快进呢?在这种模式下,不会创建合并提交,因此不会调用挂钩。这很痛苦:要“强制”合并,您可以指示 pull 操作禁止快进。有一个选项:
git pull --no-ff origin master
接下来检查新HEAD 的第一个子项(合并提交)是否引用last_master 的相同提交,如果是,则对新origin/master 执行硬重置:
test $(git rev-parse master^1) = $(git rev-parse last_master) && git reset --hard HEAD^2
您可以将其与git pull 连接并为其创建别名,或者将其放在post-merge 挂钩中。
现在,有几点考虑:
-
last_master 标记将进行不必要的更新,但这不是一个真正的问题,因为它保留在您的本地存储库中。如果由于某种原因太烦人,只需使用 git pull --no-verify 来禁用该命令的挂钩。
-
--no-ff 非常常见,您可以将其设为默认选项
git config pull.ff 'false'
明显的副作用是每个分支的拉取都会遵循这种行为。在极限情况下,您可能需要声明一些新别名。
-
我喜欢这一切吗?没有。有没有更痛苦的解决方案?可能有,但(90% 肯定)忘记了简单的单行命令,除非您从 reflog 获取它或浏览 .git 文件夹。