views:

544

answers:

3

How can you put the prefix ?v=VersionNumber to each file at your repository efficiently by Git/Svn?

I found out that SO uses the practise to give version numbers to each specific file in its repo.

They use SVN. I would like to know how you can do the same by Git.

A few examples.

#1

<link rel="stylesheet" href="/content/all.css?v=3959">

#2

<script src="./js/question.js?v=3955" type="text/javascript"></script>
+5  A: 

"at your repository"? at your repository directly?
That would be call "keyword expansion" and that is not recommended (as discussed in this SO question)

Putting meta-data (revision number) into data stored into a repository can lead to merge issues.

What you see in SO pages are the result of a deployment process which takes the meta-data from SVN (the revision) and puts it into the generated HTML pages.

GitFaq does not recommend it either.
The equivalent to a SVN revision number integrated into files deployed on a server would be using git describe, in order to get some sort of a "commit count" to be displayed during deployment step.

But recording it directly in the repository would mean keyword expansion, and keyword unexpansion.


To illustrate that, let's check out what Linus said at the time of the original discussion on this topic (April 2007):

Adding expansion is not just "harder". It's basically impossible to do with any kind of performance.
Think "git checkout newbranch".
And think what we do about files (and whole subdirectories!) that haven't even changed. And finally, think about how important that optimization is in an SCM like git that supports branches.

[the] fundamental problems that keyword expansion has (ie switching branches is basically impossible to do without checking out *every_single_file* with the "keyword" attribute set. There are others).

Now, unexpansion is trivial to do (it really is the same as the "CRLF->LF" translation: that's technically really just an "unexpansion" too). And it should work.

The way this does unexpansion also breaks "git diff" in that it basically always makes diff ignore the keywords. In other words, when you do

git diff A..B

and send the diff to somebody else, they'll never see any keywords at all!

Now, that obviously fulfills my requirement that the diff be empty if A and B are the same, so you should expect me to be happy.
But I'm not happy, because if the other person also is using git, HE CANNOT EVEN APPLY THE DIFF!
Even if he's at "A", and thus gets a diff that is supposed to apply exactly, he'll get rejects if there were other changes around the unexpanded keyword (which he will have expanded in his working tree, of course!)

See? Keywords simply cannot work. They're broken. Either you can ignore them (and not show them in diffs), in which case the diff is broken, or you can not ignore them (and show them in diffs) in which case the diff is also broken, just differently.

The only sane and workable case is to not have them at all. Any keyword expansion will always result in problems. You simply cannot do it right.

VonC
@VonC: Your answer raises a question. Which feature do you use instead of `keyword expansion`? --- I have never used it on my projects.
Masi
I am surprised why SO uses the `keyword expansion`. There must be some reasons behind that. Perhaps, they do not use git-svn which causes them to use the `keyword expansion`.
Masi
@Masi: in the context of your question, that would be "git describe", in order to get some sort of technical version number (for instance, to be included to files at deployment stage).
VonC
@Masi: my point is: I do not think SO uses keyword expansion at all, but rather uses the known SVN revision number in a file read by a php script and generating the right HTML page. It is a matter of replacing the right variable once deployed, not embedded the meta-data (keyword expansion) during a commit.
VonC
@VonC: Why do they do that? --- To confuse newbies? Or to give a way for non-programmers to see the current version number?
Masi
@Masi: to allow user to say: your technical version "SVN revision number" Stackoverflow website has such and such issues. Then SO team can just copy that revision number into a SVN "BugFix" branch and start fixing bugs. It is a link between public deployed website (the "distributed" files, not stored but generated) and internal data (the "development" files, stored in a SVN repo)
VonC
+4  A: 

If this version number is generated by some server script: PHP, Perl, ASP.NET, Ruby on Rails (VonC explained why keyword expansion is a bad idea, i.e. why making Git and not web server update such information is a bad idea), then it is simply matter of running git describe in this script.

Another solution is to make deployment (build) system, which copies files from version control system to web server, embed this data. For example gitweb, git web interface for Git written in Perl, has

our $version = "++GIT_VERSION++";

replaced by build system (make gitweb/gitweb.cgi) by result of running GIT-VERSION-GEN. This means for example that running gitweb shows in "generator" meta header for example:

<meta name="generator" content="gitweb/1.6.4.rc0.22.gfc1cf.dirty git/1.6.3.2.317.g2dd3f"/>
Jakub Narębski
Great answer, thanks!
Masi
+1  A: 

Ignoring the word "efficiently" in your question, you should look up "filter driver". A simple smudge to insert the revision and a clean to remove it should do what you (think you) want.