修订号的Git等价物是多少?

时间:2010-11-07 22:16:53

标签: git version-control revision-history version-numbering

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

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

20 个答案:

答案 0 :(得分:157)

使用现代Git(在我的情况下是1.8.3.4)并且不使用分支,你可以这样做:

$ git rev-list --count HEAD
68

答案 1 :(得分:140)

好消息或坏消息,哈希是修订号。当我从SVN切换到git时,我也遇到了麻烦。

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

要理解的关键是git不能有修订号 - 考虑分散性。如果用户A和B都提交到他们的本地存储库,那么git如何合理地分配顺序修订版号? A在推/拉彼此变化之前不知道B。

另一件需要关注的是修复bugfix分支的简化:

从版本开始:3.0.8。然后,在该版本之后,执行以下操作:

git branch bugfixes308

这将为错误修正创建一个分支。检查分支:

git checkout bugfixes308

现在进行任何你想要的错误修改。

git commit -a

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

git checkout master

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

git merge bugfixes308

这样,你有一个单独的特定于发行版的bugfix分支,但你仍然将bug修改改为你的主开发中继。

答案 2 :(得分:94)

git describe命令创建一个稍微更人性化的名称,引用特定的提交。例如,来自文档:

  

使用像git.git当前树这样的东西,我得到:

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

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

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

答案 3 :(得分:67)

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

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

但是我将以下内容用于假修订号(仅供客户查看修订和进度,因为他们希望从git获得与subit一样的增加修订版本)。

使用以下方法模拟显示​​“HEAD”的“当前版本”:

git rev-list HEAD | wc -l

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

为此,我将以下内容添加到〜/ .gitconfig的

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

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

我前段时间对这个“技术”做了Blog Post (in german)

答案 4 :(得分:25)

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

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

其次,可以在不同的机器上生成修订号。这使得数字同步更加困难 - 特别是因为连接是单向的;您可能甚至无法访问具有存储库的所有计算机。

第三,在git中,有点由现已解散的OpenCM系统开创,提交的身份(提交的内容)等同于 name (SHA) ID)。这个命名=身份概念非常强大。当您使用提交名称时,它还以不可伪造的方式标识提交。这反过来允许您使用git fsck命令检查所有提交回到第一个初始以查找损坏。

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

通常,如果您需要处理特定的代码片段,那么该片段正在进行更改,因此应该是具有说法主题名称的分支。创建大量的分支(每个程序员20-30个是闻所未闻的,其中有4-5个发布供其他人使用)是有效git的技巧。每一项工作都应该从它自己的分支开始,然后在测试时合并。未发表的分支可以完全重写,这部分破坏历史是git的力量。

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

答案 5 :(得分:17)

如果您有兴趣,我会根据格式

从git infos here自动管理版本号
<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)

答案 6 :(得分:9)

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

答案 7 :(得分:8)

SHA1 hash of the commit相当于Subversion版本号。

答案 8 :(得分:6)

这是我在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

答案 9 :(得分:5)

我编写了一些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
}

答案 10 :(得分:4)

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

答案 11 :(得分:4)

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

答案 12 :(得分:3)

我想注意另一种可能的方法 - 就是使用git git-notes(1),因为v 1.6.6(Note to Self - Git)(我正在使用{ {1}}版本1.7.9.5)。

基本上,我使用git来克隆具有线性历史记录的SVN存储库(没有标准布局,没有分支,没有标记),我想比较克隆的git svn存储库中的修订版号。默认情况下,此git克隆没有标记,因此我无法使用git。这里的策略可能仅适用于线性历史 - 不确定它将如何与合并等结合。但这是基本策略:

  • 询问git describe所有提交历史记录的列表
    • 由于git rev-list默认为“反向时间顺序”,我们将使用其rev-list开关获取按最早排序的提交列表
  • 使用--reverse shell
    • 在每次提交时将计数器变量增加为修订计数器,
    • 为每次提交生成并添加“临时”git备注
  • 然后,使用带有bash的{​​{1}}浏览日志,这也将转储提交的注释,在这种情况下将是“修订号”
  • 完成后,删除临时笔记( NB:我不确定这些笔记是否已提交;它们并未真正显示在git log

首先,让我们注意--notes有一个默认的笔记位置 - 但您也可以为笔记指定git status(erence) - 这会将它们存储在{{1}下的不同目录中};例如,在git repo文件夹中,您可以调用ref来查看将成为的目录:

.git

需要注意的是,如果您git使用git notes get-ref,则必须再次使用该引用 - 否则您可能会收到错误,例如“找不到对象XXX的注释... ”。

对于这个例子,我选择调用注释“linrev”的$ git notes get-ref refs/notes/commits $ git notes --ref=whatever get-ref refs/notes/whatever (用于线性修订) - 这也意味着该过程不太可能干扰已经存在的注释。我也在使用notes add开关,因为作为--ref新手,我在理解它时遇到了一些问题 - 所以我想“以后再记住”ref;我在使用--git-dir时也使用git来抑制:)的产生。

所以,假设你在一个目录中,子文件夹--no-pager是一个less存储库;一个人可以这样做:

git log

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

希望这有助于某人,
干杯!


编辑:好的,这里有点容易,上面的循环有git个别名,叫### 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;在你的git存储库文件夹中,执行(注意讨厌的git转义,另请参阅#16136745 - Add a Git alias containing a semicolon ):

setlinrev

...所以你可以在尝试做涉及线性修订笔记的日志之前简单地调用unsetlinrev;并且bash在完成后删除这些注释; git repo目录中的一个例子:

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

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

答案 13 :(得分:2)

对于拥有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

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

答案 14 :(得分:1)

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

这样的事情:

  

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

答案 15 :(得分:1)

We're using此命令从git获取版本和修订:

git describe --tags --exact-match 2> /dev/null || git describe --always

返回

  • 在不使用标签的情况下(例如gcc7b71f)将哈希提交为修订版本
  • 在标签上使用标签名称作为版本(例如v2.1.0,用于发布)
  • 标签名称,自上一个标签以来的修订版本号和位于标签后的提交哈希(例如v5.3.0-88-gcc7b71f

答案 16 :(得分:1)

从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 Basics - Tagging

答案 17 :(得分:0)

长期研究在线存储库后,我发现逻辑上Git中的修订号和提交号没有区别。

答案 18 :(得分:0)

Visual Studio的发布后事件

echo  >RevisionNumber.cs static class Git { public static int RevisionNumber =
git  >>RevisionNumber.cs rev-list --count HEAD
echo >>RevisionNumber.cs ; }

答案 19 :(得分:-1)

考虑使用

git-rev-label

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