每当我执行git pull时,我已经配置git来使用rebase。但是,如果我在头上设置了标记,并且存在远程更改,那么将拉动那些远程更改,然后我的本地更改将作为分支时间轴上的新提交重播,但我的标记将保留在旧提交中。旧提交现在成为其时间轴的叶节点,并且它给出了一个令人困惑的历史视图。
是否可以(通过简单的脚本或最好通过git命令)来实现“git pull'只有当HEAD上没有标签时才进行rebase(或者甚至更好的是没有标签导致HEAD的未提交的提交)。
PS:对我来说,从来没有在我已经推动的东西上设置标签可能是明智的,因为这样可以解决时间线凌乱的问题,但这不是我想到的解决方案答案 0 :(得分:2)
内置任何内容,但如果您愿意使用git fetch
代替git pull
,则构建起来很容易:
步骤1只是(假设 1 当前分支在更新方面映射到origin/branch
):
git update-ref refs/save/origin/branch refs/remotes/origin/branch
您实际上不必命名此refs/save/origin/branch
,但显然拥有已保存上游的整个名称空间可以实现未来的灵活性。但是,它更简单(不需要映射到上游分支名称)来使用固定名称,例如ORIG_UPSTREAM
(只需使用它来代替拼写出的refs/save/
名称)
步骤3需要列出(或至少计数/测试 - 非空)提交已添加或删除的提交。要获取修订列表,我们需要git rev-list
。我们可以很容易地看到使用DAG子集操作添加和删除的内容:
git rev-list refs/save/origin/branch..origin/branch # these were added
git rev-list origin/branch..refs/save/origin/branch # these were removed
我们在这里不需要实际的提交ID,因此我们可以添加--count
并获得两个计数。如果总和(或任何一个)非零,则上游已发生变化,您可能会进行变基。 (如果上游有删除了修订版,你可能不想在没有特别小心的情况下进行修改,但我会在这里忽略它。)
现在,test-and-maybe-rebase序列如下:
在这里,对于第1步,我们确实需要修订列表,但这很容易获得:
git rev-list refs/save/origin/branch..HEAD
这些是您在fetch
之前没有上游的提交。 (您可以使用origin/branch..HEAD
来获取上游不再拥有的提交,但这可能包括故意删除上游的提交,您仍然拥有副本。一如既往,您可以省略{{1}这个词我在这里使用它来强调它。)
现在您只需要查看这些提交ID是否是您的代码的目标,您可以使用HEAD
进行测试以迭代自己的代码。如果使用带注释的标记,我们必须注意在比较之前解析对提交的标记引用,因为您将在此处看到带注释的标记对象ID。
这可能看起来像这样(未经测试):
git for-each-ref refs/tags
(如果列表通常很小,那么对提交ID列表的两个文件进行排序可能是过度的,但如果不是,则会给你O(n log n)行为 - 如果你不熟悉{{1它找到两个文件唯一且通用的行,将它们打印在三列中;使用TF1=$(mktemp -t rbcheck) || exit 1
TF2=$(mktemp -t rbcheck) || { rm -f $TF1; exit 1; }
trap "rm -f $TF1 $TF2" 0 1 2 3 15
git rev-list refs/save/origin/branch.. | sort > $TF1
git for-each-ref refs/tags | while read sha1 objtype tagname; do
[ $objtype = tag ] && sha1=$(git rev-parse $sha1^{commit}
echo $sha1
done | sort > $TF2
if [ $(comm -12 $TF1 $TF2 | wc -l) -gt 0 ]; then
echo there are some tags in the to-be-rebased commits
else
echo there are no tags, it is safe to rebase
fi
跳过除常用项目列之外的所有文件的打印。)
但最终,我怀疑你真正想要的是这个(更难):
要在此处实施第3步,我们需要使用comm
来获取" pre-rebase"和" post-rebase"提交。如果这些列表长度相同,我们就会处于良好状态。如果post-rebase列表较短,则省略一些提交,可能是由于上游的冗余。 (如果rebase后列表更长出现问题:这不应该发生,至少除非你做了交互式rebase并拆分了一些提交。)
如果提交已经消失,则来自" pre"到"发布" rebase不再是1比1,你必须决定如何处理一个" new"提交不存在。 (这部分取决于你,你可以重新映射到一个祖先或孩子,或者认为它是一个错误。)此外,并不总是明显哪些提交被省略。为了完全理解这一点,您可以尝试通过-12
一次重复一次提交的rebase过程;或者您可以比较提交消息文本,如果这些文本足够独特(这会更快)。
我会给你(或其他人)实施更高级的方法。 : - )
1 如果你的git不是太古老,那么获取当前分支的上游名称实际上很容易:
git rev-list
通常应采用git cherry-pick
形式。请注意,如果没有上游,upstream=$(git rev-parse --symbolic-full-name @{u}) || exit 1
将退出并显示错误,因此此处为refs/remotes/remote/branch
。要将其转换为rev-parse
之类的名称,请首先确保它以|| exit 1
开头,然后替换为:
refs/save/
例如。