如何拥有自动递增的版本号(Visual Studio)? [复制]

Posted

技术标签:

【中文标题】如何拥有自动递增的版本号(Visual Studio)? [复制]【英文标题】:How to have an auto incrementing version number (Visual Studio)? [duplicate] 【发布时间】:2010-10-24 00:42:51 【问题描述】:

我想存储一组在构建时自动递增的整数:

int MajorVersion = 0;
int MinorVersion = 1;
int Revision = 92;

当我编译时,它会自动递增Revision。当我构建安装项目时,它会增加MinorVersion(我可以手动执行此操作)。 MajorVersion 只能手动递增。

然后我可以在菜单 Help/About 中向用户显示版本号:

版本:0.1.92

如何做到这一点?

这个问题不仅问如何拥有一个自动递增的版本号,还问如何在代码中使用它,这是一个比其他问题更完整的答案。

【问题讨论】:

尽管问题已经得到了答案,但 Noel Kennedy 和 Matthieu 的答案比其他问题/答案更有用 【参考方案1】:

如果您将AssemblyInfo 类添加到您的项目并修改AssemblyVersion 属性以以星号结尾,例如:

[assembly: AssemblyVersion("2.10.*")]

Visual Studio 将根据these rules 为您增加最终数字(感谢 galets,我完全错了!)

要在代码中引用此版本,以便将其显示给用户,请使用reflection。例如,

Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
                        .AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"version (buildDate)";

你应该知道的三个重要问题

来自@ashes999:

还值得注意的是,如果同时指定了 AssemblyVersionAssemblyFileVersion,您将不会在 .exe 上看到它。

来自@BrainSlugs83:

仅将第 4 个数字设置为 * 可能不好,因为版本不会总是递增。 第三个数字是自 2000 年以来的天数第四个数字是自午夜以来的秒数(除以 2)[它不是随机的]。因此,如果您在一天的晚些时候构建解决方案,而在第二天的早些时候构建解决方案,则较晚的构建将具有较早的版本号。我建议始终使用X.Y.* 而不是X.Y.Z.*,因为您的版本号总是会以这种方式增加。

较新版本的 Visual Studio 会出现此错误:

(此主题始于 2009 年)

指定的版本字符串包含通配符,与确定性不兼容。从版本字符串中删除通配符,或禁用此编译的确定性。

查看这个 SO 答案,它解释了如何remove determinism (https://***.com/a/58101474/1555612)

【讨论】:

另外值得注意的是,如果同时指定了AssemblyVersionAssemblyFileVersion,您将不会在.exe 上看到它 只将第 4 个数字设置为“*”可能不好,因为版本不会总是递增。第 3 个数字是自 2000 年以来的天数,第 4 个数字是自午夜以来的秒数(除以 2)[它不是随机的]。因此,如果您在一天的晚些时候构建解决方案,而在第二天的早些时候构建解决方案,则较晚的构建将具有较早的版本号。我建议始终使用“XY*”而不是“XYZ*”,因为您的版本号总是会以这种方式增加(除非您碰巧从 TARDIS 内部编译代码——在这种情况下,我可以来吗?)。 我们可以设置 * 开始的值吗?而不是使用自 2000 年以来的天数? 您应该如何将此更改恢复到源代码控制中? 顺便说一句,您实际上不必编辑和添加程序集信息文件。一个更简单的方法是转到项目属性,应用程序选项卡,单击“程序集信息”并输入您喜欢的主要版本,次要版本,然后在第三个框中输入 * 并将第四个框留空。 Visual Studio 将负责更新 .cs 文件【参考方案2】:

你可以使用T4 templating mechanism in Visual Studio to generate the required source code from a simple text file:

我想为某些 .NET 配置版本信息生成 项目。很久没研究可用了 选项,所以我四处寻找希望找到一些简单的方法 这。我的发现看起来不太令人鼓舞:人们写 Visual Studio 加载项和自定义 MsBuild 任务只是为了获得一个 整数(好吧,也许是两个)。这对于一个小人物来说感觉有点过头了 个人项目。

灵感来自 *** 的一次讨论,其中 有人建议 T4 模板可以完成这项工作。而且当然 他们能。该解决方案需要最少的工作,并且不需要 Visual Studio 或构建流程定制。这里应该做什么:

    创建一个扩展名为“.tt”的文件,并在其中放置将生成 AssemblyVersion 和 AssemblyFileVersion 属性的 T4 模板:
<#@ template language="C#" #>
// 
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
// 

using System.Reflection;

[assembly: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
    int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>

您必须决定版本号生成算法。为了 我足以自动生成设置为的修订号 自 2010 年 1 月 1 日以来的天数。如您所见, 版本生成规则是用纯 C# 编写的,因此您可以轻松 根据您的需要进行调整。

    上面的文件应该放在其中一个项目中。我只用这个文件创建了一个新项目来进行版本管理 技术清楚。当我构建这个项目时(实际上我什至不需要 构建它:保存文件足以触发 Visual Studio action),生成以下 C#:
// 
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
// 

using System.Reflection;

[assembly: AssemblyVersion("1.0.1.113")]
[assembly: AssemblyFileVersion("1.0.1.113")]

是的,今天是自 2010 年 1 月 1 日以来的 113 天。明天 修订号会改变。

    下一步是从所有项目中的 AssemblyInfo.cs 文件中删除 AssemblyVersion 和 AssemblyFileVersion 属性。 共享相同的自动生成的版本信息。而是选择“添加 现有项目”,导航到带有 T4 的文件夹 模板文件,选择对应的“.cs”文件并添加为链接。 就可以了!

我喜欢这种方法的地方在于它是轻量级的(没有自定义 MsBuild 任务),并且自动生成的版本信息不会添加到 源头控制。当然使用 C# 进行版本生成 算法适用于任何复杂度的算法。

【讨论】:

我认为这是一个很好的解决方案,因为它具有插件和自定义可执行文件的灵活性,但它是一个纯粹的开箱即用的 Visual Studio 解决方案。 很好地满足了我的需求,使用 bzr revno 填充部分版本信息 这也适用于为 JS 和 CSS 引用生成特定于构建的缓存破坏令牌。 我不明白这个解决方案......我们必须调用TransformText()方法来获取结果文件...... 此外,这些模板仅在模板更改时才会呈现。这仅适用于 AutoT4 Visual Studio Extension 或类似的东西。【参考方案3】:

这是我对 T4 建议的实现...无论选择何种配置(即调试|发布),每次构建项目时都会增加版本号,并且每次执行时都会增加版本号发布构建。您可以通过Application➤Assembly Information...

继续更新主要和次要版本号

为了更详细地解释,这将读取现有的AssemblyInfo.cs 文件,并使用正则表达式查找AssemblyVersion 信息,然后根据来自TextTransform.exe 的输入增加修订和内部版本号。

    删除现有的AssemblyInfo.cs 文件。

    在其位置创建一个AssemblyInfo.tt 文件。保存 T4 文件后,Visual Studio 应创建 AssemblyInfo.cs 并将其与 T4 文件分组。

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ output extension=".cs" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Text.RegularExpressions" #>
    <#
        string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs"));
        Regex pattern = new Regex("AssemblyVersion\\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
        MatchCollection matches = pattern.Matches(output);
        if( matches.Count == 1 )
        
            major = Convert.ToInt32(matches[0].Groups["major"].Value);
            minor = Convert.ToInt32(matches[0].Groups["minor"].Value);
            build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1;
            revision = Convert.ToInt32(matches[0].Groups["revision"].Value);
            if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" )
                revision++;
        
    #>
    
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Resources;
    
    // General Information
    [assembly: AssemblyTitle("Insert title here")]
    [assembly: AssemblyDescription("Insert description here")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("Insert company here")]
    [assembly: AssemblyProduct("Insert product here")]
    [assembly: AssemblyCopyright("Insert copyright here")]
    [assembly: AssemblyTrademark("Insert trademark here")]
    [assembly: AssemblyCulture("")]
    
    // Version informationr(
    [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: NeutralResourcesLanguageAttribute( "en-US" )]
    
    <#+
        int major = 1;
        int minor = 0;
        int revision = 0;
        int build = 0;
    #>
    

    将此添加到您的预构建事件中:

    "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
    

【讨论】:

您可以将当前 Visual Studio 版本作为变量引用,而不是 10"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!build!true "$(ProjectDir)Properties\AssemblyInfo.tt" @BurnsBA,感谢您的建议!我更改了答案以反映这一点。 预构建事件非常重要!谢谢!一旦我这样做了,每次我从 VS2017 或通过控制台构建项目时,我的版本号都会更新。 对于 2017 社区版,我已将预构建事件更改为:"c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\TextTransform.exe" "$(ProjectDir)Properties\AssemblyInfo.tt",它对我来说很好用。问候 "$(DevEnvDir)TextTransform.exe"可以代替"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\TextTransform.exe"【参考方案4】:

如果您为构建和修订添加星号,则 Visual Studio 使用自 2000 年 1 月 1 日以来的天数作为内部版本号,并将自午夜以来的秒数除以 2 作为修订版本。

一个更好的救生解决方案是http://autobuildversion.codeplex.com/

它的作用就像一个魅力,而且非常灵活。

【讨论】:

不适用于 VS2013。 感谢您的解释 - 我试图弄清楚为什么内部版本号没有增加(在同一天)而不查看版本号。这就解释了,谢谢。【参考方案5】:

这是quote on AssemblyInfo.cs from MSDN:

你可以指定所有的值,或者你 可以接受默认的内部版本号, 修订号,或两者都使用 星号 ()。例如, [程序集:AssemblyVersion("2.3.25.1")] 表示 2 为主要版本, 3 为 次要版本,25 作为构建 编号,1 作为修订号。 版本号,例如 [程序集:AssemblyVersion("1.2.")] 将 1 指定为主要版本,将 2 指定为 次要版本,并接受 默认构建和修订号。一种 版本号如 [程序集:AssemblyVersion("1.2.15.*")] 将 1 指定为主要版本,将 2 指定为 次要版本,15 作为构建 编号,并接受默认值 修订号。默认构建 数字每天递增。默认 修订号是随机的

这实际上是说,如果您将 1.1.* 放入程序集信息中,则只有内部版本号会自动递增,并且不会在每次构建之后发生,而是每天发生。修订号会在每次构建时更改,但会随机更改,而不是以递增的方式。

这对于大多数用例来说可能已经足够了。如果这不是您想要的,那么您将不得不编写一个脚本,该脚本将在预构建步骤中自动增加版本#

【讨论】:

随机递增?他们是在跟我开玩笑吗? 根据msdn.microsoft.com/en-us/library/… 留下的评论,修订号不是随机的,而是从凌晨 12 点开始的秒数除以 2,在我看来这还不错。 有SemVer 标准。但微软一如既往地拥有自己的 rake 默认修订号不是随机的 - 在您提供的链接中指出“默认修订号是自当地时间午夜以来的秒数(不考虑夏令时的时区调整) ),除以 2。'【参考方案6】:

使用 AssemblyInfo.cs

在 App_Code 中创建文件:并填写以下内容或使用 Google 搜索其他可能的属性/属性。

AssemblyInfo.cs

using System.Reflection;

[assembly: AssemblyDescription("Very useful stuff here.")]
[assembly: AssemblyCompany("companyname")]
[assembly: AssemblyCopyright("Copyright © me 2009")]
[assembly: AssemblyProduct("NeatProduct")]
[assembly: AssemblyVersion("1.1.*")]

AssemblyVersion 是您真正追求的部分。

那么如果你在一个网站上工作,在任何aspx页面,或者控件中,你可以在标签中添加如下内容:

CompilerOptions="<folderpath>\App_Code\AssemblyInfo.cs"

(当然用适当的变量替换文件夹路径)。

我认为您不需要以任何方式为其他类添加编译器选项; App_Code中的所有的都应该在编译时收到版本信息。

希望对您有所帮助。

【讨论】:

【参考方案7】:

星号版本(如“2.10.3.*”)- 很简单,但数字太大

AutoBuildVersion - 看起来不错,但不适用于我的 VS2010。

@DrewChapin 的脚本有效,但我无法在我的工作室中为 Debug 预构建事件和 Release 预构建事件设置不同的模式。

所以我稍微改变了脚本...... 命令:

"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!$(ConfigurationName)!1 "$(ProjectDir)Properties\AssemblyInfo.tt"

和脚本(这适用于“调试”和“发布”配置):

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
    int incRevision = 1;
    int incBuild = 1;

    try  incRevision = Convert.ToInt32(this.Host.ResolveParameterValue("","","Debug")); catch( Exception )  incBuild=0; 
    try  incBuild = Convert.ToInt32(this.Host.ResolveParameterValue("","","Release"));  catch( Exception )  incRevision=0; 
    try 
        string currentDirectory = Path.GetDirectoryName(Host.TemplateFile);
        string assemblyInfo = File.ReadAllText(Path.Combine(currentDirectory,"AssemblyInfo.cs"));
        Regex pattern = new Regex("AssemblyVersion\\(\"\\d+\\.\\d+\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
        MatchCollection matches = pattern.Matches(assemblyInfo);
        revision = Convert.ToInt32(matches[0].Groups["revision"].Value) + incRevision;
        build = Convert.ToInt32(matches[0].Groups["build"].Value) + incBuild;
    
    catch( Exception )  
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Game engine. Keys: F2 (Debug trace), F4 (Fullscreen), Shift+Arrows (Move view). ")]
[assembly: AssemblyProduct("Game engine")]
[assembly: AssemblyDescription("My engine for game")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © Name 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. Only Windows
// assemblies support COM.
[assembly: ComVisible(false)]

// On Windows, the following GUID is for the ID of the typelib if this
// project is exposed to COM. On other platforms, it unique identifies the
// title storage container when deploying this assembly to the device.
[assembly: Guid("00000000-0000-0000-0000-000000000000")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
[assembly: AssemblyVersion("0.1.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("0.1.<#= this.revision #>.<#= this.build #>")]

<#+
    int revision = 0;
    int build = 0;
#>

【讨论】:

我用了这个方法但是发现新的assimblyinfo.cs生成时版权符号变成了问号。关于如何解决它的任何想法? @TheKing 使用 unicode 代码点而不是文字字符。 我没有得到 + 号 @jaysonragasa 我只是稍微更改了 Drew Chapin 的版本 ***.com/a/15050041/1821428 。所以最好问问他。 好东西,只需将它用于 TextTransform.exe,它更简洁:“$(DevEnvDir)TextTransform.exe”【参考方案8】:

您可以尝试使用 Matt Griffith 的 UpdateVersion。现在已经很老了,但效果很好。要使用它,您只需设置一个指向您的 AssemblyInfo.cs 文件的预构建事件,应用程序将根据命令行参数相应地更新版本号。

由于该应用程序是开源的,我还创建了一个版本以使用 (主要版本).(次要版本).([year][dayofyear]).(increment 格式)。我已将我的 UpdateVersion 应用程序修改版本的代码放在 GitHub 上:https://github.com/munr/UpdateVersion

【讨论】:

【参考方案9】:

您可以使用构建脚本(例如 Build Versioning)进行更高级的版本控制

【讨论】:

以上是关于如何拥有自动递增的版本号(Visual Studio)? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

visual studio除了6还有哪个版本用得多而又不占内存?如何实现多visual studi

如何在 ASP.Net MVC - 5 应用程序中显示版本号并自动递增

使用 Visual Studio 2008 和 SVN 在 C++ 中进行自动版本控制

XCode自动递增内部版本号脚本

GitVersion 使用描述符和自动递增版本号进行基于主干的开发

如何在 Latex 中添加自动版本号?