git 教程(7)

来源:互联网 发布:校园翼讯mac 编辑:程序博客网 时间:2024/05/22 15:35
git 教程(7)
==============

名称
----
git 教程 - 介绍git的教程 (仅用于 1.5.1 版本或以上)

摘要
--------
git *

描述
-----------

本教程讲述如何将一个新项目导入到git,如何做修改并将所做的改动共享给其他开发者。
如果你主要是想知道如何用git获取一个项目,比如想测试最新的版本,你可能更适合从
user-manual.html[Git 用户手册]的前两章开始。

首先,要知道可以用下面的方式来获得某个命令的的用法:

------------------------------------------------
$ man git-log
------------------------------------------------

或者:

------------------------------------------------
$ git help log
------------------------------------------------

上面命令会列出log的各种用法; 详细可参看linkgit:git-help[1]。


建议你在做任何git操作前先公布一下你的名字和邮箱,做法很简单:
------------------------------------------------
$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com
------------------------------------------------


导入一个新项目
-----------------------

假如你有一个新项目为project.tar.gz,你可以通过下面的操作将git版本控制加进去

------------------------------------------------
$ tar xzf project.tar.gz
$ cd project
$ git init
------------------------------------------------

Git 会打印出:

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

你已经初始化了一个工作目录--你可能注意到已创建了一个名为".git"的文件夹.

下面,用 'git add' 让git将当前录所有文件的内容拍个快照:

------------------------------------------------
$ git add .
------------------------------------------------

这个快照会被存储在一个git称为“索引”的临时缓冲区里。你可以通过'git commit'将
索引的内容永久地存储在版本控制仓库里:

------------------------------------------------
$ git commit
------------------------------------------------

该命令会提示你输入提交信息。至此,你已将项目的第一个版本存储到git了。


作修改
--------------

修改文件,并将已更改的内容添加到索引:

------------------------------------------------
$ git add file1 file2 file3
------------------------------------------------

现在就可以提交了。你还可以用下面的命令来查看所做的改动:
用 'git diff' 带 --cached 选项:

------------------------------------------------
$ git diff --cached
------------------------------------------------

(不带 --cached, 'git diff' 将会显示还没添加到索引的改动.)  你还可以通过 'git status'
来查看哪些文件有改动:

------------------------------------------------
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    modified:   file1
#    modified:   file2
#    modified:   file3
#
------------------------------------------------

如果你还想作一些改动,可以继续改,改完后再将它们添加到索引,最后用下面的命令来提交所做的改动:

------------------------------------------------
$ git commit
------------------------------------------------

该命还会提醒你输入描述改动的提交信息,然后会记下项目的一个新版本号。

还有,不想运行'git add',你还可以用:

------------------------------------------------
$ git commit -a
------------------------------------------------

该命令会自动识别那些改动的文件(新创建的除外,新建的文件必须得用git add),将
它们添加到索引,并提交,所有操作一步到位。

提交信息格式的建议:
虽然不是强制要求,但最好还是写一句关于改动的简短概要(少于50个字符),
然后写一个间隔线隔开,接着再写详细描述。因为工具在将提交信息发到邮箱时,
会将第一行作为标题,其他作为文本内容。格式如下:

Git 跟踪的是内容,而不是文件
----------------------------

一些版本控制系统提供add命令用于告诉系统开始跟踪一个新文件的变动。Git的add命令
也做一些相似的功能,但还有更强大的功能:add可以用于新创建,也可以用于改动的文件,
这两种情况下,都会对文件的内容拍一个快照存储在临时工作区,即索引上,然后再下一步
提交时永久存储到仓库。


查看项目历史记录
-----------------------

用下面的命令,可以查看所有你作修改的历史记录:

------------------------------------------------
$ git log
------------------------------------------------

如果还想看每次改动的差异,还可以使用:

------------------------------------------------
$ git log -p
------------------------------------------------

通常查看更改概要也有助于了解每一次的改动:

------------------------------------------------
$ git log --stat --summary
------------------------------------------------

Managing branches
-----------------

单个git仓库可以维持多个开发分支。比如创建一个"experimental"分支,可使用:

------------------------------------------------
$ git branch experimental
------------------------------------------------

如果你现在运行:

------------------------------------------------
$ git branch
------------------------------------------------

你会看到所有已存分支的列表:

------------------------------------------------
  experimental
* master
------------------------------------------------

"experimental" 正是你刚创建的分支,"master" 分支是默认分支,是系统自动给你创建的。
*号表示你当前所处的分支是master。


敲入如下命令:

------------------------------------------------
$ git checkout experimental
------------------------------------------------

将会切换到 experimental 分支。此时编辑一个文件,并提交改动,然后再切换回master分支:

------------------------------------------------
(edit file)
$ git commit -a
$ git checkout master
------------------------------------------------

可以看到你的改动不见了,这因为你作的改动是在experimental分支上,而现在你是在master分支了。

你还可以在master上作一个不同的改动:

------------------------------------------------
(edit file)
$ git commit -a
------------------------------------------------

这样两个分支就分流了,彼此有不同的改动。将experimental上的改动合并到master,可以运行:

------------------------------------------------
$ git merge experimental
------------------------------------------------

如果彼此的改动不冲突,那么你就完成了。如果存在冲突,会有显示冲突的标识留在冲突的文件上,让你手动更改。

------------------------------------------------
$ git diff
------------------------------------------------

上面命令会显示冲突的地方。一旦改好冲突文件后,

------------------------------------------------
$ git commit -a
------------------------------------------------

上面将提交并合的结果。最后,

------------------------------------------------
$ gitk
------------------------------------------------

将显示一个关于操作历史记录的友好图形界面。

此时,你可以将experimental分支删除,使用下面命令:

------------------------------------------------
$ git branch -d experimental
------------------------------------------------

该命令提示你是否已将experimental所有的改动合并到当前分支了,如果没有,则不让删除。

如果你创建了一个分支叫crazy-idea,想丢弃它,可以用下面命令强制删除:

-------------------------------------
$ git branch -D crazy-idea
-------------------------------------

使用分支方便节省,这是个作不同尝试的好方法。


git用于合作开发
---------------------------

Alice创建了一个带git仓库的项目/home/alice/project,
Alice 和 Bob两人同时进行开发。

Bob 开始下载源码:

------------------------------------------------
bob$ git clone /home/alice/project myrepo
------------------------------------------------

这将创建一个名为"myrepo"的目录,该目录包含服务器仓库的一份克隆。该克隆地位
同等服务器仓库,可以处理拷自原始仓库的历史记录。


Bob 做了一些修改并提交:

------------------------------------------------
(edit files)
bob$ git commit -a
(repeat as necessary)
------------------------------------------------

当Bob完成后,告诉Alice去更新这些改动。
Alice将会做:

------------------------------------------------
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
------------------------------------------------

上面的操作将会将Bob库分支"master"的改动合并到Alice当前的分支。
如果Alice也对这些文件有作改动,则需要手动修复冲突。


"pull"命令执行了两个操作:从服务器上将改动的文件抓下来,然后将它们合并到当前分支。

注意,一般情况下,Alice会在"pull"前将自己的改动提交。
如果Bob的工作与 Alice的有冲突,Alice会用自己的工作树和索引去解决这些冲突,
冲突越多,解决时间越长;冲突发生时git 不会执行合并的操作,Alice解决完冲突后,还需
再pull一下。

Alice可以使用"fetch"命令,先将改动的文件抓下来,用"FETCH_HEAD"查看改动,再做是否需要更新的决定:

------------------------------------------------
alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------

即使Alice没有提交本地的更改,该操作也是安全的。
"HEAD..FETCH_HEAD" 的意思是:显示HEAD与FETCH_HEAD历史记录分开后FETCH_HEAD的记录。

还可以用图形化工具查看:

------------------------------------------------
$ gitk HEAD..FETCH_HEAD
------------------------------------------------

Alice 还可以查看HEAD与FETCH_HEAD历史记录分开后彼此的记录
她可以用三点形式来代替两点形式:

------------------------------------------------
$ gitk HEAD...FETCH_HEAD
------------------------------------------------

看了Bob的改动后,如果没什么要紧的改动,Alice或许不会去更新。如果有比较急需的,
Alice可能先将自己的改动移走,更新最新代码,最后再把原先的工作放回来。

当你是在一个小型紧凑型团队工作,会经常对同一个服务器打交道。通过简单定义一个'remote'
仓库,这样你做起来会更简单:

------------------------------------------------
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------

该命令的意思是将bob映射为远程仓库/home/bob/myrepo,其实就是用bob表示/home/bob/myrepo。
执行该命令之后,Alice就可以执行"pull"操作的第一部分,即'git fetch':

-------------------------------------
alice$ git fetch bob
-------------------------------------

不像一般形式,fetch后面跟的是远程仓库的地址,现在采用的是git remote add 建立代的代号,
其映射关系可以通过'git remote'命令来查看。
bob后面没跟分支,表示`bob/master`。
fetch操作之后执行:

-------------------------------------
alice$ git log -p master..bob/master
-------------------------------------

将显示Bob和Alice主分支历史记录分开后Bob的记录,其功能相当于git log -p HEAD..FETCH_HEAD

检查完改动后,Alice可以将这些改动合并到她的当前分支:

-------------------------------------
alice$ git merge bob/master
-------------------------------------

`merge` 的操作也可用'pull'来代替:

-------------------------------------
alice$ git pull . remotes/bob/master
-------------------------------------

注意,不管给什么参数,git pull的操作总会将代码合并到当前分支

后面,Bob可以更新Alice的最新改动。

-------------------------------------
bob$ git pull
-------------------------------------

注意到Bob并不需要提定Alice的仓库地址,因为Bob在克隆Alice的仓库后,本地的仓库配置已存储了
Alice的仓库地址了,如下命令可获得该地址:

-------------------------------------
bob$ git config --get remote.origin.url
/home/alice/project
-------------------------------------

('git clone' 创建的配置信息可以通过`git config -l`来查看, 详细请参看linkgit:git-config[1])

Git也保留了Alice 主分支的原始拷贝在"origin/master":

-------------------------------------
bob$ git branch -r
  origin/master
-------------------------------------

如果Bob以后想换个电脑,他还可以通过ssh 协议来执行clone和pull操作:

-------------------------------------
bob$ git clone alice.org:/home/alice/project myrepo
-------------------------------------

还有,git 可以用git协议,或者rsync或者http;详细请参看linkgit:git-pull[1]


Git还可以像CVS那样,作为一个中央仓库,让很多人可以提交改动,详细请参看linkgit:gitcvs-migration[7]。

浏览历史记录
-----------------

Git 历史记录是用一连串相关提交信息组成的。我们已知道可以通过'git log'命令来列出这些提交信息。
注意每个git log列出的第一行是提交名称:

-------------------------------------
$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date:   Tue May 16 17:18:22 2006 -0700

    merge-base: Clarify the comments on post processing.
-------------------------------------

我们可以'git show'来看某个提交名称所包含的详细信息。

-------------------------------------
$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-------------------------------------

还有其他方法可以查看提交信息。可以用提交名称前几个字符,只要足以定位就行,去查看该提交的详细信息:

-------------------------------------
$ git show c82a22c39c    # the first few characters of the name are
            # usually enough
$ git show HEAD        # the tip of the current branch
$ git show experimental    # the tip of the "experimental" branch
-------------------------------------

每一个提交一般有一个表示项目上一个状态点的“父级”提交:

-------------------------------------
$ git show HEAD^  # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD
-------------------------------------

注意,合并的提交可能会有多个“父级”

-------------------------------------
$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
$ git show HEAD^2 # show the second parent of HEAD
-------------------------------------

通过运行下面的命令,可以将提交名称改为自定义的:

-------------------------------------
$ git tag v2.5 1b2e1d63ff
-------------------------------------

可以用"v2.5"来代替1b2e1d63ff。如果你想将这个名称与其他人分享(比如,标识一个发布版本号),
你需创建一个"tag"的对象,可能要签名;详细请参看linkgit:git-tag[1]。


任何git命令需要提交名称的都可以用tag或都HEAD的表达来代替,例如:

-------------------------------------
$ git diff v2.5 HEAD     # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
             # at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
             # directory to its state at HEAD^
-------------------------------------

注意最后一个命令:除了会丢掉当前所有的改动,还会将其后面的提交删除。
如果这些已提交的东西只有当前分支有,则执行完这个命令后会永久丢失。
同样,不要在一个共用的分支上使用'git reset'命令,否则会引起一些不必要的合并,迫使
其他开发者清除历史记录。如果想撤消已提交的改动,可以使用'git revert'来代替'git reset'。


'git grep'命令可以搜索项目任何版本的字符串。

-------------------------------------
$ git grep "hello" v2.5
-------------------------------------

在v2.5版本搜索所有出现"hello"的文件。

如果不加提交名称,'git grep'会搜索当前目录git管理的所有文件。


-------------------------------------
$ git grep "hello"
-------------------------------------

这是一个在git所记录的文件里搜索的捷径。


有些git命令可以带几个提交名称,这些名称有几种表达方式,例如'git log':

-------------------------------------
$ git log v2.5..v2.6            # commits between v2.5 and v2.6
$ git log v2.5..                # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile       # commits since v2.5 which modify
                # Makefile
-------------------------------------

git log 提交名称之间的范围符号,即'..',还可以表只存在于第二个名称里,但不存在于
第一个名称里;例如,有"stable"  和 "master"两个分支,它们的提交记录在某个时间就已
分开:

-------------------------------------
$ git log stable..master
-------------------------------------

将列出stable分支没有,master分支有的历史记录。

-------------------------------------
$ git log master..stable
-------------------------------------

将列出master分支没有,stable分支有的历史记录。

'git log'命令有一个缺陷:只能以列表的形式来表现提交记录。如果同时有多条
开发分支,后面合并到一起,用git log所列出来的提交顺序是没意义的。

大多项目会有许多开发分支,会经常合并,使用gitk可以更好浏览历史记录。例如:

-------------------------------------
$ gitk --since="2 weeks ago" drivers/
-------------------------------------

允许你浏览两周来,在drivers目录下的修改记录。(提示:你可以通过'ctrl' + '-' 或 'ctrl' + '+'
来调整gitk的字体)

最后,大多数命令可以带文件名,这样可以优先处理该文件,如指定一个文件的版本:

-------------------------------------
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------

还可以用'git show'来看任何文件:

-------------------------------------
$ git show v2.5:Makefile
-------------------------------------

往后
----------

通过本教程的学习,应该可以做一般的分布式版本控制项目了。然而,想全面了git的深度和力量,还需要
理解下面两个简单的思想:

  * 对象数据库是一种比较高端的系统,用于存储项目的历史记录,比如文件,目录,提交等。

  * 索引文件是目录树状态的一个缓存,用于创建提交,切换工作目录,保留合并后的不同树。


本教程的第二部分解释了对象数据库,文件索引,和一些通命令用法。

如果你不想走寻常路,下面一些东西可能会适合你:
If you don't want to continue with that right away, a few other
digressions that may be interesting at this point are:

  * linkgit:git-format-patch[1], linkgit:git-am[1]: These convert
    series of git commits into emailed patches, and vice versa,
    useful for projects such as the Linux kernel which rely heavily
    on emailed patches.

  * linkgit:git-bisect[1]: When there is a regression in your
    project, one way to track down the bug is by searching through
    the history to find the exact commit that's to blame.  Git bisect
    can help you perform a binary search for that commit.  It is
    smart enough to perform a close-to-optimal search even in the
    case of complex non-linear history with lots of merged branches.

  * linkgit:gitworkflows[7]: Gives an overview of recommended
    workflows.

  * link:everyday.html[Everyday GIT with 20 Commands Or So]

  * linkgit:gitcvs-migration[7]: Git for CVS users.

还可以参看
--------
linkgit:gittutorial-2[7],
linkgit:gitcvs-migration[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
linkgit:git-help[1],
linkgit:gitworkflows[7],
link:everyday.html[Everyday git],
link:user-manual.html[The Git User's Manual]

GIT
---
Part of the linkgit:git[1] suite.