Git标记也会标记所有以前的提交

时间:2018-05-26 12:44:35

标签: git github git-tag

目前我正在尝试在github上提供我的lib。有两个版本:0.10.2。我知道pip可以通过git上的标签找到包版本,所以我想考虑标记它。

当我这样做时:

git add .
git commit -m "msg1"
git tag -a 0.1 -m "lib v0.1"
git push origin master --tag 0.1

第一次提交标记为0.1

但是当我在代码中更改某些内容时,我的功能几乎相同:

git add .
git commit -m "msg2"
git tag -a 0.2 -m "lib v0.2"
git push origin master --tag 0.2

最后一次提交标记为0.2,但第一次提交标记为0.2和0.1。难道我做错了什么?或者它是否应该是它?

@Edit。这就是它在我的git上的样子:

首次提交: enter image description here

第二次提交: enter image description here

Releases标签:

enter image description here

2 个答案:

答案 0 :(得分:2)

这只是基于github如何在其UI中显示标签的误解。当git在提交上显示标记时,这并不一定意味着使用该版本标记了提交。要在github中查看实际标签,可以单击“Releases”选项卡。

答案 1 :(得分:2)

TL; DR

一切都很好。

GitHub尝试从GitHub用户隐藏很多Git的复杂性。我认为这是一个错误。虽然众所周知Git是用户不友好的(例如,"10 things I hate about Git"xkcd #1597),但某些的复杂性确实是必要的。 1

在Git标签的情况下,关于标签的实现是任何一个标签只是某个特定哈希ID的人类可读名称。哈希ID是那些GitHub灰白和缩写并且几乎无法读取的丑陋数字的东西。在屏幕截图中,此处显示的两个是a89f1cc31a6a2d

这些哈希ID是Git对象的真实名称,即Git自身用来查找对象的名称。内容。这些哈希ID本身是通过将加密哈希应用于内容而生成的,因此哈希ID是键值数据库的短(ish)键:给定密钥,保证是密钥对于那些特定内容是唯一的, 2 Git可以查找值并获取整个内容。由于两个哈希值不同,因此两个对象也必然不同。如果两个对象相同,则两个哈希值相同。

对于带注释的标记对象,实际上需要更深入一些:带注释标记的内容包括目标对象的哈希值。这很容易从命令行完成 - 再次,GitHub隐藏了细节,而不是命令行都清楚:

git rev-parse a89f1cc^{}
例如,

会查找对象a89f1cc,检查它是否是带注释的标记对象,如果是,请将其跟随标记本身命名的其他对象。如果a89f1cc是其他类型的对象,则后缀^{}无效。我们也可以写:

git rev-parse a89f1cc^{commit}

将找到a89f1cc解析的 commit 对象,或者产生错误,在这种特殊情况下,这将是我们想要的:这将为我们提供完整的哈希a89f1cc本身的ID,如果它已经是提交,或者生成a89f1cc解析的提交的哈希ID,如果它解析为提交,或者错误。

更实际上,作为使用系统的人,给定两个标签名称,您只需使用名称

git rev-parse v0.1^{commit}

git rev-parse v0.2^{commit}

查找标记所指向的提交。 (有些shell可能需要围绕帽^和/或大括号{...}字符进行某种引用;这取决于您是使用bash,tcsh,PowerShell还是其他。您可能需要调整这些命令-line命令稍微让你的shell满意。)

将两个标记哈希中的每一个解析为提交将告诉您哪个提交或提交两个不同的标记名称。可以为单个提交提供多个标记,但您没有这样做,因此您将获得两个不同的提交哈希值。这些提交是pip install将签出,构建和安装的提交。

1 Albert Einstein is often paraphrased as saying Everything should be made as simple as possible, but not simpler,虽然Wikiquote says he actually wrote It can scarcely be denied that the supreme goal of all theory is to make the irreducible basic elements as simple and as few as possible without having to surrender the adequate representation of a single datum of experience.

2 这有点夸大其词,取决于您的Git版本。有关详细信息,请参阅Hash collision in git

还有更多要知道你是否是Git用户:标签与分支机构以及提交图

如果您只是要安装,以上可能就是您关注的所有内容。但是,作为使用Git本身的人,可以从中学到另一件事。

我们在上面看到,标签名称通过git rev-parse(大多数Git命令在适当的时候内部执行)解析为哈希ID。但同样如此 - 分支名称 ,如masterdevelop。我们可以运行:

$ git rev-parse v2.16.0
e1c2c6b098dfb717a4a6ff7f3894d57343210a41

并获取这样的哈希ID,但我们也可以运行:

$ git rev-parse master
ccdcbd54c4475c2238b310f7113ab3075b5abc9c

并获取哈希ID。此哈希ID是名称master指向的(单个,单个!)提交。所有Git的引用都是如此:分支名称,标记名称,远程跟踪名称(如origin/master等)都是引用的形式< / em>,在Git中,每个引用转换为一(1)个哈希ID。

分支机构名称的特殊之处在于它们随着时间的推移更改。它们现在存储一个哈希ID,然后在运行git commit之后,某些分支名称存储新的,不同的哈希ID。这实际上是分支增长的方式:你告诉Git你希望 on 某个分支,通过运行,例如:

git checkout master

之后git statuson branch master在分支上的含义是git commit更改该分支名称:Git将进行 new 提交,它将获得一些新的,随机的哈希ID,然后Git会将 new 提交的哈希ID存储到名称master中。

这个的基本机制是特殊名称HEAD(在所有大写字母中,虽然在Windows和Mac系统上进行大小写折叠,但您通常可以使用全小写)。 Git 将单词HEAD附加到分支名称,以便记住您已向Git询问的分支。

如果我们有分支名称的单个大写字母,我们可以这样画出来:

A <-B <-C   <-- master (HEAD)

表示HEAD附加到master,名称master 指向提交C - 它包含哈希ID提交C。提交C本身包含先前提交B的哈希ID,提交B包含提交A的哈希ID。

在我们的例子中,我们的存储库很小:它只有这三个提交。提交A没有先前的提交 - Git将其称为 root commit - 因此它不指向任何地方。这显示了Git的工作原理:它使用名称 master来查找当前提交C的哈希ID,然后使用其中的内容提交C以查找C 提交BB的内容让Git找到B的父AA没有父级,所以现在动作停止了:Git显示你提交{{1然后C,然后B,然后停止。

换句话说,Git向后工作

当您进行新的提交A时,Git通过记录所有代码的快照,记录先前提交D的实际哈希ID,然后写出提交和获取来创建此提交它的实际哈希ID(无论是什么)。然后Git使用C知道将新的哈希ID写入HEAD,给出:

master

现在A <-B <-C <-D <-- master (HEAD) 名称(指向)提交master

同样,这就是分支正常移动和增长的方式。 分支名称 D标记名称 master之间的区别在于分支名称​​应该移动 - 提供随时间变化,为该分支命名 last 提交 - 但标签名称​​不会移动。一旦你指定了一个标记名称来指向某个特定的提交,它就会坚持下去:它一直指向那个提交。

从提交到提交的链接形成了一个图形,而这个提交图实际上将Git粘合在一起。 GitHub尝试隐藏您的提交图。因为Git主要是关于图形的文件只是为了骑行 - 这是一个可怕的伤害。理解提交图对于使用Git至关重要。