如何拥有自动递增的版本号(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:
还值得注意的是,如果同时指定了 AssemblyVersion
和 AssemblyFileVersion
,您将不会在 .exe 上看到它。
来自@BrainSlugs83:
仅将第 4 个数字设置为 *
可能不好,因为版本不会总是递增。
第三个数字是自 2000 年以来的天数,第四个数字是自午夜以来的秒数(除以 2)[它不是随机的]。因此,如果您在一天的晚些时候构建解决方案,而在第二天的早些时候构建解决方案,则较晚的构建将具有较早的版本号。我建议始终使用X.Y.*
而不是X.Y.Z.*
,因为您的版本号总是会以这种方式增加。
较新版本的 Visual Studio 会出现此错误:
(此主题始于 2009 年)
指定的版本字符串包含通配符,与确定性不兼容。从版本字符串中删除通配符,或禁用此编译的确定性。
查看这个 SO 答案,它解释了如何remove determinism (https://***.com/a/58101474/1555612)
【讨论】:
另外值得注意的是,如果同时指定了AssemblyVersion
和AssemblyFileVersion
,您将不会在.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++ 中进行自动版本控制