原文:Go’s Version Control History
引用:Why Google Stores Billions of Lines of Code in a Single Repository
A TUTORIAL INTRODUCTION TO THE LANGUAGE B
open(2) — Linux manual page
THE PROGRAMMING LANGUAGE B

当我们使用 git clone https://github.com/golang/go.git 拉取Go的源码后,想必有不少人会和我一样拉到git history的最后,想追寻一下Go的起点,那我们会看到
image.png
这就是Go代码库的最早的四个提交,然而让人惊讶的是,最早的提交竟然在 1972年!!
那为什么最早的提交在1972年呢?

在Go作者之一的 Russ Cox 的博客中,第一段就回答了这个有趣的问题。

Every once in a while someone notices the first commit in the Go repo is dated 1972:

% git log --reverse --stat
commit 7d7c6a97f815e9279d08cfaea7d5efb5e90695a8
Author:     Brian Kernighan <bwk>
AuthorDate: Tue Jul 18 19:05:45 1972 -0500
Commit:     Brian Kernighan <bwk>
CommitDate: Tue Jul 18 19:05:45 1972 -0500

    hello, world

    R=ken
    DELTA=7  (7 added, 0 deleted, 0 changed)

 src/pkg/debug/macho/testdata/hello.b | 7 +++++++
 1 file changed, 7 insertions(+)

...

bviously something silly is going on, and people usually stop there.

Cox 回答到,每隔一段时间就会有人来问这个问题,但是把重点放在这里,显然是一件傻事。
然而事实上,Go的真正起点是第五个提交。
image.png

这个提交只写了一个go_spec的文本文件,里面记录了一些最初的Go语法规则。
在之后被重命名为go_lang.txt
而此处有个有意思的点,SVN=111041,即该提交的svn版本号是111041,而提交时间也是2008年,难道说1972-2008年间还有111040个提交,只是没有显示出来?
现实很尴尬,Go起点确实就是2008年,并不是1972年,而且细看会发现,最早提交信息hello, world里是一个用B语言写的hello world。那到底是怎么回事呢?

Subversion

Go最开始使用的svn做的版本控制,代码放在一个小型的monorepo服务器上,这个服务器并不只有Go,还有其它项目,所以这个111041只是Go开始的版本号而以,而且之后的svn提交,其版本号也并不连续。

Perforce

svn并没有用多久,很快,在2008/7/22提交了最后一个svn提交

commit 777ee7163bba96f2c9b3dfe135d8ad4ab837c062
Author:     Rob Pike <r@golang.org>
AuthorDate: Mon Jul 21 16:18:04 2008 -0700
Commit:     Rob Pike <r@golang.org>
CommitDate: Mon Jul 21 16:18:04 2008 -0700

    map delete

    SVN=128258

 doc/go_lang.txt | 6 ++++++
 1 file changed, 6 insertions(+)

随后代码迁移到Perforce服务器,并做了第一个提交

commit 05caa7f82030327ccc9ae63a2b0121a029286501
Author:     Rob Pike <r@golang.org>
AuthorDate: Mon Jul 21 17:10:49 2008 -0700
Commit:     Rob Pike <r@golang.org>
CommitDate: Mon Jul 21 17:10:49 2008 -0700

    help management of empty pkg and lib directories in perforce

    R=gri
    DELTA=4  (4 added, 0 deleted, 0 changed)
    OCL=13328
    CL=13328

 lib/place-holder      | 2 ++
 pkg/place-holder      | 2 ++
 src/cmd/gc/mksys.bash | 0
 3 files changed, 4 insertions(+)

从提交信息中可以看到新的标记,OCL源版本号,CL最终版本号,DELTA改动总数,R reviewer
由于经过代码审查后也可能会有一些更改,所以OCL通常表示最初提交的版本号,CL则表示最终版本号,而R则代表代码审核人,gri即Robert Griesemer,而大多数的提交OCL和CL都是相同的,即review后并没有修改。
谷歌是一个重度的Perforce使用者,而且很多代码都放在一个超大的monorepo服务器中,而Go代码不必在负载很高的服务器内,所以托管在辅助服务器上了。
Go 的大部分预开源开发都是在 Perforce 服务器上完成的。

Mercurial

直到2009年10月,Go的代码完成了最后一个Perforce提交,并迁移到了Mercurial

commit 942d6590d9005f89e971ed5af0374439a264a20e
Author:     Kai Backman <kaib@golang.org>
AuthorDate: Fri Oct 23 11:03:16 2009 -0700
Commit:     Kai Backman <kaib@golang.org>
CommitDate: Fri Oct 23 11:03:16 2009 -0700

    one more argsize fix. we were copying with the correct
    alignment but not enough (duh).

    R=rsc
    APPROVED=rsc
    DELTA=16  (13 added, 0 deleted, 3 changed)
    OCL=36020
    CL=36024

 src/cmd/5g/ggen.c |  2 +-
 test/arm-pass.txt | 17 +++++++++++++++--
 2 files changed, 16 insertions(+), 3 deletions(-)

也正是从Perforce迁移到Mercurial的时候Russ Cox引入了最初的这个hello, world提交。迁移的过程非常的繁琐,Subversion 和 Perforce 存储库都是 Google 内部的服务器,每个人都有“用户目录”,就像/usr/rsc在 repo 中一样。这些目录包含各种未发布代码,无论是因为它是 Google 内部技术,还是因为它根本不值得发布。

Cox花了大约一周的时间,而且非常困难。因为如果从某些提交中删除了一个文件,但随后它在其他提交中被重命名,Mercurial 会提醒重命名了未创建的文件。如果在创建文件时添加了版权声明,则必须小心以后的提交,以免在更改文件头部时出现合并冲突。

由于Cox将 repo 的提交拆分为文件形式,因此很容易创建一些虚假提交,这些提交作为节彩蛋,至少显示了该程序的真实历史的一部分。

hello, world

1972 年 7 月的提交展示了第一个“hello, world”程序,复制自 Brian Kernighan 的“A Tutorial Introduction to the Language B”(链接见引用 )

main( ) {
 extrn a, b, c;
 putchar(a); putchar(b); putchar(c); putchar(’!*n’);
}

a ’hell’;
b ’o, w’;
c ’orld’;

1974 年 1 月的提交 convert to C,如 Kernighan 的“ Programming in C — A Tutorial ”中所述(链接见引用)。链接的 PDF 是 Dennis Ritchie 重新输入的副本,没有日期,但 Ritchie于​​ 1974 年 1 月 15 日的“C Reference Manual”技术备忘录将 Kernighan 的教程引用为“Unpublished internal memorandum, Bell Laboratories, 1974”,暗示该教程必须也是一月份写的。那个 C 程序比我们今天习惯的要短,但比 B 程序好得多:

main( ) {
	printf("hello, world");
}

Cox并没有完全使用 The C Programming Language 第一版中的试例,原书中的试例应该是这样的:

main() { 
	printf("hello, world\n"); 
}

1988年4 月的提交了来自The C Programming Language 第二版的“Draft-Proposed ANSI C”版本的程序:

#include <stdio.h> 

main() 
{ 
	printf("hello, world\n"); 
}

1988 年 4 月的第二次提交 显示了我们今天所知道的最终完整的 ANSI C 版本:

#include <stdio.h> 

int 
main(void) 
{ 
	printf("hello, world\n"); 
	return 0;
}

而这也就是Go最初的四个提交的来历。

Public Mercurial

2009 年 11 月 10 日 Google Code Mercurial 存储库正式发布,为了纪念这一时刻,Go项目组又加了一个彩蛋。
Brian Kernighan 和 Rob Pike 1984 年出版的《Unix 编程环境》一书中的脚注中写到:

Ken Thompson 曾经被问到,如果让他来重新设计UNIX系统,他会做些什么不同的事情。他的回答是:“我会把creat写成e。”

哈哈哈哈,这是一个笑话,这指的是unix的系统函数creat和文件打开标志O_CREAT。由于使用的是 creat 而不是 create 少写了一个 e ,所以Ken表示,要是我来写,那我就直接用e, creat都不用。其实就是调侃少写个字母。

于是便有了这么一个有趣的提交
image.png

该提交也只是在file.go内的文件标记常量中增加一行 O_CREATE = O_CREAT
image.png

Git

终于到我们熟悉的“伙伴”上了,到2014年后,Google Code Project Hosting 即将关闭,此时的Go代码需要一个新家,最后选择了 Gerrit Code Review,许多人认为 Go 托管在 GitHub 上,但 GitHub 只是问题跟踪器的主要来源:源代码的官方主要副本位于 go.googlesource.com
2014年12月8日,第一个Git提交出现,至此到今天,Go依然使用Git做为版本控制系统。

commit 369873c6e5d00314ae30276363f58e5af11b149c
Author:     David Symonds <dsymonds@golang.org>
AuthorDate: Mon Dec 8 13:50:49 2014 +1100
Commit:     David Symonds <dsymonds@golang.org>
CommitDate: Mon Dec 8 13:50:49 2014 +1100

    convert .hgignore to .gitignore.

 .hgignore => .gitignore | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

commit f33fc0eb95be84f0a688a62e25361a117e5b995b
Author:     David Symonds <dsymonds@golang.org>
AuthorDate: Mon Dec 8 13:53:11 2014 +1100
Commit:     David Symonds <dsymonds@golang.org>
CommitDate: Mon Dec 8 13:53:11 2014 +1100

    cmd/dist: convert dist from Hg to Git.

 src/cmd/dist/build.c | 100 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 59 insertions(+), 41 deletions(-)

commit 26399948e3402d3512cb14fe5901afaef54482fa
Author:     David Symonds <dsymonds@golang.org>
AuthorDate: Mon Dec 8 11:39:11 2014 +1100
Commit:     David Symonds <dsymonds@golang.org>
CommitDate: Mon Dec 8 04:42:22 2014 +0000

    add bin/ to .gitignore.

    Change-Id: I5c788d324e56ca88366fb54b67240cebf5dced2c
    Reviewed-on: https://go-review.googlesource.com/1171
    Reviewed-by: Andrew Gerrand <adg@golang.org>

 .gitignore | 1 +
 1 file changed, 1 insertion(+)

而这就是故事的结尾,直到在未来的某个时刻转向第五个版本控制系统。