256

我们在工作中使用 SVN,但对于我的个人项目,我决定使用 Git。所以我昨天安装了 Git,我想知道Git中等效的修订号是多少。

假设我们在版本 3.0.8 上工作,并且每个错误修复都有自己的修订号,当我们谈论这个错误修复时我们可以使用它。因此,如果我将 Git 中的代码标记为 3.0.8,那么我可以将其用作修订号或其他更详细的标识?我发现哈希对人类不太友好。

4

19 回答 19

193

使用现代 Git(在我的情况下为 1.8.3.4)而不使用分支,您可以执行以下操作:

$ git rev-list --count HEAD
68

但这有各种各样的问题,如果需要,可能不容易重现或不容易返回到提交哈希。因此,请尽量避免使用它或仅将其用作提示。

于 2013-09-16T17:53:06.810 回答
157

对您来说是好消息还是坏消息,哈希是修订号。当我从 SVN 切换到 git 时,我也遇到了这个问题。

您可以在 git 中使用“标记”将某个修订标记为特定版本的“发布”,从而轻松引用该修订。看看这篇博文

要理解的关键是 git 不能有修订号——想想去中心化的性质。如果用户 A 和 B 都提交到他们的本地存储库,git 如何合理地分配一个连续的修订号?在他们推/拉对方的更改之前,A 不知道 B。

要查看的另一件事是错误修复分支的简化分支:

从发布开始:3.0.8。然后,在发布之后,执行以下操作:

git branch bugfixes308

这将为错误修复创建一个分支。签出分支:

git checkout bugfixes308

现在进行您想要的任何错误修正更改。

git commit -a

提交它们,然后切换回主分支:

git checkout master

然后从另一个分支中提取这些更改:

git merge bugfixes308

这样,您就有了一个单独的特定于发布的错误修复分支,但您仍然将错误修复更改拉入您的主开发主干。

于 2010-11-07T22:24:42.840 回答
108

git describe命令创建了一个更易于人类阅读的名称,用于引用特定的提交。例如,从文档中:

使用 git.git current tree 之类的东西,我得到:

[torvalds@g5 git]$ git describe parent
v1.0.4-14-g2414721

即我的“父”分支的当前负责人基于v1.0.4,但由于它有一些提交,因此描述添加了额外提交的数量(“14”)和提交的缩写对象名称本身(“2414721”)在最后。

只要您使用合理命名的标签来标记特定版本,就可以认为这大致相当于一个 SVN 的“修订号”。

于 2010-11-07T23:00:04.767 回答
68

其他海报是对的,没有“修订号”。

我认为最好的方法是使用标签进行“发布”!

但是我利用以下内容来伪造修订号(只是为了让客户查看修订和进度,因为他们希望从 git 获得与颠覆所使用的相同的不断增加的修订)。

显示“HEAD”的“当前版本”是通过使用这个来模拟的:

git rev-list HEAD | wc -l

但是,如果客户告诉我“修订版”1302 中存在错误怎么办?

为此,我在 ~/.gitconfig 的 [alias] 部分添加了以下内容:

show-rev-number = !sh -c 'git rev-list --reverse HEAD | nl | awk \"{ if(\\$1 == "$0") { print \\$2 }}\"'

然后使用git show-rev-number 1302将打印“修订”的哈希值:)

不久前,我发表了一篇关于该“技术”的博客文章(德语) 。

于 2012-06-04T00:34:44.710 回答
28

Git 没有与 subversion 相同的修订号概念。相反,每个通过提交生成的给定快照都由 SHA1 校验和标记。为什么?在分布式版本控制系统中运行 revno 存在几个问题:

首先,由于开发根本不是线性的,数字的附加作为一个问题很难解决,以满足您作为程序员的需求。当数字不符合您的预期时,尝试通过添加数字来解决此问题可能很快就会出现问题。

其次,修订号可能会在不同的机器上生成。这使得数字同步变得更加困难——尤其是因为连接是单向的;您甚至可能无法访问拥有该存储库的所有机器。

第三,在 git 中,在某种程度上由现已失效的 OpenCM 系统开创,提交的身份(提交是什么)等同于它的名称(SHA id)。这个命名=身份的概念很强烈。当您拿着提交名称坐下来时,它还会以不可伪造的方式识别提交。这反过来又让您可以使用命令检查所有提交回第一个初始提交是否损坏git fsck

现在,由于我们有修订的 DAG(有向无环图)并且这些构成了当前树,我们需要一些工具来解决您的问题:我们如何区分不同的版本。首先,如果给定的前缀(例如 1516bd)唯一标识您的提交,您可以省略部分哈希。但这也是相当做作的。相反,诀窍是使用标签和/或分支。标签或分支类似于附加到给定提交 SHA1-id 的“黄色便签”。本质上,标签是不移动的,而当对它的 HEAD 进行新的提交时,分支会移动。有一些方法可以引用标记或分支周围的提交,请参阅 git-rev-parse 的手册页。

通常,如果您需要处理特定的代码段,那段代码正在发生变化,因此应该是一个带有主题名称的分支。创建大量分支(每个程序员 20-30 个并非闻所未闻,发布了一些 4-5 个供其他人使用)是有效 git 的诀窍。每一项工作都应该从自己的分支开始,然后在测试时合并。未发布的分支可以完全重写,这部分破坏历史是 git 的力量。

当改变被主人接受时,它有点冻结并变成了考古学。此时,您可以标记它,但更常见的是,通过 sha1 总和在错误跟踪器或问题跟踪器中对特定提交进行引用。标签往往是为维护分支(旧版本)的版本颠簸和分支点保留的。

于 2010-11-07T22:46:51.937 回答
20

如果你有兴趣,我会从这里的 git infos 自动管理版本号,格式如下

<major>.<minor>.<patch>-b<build>

其中 build 是提交的总数。您将在Makefile. 这是访问版本号不同部分的相关部分:

LAST_TAG_COMMIT = $(shell git rev-list --tags --max-count=1)
LAST_TAG = $(shell git describe --tags $(LAST_TAG_COMMIT) )
TAG_PREFIX = "latex-tutorial-v"

VERSION  = $(shell head VERSION)
# OR try to guess directly from the last git tag
#VERSION    = $(shell  git describe --tags $(LAST_TAG_COMMIT) | sed "s/^$(TAG_PREFIX)//")
MAJOR      = $(shell echo $(VERSION) | sed "s/^\([0-9]*\).*/\1/")
MINOR      = $(shell echo $(VERSION) | sed "s/[0-9]*\.\([0-9]*\).*/\1/")
PATCH      = $(shell echo $(VERSION) | sed "s/[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/")
# total number of commits       
BUILD      = $(shell git log --oneline | wc -l | sed -e "s/[ \t]*//g")

#REVISION   = $(shell git rev-list $(LAST_TAG).. --count)
#ROOTDIR    = $(shell git rev-parse --show-toplevel)
NEXT_MAJOR_VERSION = $(shell expr $(MAJOR) + 1).0.0-b$(BUILD)
NEXT_MINOR_VERSION = $(MAJOR).$(shell expr $(MINOR) + 1).0-b$(BUILD)
NEXT_PATCH_VERSION = $(MAJOR).$(MINOR).$(shell expr $(PATCH) + 1)-b$(BUILD)
于 2012-07-25T23:22:34.530 回答
10

一个 Bash 函数:

git_rev ()
{
    d=`date +%Y%m%d`
    c=`git rev-list --full-history --all --abbrev-commit | wc -l | sed -e 's/^ *//'`
    h=`git rev-list --full-history --all --abbrev-commit | head -1`
    echo ${c}:${h}:${d}
}

输出类似

$ git_rev
2:0f8e14e:20130220

那是

commit_count:last_abbrev_commit:date_YYmmdd
于 2013-02-20T23:19:39.783 回答
9

提交的SHA1 哈希等同于 Subversion 修订号。

于 2010-11-07T22:24:32.047 回答
7

这是我在基于其他解决方案的 makefile 中所做的。请注意,这不仅为您的代码提供了一个修订号,它还附加了允许您重新创建版本的哈希。

# Set the source control revision similar to subversion to use in 'c'
# files as a define.
# You must build in the master branch otherwise the build branch will
# be prepended to the revision and/or "dirty" appended. This is to
# clearly ID developer builds.
REPO_REVISION_:=$(shell git rev-list HEAD --count)
BUILD_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD)
BUILD_REV_ID:=$(shell git rev-parse HEAD)
BUILD_REV_ID_SHORT:=$(shell git describe --long --tags --dirty --always)
ifeq ($(BUILD_BRANCH), master)
REPO_REVISION:=$(REPO_REVISION_)_g$(BUILD_REV_ID_SHORT)
else
REPO_REVISION:=$(BUILD_BRANCH)_$(REPO_REVISION_)_r$(BUILD_REV_ID_SHORT)
endif
export REPO_REVISION
export BUILD_BRANCH
export BUILD_REV_ID
于 2015-04-28T14:14:18.950 回答
6

使用 git hash 作为内部版本号的问题在于它不是单调递增的。OSGi 建议使用时间戳作为内部版本号。看起来可以使用提交到分支的数量来代替 subversion 或 perforce 更改数量。

于 2012-08-24T16:30:34.603 回答
6

我编写了一些 PowerShell 实用程序,用于从 Git 检索版本信息并简化标记

功能:Get-LastVersion、Get-Revision、Get-NextMajorVersion、Get-NextMinorVersion、TagNextMajorVersion、TagNextMinorVersion:

# Returns the last version by analysing existing tags,
# assumes an initial tag is present, and
# assumes tags are named v{major}.{minor}.[{revision}]
#
function Get-LastVersion(){
  $lastTagCommit = git rev-list --tags --max-count=1
  $lastTag = git describe --tags $lastTagCommit
  $tagPrefix = "v"
  $versionString = $lastTag -replace "$tagPrefix", ""
  Write-Host -NoNewline "last tagged commit "
  Write-Host -NoNewline -ForegroundColor "yellow" $lastTag
  Write-Host -NoNewline " revision "
  Write-Host -ForegroundColor "yellow" "$lastTagCommit"
  [reflection.assembly]::LoadWithPartialName("System.Version")

  $version = New-Object System.Version($versionString)
  return $version;
}

# Returns current revision by counting the number of commits to HEAD
function Get-Revision(){
   $lastTagCommit = git rev-list HEAD
   $revs  = git rev-list $lastTagCommit |  Measure-Object -Line
   return $revs.Lines
}

# Returns the next major version {major}.{minor}.{revision}
function Get-NextMajorVersion(){
    $version = Get-LastVersion;
    [reflection.assembly]::LoadWithPartialName("System.Version")
    [int] $major = $version.Major+1;
    $rev = Get-Revision
    $nextMajor = New-Object System.Version($major, 0, $rev);
    return $nextMajor;
}

# Returns the next minor version {major}.{minor}.{revision}
function Get-NextMinorVersion(){
    $version = Get-LastVersion;
    [reflection.assembly]::LoadWithPartialName("System.Version")
    [int] $minor = $version.Minor+1;
    $rev = Get-Revision
    $next = New-Object System.Version($version.Major, $minor, $rev);
    return $next;
}

# Creates a tag with the next minor version
function TagNextMinorVersion($tagMessage){
    $version = Get-NextMinorVersion;
    $tagName = "v{0}" -f "$version".Trim();
    Write-Host -NoNewline "Tagging next minor version to ";
    Write-Host -ForegroundColor DarkYellow "$tagName";
    git tag -a $tagName -m $tagMessage
}

# Creates a tag with the next major version (minor version starts again at 0)
function TagNextMajorVersion($tagMessage){
    $version = Get-NextMajorVersion;
    $tagName = "v{0}" -f "$version".Trim();
    Write-Host -NoNewline "Tagging next majo version to ";
    Write-Host -ForegroundColor DarkYellow "$tagName";
    git tag -a $tagName -m $tagMessage
}
于 2013-11-19T23:57:56.880 回答
5

每个提交都有一个唯一的哈希。除此之外,git 中没有修订号。如果您想要更多的用户友好性,您必须自己标记提交。

于 2010-11-07T22:24:26.220 回答
4

我只想指出另一种可能的方法——那就是使用git git-notes(1),自 v 1.6.6 以来就存在(自我注释 - Git)(我使用的是git1.7.9.5 版本)。

基本上,我曾经git svn克隆一个具有线性历史(没有标准布局、没有分支、没有标签)的 SVN 存储库,并且我想比较克隆git存储库中的修订号。这个 git clone 默认没有标签,所以我不能使用git describe. 这里的策略可能仅适用于线性历史 - 不确定合并等结果如何;但这是基本策略:

  • 询问git rev-list所有提交历史的列表
    • 由于rev-list默认情况下按“时间倒序”,我们将使用它的--reverse开关来获取按最早排序的提交列表
  • 使用bash外壳来
    • 在每次提交时增加一个计数器变量作为修订计数器,
    • 为每个提交生成并添加一个“临时”git note
  • 然后,使用git logwith浏览日志--notes,这也将转储提交的注释,在本例中为“修订号”
  • 完成后,擦除临时注释(注意:我不确定这些注释是否已提交;它们并没有真正显示git status

首先,让我们注意git有一个默认的笔记位置——但你也可以ref为笔记指定一个(erence)——这会将它们存储在不同的目录中.git;例如,在gitrepo 文件夹中,您可以调用git notes get-ref以查看将是哪个目录:

$ git notes get-ref
refs/notes/commits
$ git notes --ref=whatever get-ref
refs/notes/whatever

需要注意的是,如果您notes add使用 a --ref,之后还必须再次使用该引用 - 否则您可能会收到类似“ No note found for object XXX... ”之类的错误。

对于此示例,我选择将ref注释称为“linrev”(用于线性修订)——这也意味着该过程不太可能会干扰现有的注释。我也在使用--git-dir开关,因为是git新手,所以我在理解它时遇到了一些问题-所以我想“以后记住” :);而且我还--no-pager用来抑制less使用时的生成git log

因此,假设您在一个目录中,其中一个子文件夹 myrepo_gitgit存储库;可以这样做:

### check for already existing notes:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.

### iterate through rev-list three, oldest first,
### create a cmdline adding a revision count as note to each revision

$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
  TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
  TCMD="$TCMD add $ih -m \"(r$((++ix)))\""; \
  echo "$TCMD"; \
  eval "$TCMD"; \
done

# git --git-dir=./myrepo_git/.git notes --ref linrev add 6886bbb7be18e63fc4be68ba41917b48f02e09d7 -m "(r1)"
# git --git-dir=./myrepo_git/.git notes --ref linrev add f34910dbeeee33a40806d29dd956062d6ab3ad97 -m "(r2)"
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev add 04051f98ece25cff67e62d13c548dacbee6c1e33 -m "(r15)"

### check status - adding notes seem to not affect it:

$ cd myrepo_git/
$ git status
# # On branch master
# nothing to commit (working directory clean)
$ cd ../

### check notes again:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# (r15)

### note is saved - now let's issue a `git log` command, using a format string and notes:

$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)
# 77f3902: _user_: Sun Apr 21 18:29:00 2013 +0000:  >>test message 14<< (r14)
# ...
# 6886bbb: _user_: Sun Apr 21 17:11:52 2013 +0000:  >>initial test message 1<< (r1)

### test git log with range:

$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)

### erase notes - again must iterate through rev-list

$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
  TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
  TCMD="$TCMD remove $ih"; \
  echo "$TCMD"; \
  eval "$TCMD"; \
done
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# Removing note for object 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# git --git-dir=./myrepo_git/.git notes --ref linrev remove f34910dbeeee33a40806d29dd956062d6ab3ad97
# Removing note for object f34910dbeeee33a40806d29dd956062d6ab3ad97
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 04051f98ece25cff67e62d13c548dacbee6c1e33
# Removing note for object 04051f98ece25cff67e62d13c548dacbee6c1e33

### check notes again:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.

因此,至少在我没有分支的完全线性历史的特定情况下,修订号似乎与这种方法相匹配 - 此外,这种方法似乎允许使用git log修订范围,同时仍然获得正确的修订号 - YMMV但是,在不同的背景下...

希望这对某人有帮助,
干杯!


编辑:好的,这里有点简单,git上面的循环有别名,称为setlinrevand unsetlinrev; 在您的 git 存储库文件夹中时,请执行(注意讨厌的bash转义,另请参见#16136745 - 添加包含分号的 Git 别名):

cat >> .git/config <<"EOF"
[alias]
  setlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
      TCMD=\"git notes --ref linrev\"; \n\
      TCMD=\"$TCMD add $ih -m \\\"(r\\$((++ix)))\\\"\"; \n\
      #echo \"$TCMD\"; \n\
      eval \"$TCMD\"; \n\
    done; \n\
    echo \"Linear revision notes are set.\" '"

  unsetlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
      TCMD=\"git notes --ref linrev\"; \n\
      TCMD=\"$TCMD remove $ih\"; \n\
      #echo \"$TCMD\"; \n\
      eval \"$TCMD 2>/dev/null\"; \n\
    done; \n\
    echo \"Linear revision notes are unset.\" '"
EOF

git setlinrev...因此您可以在尝试记录涉及线性修订注释的日志之前简单地调用;并git unsetlinrev在完成后删除这些笔记;来自 git repo 目录的示例:

$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 <<

$ git setlinrev
Linear revision notes are set.
$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)
$ git unsetlinrev
Linear revision notes are unset.

$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 <<

shell 完成这些别名所花费的时间将取决于存储库历史记录的大小。

于 2013-04-21T20:30:49.690 回答
3

对于有Ant构建过程的人,您可以使用以下目标在 git 上为项目生成版本号:

<target name="generate-version">

    <exec executable="git" outputproperty="version.revisions">
        <arg value="log"/>
        <arg value="--oneline"/>
    </exec>

    <resourcecount property="version.revision" count="0" when="eq">
        <tokens>
            <concat>
                <filterchain>
                    <tokenfilter>
                        <stringtokenizer delims="\r" />
                    </tokenfilter>
                </filterchain>
            <propertyresource name="version.revisions" />
            </concat>
        </tokens>
    </resourcecount>
    <echo>Revision : ${version.revision}</echo>

    <exec executable="git" outputproperty="version.hash">
        <arg value="rev-parse"/>
        <arg value="--short"/>
        <arg value="HEAD"/>
    </exec>
    <echo>Hash : ${version.hash}</echo>


    <exec executable="git" outputproperty="version.branch">
        <arg value="rev-parse"/>
        <arg value="--abbrev-ref"/>
        <arg value="HEAD"/>
    </exec>
    <echo>Branch : ${version.branch}</echo>

    <exec executable="git" outputproperty="version.diff">
        <arg value="diff"/>
    </exec>

    <condition property="version.dirty" value="" else="-dirty">
        <equals arg1="${version.diff}" arg2=""/>
    </condition>

    <tstamp>
        <format property="version.date" pattern="yyyy-mm-dd.HH:mm:ss" locale="en,US"/>
    </tstamp>
    <echo>Date : ${version.date}</echo>

    <property name="version" value="${version.revision}.${version.hash}.${version.branch}${version.dirty}.${version.date}" />

    <echo>Version : ${version}</echo>

    <echo file="version.properties" append="false">version = ${version}</echo>

</target>

结果如下所示:

generate-version:
    [echo] Generate version
    [echo] Revision : 47
    [echo] Hash : 2af0b99
    [echo] Branch : master
    [echo] Date : 2015-04-20.15:04:03
    [echo] Version : 47.2af0b99.master-dirty.2015-04-20.15:04:03

当您在生成版本号时未提交文件时,脏标志就在这里。因为通常,当您构建/打包应用程序时,每个代码修改都必须在存储库中。

于 2015-03-20T19:13:00.130 回答
3

我们使用这个命令从 git 获取版本和修订:

git describe --always --tags --dirty

它返回

  • 不使用标记时提交哈希作为修订版(例如gcc7b71f
  • 在标签上时将标签名称作为版本(例如v2.1.0,用于发布)
  • 标签名称,自上一个标签以来的修订号以及标签之后的提交哈希(例如v5.3.0-88-gcc7b71f
  • v5.3.0-88-gcc7b71f-dirty如果工作树有本地修改(例如),则与上面相同加上“脏”标签

另请参阅:https ://www.git-scm.com/docs/git-describe#Documentation/git-describe.txt

于 2019-07-15T12:46:17.820 回答
2

连同提交的 SHA-1 id,服务器时间的日期和时间会有所帮助吗?

像这样的东西:

提交发生在 2013 年 8 月 19 日 11:30:25 将显示为 6886bbb7be18e63fc4be68ba41917b48f02e09d7_19aug2013_113025

于 2013-08-19T11:07:37.283 回答
2

在 Git 手册中,标签是这个问题的绝妙答案:

在 Git 中创建带注释的标签很简单。最简单的方法是在运行 tag 命令时指定 -a:

$ git tag -a v1.4 -m 'my version 1.4'

$ git tag
v0.1
v1.3
v1.4

查看2.6 Git 基础 - 标记

于 2013-10-24T13:18:58.380 回答
0

Visual Studio 的发布构建事件

echo  >RevisionNumber.cs static class Git { public static int RevisionNumber =
git  >>RevisionNumber.cs rev-list --count HEAD
echo >>RevisionNumber.cs ; }
于 2018-09-10T15:35:17.027 回答
-2

考虑使用

git-rev-label

提供有关 Git 存储库修订的信息,格式如master-c73-gabc6bec. 可以使用来自 Git 的环境变量和信息填充模板字符串或文件。可用于提供有关程序版本的信息:分支、标记、提交哈希、提交计数、脏状态、日期和时间。最有用的事情之一是提交计数,不考虑合并的分支 - 只考虑第一个父级。

于 2019-09-10T10:27:48.153 回答