Android深度探索(卷1):HAL与驱动开发
上QQ阅读APP看书,第一时间看更新

第3章 Git使用入门

一提到Linux、Android,大家就会不约而同地想到同一个词:开源。经常使用Windows或Mac OS X的用户可能对开放源代码软件的体会没有那么深,但资深的Linux用户简直就是在开源软件的陪伴下长大的。Linux下的软件有很多都不直接以二进制形式的安装包提供,而是直接提供了源代码。用户需要先下载源代码,然后在本机上编译并安装(一般使用make、make install等命令)。在这些提供源代码的软件中,与内核紧密相关的驱动以及其他底层程序占很大比重。因为如果不提供源代码,而直接提供安装包,就需要为Linux的各个内核版本都生成一个二进制的安装包。大家都知道,Linux内核版本非常繁多,可能会有数以百计的版本(包括衍生的一些Linux内核版本),如果要这样做,恐怕软件的安装包要以GB为单位了。因此,为了减小发行包的大小,干脆直接提供源代码,由用户在指定Linux内核上进行编译。

既然涉及源代码,就需要对源代码进行管理。Linux内核代码及很多著名的项目(如Android、Eclipse、KDE、QT、Ruby on Rails等)都使用了Linux之父Linus编写的Git进行源代码管理。Linus以一个文件系统专家和内核设计者的视角对Git进行了设计,其独特的设计让Git拥有非凡的性能和最为优化的存储能力,Git在各方面都优于其他同类的源代码管理软件(如CVS、SVN等)。在学习 Android 及 Linux 内核、驱动开发的过程中会涉及大量的源代码,而这些源代码基本都是由Git 管理的,因此,在开发正式学习本书的主要内容(Android 移植和 Linux 驱动开发)之前了解Git的理论和基本使用方法会有助于获取更多的学习资源。

3.1 安装Git

在使用Git之前首先应安装Git。很多Linux系统已经带了Git。如果读者的Linux系统没有安装Git,可使用下面的方法来安装Git的最新版本。

Ubuntu Linux 10.10(maverick)或更新的版本,可以使用下面的命令来安装Git。

    # apt-get install git
        # apt-get install git-doc git-svn git-email git-gui gitk

其中Git软件包包含了大部分Git命令,是必须安装的软件包。而第二条语句中安装的git-doc、git-svn、git-email、git-gui和gitk本来也是Git软件包的一部分,但是因为有着不一样的软件包依赖(如更多的perl模组和tk等),所以单独作为软件包发布。如果不需要使用这些软件包,可以不安装它们。

注意

本书所执行的Linux命令都是在root用户下完成的。如果读者使用其他用户登录,遇到必须使用root权限才能执行的命令,可以命令前面加sudo。这样系统会要求用户输入root用户的密码。如果输入正确,系统会切换到root权限来执行这些命令。如果读者的Linux系统没有为root用户设置密码,请使用sudo passwd root命令设置root的密码。然后可以使用root用户登录来执行本书中的Linux命令。

□ Ubuntu 10.04或更低的版本。

在低版本的Ubuntu Linux中,软件包Git实际上是指GNU Interactive Tools,而非作为版本控制系统的 Git。也就是说 Git 这个名字被另的软件包占了,为了加以区分,将用于版本控制的 Git软件包改为git-core。因此,需要使用下面的命令来下载用于版本控制的Git。

    # apt-get install git-core
        # apt-get install git-doc git-svn git-email git-gui gitk

□ RHEL、Fedora和CentOS。

如果读者使用RHEL、Fedora和CentOS,可以使用下面的命令安装Git。

    # yum install git
        # yum install git-doc git-svn git-email git-gui gitk

在其他Linux发行版中安装Git的过程与前面几种安装方法类似,读者可以参考相关的文档来安装Git。在这些Linux发行版中Git安装包或称为git,或称为git-core。

3.2 查看Git文档

在Linux下可以直接使用man命令查看指定命令的帮助文档。如要查询git-checkout命令的帮助文档,可以使用下面的命令。

    # man git-checkout

执行上面的命令行,会在Linux终端显示如图3-1所示的帮助信息,按“q”键退出帮助。

▲图3-1 git-checkout命令的帮助信息

安装git-doc后会安装git的文本格式和HTML格式的文档,所有的文档都存在/usr/share/doc/git-doc目录中。以文本形式查看指定的文档可以使用下面的命令。

    # git help <sub-command>

如要查询git-checkout命令的文档,可使用下面的命令。

    # git help git-checkout

执行上面的命令后,会在Linux终端显示与图3-1相同的帮助信息。如果想查看HTML格式的文档,需要使用如下的命令

    # git help –w git-checkout

执行上面的命令行,会在浏览器中显示git-checkout命令的帮助信息,如图3-2所示。

▲图3-2 在浏览器中显示git-checkout命令的帮助信息

3.3 源代码的提交与获取

Git的功能很复杂,为了使读者尽快了解Git的基本用法。本节给出一个完整的例子来演示如何创建版本库、提交源代码、创建分支、向远程服务器上传源代码,从远程服务器获取源代码等技术。通过本节的学习,读者可以基本掌握如何使用git从源代码托管服务器获取自己想要的源代码,也可以很容易理解从网上搜索到的通过git下载源代码的命令的含义。

3.3.1 创建版本库:git init

任何版本管理软件都必须有一个版本库,所不同的是这些软件对版本库的管理方式。Git的版本库与其他版本管理软件(如CVS、SVN等)的版本库的组织方式有很大的差异。Git的版本库分为本地版本库和远程版本库。在使用Git管理源代码版本时可以不连接Internet,在这种情况下Git直接与本地版本库通信,当连接Internet时,再将本地版本库同步到远程版本库。访问本地版本库并不需要任何的权限,也就是说自己就是本地版本库的主人。任何人想修改Git源代码托管服务器中的源代码,必须使用git clone命令在本地建立一个与远程版本库一模一样的本地版本库。

在建立开源项目之初,需要使用git init在本地创建一个空的版本库。先执行下面的命令建立一个开源项目的工作目录(/demo/helloworld-git),并进入工作目录。

    # mkdir –p /demo/helloworld-git
        # cd /demo/helloworld-git

然后执行下面的命令。

    # git init

执行完git init命令后,会输出如下的信息。

Initialized empty Git repository in /demo/helloworld-git/.git/

在helloworld-git目录中使用ls命令什么也不会显示。不过要执行如下的命令,会显示如图3-3所示的.git目录(隐藏目录)。

    # ls –al

▲图3-3 工作目录的结构

现在一个空的版本库已经成功建立了。在源代码工作目录(helloworld-git)中有一个隐藏的.git目录。这个目录就是前面所说的本地版本库。现在进入.git目录,并使用ls命令列出该.git目录中的子目录和文件,如图3-4所示。这些目录和文件目前都是初始状态,在后面不断操作这个本地版本库,会修改.git目录中的相关子目录和文件的内容。

▲图3-4 .git目录的结构

3.3.2 将文件提交到本地版本库:git commit

使用Git管理文件(Git不仅仅是管理源代码的工具,实际上它还管理任何的文件),首先要将文件提交到本地版本库(.git 目录)。现在执行下面的命令进入/demo/helloworld-git 目录,并在helloworld-git目录下建立一个helloworld.txt文件。

    # cd /demo/helloworld-git
        # echo "helloworld" > helloworld.txt

现在 helloworld.txt 文件中有一行文本:hello world。接下来执行如下的命令将 helloworld.txt文件加到本地版本库的索引中,并将helloworld.txt文件提交到版本库。

    # git add helloworld.txt
        # git commit –m 'helloworld-master'

其中,-m命令行参数helloworld-master是本次提交的备注,Git要求必须指定该信息。如果git commit 命令未指定该信息,系统会先调用默认文本编辑器(一般为 vi)要求输入该信息。执行下面的命令可以显示日志信息。

    # git log

日志信息的内容如图3-5所示。

▲图3-5 Git日志

一旦将工作目录中的文件提交到本地版本库,就再也不怕源代码误册或误改了。例如,使用下面的代码在helloworld.txt后面添加一行文本。

    # echo "世界你好" > helloworld.txt
        # cat helloworld.txt

执行下面的命令可以立刻恢复到最近一次提交的状态。

    # git checkout helloworld.txt

删除helloworld.txt文件也同样可以恢复。

3.3.3 创建本地分支:git branch

由于一个源代码工程可能由多人共同完成,因此,Git提供了分支的概念。也就是说,参与开发的人员会为每一处修改(可能是增加一个性能,也可能是修改原来的bug)建立一个分支,这样在修改后提交不会影响主分支(master)的代码。提交后由测试人员审核后会将该分支合并到主分支中。本节只介绍如何创建本地分支,如果使本地版本库和远程版本库同步后,还会有远程版本库,将在后面详细介绍。

在创建本地分支之前可以使用下面的命令了解以下当前版本库包含哪些本地分支。

    # git branch

如果读者按着前面的步骤操作,会显示如图3-6所示的分支。

▲图3-6 当前版本库的本地分支

使用下面的命令可以建立一个新的分支。

    # git branch new-branch

现在使用git branch命令可以显示如图3-7所示的分支。

▲图3-7 新增加的本地分支

分支前面的星号(*)表示当前工作目录在哪个分支下。使用git commit命令会将修改后的文件提交到工作目录当前所在的本地分支。使用下面的命令可以删除刚建立的分支(在分支中所做的一切修改都将消失,因此执行这条命令时要小心)。

    # git branch -D new-branch

3.3.4 切换本地分支:git checkout

本地分支是为了隔离主分支不同部分的修改。使用git checkout命令可以在不同的本地分支之间切换。下面来做一个本地分支切换的实验。

使用下面的命令将当前本地分支切换到new-branch上。

    # git checkout new-branch

使用下面的命令修改helloworld.txt文件的内容(要保证与master分支的内容不同),并重新提交到本地版本库。

    # echo '世界你好' > helloworld.txt
        # git add helloworld.txt
        # git commit –m helloworld-new-branch

现在使用 git checkout master 和 git checkout new-branch 来回切换本地版本库,会发现helloworld.txt文件的内容会随着分支的变化而变化。

3.3.5 在GitHub上创建开源项目

前面几节一直都是操作本地版本库和本地分支。如果只在本地操作是没有任何意义的。使用Git 管理源代码都会使用远程的 Git 托管服务器(可能是自己配置的,也可以是免费或收费的 Git托管服务器)。为了使读者尽快了解如何提交本地代码到Git托管服务器,本节使用了GitHub来托管刚才创建的文件(helloworld.txt)。GitHub是目前比较流行的Git托管服务提供商。使用GitHub之前需要在https://github.com/signup/free页面注册一个免费的用户。注册界面如图3-8所示。

▲图3-8 GitHub的注册页面

如果输入没有什么问题,单击页面下方的“Create an account”按钮会成功创建一个用户。然后用这个用户登录。用自己建立的用户登录后(这里用androidguy登录),进入GitHub的首页,如图3-9所示,单击页面右下角的“New repository”按钮创建一个新的项目。

▲图3-9 GitHub的首页

建立项目的页面如图3-10所示。使用GitHub建立项目很简单,只需要输入一个项目名(必须在GitHub上没有使用过)即可。但要注意。免费账号只能建立开源项目(任何人都可下载项目的源代码),并不能建立闭源项目(只能通过授权才能访问源代码)。如果读者不想让别人看到自己的源代码,需要向GitHub交纳一定的费用(至少7美元/月)。

▲图3-10 建立项目的页面

建立完项目后,会显示如图3-11所示的页面,该页面会告诉用户如何将源代码上传到GitHub上。在下一节会详细介绍如何将刚才建立的本地版本库同步到GitHub上。

▲图3-11 将源代码上传到GitHub上的命令

3.3.6 上传源代码到GitHub:git push

由于GitHub上传代码时需要SSH校验。因此,需要使用下面的命令在~/.ssh目录中生成一个密钥文件(id_rsa)和一个公钥文件(id_rsa.pub)。如果这两个文件已经存在,请备份它们。

    # ssh-keygen –t rsa -C "helloworld@126.com"

请将helloworld@126.com换成注册GitHub账号时输入的E-mail。执行上面的命令会要求做一些选择或输入。如果~/.ssh目录中存在id_rsa和id_rsa.pub文件,会询问是否覆盖它们。然后会要求输入在注册 GitHub 账号时输入的密码(屏幕不回显)。如果操作无误,会显示如图3-12所示的信息。

▲图3-12 生成公钥和密钥文件

生成的~/.ssh/id_rsa 和~/.ssh/id_rsa.pub文件都是纯文本格式。使用自己喜欢的文本 编 辑 器(vi、gedit 等)打 开~/.ssh/id_rsa.pub 文件,将该文件中的所有内容复制到剪贴板(注意不要修改文件的任何内容,如增加空行,用 gedit打开该文件,只要按Ctrl -A、Ctrl-C即可)。然后进入 GitHub 的账户设置页面(单击图3-9所示页面右上角中间那个按钮),在账户设置页面左侧选择“SSH Public Keys”项,单击页面中间的“Add another public key”链接,会显示如图3-13所示的添加public key的输入框,将刚才复制到剪贴板的内容粘贴到Key输入框中。Title输入框可以随意输入。输入完成后,单击“Add key”按钮添加一个public key。

▲图3-13 添加public key

设置完public key后,可以使用如下的命令(不要修改git@github.com)检测公钥、密钥以及刚才的设置是否正确。

    # ssh -T git@github.com

如果生成的公钥、密钥错误或设置不正确,则会输出如下的信息。

Permission denied (publickey).

fatal: The remote end hung up unexpectedly

如果一切都做得很完美,就会输出如图3-14所示的信息。

▲图3-14 测试GitHub成功

笔者发现有一些Linux系统(如Ubuntu Linux)就算成功完成上面的操作也无法通过测试,在这种情况下,需要执行如下的命令向代理身份验证添加RSA身份。

    # ssh-add

执行ssh-add命令后要求输入图3-12要求输入的密码。输入正确后,会显示如图3-15所示的信息。

▲图3-15 成功向代理身份验证添加RSA身份

上传文件之前需要使用git config命令设置上传者的名字和email。这些信息在客户端并不验证,可能有的Git托管服务器会验证这些信息。读者要使用自己的名字和email。

    #  git config --global user.name "Your Name"
        #  git config --global user.email helloworld@126.com

接下来需要使用git remote add和git push命令上传工作目录中的文件。首先使用git remote命令设置helloworld工程在GitHub上的URI。

    # git remote add origin git@github.com:androidguy/helloworld.git

git remote add命令后面的origin是远程代码库名,可以任意起名。如果是第1次向helloworld工程上传文件,可以从如图3-11所示的页面中找到与工程对应的URI(git@github.com:androidguy/helloworld.git),如果工程中没有任何的文件,是无法进入工程管理页面的。只能通过图3-11所示的页面给出的命令上传文件后才可以进入工程管理页面。

最后使用下面的命令将本地版本库中的文件上传到GitHub。

    # git push –u origin master

其中master是远程版本库(origin)中的主分支。如果上传成功,会输出如图3-16所示的信息。

▲图3-16 成功上传文件到GitHub

现在执行如下的命令查看所有的分支(本地分支和远程分支)。

    # git branch -a

当前版本库所有的分支如图3-17所示。其中remotes/origin/master为远程分支,其他两个为本地分支。

▲图3-17 当前版本库所有的分支

读者可以在GitHub页面上看到刚刚上传的文件(helloworld.txt),如图3-18所示,并且可以在该页面中找到用于上传的URI(黑框中的部分)。

▲图3-18 helloworld工程的主页面

3.3.7 从GitHub下载源代码:git clone

使用如下的命令可以下载整个工程。

    # git clone git@github.com:androidguy/helloworld.git

如果下载成功,会输出如图3-19所示的信息。

▲图3-19 成功下载工程源代码

下载完成后,会发现当前目录下多了一个helloworld目录,该目录就是与前面的helloworld-git目录一模一样的工作目录。helloworld目录中也包含一个.git本地版本库目录。

如果只想获取某一分支的最新内容,可以使用下面的命令。

    # git pull origin master

3.4 小结

虽然本书的主要内容并不是介绍Git,但还是用了一整章为读者展示了Git的基本用法。尽管Git并不是学习Android移植和Linux内核、驱动开发必须掌握的技术。但对于想深入研究这些低层技术的读者,Git将成为学习过程中必不可少的工具。

学习新技术的最好方式不是阅读技术书籍、也不是在网上查看别人写的文章,而是直接阅读自己感兴趣的源代码。毕竟源代码是最能体现软件作者的真正思路的。就像学习Linux内核开发,只是找几本所谓的“权威”书籍来看,并不能真正体会 Linux 内核的核心设计理念。而唯一可以和Linux内核走近一点,甚至融入Linux内核的方式就是直接阅读Linux内核的源代码。虽然一开始很难理解这些晦涩到使人崩溃的代码,不过随着不断做各种实验,并通过一些内核理论相辅助,那些曾经晦涩的源代码会像潘多拉魔盒一样打开。当然,与希腊神话中的潘多拉魔盒不同的是释放出来的不是瘟疫,而是智慧。

自从2005年Git问世以来(事实上第1版只用了4天就发布了,够快的),以其强大的功能,近乎完美的理念和极高的性能逐渐征服了广大技术人员的心。现在已经有越来越多的开源项目由其他的版本管理工具迁移到Git上。这些开源的项目对于开发人员来说无疑是巨大的宝藏。但打开宝藏大门的钥匙并不是求知的欲望,也不是好奇心,而是Git。因为要想获取这些开源项目的源代码,必须使用Git,而不是很多人喜欢的HTTP/HTTPS、FTP下载。因此,只有掌握Git才可以很容易地获取属于我们的宝藏。

如果读者有更高的追求,例如,想参与Linux内核的开发。那么Git就成为了必修课。因为Linux内核完全是使用Git管理的。不掌握Git,简直就是寸步难行。总之一句话,对于想快速提高技术水平的开发人员来说,Git已成为必须掌握的重要技能之一。