修复git标记?

时间:2016-08-13 00:22:03

标签: git

我刚才做了以下事情:

// make change
// git add .
// git commit -m "2.0.0"
// git tag -a v2.0.0 <sha-of-above-commit>
// git push --tags

但是,我忘了推送实际的提交,现在我的标签没有显示出来(可能是因为我实际上没有推送我标记的提交。)

然后我重新克隆了回购并运行了git tag,并在那里看到了我的标签。

但是,我的提交未列在git log下。所以我重新制作了我的更改,并运行了git push。这成功了。但是,git push --tags失败了,因为它说标签已存在于遥控器上。

对此有何解决方案?我尝试删除远程v2.0.0标记,但出现(hook declined)错误。

1 个答案:

答案 0 :(得分:2)

TL; DR:git push origin master

ElpieKay's comment有正确的答案:您的git push推送了提交和标记,但其他(远程)Git存储库中没有分支包含提交。也就是说,就你自己的Git提交图而言,你有 - 我在这里猜测有问题的分支是master - 这个:

...--o     <-- origin/master
      \
       o   <-- master, tag:v2.0.0

您随后向Git on origin发送了提交本身(根据需要发送标记v2.0.0)以及 it 的请求以创建名为的标记v2.0.0指向新提交 - 它做了 it 图表:

...--o     <-- master
      \
       o   <-- tag:v2.0.0

现在从其他Git(包括您自己)克隆存储库的任何人都会在git tag输出中看到标记,但不会在分支master上看到提交,因为它不是 on 分支master。新提交的唯一链接是标记。

解决方案很简单:做一个git push让你的Git让他们(来源的)Git设置他们的分支master来指向新的提交。例如,如果提交的哈希ID是1234567,那么这就可以解决问题:

git push origin 1234567:master

甚至来自你的新克隆。或者,因为标记v2.0.0解析为正确的提交哈希: 1

git push origin v2.0.0^{commit}:master

这个简单修复的最简单版本是从原始开发存储库执行push操作,其中master分支指向与v2.0.0标记相同的提交。在这种情况下,您不需要指定refspec参数的两半:

git push origin master

(当然,这确实假设起源master从那时起没有增加新的提交。)

1 我说“解析为”,然后介绍这个时髦的v2.0.0:^{commit}语法。那是什么意思?

由于v2.0.0带注释的标记(由git tag -a生成),因此名称本身实际上指向存储库中的标记对象。它是指向提交的标记对象。当我绘制提交图时,我绘制了 commit 图,而不是commit-and-tag图。 :-)所以我离开了这一点。

但是,当我们转到git push时,确保我们要求他们的Git将其分支master设置为直接指向提交而不是标记,这可能是明智之举。分支名称不允许指向标记。也许请求会起作用 - 也许Git会知道“不允许分支名称指向标签”,并且会使用适当的魔法将标记对象转换为其目标提交ID,但可能不会。我们可以通过告诉我们的 Git将任何标记名称转换为其目标提交来完全避免这个问题。

这就是这个时髦的语法。如the gitrevisions documentation中所述,name:^{type}首先告诉Git解析名称,然后根据需要“剥离”该名称以找到给定类型的Git对象。

当您为Git提供分支名称时,该名称将保证解析为提交对象,因为分支名称​​必须指向提交对象。另一方面,标记名称可以指向all-commit,tag,tree或blob中的任何Git对象。通常它们仅指向标记对象或提交对象,但Git不会阻止您创建指向blob或树的对象。我已经在我自己的存储库中为各种实验目的做了这个。因此,对于标记,您可以使用^{commit}强制它解析为提交。如果名称指向带注释的标记对象,则该标记将跟随其提交。如果名称已经指向提交,则它什么都不做。如果名称以某种方式指向树或blob,则会产生错误。

您还可以使用:^{tree}:^{blob}来验证名称是否指向树或blob对象。当然,如果名称是分支名称,但它不是,但 name 部分也可以包含路径:例如,master:Documentation命名一个树对象Git本身的Git存储库中的分支master,如果您正在编写脚本并且需要非常确定您正在获取树的哈希ID,您可以写:

treehash=$(git rev-parse master:Documentation^{tree}) || die ...

在你的剧本中。