如何在 Git 中管理版本号?

让我们想象一下在 上维护的 哔哔命令行工具。这个工具有(隐藏的) --version选项,它返回它的 版本(假设是 0.1.2)和另一个 --commit,它返回构建它的提交号。

版本号和提交号都在代码基上进行了硬编码。

现在我做了一个错误修复,然后提交和重建我的程序。我仍然会看到 0.1.2,虽然这个新版本不同于原来的 0.1.2。只有提交才会告诉我它不是同一个 0.1.2。这个错误修复值不值一个不同的版本号?

一种解决方案是,每次提交时,我都增加硬编码的版本号(这意味着每次提交至少要修改2个文件)。这是一个绑定解决方案,当开发人员在不同的活动分支上工作时,它不起作用。如果 Bob 从 0.1.2版本的特性 foo开始工作,而 Alice 从同一版本的特性 bar开始工作,那么他们是如何增加版本号的呢?鲍勃可以用奇数,爱丽丝用偶数。如果伊芙在拍第三部电影呢?

另一种解决方案是使用 Git 标记自动生成版本号。脚本可以找到最接近的以 v开头的标记,例如 v0.1.2,并使用标记名作为版本号加上当前提交(v0.1.2 (build 4acd21))的前 n 位。如果工作目录是干净的,这种方法就很有效。你可以想象在构建数字前面加上一个 ABc3来表示工作目录不干净。这个解决方案的主要问题是,如果有人导出源代码,它将无法构建 哔哔

有什么办法可以解决这个问题?

141915 次浏览

As you say, versioning issues are usually solved in git using branch and tags(like the semantic versioning pattern).

The better way is to use git to track only changes in the codebase, ignoring (using .gitignore file) builds files and maintaining a clean repository.

Builds results (pre/compiled files, executables files, distribution files, zips, exe...) could depend on environment variables (platform, system arch, etc) and should be keep separate in a registry.

If the codebase is very big and hard to maintain, maybe you should consider dividing it into smaller components (or git submodules) to avoid cross-dependencies at development time.

Revision numbers should be maintained by you, not by git. As, opposed to SVN, you don't have a incremental revision number growing on each commit, there's no way out of the box to git to contextualize what your version is.

Please, have a look at git describe command. This command shows you the latest tag and an amount of commits made after the tag was set. It also possible to show the dirtiness of the repository.

As you mentioned this command wouldn't work without the git repository (.git folder) and git installed. But it's almost unimaginable developer today without git but with all other tools installed.

Alexey Kiselev and Dario already hinted towards the answer, but I will try to explain it in detail.

Versioning Schemes

There are two types of versioning schemes:

  1. Internal version number: This can be incremented many times in a day (e.g. revision control number)
  2. Released version: This changes less often (e.g. semantic versioning)

People use different schemes as per their need, but semantic versioning is fairly widely used and authored by Tom Preston-Werner, co-founder of GitHub.

Semantic Versioning

Semantic versioning follows the pattern of X.Y.Z

Or more readable would be [major].[minor].[patch]-[build/beta/rc]

E.g. 1.2.0-beta

major or X can be incremented if there are major changes in software, like backward-incompatible API release.

minor or Y is incremented if backward compatible APIs are introduced.

patch or Z is incremented after a bug fix.

How do we achieve this using Git?

By using tags:

Tags in Git can be used to add a version number.

git tag -a "v1.5.0-beta" -m "version v1.5.0-beta"

adds a version tag of v1.5.0-beta to your current Git repository. Every new commit after this will auto-increment tag by appending commit number and commit hash. This can be viewed using the git describe command.

v1.5.0-beta-1-g0c4f33f here -1- is the commit number and 0c4f33f the abbreviation of commit's hash. The g prefix stands for "git".

Complete details can be viewed using:

git show v1.5.0-beta

  1. Create file in project dir (or where you want) build_number and put the value 1 in this file

  2. Go to git dir and create file called "pre-commit" in .git/hooks/ (without .sample)

  3. Put this code there

#!/bin/sh


currentbuildnumber=`cat build_number`
let "currentbuildnumber++"
printf $currentbuildnumber > build_number
currentbranch=`git branch | tr -cd "[:alpha:]"`
git log $currentbranch --pretty=format:"%h - %an, %ar : %s, Build: $currentbuildnumber"

Working for me :) enjoy!