问题
Right now, we are using Perforce for version control. It has the handy feature of a strictly increasing change number that we can use to refer to builds, eg "you'll get the bugfix if your build is at least 44902".
I'd like to switch over to using a distributed system (probably git) to make it easier to branch and to work from home. (Both of which are perfectly possible with Perforce, but the git workflow has some advantages.) So although "tributary development" would be distributed and not refer to a common revision sequencing, we'd still maintain a master git repo that all changes would need to feed into before a build was created.
What's the best way to preserve strictly increasing build ids? The most straightforward way I can think of is to have some sort of post-commit hook that fires off whenever the master repo gets updated, and it registers (the hash of) the new tree object (or commit object? I'm new to git) with a centralized database that hands out ids. (I say "database", but I'd probably do it with git tags, and just look for the next available tag number or something. So the "database" would really be .git/refs/tags/build-id/.)
This is workable, but I'm wondering if there is an easier, or already-implemented, or standard/"best practice" way of accomplishing this.
回答1:
I second the suggestion of using git describe
. Provided that you have a sane versioning policy, and you don't do any crazy stuff with your repository, git describe
will always be monotonic (at least as monotonic as you can be, when your revision history is a DAG instead of a tree) and unique.
A little demonstration:
git init
git commit --allow-empty -m'Commit One.'
git tag -a -m'Tag One.' 1.2.3
git describe # => 1.2.3
git commit --allow-empty -m'Commit Two.'
git describe # => 1.2.3-1-gaac161d
git commit --allow-empty -m'Commit Three.'
git describe # => 1.2.3-2-g462715d
git tag -a -m'Tag Two.' 2.0.0
git describe # => 2.0.0
The output of git describe
consists of the following components:
- The newest tag reachable from the commit you are asking to describe
- The number of commits between the commit and the tag (if non-zero)
- The (abbreviated) id of the commit (if #2 is non-zero)
#2 is what makes the output monotonic, #3 is what makes it unique. #2 and #3 are omitted, when the commit is the tag, making git describe
also suitable for production releases.
回答2:
Monotonically increasing number corresponding to the current commit could be generated with
git log --pretty=oneline | wc -l
which returns a single number. You can also append current sha1 to that number, to add uniqueness.
This approach is better than git describe
, because it does not require you to add any tags, and it automatically handles merges.
It could have problems with rebasing, but rebasing is "dangerous" operation anyway.
回答3:
git rev-list BRANCHNAME --count
this is much less resource intensive than
git log --pretty=oneline | wc -l
回答4:
git tag
may be enough for what you need. Pick a tag format that everyone will agree not to use otherwise.
Note: when you tag locally, a git push
will not update the tags on the server. Use git push --tags
for that.
回答5:
You should investigate git describe
. It gives a unique string that describes the current branch (or any passed commit id) in terms of the latest annotated tag, the number of commits since that tag and an abbreviated commit id of the head of the branch.
Presumably you have a single branch that you perform controlled build releases off. In this case I would tag an early commit with a known tag format and then use git describe with the --match option to describe the current HEAD relative to a the known tag. You can then use the result of git describe as is or if you really want just a single number you can use a regex to chop the number out of the tag.
Assuming that you never rewind the branch the number of following commits will always identify a unique point in the branch's history.
e.g. (using bash or similar)
# make an annotated tag to an early build in the repository:
git tag -a build-origin "$some_old_commitid"
# describe the current HEAD against this tag and pull out a build number
expr "$(git describe --match build-origin)" : 'build-origin-\([0-9]*\)-g'
回答6:
I'd use "Labels" Create a label whenever you have a successful (or even unsuccessful) build, and you'll be able to identify that build forever. It's not quite the same, but it does provide those build numbers, while still providing the benefits of distributed development.
回答7:
As you probably know, git computes a hash (a number) that uniquely identifies a node of the history. Using these, although they are not strictly increasing, seems like it would be good enough. (Even better, they always correspond to the source, so if you have the hash, you have the same code.) They're big numbers, but mostly you can get by with 6 or so of the leading digits.
For example,
That bug was fixed at 064f2ea...
回答8:
With Mercurial you can use the following command :
# get the parents id, the local revision number and the tags
[yjost@myhost:~/my-repo]$ hg id -nibt
03b6399bc32b+ 23716+ default tip
See hg identify
来源:https://stackoverflow.com/questions/122424/build-sequencing-when-using-distributed-version-control