第1章如何获取Git存储库
在阅读本手册时,让Git存储库进行试验会很有用。
获得它的最好方法是使用git-clone(1)命令下载现有存储库的副本。如果你还没有一个项目,这里有一些有趣的例子:
#Git本身(大约40MB下载):
$ git clone git://git.kernel.org/pub/scm/git/git.git
#Linux内核(约640MB下载):
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
对于大型项目来说,初始克隆可能非常耗时,但您只需要克隆一次。
clone命令将创建一个以项目命名的新目录(git或linux上面的示例中)。在你进入这个目录之后,你会看到它包含了一个名为工作树的项目文件的副本以及一个名为的特殊顶层目录.git,其中包含有关项目历史的所有信息。
第2章如何检出不同版本的项目
Git最好被认为是存储文件集合历史的工具。它将历史记录存储为项目内容的相关快照的压缩集合。在Git中,每个这样的版本都被称为提交。
这些快照不一定都是从最旧到最新排列成一行,相反,工作可以沿着平行的发展路线同时进行,称为分支,这可能会合并和分化。
单个Git存储库可以跟踪多个分支上的开发。它通过保存引用每个分支上最新提交的头的列表来实现这一点; git-branch(1)命令会显示分支头的列表:
$ git branch
* master
新克隆的存储库包含一个单独的分支头,默认名为“master”,工作目录初始化为该分支头引用的项目的状态。
大多数项目也使用标签。像头部一样,标签是对项目历史的引用,可以使用git-tag(1)命令列出:
$ git tag -l
v2.6.11
v2.6.11-tree
v2.6.12
v2.6.12-rc2
v2.6.12-rc3
v2.6.12-rc4
v2.6.12-rc5
v2.6.12-rc6
v2.6.13
...
预计标签总是指向相同版本的项目,而标签预计会随着开发的进展而提前。
创建一个指向这些版本之一的新分支头,并使用git-checkout(1)检出它:
$ git checkout -b new v2.6.13
然后工作目录反映了项目标签为v2.6.13时的内容,而git-branch(1)显示了两个分支,其中星号标记了当前签出的分支:
$ git branch
master
* new
如果您决定宁愿看到版本2.6.17,则可以修改当前分支,使其指向v2.6.17
$ git reset --hard v2.6.17
请注意,如果当前分支头是您对历史中某个特定点的唯一引用,那么重置该分支可能使您无法找到用于指向的历史记录; 所以请谨慎使用此命令。
第3章了解历史:提交
目录
了解历史:提交,父母和可达性
了解历史:历史图表
了解历史:什么是分支?
项目历史的每一个变化都由一个提交表示。git-show(1)命令显示当前分支上最近的提交:
$ git show
commit 17cf781661e6d38f737f15f53ab552f1e95960d7
Author: Linus Torvalds <torvalds@ppc970.osdl.org.(none)>
Date: Tue Apr 19 14:11:06 2005 -0700
Remove duplicate getenv(DB_ENVIRONMENT) call
Noted by Tony Luck.
diff --git a/init-db.c b/init-db.c
index 65898fa..b002dc6 100644
--- a/init-db.c
+++ b/init-db.c
@@ -7,7 +7,7 @@
int main(int argc, char **argv)
{
- char *sha1_dir = getenv(DB_ENVIRONMENT), *path;
+ char *sha1_dir, *path;
int len, i;
if (mkdir(".git", 0755) < 0) {
正如你所看到的,一个提交表明了谁做出了最新的改变,他们做了什么以及为什么。
每个提交都有一个40位十六进制的id,有时称为“对象名称”或“SHA-1 id”,显示在git show输出的第一行。您通常可以使用较短的名称(如标签或分支名称)引用提交,但此较长的名称也可能有用。最重要的是,它是这个提交的一个全球唯一的名称:所以如果你告诉其他人的对象名称(例如在电子邮件中),那么你可以保证这个名称将引用它的存储库中的相同的提交,它在你的假设他们的存储库有这个提交)。由于对象名称是作为提交内容的散列来计算的,因此可以保证,提交不会更改,而其名称也不会更改。
事实上,在第七部分“Git概念”中,我们将看到存储在Git历史记录中的所有内容(包括文件数据和目录内容)都存储在名称为内容散列的对象中。
了解历史:提交,父母和可达性
每次提交(除了项目中的第一次提交)还有一个父提交,它显示了在提交之前发生了什么。继父母之后,最终会让你回到项目的开始阶段。
但是,提交并不构成一个简单的列表; Git允许发展路线发散并重新聚合,两条发展重新聚合的点被称为“合并”。因此,表示合并的提交可以有多个父代,每个父代表代表最近一次提交到该点的开发线上的提交。
看看这是如何工作的最好方法是使用gitk(1)命令; 现在在git仓库上运行gitk并寻找合并提交将有助于理解Git如何组织历史记录。
在下文中,我们说如果提交X是提交Y的祖先,那么提交X就是来自提交Y的“可达”。相等地,可以说Y是X的后代,或者是存在由提交提交的父项链Y提交X.
了解历史:历史图表
我们有时会使用下面的图表来表示Git历史记录。提交显示为“o”,并使用 - /和\绘制线条之间的链接。时间从左到右:
o - o - o < - Branch A
/
o - o - o < - 主
\
o - o - o < - 分支B
如果我们需要谈论某个特定的提交,可以用另一个字母或数字替换字符“o”。
了解历史:什么是分支?
当我们需要精确时,我们将使用“分支”一词来表示一条开发线,“分支头”(或者“头”)意味着对分支上最近提交的引用。在上面的例子中,名为“A”的分支头是指向一个特定提交的指针,但我们将引向该点的三个提交的行称为“分支A”的一部分。
但是,如果不会造成混淆,我们通常只是在分支机构和分支机构使用“分支”一词。
第4章操作分支
创建,删除和修改分支是快速而简单的; 以下是这些命令的摘要:
git branch
列出所有分支。
git branch <branch>
创建一个名为的新分支<branch>
,引用历史上与当前分支相同的点。
git branch <branch> <start-point>
<branch>
referencing 的新分支
<start-point>
,它可以用任何你喜欢的方式指定,包括使用分支名称或标签名称。
git branch -d <branch>
删除分支
<branch>
; 如果分支未在其上游分支中完全合并或包含在当前分支中,则此命令将失败并显示警告。
git branch -D <branch>
<branch>
不管其合并状态如何,都要删除该分支。
git checkout <branch>
使当前分支
<branch>
,更新工作目录以反映引用的版本
<branch>
。
git checkout -b <new> <start-point>
创建一个新的分支
<new>
引用
<start-point>
,并检查出来。
特殊符号“HEAD”总是可以用来指代当前分支。事实上,Git使用目录HEAD
中的一个文件.git
来记住哪个分支是当前的:
$ cat .git/HEAD
ref: refs/heads/master
第5章检查旧版本而不创建新分支
该git checkout
命令通常期望分支头,但也会接受任意提交; 例如,您可以检出由标签引用的提交:
$ git checkout v2.6.17
注意:检出'v2.6.17'。
你处于'分离头部'状态。你可以环顾四周,做实验
更改并提交它们,并且您可以放弃您在此提交的任何提交
通过执行另一次结账而不影响任何分支机构。
如果你想创建一个新分支来保留你创建的提交,你可以
(现在或以后)再次使用-b和checkout命令来执行此操作。例:
git checkout -b new_branch_name
HEAD现在位于427abfa Linux v2.6.17
注意:检出'v2.6.17'。
你处于'分离头部'状态。你可以环顾四周,做实验
更改并提交它们,并且您可以放弃您在此提交的任何提交
通过执行另一次结账而不影响任何分支机构。
如果你想创建一个新分支来保留你创建的提交,你可以
(现在或以后)再次使用-b和checkout命令来执行此操作。例:
git checkout -b new_branch_name
HEAD现在位于427abfa Linux v2.6.17
HEAD然后引用提交的SHA-1而不是一个分支,并且git分支显示你不再是一个分支:
$ cat .git / HEAD
427abfa28afedffadfca9dd8b067eb6d36bac53f
$ git分支
*(与v2.6.17分离)
主
427abfa28afedffadfca9dd8b067eb6d36bac53f
$ git分支
*(与v2.6.17分离)
主
在这种情况下,我们说HEAD是“分离的”。
这是检查特定版本的简单方法,无需为新分支创建一个名称。如果你决定,你仍然可以为这个版本创建一个新的分支(或标签)。
第6章检查远程存储库中的分支
您克隆时创建的“主”分支是您从克隆的存储库中的HEAD副本。尽管如此,该存储库也可能有其他分支,并且您的本地存储库会保留跟踪每个远程分支的分支,称为远程跟踪分支,您可以使用-r
选项查看这些分支git-branch(1):
$ git branch -r
origin/HEAD
origin/html
origin/maint
origin/man
origin/master
origin/next
origin/pu
origin/todo
在本例中,“origin”被称为远程存储库,简称“remote”。从我们的角度来看,这个存储库的分支被称为“远程分支”。上面列出的远程跟踪分支是在克隆时基于远程分支创建的,并将由git fetch
(因此git pull
)和git push
。
您可能想要在您自己的分支上构建这些远程跟踪分支之一,就像您使用标记一样:
$ git checkout -b my-todo-copy origin / todo
您也可以origin/todo
直接退房查看或编写一次性补丁。
请注意,名称“origin”只是Git默认使用的名称,用于引用您从中克隆的存储库。
第7章命名分支,标签和其他参考
分支,远程跟踪分支和标签都是对提交的引用。所有引用都以斜杠分隔的路径名称开头refs
; 我们迄今使用的名字实际上是简写:
- 该分支
test
是短暂的refs/heads/test
。 - 标签
v2.6.18
是简短的refs/tags/v2.6.18
。 origin/master
是简短的refs/remotes/origin/master
。
例如,如果存在标签和具有相同名称的分支,则全名偶尔是有用的。
(新创建的refs实际上存储在.git/refs
目录下,在它们的名字给出的路径下。但是,出于效率的原因,它们也可能被打包在一个文件中;请参阅git-pack-refs(1))。
作为另一个有用的捷径,可以仅使用该存储库的名称来引用存储库的“HEAD”。因此,例如,“origin”通常是存储库“origin”中HEAD分支的快捷方式。
有关Git检查引用的完整路径列表,以及它用于决定在具有相同简写名称的多个引用时要选择哪个的顺
第8章使用git fetch更新仓库
在克隆存储库并对自己进行一些更改后,您可能希望检查原始存储库以获取更新。
该git-fetch
命令不带任何参数,会将所有远程跟踪分支更新为原始存储库中找到的最新版本。它不会触及你自己的任何分支,甚至不会触及你为克隆创建的“主”分支。
第9章从其他存储库获取分支
你也可以使用git-remote(1)来跟踪从你克隆的存储库以外的分支:
$ git remote add staging git://git.kernel.org/.../gregkh/staging.git
$ git fetch staging
...
From git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
* [new branch] master -> staging/master
* [new branch] staging-linus -> staging/staging-linus
* [new branch] staging-next -> staging/staging-next
git remote add
在这种情况下,新的远程跟踪分支将以您提供的简写名称进行存储
staging
:
$ cat .git/config
...
[remote "staging"]
url = git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
fetch = +refs/heads/*:refs/remotes/staging/*
...
如果git fetch <remote>
稍后运行,<remote>
则会更新指定的远程跟踪分支。
如果您检查该文件.git/config
,您会看到Git添加了一个新节:
这就是Git跟踪远程分支的原因。您可以通过.git/config
使用文本编辑器进行编辑来修改或删除这些配置选项。