Whether you like it or not, there is 翻唱somethinglike ab

GitUserManualChinese - Robin Wiki
Git 用户手册(1.5.3 及后续版本适用)
翻译: 罗峥嵘 (Robin Steven)
Preface 前言
Git is a fast distributed revision control system.
Git 是一个快速的分布式版本控制系统
This manual is designed to be readable by someone with basic UNIX command-line skills, but no previous knowledge of git.
这个手册是面向那些具有基本的 Unix 命令行使用技能,但是没有 Git 知识的人设计的。
1, Repositories and Branches and Chapter 2, Exploring git history
explain how to fetch and study a project using git&read these chapters
to learn how to build and test a particular version of a software
project, search for regressions, and so on.
第一章 版本库与分支 和 第二章 考查 git 历史 将展示如何用 git 来获取和研究一个项目,通过阅读这些章节,我们学习如何建立和测试一个具体的软件项目的版本,学习&撤退&等等。
needing to do actual development will also want to read Chapter 3,
Developing with git and Chapter 4, Sharing development with others.
人们是需要开展真正的研发工作的,那么就学习 第三章, 用 git 进行开发 和 第四章,与他人共享研发成果。
Further chapters cover more specialized topics.
更多的一些章节会涉及到许多的专题话题。
Comprehensive
reference documentation is available through the man pages, or
git-help(1) command. For example, for the command "git clone
&repo&", you can either use:
参考文档可以通过系统的手册页命令,或者是 git-help(1) 命令来查看。譬如,你想参考 "git clone &repo&", 你可以用下面的两种方式:
$ man git-clone
or: 或者:
$ git help clone
With the latter, you can use the manual v see git-help(1) for more information.
晚一点你就有机会用到这些手册查看器的;看 git-help(1) 会得到比较多的信息。
See also Appendix A, Git Quick Reference for a brief overview of git commands, without any explanation.
阅读 附录A,那里是一个 git 命令的快速纵览,但是它不带任何的解说。
Finally, see Appendix B, Notes and todo list for this manual for ways that you can help make this manual more complete.
最后,看看 附录B,这份手册的工作备忘和计划,通过它你可以帮助这份文档变得更完善。
Chapter 1. Repositories and Branches 第一章. 版本库与分支
It will be useful to have a git repository to experiment with as you read this manual.
有一个实验性的 git 版本库对我们阅读这份手册将非常有用。
best way to get one is by using the git-clone(1) command to download a
copy of an existing repository. If you don't already have a project in
mind, here are some interesting examples:
获取一个已经存在的版本库,最佳的方法是用 git-clone 命令,如果你还没有什么心目中的项目的话,那么这里有些有趣的例子:
# git itself (approx. 10MB download):
$ git clone git://git.kernel.org/pub/scm/git/git.git
# the Linux kernel (approx. 150MB download):
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
The initial clone may be time-consuming for a large project, but you will only need to clone once.
对于一个大型项目来说,初始性的克隆是挺费时的,不过克隆只需要做一次。
clone command creates a new directory named after the project ("git" or
"linux-2.6" in the examples above). After you cd into this directory,
you will see that it contains a copy of the project files, called the
working tree, together with a special top-level directory named ".git",
which contains all the information about the history of the project.
隆命令会创建一个新的目录,并根据项目的名称来命名这个项目(譬如上说例子中的 &git& 和
&linux-2.6&)。当你进入这个目录的时候,你可以看到它已经包含了项目的所有文件,我们称之为工作树,在顶层目录中还连带了一个叫
".git" 的特殊的目录,里面包含了项目的发展历史的所有信息。
How to check out a different version of a project 如何提取项目的不同版本
Git is best
thought of as a tool for storing the history of a collection of files.
It stores the history as a compressed collection of interrelated
snapshots of the project's contents. In git each such version is called
最好将 git 当作是文件发展的历史纪录的收集工具,它压缩并保存了项目的发展的关联性快照。在 git 中,每个这些变更称作交付(commit)。
snapshots aren't necessarily all arranged in a single line from oldest
instead, work may simultaneously proceed along parallel
lines of development, called branches, which may merge and diverge.
这些快照并不需要按从旧到新单线索地发展;它可以是同步并行地发展的,称之为分支,它们是可以合并和分割的。
single git repository can track development on multiple branches. It
does this by keeping a list of heads which reference the latest commit
the git-branch(1) command shows you the list of branch
一个 git 版本库可以跟踪多个分支的发展,它通过保存一个分支头列表的方式来做到这一点,每个分支头都是一个引用(reference),它指向该分支最后的一个交付(commit); git-branch(1) 命令可以向你展示每个分支头:
$ git branch
freshly cloned repository contains a single branch head, by default
named "master", with the working directory initialized to the state of
the project referred to by that branch head.
一个刚刚克隆的版本库只包含一个分支头,默认叫 &master& (主分支),并且工作目录已经被初始化为这个分支头所指向的项目状态。
projects also use tags. Tags, like heads, are references into the
project's history, and can be listed using the git-tag(1) command:
大部分的项目还用到标签(tags)。标签(Tags)就好像头(heads),它指向项目的某个历史场面,它们可以通过 git-tag(1) 命令列举出来:
$ git tag -l
v2.6.11-tree
v2.6.12-rc2
v2.6.12-rc3
v2.6.12-rc4
v2.6.12-rc5
v2.6.12-rc6
are expected to always point at the same version of a project, while
heads are expected to advance as development progresses.
Tags 被当做是项目统一的版本来对待,而 heads 则是项目前进的每一个步伐。
Create a new branch head pointing to one of these versions and check it out using git-checkout(1):
下面创建一个新的分支头,使其指向其中的某个版本,同时将它提取出来,可以用 git-checkout(1) 命令:
$ git checkout -b new v2.6.13
working directory then reflects the contents that the project had when
it was tagged v2.6.13, and git-branch(1) shows two branches, with an
asterisk marking the currently checked-out branch:
工作目录将被镜像为项目中标记为 v2.6.13 的版本的内容,用 git-branch(1) 命令展示这个两个分支,前面带星号(*)的就是当前抽取的分支。
$ git branch
If you decide that you'd rather see version 2.6.17, you can modify the current branch to point at v2.6.17 instead, with
如果你打算看看 2.6.17 的版本,你可以迁移你当前的分支,让它指向 2.6.17, 使用一下命令:
$ git reset --hard v2.6.17
that if the current branch head was your only reference to a particular
point in history, then resetting that branch may leave you with no way
to find the history so use this command carefully.
注意,如果当前的分支头是你唯一的指向具体的历史场面的引用的话,那么复位 (resetting) 这个分支将令你无法找回这个分支以前的所有历史纪录,所以这个命令要慎用。
Understanding History: Commits 理解历史: 交付
change in the history of a project is represented by a commit. The
git-show(1) command shows the most recent commit on the current branch:
项目的每一个历史变更体现为每一个交付 (commit)。git-show(1) 命令展示当前分支的最新交付:
$ git show
commit 17cfd38f737f15f53ab552f1e95960d7
Author: Linus Torvalds &torvalds@ppc970.osdl.org.(none)&
Tue Apr 19 14:11:06
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), *
char *sha1_dir, *
if (mkdir(".git", 0755) & 0) {
As you can see, a commit shows who made the latest change, what they did, and why.
正如你看到的那样,交付表明了谁做的最后的更改,改了什么,为什么改。
commit has a 40-hexdigit id, sometimes called the "object name" or the
"SHA1 id", shown on the first line of the "git-show" output. You can
usually refer to a commit by a shorter name, such as a tag or a branch
name, but this longer name can also be useful. Most importantly, it is
a globally unique name for this commit: so if you tell somebody else
the object name (for example in email), then you are guaranteed that
name will refer to the same commit in their repository that it does in
yours (assuming their repository has that commit at all). Since the
object name is computed as a hash over the contents of the commit, you
are guaranteed that the commit can never change without its name also
个交付都有一个40个16进制字符的标识号,称为 &对象名& 或者叫 &SHA1 id&,它显示在 git-show
命令的输出的第一行中。你通常可以用较简短的名字来指明一个交付,譬如标签和分支的名称等等,但是这个长长的名字是很有用的。最重要的是,对于某个交付来
说它是全局唯一的名字: 譬如你告诉其他人某个对象名(通过
email等方式),那么你需要确保这个名字不管是在你的版本库中,还是在他们的版本库中都是指向同一个交付的(假设他们的版本库也被提交了很多东西)。
当对象名根据每个交付的内容通过哈希算法(hash)算出之后,你就可以确保每个交付中的内容的修改都不可能脱离它的名字。
fact, in Chapter 7, Git concepts we shall see that everything stored in
git history, including file data and directory contents, is stored in
an object with a name that is a hash of its contents.
事实上,在 第七章,Git 的概念 中,我们可以看到保存在 git 历史中的所有东西,包括文件数据与目录内容都会被保存为对象,对象名就是他们的内容的哈希特征值。
Understanding history: commits, parents, and reachability 交付,父交付与可及性
commit (except the very first commit in a project) also has a parent
commit which shows what happened before this commit. Following the
chain of parents will eventually take you back to the beginning of the
每个交付(除非是项目的第一个交付)总是有他的父交付,这样就说明了到当前的交付为止到底发生过什么。追索父交付链,可以将我们带回项目的起始点。
the commits do no git allows lines of development
to diverge and then reconverge, and the point where two lines of
development reconverge is called a "merge". The commit representing a
merge can therefore have more than one parent, with each parent
representing the most recent commit on one of the lines of development
leading to that point.
无论如何,这些交付的组织形式都不会是简单的;git 容许开发路线可以分道扬镳,也可以殊途同归,两条开发线路的结合点我们叫&合并&(merge)。表示合并的交付就等于有一个以上的父交付了,每个父交付表示每个开发线路发展到这里的最贴近的交付。
best way to see how this works is using the gitk(1) running
gitk now on a git repository and looking for merge commits will help
understand how the git organizes history.
最好的查看这个机制的方法是用 gitk(1) 命令;现在在版本库中运行 gitk 命令,并查看一下那些合并交付会对你理解 git 是如何组织历史的很有帮助。
the following, we say that commit X is "reachable" from commit Y if
commit X is an ancestor of commit Y. Equivalently, you could say that Y
is a descendant of X, or that there is a chain of parents leading from
commit Y to commit X.
接着,我们说 交付X 对于 交付Y 来说是&可及的&, 如果 交付X 是 交付Y 的祖先的话。同样地,你可以说 Y 是 X 的一个后裔, 或者说存在一个从 Y 追索到 X 的世系族谱。
Understanding history: History diagrams 历史沿革示图
sometimes represent git history using diagrams like the one below.
Commits are shown as "o", and the links between them with lines drawn
with - / and /. Time goes left to right:
某些时候,我们会用下面的示图来描述 git 的历史。所有的交付用 "o" 表示, 联系他们各个发展线路之间画上 / 和 /。时间的推移是由左至右。
o--o--o &-- Branch A
o--o--o &-- master
o--o--o &-- Branch B
If we need to talk about a particular commit, the character "o" may be replaced with another letter or number.
如果需要具体地谈论某个交付,那么就用其他的字母或者是数字来替代 "o" 。
Understanding history: What is a branch? 理解历史:什么是分支
need to be precise, we will use the word "branch" to mean a line of
development, and "branch head" (or just "head") to mean a reference to
the most recent commit on a branch. In the example above, the branch
head named "A" is a pointer to one particular commit, but we refer to
the line of three commits leading up to that point as all being part of
"branch A".
准确起见,我们用 &分支& 这个词来表达开发的线路, 并且用 &分支头&(或者是 &头&)来表达一个分支中最新的交付。在上面的例子中,那个叫
&A& 的分支头是一个指向一个具体的交付的指针。但是我们指出,该线路上发展到这个点的三个交付全都是 &分支A& 的组成部分。
However, when no confusion will result, we often just use the term "branch" both for branches and for branch heads.
不过, 在不至于产生混淆的前提下,我们常常只是用 &分支& 这个术语来表示分支和分支头。
Manipulating branches 操作分支
Creating, deleting, and modifying branch here's a summary of the commands:
创建,删除,和更改分支都是很快而容易的;这里是这个命令的摘要:
git branch
list all branches
列举所有的分支
git branch &branch&
create a new branch named &branch&, referencing the same point in history as the current branch
创建一个新的分支,并引用当前分支作为同一历史沿革
git branch &branch& &start-point&
a new branch named &branch&, referencing &start-point&,
which may be specified any way you like, including using a branch name
or a tag name
创建一个名叫 &branch& 的新分支,引用 &start-point&,它是可以任意指定的,可以是现存的分支的名称或者是标签的名称
git branch -d &branch&
the branch &branch&; if the branch you are deleting points to a
commit which is not reachable from the current branch, this command
will fail with a warning.
删除一个叫 &branch& 的分支;如果你要删除的这个分支所指向的当前分支中一个不可及的交付的话,那么命令将返回失败并作出提示
git branch -D &branch&
if the branch points to a commit not reachable from the current branch,
you may know that that commit is still reachable from some other branch
or tag. In that case it is safe to use this command to force git to
delete the branch.
尽管需要删除一个当前分支不可及的交付,但是你知道那个交付仍然可有其他的分支或者是标签可及。在这种情况下,用这个命令强制删除一个分支是安全的。
git checkout &branch&
make the current branch &branch&, updating the working directory to reflect the version referenced by &branch&
提取分支,也即是引用 &branch& 版本状态更新工作目录的内容
git checkout -b &new& &start-point&
create a new branch &new& referencing &start-point&, and check it out.
引用 &start-point& 创建一个叫 &new& 的分支,并且将它提取出来。
special symbol "HEAD" can always be used to refer to the current
branch. In fact, git uses a file named "HEAD" in the .git directory to
remember which branch is current:
特殊的标号 "HEAD" 总是被用作引用,指向当前分支。事实上,git 是用 .git 目录中的名叫 "HEAD" 的文件来记住那个是当前分支。
$ cat .git/HEAD
ref: refs/heads/master
Examining an old version without creating a new branch 不通过创建新分支来调查旧版本
git-checkout command normally expects a branch head, but will also
accept for example, you can check out the commit
referenced by a tag:
git-checkout 命令按常规是抽取分支头的,但是也可以接受任意的交付;例如,你可以引用一个标签来进行提取。
$ git checkout v2.6.17
Note: moving to "v2.6.17" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b &new_branch_name&
HEAD is now at 427abfa... Linux v2.6.17
The HEAD then refers to the SHA1 of the commit instead of to a branch, and git branch shows that you are no longer on a branch:
此时,HEAD 将指向交付的 SHA1 来代替分支名称, git branch 命令表明你现在的项目状态不从属于任何一个分支:
$ cat .git/HEAD
427abfa28afedffadfca9dd8b067eb6d36bac53f
$ git branch
* (no branch)
In this case we say that the HEAD is "detached".
这种情况,我们说 HEAD 是 &游离的&。
is an easy way to check out a particular version without having to make
up a name for the new branch. You can still create a new branch (or
tag) for this version later if you decide to.
这是一个方便的途径,既可以提取某个版本,又避免了创建与命名一个新的分支。如果你愿意,你当然还可以以这个版本为标本来创建一个新分支(或者是标签)。
Examining branches from a remote repository 调查远程版本库上的分支
"master" branch that was created at the time you cloned is a copy of
the HEAD in the repository that you cloned from. That repository may
also have had other branches, though, and your local repository keeps
branches which track each of those remote branches, which you can view
using the "-r" option to git-branch(1):
分支是你克隆版本库的时候创建的,它是你的克隆的那个远程版本库上的 HEAD
的复件。那么远程版本库上可能还存在其他的分支,故而你的本地版本库中也保留了那些远程分支的踪迹。你可以用 git branch(1) 命令加上
"-r" 选项来查看。
$ git branch -r
origin/HEAD
origin/html
origin/maint
origin/man
origin/master
origin/next
origin/todo
You cannot check out these remote-tracking branches, but you can examine them on a branch of your own, just as you would a tag:
你不可能将这些远程分支提取出来,但是你可以用一个你自己的分支来调查他们,你当他们是一个标签好了。
$ git checkout -b my-todo-copy origin/todo
Note that the name "origin" is just the name that git uses by default to refer to the repository that you cloned from.
注意一下,"origin" 是 git 用来指向你的版本库的克隆来源的默认名称。
remote-tracking branches, and tags are all references to commits. All
references are named with a slash-separated path name starting with
"refs"; the names we've been using so far are actually shorthand:
分支,远程踪迹分支,与标签所有这些都是交付的引用。它们都被命名为以 "refs" 起头的带斜杠的路径名;实际上我们一直以来都用他们的速记名。
The branch "test" is short for "refs/heads/test".
The tag "v2.6.18" is short for "refs/tags/v2.6.18".
"origin/master" is short for "refs/remotes/origin/master".
分支 "branch" 作为 "refs/heads/test" 的简称。
标签 "v2.6.18" 作为 "refs/tags/v2.6.18" 的简称
"origin/master" 作为 "refs/remotes/origin/master" 的简称
The full name is occasionally useful if, for example, there ever exists a tag and a branch with the same name.
全名偶尔也会很有用,例如存在一个同名的分支和标签的时候。
created refs are actually stored in the .git/refs directory, under the
path given by their name. However, for efficiency reasons they may also
be packed toget see git-pack-refs(1)).
(新创建的引用实际是保存在 .git/refs 目录中,在他们的名字表明的路径下面。不过,由于效率的原因,它们几乎总是被打包到一个单独的文件中了;参考 git-pack-refs(1))
another useful shortcut, the "HEAD" of a repository can be referred to
just using the name of that repository. So, for example, "origin" is
usually a shortcut for the HEAD branch in the repository "origin".
还有一个很有用的捷径,版本库中的 "HEAD" 可以被引用为一个版本库的名称。作为例子,"origin" 常常作为 "origin" 版本库中的 HEAD 分支的快捷引用。
the complete list of paths which git checks for references, and the
order it uses to decide which to choose when there are multiple
references with the same shorthand name, see the "SPECIFYING REVISIONS"
section of git-rev-parse(1).
完整的路径令 git 可以查验引用,并在速记名相同的情况下决定准确的引用。参考 git rev-parse(1) 中 "SPECIFYING REVISIONS" 一段。
Updating a repository with git-fetch 用 git fetch 更新版本库
Eventually
the developer cloned from will do additional work in her repository,
creating new commits and advancing the branches to point at the new
你向她克隆版本库的那个开发者,总归是要将新的工作加入到版本库中的,如创建了新的交付,将分支推进到新的交付点上。
command "git fetch", with no arguments, will update all of the
remote-tracking branches to the latest version found in her repository.
It will not touch any of your own branches&not even the "master" branch
that was created for you on clone.
命令 "git fetch",不用带任何参数,本地版本库中所有远程关联分支都会被更新到远程版本库中对应的分支的最新版本。它不会触动你的专属分支的任何东西,甚至是克隆的时候为你创建的 "master" 分支。
你可以直接修改 .git/config 文件将 master 分支的远程跟踪属性去掉。
Fetching branches from other repositories 获取其他版本库的分支
You can also track branches from repositories other than the one you cloned from, using git-remote(1):
你同样可以跟踪一个并不是你的克隆源头的版本库上的分支。使用 git remote(1):
$ git remote add linux-nfs git://linux-nfs.org/pub/nfs-2.6.git
$ git fetch linux-nfs
* refs/remotes/linux-nfs/master: storing branch 'master' ...
commit: bf81b46
New remote-tracking branches will be stored under the shorthand name that you gave "git-remote add", in this case linux-nfs:
新的远程跟踪分支将以速记名的形式保存,这个名称是由命令 "git remote add" 给定的,在这里是 linux-nfs:
$ git branch -r
linux-nfs/master
origin/master
If you run "git fetch &remote&" later, the tracking branches for the named &remote& will be updated.
如果在晚一点的时候再你运行 "git fetch &remote&",那么这个跟踪分支就会被更新。
If you examine the file .git/config, you will see that git has added a new stanza:
如果你检查一下 .git/config 文件,你发现 git 增加了一个新的配置段。
$ cat .git/config
[remote "linux-nfs"]
url = git://linux-nfs.org/pub/nfs-2.6.git
fetch = +refs/heads/*:refs/remotes/linux-nfs/*
is what causes git to track the remote' you may modify or
delete these configuration options by editing .git/config with a text
editor. (See the "CONFIGURATION FILE" section of git-config(1) for
这里的配置就是 git 进行远端分支跟踪的机制,你可以用文本编辑器修改或者是删除 .git/config 文件中的配置。(详情请参考 git config(1) 中的 "CONFIGURATION FILE")
Chapter 2. Exploring git history 第二章. 检索 git 历史
best thought of as a tool for storing the history of a collection of
files. It does this by storing compressed snapshots of the contents of
a file hierarchy, together with "commits" which show the relationships
between these snapshots.
最好将 Git 当做是纪录文件历史变更集的工具。它压缩并逐层地保存文件的快照,收集这些 "交付",就展示了文件快照之间的关系。
Git provides extremely flexible and fast tools for exploring the history of a project.
Git 在项目的历史搜索上提供了很强的检索弹性和快速工具。
We start with one specialized tool that is useful for finding the commit that introduced a bug into a project.
我们用一个特别点的工具作为开始,它对于如何发现一个将 bug 引入到项目中的交付很有用。
How to use bisect to find a regression 如何用平分来定位撤退
version 2.6.18 of your project worked, but the version at "master"
crashes. Sometimes the best way to find the cause of such a regression
is to perform a brute-force search through the project's history to
find the particular commit that caused the problem. The git-bisect(1)
command can help you do this:
假设项目中的 2.6.18 版本工作良好,但是 "master" 分支不稳定。某些时候,通过对项目历史进行暴力搜索,确定是那个交付造成的问题,这样我们就可以知道我们应该撤退到什么地方。git-bisect(1) 命令可以帮你做到这点:
$ git bisect start
$ git bisect good v2.6.18
$ git bisect bad master
Bisecting: 3537 revisions left to test after this
[b88e83e2b0f8b3f8e] BLOCK: Make USB storage depend on SCSI rather than selecting it [try #6]
you run "git branch" at this point, you'll see that git has temporarily
moved you in "(no branch)". HEAD is now detached from any branch and
points directly to a commit (with commit id 65934&) that is reachable
from "master" but not from v2.6.18. Compile and test it, and see
whether it crashes. Assume it does crash. Then:
果这个时候你运行 "git branch",你会发现 git 已经将你移到 &无分支的状态&。HEAD
目前是处于游离的状态的,他不从属于任何的分支,并直接指向一个交付(id 为 65934...),这个交付对于 "master"
分支来说是可及的,但对于 v2.6.18 来说就不是。现在可以编译和测试一下,看它是否会崩溃,如果是,那么:
$ git bisect bad
Bisecting: 1769 revisions left to test after this
[7eff82c8b5f0c99ac275a7e21b867] i2c-core: Drop useless bitmaskings
out an older version. Continue like this, telling git at each stage
whether the version it gives you is good or bad, and notice that the
number of revisions left to test is cut approximately in half each
现在 git 提取出了更旧的版本,继续类似的步骤(编译和测试),将 git 每次给你的版本的测试结果用 good
或者是 bad
告诉 git,并且注意每次提取出来用于测试的版本都大致是截取一半的变更跨度。
git 每次都抽取大致从 good 至 bad 之间这个项目发展区间一半的那个版本进行测试,如果测试的结果是 good,那么就以当前被提取出来的这个版本到 bad 版本为区间再次进行平分提取,如此不断循环,很快就定位到项目的漏洞。
about 13 tests (in this case), it will output the commit id of the
guilty commit. You can then examine the commit with git-show(1), find
out who wrote it, and mail them your bug report with the commit id.
Finally, run
在这个例子中,经过13个测试之后,它终于定位到了那个出现问题的交付的 id 。你可以通过 git show(1) 命令来检查是谁写的这个东西,并将缺陷报告通过邮件告诉他们,记得写上那个交付的 id 。最后运行:
$ git bisect reset
to return you to the branch you were on before.
这样就返回到你原来所在的分支了。
that the version which git-bisect checks out for you at each point is
just a suggestion, and you're free to try a different version if you
think it would be a good idea. For example, occasionally you may land
on a commit that broke run
提醒一下,git bisect 为你提取的版本只是一个建议性的东西,其实你可以尝试任何的版本,如果你认为这样是个好主意的话,偶尔可能会空降到某个造成问题的交付上去;运行:
$ git bisect visualize
will run gitk and label the commit it chose with a marker that says
"bisect". Choose a safe-looking commit nearby, note its commit id, and
check it out with:
这个命令会运行 gitk 并将它选取的那个交付标贴上一个叫 "bisect" 的记号,就近这个标记选择一个看起来是安全的交付,纪录下它的 id,并将它提取出来:
$ git reset --hard fb47ddb2db...
then test, run "bisect good" or "bisect bad" as appropriate, and continue.
进行测试,并恰当地运行 "bisect good" 或 "bisect bad",不断尝试。
of "git bisect visualize" and then "git reset &hard fb47ddb2db&", you
might just want to tell git that you want to skip the current commit:
要是不想去做 "git bisect visualize" 和 "git reset --hard fb47ddb2db" 。你只是想跳过 git 为你选择的那个交付的话:
$ git bisect skip
this case, though, git may not eventually be able to tell the first bad
one between some first skipped commits and a later bad commit.
如此一来,git 就无法得知在第一个跳过的交付到最后一个坏交付中那些交付是坏交付。
are also ways to automate the bisecting process if you have a test
script that can tell a good from a bad commit. See git-bisect(1) for
more information about this and other "git bisect" features.
其实存在自动进行平分操作的方法,不过你需要一个脚本来告诉 git 好和坏的交付,参考 git bisect(1) 有更多的信息,这是 git bisect 的一个特性。
Naming commits 交付的称谓
We have seen several ways of naming commits already:
我们有一系列的方法来称呼交付:
40-hexdigit object name
branch name: refers to the commit at the head of the given branch
tag name: refers to the commit pointed to by the given tag (we've seen branches and tags are special cases of references).
HEAD: refers to the head of the current branch
40个十六进制字符的对象名
分支名: 指向给定的分支头的交付
标签名: 指向给定的标签的交付的引用(我们已经了解过分支和标签都是引用的特例);
头: 指向当前分支的引用
see the "" section of the git-rev-parse(1) man page for
the complete list of ways to name revisions. Some examples:
还有更多的称谓; 参考 git rev-parse(1) 手册页中的 "SPECIFYING REVISIONS" 的章节,那里有有关&世系名称&的介绍,例如:
$ git show fb47ddb2 # the first few characters of the object name
# are usually enough to specify it uniquely
$ git show HEAD^
# the parent of the HEAD commit
$ git show HEAD^^
# the grandparent
$ git show HEAD~4
# the great-great-grandparent
that merge commits may have
by default, ^ and ~
follow the first parent listed in the commit, but you can also choose:
回想一下,一个合并的交付可能有一个以上的父交付;默认地,^ 和 ~ 是他们的父辈列表中的一个父交付,当然你也可以显式地指出他们,譬如:
$ git show HEAD^1
# show the first parent of HEAD
$ git show HEAD^2
# show the second parent of HEAD
In addition to HEAD, there are several other special names for commits:
附带说明一下,对于 HEAD,对于它还有一系列特殊的称谓。
(to be discussed later), as well as operations such as git-reset, which
change the currently checked-out commit, generally set ORIG_HEAD to the
value HEAD had before the current operation.
合并(将会在后面讨论到),有如 git reset 操作,均是改变当前提取的交付,他们通常都是将命名执行之前的 HEAD 的值保存到 ORIG_HEAD。
这就等于是一服后悔药,如果你对 git reset,git merge 和 git pull 之类的命令的结果不满意,那么用下面的命令倒退回去就了:
$ git reset --hard ORIG_HEAD
git-fetch operation always stores the head of the last fetched branch
in FETCH_HEAD. For example, if you run git fetch without specifying a
local branch as the target of the operation
git fetch 操作总是将最后抓取的那个分支的头 (head) 保存到 FETCH_HEAD 中,如果你在运行 git fetch 的时候没有给定本地分支作为操作的目标的话。
$ git fetch git://example.com/proj.git theirbranch
the fetched commits will still be available from FETCH_HEAD.
抓取的交付将总是在 FETCH_HEAD 中。
we discuss merges we'll also see the special name MERGE_HEAD, which
refers to the other branch that we're merging in to the current branch.
当我们要讨论合并的时候,还将看到一个特殊称谓 MERGE_HEAD,它指向被我们刚刚合并进当前分支的另外一个分支。
git-rev-parse(1) command is a low-level command that is occasionally
useful for translating some name for a commit to the object name for
that commit:
git rev-parse 命名是一个底层命令,我们偶尔要将某些称谓翻译成对象名的时候非常有用。
$ git rev-parse origin
e05db0fd4f31ddef96b360d05984b
We can also create a tag to refer to after running
我们可以创建一个标签指向某个具体的交付,运行下面命令之后
$ git tag stable-1 1b2e1d63ff
You can use stable-1 to refer to the commit 1b2e1d63ff.
你可以看到 stable-1 指向交付 1b2e1d62ff。
creates a "lightweight" tag. If you would also like to include a
comment with the tag, and possibly sign it cryptographically, then you
should create
see the git-tag(1) man page for
这是创建一个 &轻量& 标签。如果你希望创建一个带注释和加密签注的标签的话,那么你应该创建一个标签对象的实例,详情请参考 git tag(1) 的手册页。
Browsing revisions 浏览修订
git-log(1) command can show lists of commits. On its own, it shows all
commits reachable fr but you can also make more
specific requests:
git log(1) 命令列举交付列表。它将列举所有可及的父交付;并且你还可以做更多指定的查询:
$ git log v2.5..
# commits since (not reachable from) v2.5
$ git log test..master
# commits reachable from master but not test
$ git log master..test
# ...reachable from test but not master
$ git log master...test # ...reachable from either test or master,
but not both
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log Makefile
# commits which modify Makefile
$ git log fs/
# ... which modify any file under fs/
$ git log -S'foo()'
# commits which add or remove any file data
# matching the string 'foo()'
of course you can
the following finds commits
since v2.5 which touch the Makefile or any file under fs:
你还可以组合这些查询请求;下面的命令就是查询 v2.6 版本一来有关 Makefile 和 fs/ 目录下的修订的交付。
$ git log v2.5.. Makefile fs/
You can also ask git log to show patches:
你还可以让 git log 出示补丁:
$ git log -p
See the "&pretty" option in the git-log(1) man page for more display options.
参考 git log(1) 手册页中的 "--pretty" 选项,会有更多的显示选项。
that git log starts with the most recent commit and works backwards
however, since git history can contain multiple
independent lines of development, the particular order that commits are
listed in may be somewhat arbitrary.
需要注意的是, git log 从最新的交付开始向后回溯父交付;然而,git 的历史中包含了许多并行的相互独立的开发线路,具体的列举顺序可能需要我们作出一定的仲裁。
Generating diffs 生成差异
You can generate diffs between any two versions using git-diff(1):
你可以用 git diff(1) 命令生成两个版本之间的差异:
$ git diff master..test
will produce the diff between the tips of the two branches. If you'd
prefer to find the diff from their common ancestor to test, you can use
three dots instead of two:
这将产生两个分支之间的差异提示。如果你期望发现他们两个的共同的祖先的差异,那你可以用三个点号代替两个点号。
$ git diff master...test
Sometimes what you want instead for this you can use git-format-patch(1):
有时候,你希望取得一个实际的补丁集;你可以用 git format-patch(1):
$ git format-patch master..test
will generate a file with a patch for each commit reachable from test but not from master.
这样会产生一个补丁文件,该文件是所有 test 可及的交付, 而不是 master。
Viewing old file versions 查看旧的文件版本
always view an old version of a file by just checking out the correct
revision first. But sometimes it is more convenient to be able to view
an old version of a single file without c this
command does that:
你当然可以通过提取文件的恰当的旧版本的方式来查看文件。不过有些时候查看单个文件可以有比提取出来更方便的办法,这个命令就是:
$ git show v2.5:fs/locks.c
Before the colon may be anything that names a commit, and after it may be any path to a file tracked by git.
冒号之前可以是任意一个交付的名称,冒号之后跟着已经纳入 git 跟踪的文件的路径。
Examples 实例
Counting the number of commits on a branch 统计一个分支中的交付数目
Suppose you want to know how many commits you've made on "mybranch" since it diverged from "origin":
假如你想知道你自己那个派生自 "origin" 的,叫 "mybranch" 的分支中有多少个交付:
$ git log --pretty=oneline origin..mybranch | wc -l
Alternatively,
you may often see this sort of thing done with the lower-level command
git-rev-list(1), which just lists the SHA1's of all the given commits:
另外一个途径是你可以通过底层命令 git rev-list(1) 来列举这些东西,不过它列举的只是那些交付的 SHA1 的 id 好。
$ git rev-list origin..mybranch | wc -l
Check whether two branches point at the same history 检查两分支是否在同一历史时期
Suppose you want to check whether two branches point at the same point in history.
若然你想检查两个分支是否在同一历史时期。
$ git diff origin..master
tell you whether the contents of the project are the same at the two
in theory, however, it's possible that the same project
contents could have been arrived at by two different historical routes.
You could compare the object names:
这样就得知一个项目的内容在两个分支中是否是相同的;理论上,项目可以经由不同的历史进程抵达相同的历史场面。你可以比较一下他们对应的对象名就知道了。
$ git rev-list origin
e05db0fd4f31ddef96b360d05984b
$ git rev-list master
e05db0fd4f31ddef96b360d05984b
you could recall that the & operator selects all commits contained
reachable from either one reference or the other but not both: so
或者你可以回顾一下,选取他们两者之中任何一个,而不是两者共同的可及的交付的操作: 如
$ git log origin...master
will return no commits when the two branches are equal.
当两个分支是相等的情况下,将不返回任何的交付。
you know that the commit e05db0fd fixed a certain problem. You'd like
to find the earliest tagged release that contains that fix.
假如你知道交付 e05db0fd 已经修正了一个问题,你一定想知道包含这个交付的最早的标签发行版本是什么。
course, there may be more than one answer&if the history branched after
commit e05db0fd, then there could be multiple "earliest" tagged
当然,可能会存在不止一个的答案,如果历史在交付 e05db0fd 之后发生了分叉的话,那么就会存在多个&最早&的标签版本。
You could just visually inspect the commits since e05db0fd:
你可能需要一个可视化的方式来检查交付 e05db0fd 之后的情况:
$ gitk e05db0fd..
you can use git-name-rev(1), which will give the commit a name based on
any tag it finds pointing to one of the commit's descendants:
又或者你可以用命令 git name-rev(1), 它可以给出你指定的那个交付的后裔中已经打过标签的那个交付。
$ git name-rev --tags e05db0fd
e05db0fd tags/v1.5.0-rc1^0~23
The git-describe(1) command does the opposite, naming the revision using a tag on which the given commit is based:
git describe(1) 命令则是逆操作,找到以给定的交付为根源的那个标签的名字。
$ git describe e05db0fd
v1.5.0-rc0-260-ge05db0f
but that may sometimes help you guess which tags might come after the given commit.
它对你要推断在给定的交付之后有那个标签会出现很有帮助。
If you just want to verify whether a given tagged version contains a given commit, you could use git-merge-base(1):
要是你只是想核实一下某个标签是否包含某个交付的话,你可以用 git merge-base(1):
$ git merge-base e05db0fd v1.5.0-rc1
e05db0fd4f31ddef96b360d05984b
merge-base command finds a common ancestor of the given commits, and
always returns one or the other in the case where one is a descendant
so the above output shows that e05db0fd actually is an
ancestor of v1.5.0-rc1.
merge-base 命令查找给定的交付的共同的祖先,它总是返回一个结果,或者是返回他们两个之中的其中一个,而这一个是另外一个的祖先;从输出的结果来看,e05db0fd 的确是 v1.5.0-rc1 的祖先。
Alternatively, note that
注意另外一个方式
$ git log v1.5.0-rc1..e05db0fd
produce empty output if and only if v1.5.0-rc1 includes e05db0fd,
because it outputs only commits that are not reachable from v1.5.0-rc1.
当且仅当 e05db0fd 是 v1.5.0-rc1 的源头的时候,这个命令输出为空, 这个命令只会输出 v1.5.0-rc1 不可及的交付。
yet another alternative, the git-show-branch(1) command lists the
commits reachable from its arguments with a display on the left-hand
side that indicates which arguments that commit is reachable from. So,
you can run something like
命令 git-show-branch(1) 根据参数之间的可及性关系向左列举各个参数, 你可以试试
$ git show-branch e05db0fd v1.5.0-rc0 v1.5.0-rc1 v1.5.0-rc2
! [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
! [v1.5.0-rc0] GIT v1.5.0 preview
! [v1.5.0-rc1] GIT v1.5.0-rc1
! [v1.5.0-rc2] GIT v1.5.0-rc2
then search for a line that looks like
查找一下类似下面的一行
+ ++ [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
Which shows that e05db0fd is reachable from itself, from v1.5.0-rc1, and from v1.5.0-rc2, but not from v1.5.0-rc0.
这个显示表明 e05db0fd 对于 v1.5.0-rc1, v1.5.0-rc2 以及它自身来说是可及的,而对于 v1.5.0-rc0 来说则不是。
注意该行前面的加号 "+" 与所对应的 v1.5.0-rc0, v1.5.0-rc1, v1.5.0-rc2 的列对齐关系。
Showing commits unique to a given branch 显示仅属于某个分支的交付
you would like to see all the commits reachable from the branch head
named "master" but not from any other head in your repository.
假如你想知道在你的版本库中,那些交付仅仅是可及分支 "master", 而对其他的分支没有可及性。
We can list all the heads in this repository with git-show-ref(1):
我们可以用 git-show-ref 命令先列出版本库中所有的分支头。
$ git show-ref --heads
bfd73353a9dcf094cb7 refs/heads/core-tutorial
db768df63ee9d6ebf9 refs/heads/maint
a024a059af44bebc1e7 refs/heads/master
24dbc180ea14dc1aebe09f14c8ecf refs/heads/tutorial-2
1e8c2f31eaa63d26fc0fd646c8af2 refs/heads/tutorial-fixes
We can get just the branch-head names, and remove "master", with the help of the standard utilities cut and grep:
我们可以用标准的辅助工具 cut 和 grep, 从分支列表中去掉 "master" 。
$ git show-ref --heads | cut -d' ' -f2 | grep -v '^refs/heads/master'
refs/heads/core-tutorial
refs/heads/maint
refs/heads/tutorial-2
refs/heads/tutorial-fixes
And then we can ask to see all the commits reachable from master but not from these other heads:
接着我们查看那些交付对 "master" 是可及的, 而对其他的分支没有可及性。
$ gitk master --not $( git show-ref --heads | cut -d' ' -f2 |
grep -v '^refs/heads/master' )
Obviously,
endless var for example, to see all commits
reachable from some head but not from any tag in the repository:
显然,上述命令是可以带无限的参数的; 譬如, 查看对于某些分支头可及,但是对于任何的标签都不可及的所有交付的命令如下:
$ gitk $( git show-ref --heads ) --not
$( git show-ref --tags )
(See git-rev-parse(1) for explanations of commit-selecting syntax such as &not.)
(参看 git-rev-parse(1), 那里有关于交付选取的语法的解释, 例如 --not)
Creating a changelog and tarball for a software release 为软件的发行制作变更日志和压缩包
The git-archive(1) command can create a tar or zip archive from any
for example:
git archive(1) 命令可以为项目的任何版本创建压缩包; 例如:
$ git archive --format=tar --prefix=project/ HEAD | gzip &latest.tar.gz
will use HEAD to produce a tar archive in which each filename is preceded by "project/".
这样将以 HEAD 为版本创建压缩包,并且每个文件名前面都将加上前缀。
you're releasing a new version of a software project, you may want to
simultaneously make a changelog to include in the release announcement.
如果你要发行一个新的软件版本, 你可能希望同时在发行声明中包含软件的变更日志。
Linus Torvalds, for example, makes new kernel releases by tagging them, then running:
譬如, Linus Torvalds 制作打过版本标签的新的内核版本时,就运行:
$ release-script 2.6.12 2.6.13-rc6 2.6.13-rc7
where release-script is a shell script that looks like:
这里的 release-scritp 是一个 shell 脚本, 它大概会象下面的样子:
stable="$1"
echo "# git tag v$new"
echo "git archive --prefix=linux-$new/ v$new | gzip -9 & ../linux-$new.tar.gz"
echo "git diff v$stable v$new | gzip -9 & ../patch-$new.gz"
echo "git log --no-merges v$new ^v$last & ../ChangeLog-$new"
echo "git shortlog --no-merges v$new ^v$last & ../ShortLog"
echo "git diff --stat --summary -M v$last v$new & ../diffstat-$new"
and then he just cut-and-pastes the output commands after verifying that they look OK.
并且他仅仅是在命令运行过之后, 验证一下输出的东西,再剪切-粘贴一下。
Finding commits referencing a file with given content 寻找一个指向包含给定内容的文件的交付
hands you a copy of a file, and asks which commits modified a file such
that it contained the given content either before or after the commit.
You can find out with this:
某人给了你一个文件的拷贝, 并请求得到修改过这个文件的那些个交付,不过,他甚至不知道这个文件现在所包含的内容是否已经被提交过。 你可以这样地查找:
git log --raw --abbrev=40 --pretty=oneline |
grep -B 1 `git hash-object filename`
out why this works is left as an exercise to the (advanced) student.
The git-log(1), git-diff-tree(1), and git-hash-object(1) man pages may
prove helpful.
思考一下为什么这个命令可以做到这样的结果,并将这个问题留给(高级的)学生作为练习。 git-log(1), git-diff-tree(1), 与 git-hash-object(1) 的手册页可能会提供有用的帮助。
Chapter 3. Developing with git 第三章. 用 git 进行研发
Telling git your name 告诉 git 你的名字
creating any commits, you should introduce yourself to git. The easiest
way to do so is to make sure the following lines appear in a file named
.gitconfig in your home directory:
在创建任何交付之前,你应该先将你自己介绍给 git。最容易的方法就是在你的家目录中创建一个叫 .gitconfig 的文件,并写入如下的配置项。
name = Your Name Comes Here
email = you@yourdomain.example.com
(See the "CONFIGURATION FILE" section of git-config(1) for details on the configuration file.)
(在 git-config(1) 中参考 "CONFIGURATION FILE" 那一节得到有关配置文件的帮助)
Creating a new repository 创建新的版本库
Creating a new repository from scratch is very easy:
从零开始创建新的版本库是很容易的:
$ mkdir project
$ cd project
$ git init
If you have some initial content (say, a tarball):
如果你已经有一个原始的内容的话 (意思是你已经有一个压缩包了):
$ tar xzvf project.tar.gz
$ cd project
$ git init
$ git add . # include everything below ./ in the first commit:
$ git commit
How to make a commit 如何制作一个交付
Creating a new commit takes three steps:
Making some changes to the working directory using your favorite editor.
Telling git about your changes.
Creating the commit using the content you told git about in step 2.
创建一个新的交付有三个步骤:
在你的工作目录中用你喜欢的编辑器做了某些变更。
告诉 git 你所做的变更。
将第二步中你告诉 git 的变更内容创建一个交付。
practice, you can interleave and repeat steps 1 and 2 as many times as
you want: in order to keep track of what you want committed at step 3,
git maintains a snapshot of the tree's contents in a special staging
area called "the index."
事实上,第一步 和 第二步 在任何时候都可以交替和重复地进行: 为了保持着对你打算在第三步提交的内容进行跟踪, git 在一个特殊的阶段性的区域内保留了你的工作目录树的内容快照,这个区域叫 "索引"。
the beginning, the content of the index will be identical to that of
the HEAD. The command "git diff &cached", which shows the difference
between the HEAD and the index, should therefore produce no output at
that point.
在开始的时候, 索引中的内容跟 HEAD 中的内容是一致的。对于命令 git&diff&--cached
,它是显示 HEAD 与 索引之间的差异的,在这个时候,它应该没有任何的输出。
Modifying the index is easy:
更改索引是很容易的:
To update the index with the new contents of a modified file, use
用一个编辑过的文件的内容去刷新索引,用:
$ git add path/to/file
To add the contents of a new file to the index, use
用一个新的文件的内容去加入到索引中,也是用:
$ git add path/to/file
To remove a file from the index and from the working tree,
从索引和工作目录中删除一个文件,
$ git rm path/to/file
After each step you can verify that
上述的每个操作之后,你都可以验证一下:
$ git diff --cached
shows the difference between the HEAD and the index file&this is what
you'd commit if you created the commit now&and that
无论如何都应该显示一下 HEAD 和索引文件之间的差异 -- 这其实就是你即将要提交的交付中的东西
$ git diff
shows the difference between the working tree and the index file.
上面的命令显示工作树与索引之间的差异。
that "git-add" always adds just the current contents of a file to the
further changes to the same file will be ignored unless you run
git-add on the file again.
注意, "git-add" 仅仅是将当前文件的内容加入索引; 在此之后的同一个文件的变更将会被忽略,除非你再次对该文件应用 git add 命令。
When you're ready, just run
当你都准备好了之后,只需运行
$ git commit
git will prompt you for a commit message and then create the new
commit. Check to make sure it looks like what you expected with
git 将在创建新的交付时向你提示交付信息。要检查你要期望的东西的话,运行
$ git show
As a special shortcut,
所为一个特殊的快捷方式,
$ git commit -a
will update the index with any files that you've modified or removed and create a commit, all in one step.
它将用你所修改和删除的内容去刷新索引,并创建一个新的交付,一步完成。
A number of commands are useful for keeping track of what you're about to commit:
一些命令对跟踪你提交的东西非常有用:
$ git diff --cached # difference between HEAD what
# would be committed if you ran "commit" now.
$ git diff
# difference between the index file and your
# changes that would not
# be included if you ran "commit" now.
$ git diff HEAD
# difference between HEAD what
# would be committed if you ran "commit -a" now.
$ git status
# a brief per-file summary of the above.
can also use git-gui(1) to create commits, view changes in the index
and the working tree files, and individually select diff hunks for
inclusion in the index (by right-clicking on the diff hunk and choosing
"Stage Hunk For Commit").
你还可以用 git-gui(1) 来创建交付,你将看到在索引和工作树文件中的变更,并可以个别地选取在索引中的变更块进行提交(在变更块上右击鼠标并选择&Stage Hunk For Commit&)。
Creating good commit messages 写好交付信息
not required, it's a good idea to begin the commit message with a
single short (less than 50 character) line summarizing the change,
followed by a blank line and then a more thorough description. Tools
that turn commits into email, for example, use the first line on the
Subject line and the rest of the commit in the body.
尽管不是必须的,但是好的交付信息应该是这样,用一个短句(少于50个字符)开头,接着跟一个空行,接下来就可以写更多的说明了。相关的工具将交付转化成电子邮件的时候,以第一行作为邮件的标题,交付的余下部分将作为邮件的正文。
工作树中的 ".git/COMMIT_EDITMSG" 文件是默认的交付信息文件,如果你的 git&commit
命令没有带 -m 参数,那么 git 将会为你打开系统默认编辑器编辑这个文件作为交付信息。
Ignoring files 忽略文件
will often generate files that you do not want to track with git. This
typically includes files generated by a build process or temporary
backup files made by your editor. Of course, not tracking files with
git is just a matter of not calling "git-add" on them. But it quickly
becomes annoying to have these untracke e.g. they
make "git add ." practically useless, and they keep showing up in the
output of "git status".
个项目总是经常产生一些你不想让 git
来跟踪的文件。典型的就是编译过程中的中间文件,或者是编辑器的临时备份文件等等。当然了,不跟踪某个文件只不过是不用 "git add"
命令将它加入 git 而已。不过你很快会不胜其扰;譬如你不小心用 "git add ." 命令将它加入了 git,并且这些文件总是在 "git
status" 命令的输出中出现。
can tell git to ignore certain files by creating a file called
.gitignore in the top level of your working directory, with contents
你可以在工作树的顶层目录中创建一个叫 .gitignore 的文件来告诉 git 那些文件是要忽略的,文件的内容大致如下:
# Lines starting with '#' are considered comments.
# Ignore any file named foo.txt.
# Ignore (generated) html files,
# except foo.html which is maintained by hand.
# Ignore objects and archives.
gitignore(5) for a detailed explanation of the syntax. You can also
place .gitignore files in other directories in your working tree, and
they will apply to those directories and their subdirectories. The
.gitignore files can be added to your repository like any other files
(just run git add .gitignore and git commit, as usual), which is
convenient when the exclude patterns (such as patterns matching build
output files) would also make sense for other users who clone your
repository.
考 gitignore(5) 得到更多的语法的解析。你还可以将 .gitignore
文件放到工作树的其他目录下,这样它将影响它所处的目录以及下级目录。.gitignore 文件当然也可以像一般的文件那样纳入为 git
的跟踪中(只需要运行 git add .gitignore 和 git commit,就像处理一般的文件那样将行了)。如果存在 "排除匹配"
的情况(譬如排除跟踪那些编译中间文件),为了对其他克隆你的版本库的用户方便起见,你应该给他们一点提示。
关于 排除匹配
可以参考 gitignore,排除匹配的表述文件是与 git 一起安装的,例如可能在 /usr/share/git-core/templates/info/exclude。
you wish the exclude patterns to affect only certain repositories
(instead of every repository for a given project), you may instead put
them in a file in your repository named .git/info/exclude, or in any
file specified by the core.excludesfile configuration variable. Some
git commands can also take exclude patterns directly on the command
line. See gitignore(5) for the details.
果你希望排除匹配只是影响某些指定的版本库(而不是一个项目的每个版本库),你可以用在你的版本库中 .git/info/exclude
文件来取代全局的排除匹配,或者是针对任何一个文件在 git 的配置文件中用 core.excludesfile 配置参数来指定。某些 git
命令是可以做命令行参数中直接接受排除匹配的。 详情参考 gitignore(5)。
How to merge 如何合并
You can rejoin two diverging branches of development using git-merge(1):
你可以将两个研发的分支用 git-merge(1) 合并在一起:
$ git merge branchname
the development in the branch "branchname" into the current branch. If
there are conflicts&for example, if the same file is modified in two
different ways in the remote branch and the local branch&then you are
the output may look something like this:
这是合并另外一个分支 "branchname" 到当前分支。如果同一个文件无论是在远程分支,还是在本地分支上的发展进程中被修改过,那么将出现冲突,此时你会得到一个提示,提示的输出大概是下面的样子:
$ git merge next
100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Au fix conflicts and then commit the result.
markers are left in the problematic files, and after you resolve the
conflicts manually, you can update the index with the contents and run
git commit, as you normally would when creating a new file.
冲突标志会被保留在文件中,并且当你手动解决冲突之后,你可以用新的内容刷新索引,并运行 git commit,这类似你创建一个新的文件之后所做的那样。
you examine the resulting commit using gitk, you will see that it has
two parents, one pointing to the top of the current branch, and one to
the top of the other branch.
如果你用 gitk 来解决冲突,你将会看到解决冲突的这个交付有两个父交付,一个指向当前分支的顶部,另一个指向两个另外一个分支的顶部。
Resolving a merge 解决合并冲突
merge isn't resolved automatically, git leaves the index and the
working tree in a special state that gives you all the information you
need to help resolve the merge.
当合并冲突不能自动解决时,git 将会让索引和工作树都保持在你可以得到所有信息的特殊状态,此时你需要协助 git 解决合并冲突。
with conflicts are marked specially in the index, so until you resolve
the problem and update the index, git-commit(1) will fail:
冲突文件会在索引中特别被标记起来,直到你解决这些冲突并刷新索引为止,否则 git commit(1) 将出错:
$ git commit
file.txt: needs merge
git-status(1) will list those files as "unmerged", and the files with
conflicts will have conflict markers added, like this:
并且,git-status(1) 将列举出 "unmerged" 的那些文件,文件中也会被加入冲突的标志,它看起来大致是这样:
&&&&&&& HEAD:file.txt
Hello world
&&&&&&& 7dbe8d65caf5208086:file.txt
All you need to do is edit the files to resolve the conflicts, and then
无论如何你都需要编辑这些文件,解决冲突,之后
$ git add file.txt
$ git commit
that the commit message will already be filled in for you with some
information about the merge. Normally you can just use this default
message unchanged, but you may add additional commentary of your own if
注意此时的交付信息中,总是会被填充一些有关合并的信息。正常情况下,你可以用它作为默认的信息而不要修改它,不过你当然可以加上你自己希望的注释。
The above is all you need to know to resolve a simple merge. But git also provides more information to help resolve conflicts:
以上你是必须知道的有关简单合并的知识,不过 git 会提供更多的信息帮助你解决冲突:
Getting conflict-resolution help during a merge 在合并过程中取得冲突解决帮助
the changes that git was able to merge automatically are already added
to the index file, so git-diff(1) shows only the conflicts. It uses an
unusual syntax:
所有 git 可以自动合并的东西都会被加入到索引中,而且 git-diff(1) 只会显示冲突,它使用一种特殊的语法来表示:
$ git diff
diff --cc file.txt
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,5 @@@
++&&&&&&& HEAD:file.txt
+Hello world
++&&&&&&& 7dbe8d65caf5208086:file.txt
that the commit which will be committed after we resolve this conflict
will have two parents instead of the usual one: one parent will be
HEAD, the tip o the other will be the tip of the
other branch, which is stored temporarily in MERGE_HEAD.
回想一下,你解决了冲突之后提交的交付将有两个父交付:一个是 HEAD,当前分支的顶端;另一个是另外一个分支的顶端,它临时性地保存为 MERGE_HEAD 。
the merge, the index holds three versions of each file. Each of these
three "file stages" represents a different version of the file:
合并的过程中,索引为每个冲突的文件保持三个版本,这三个 "文件阶段(file stages)" 表示三个文件的不同版本:
$ git show :1:file.txt
# the file in a common ancestor of both branches
$ git show :2:file.txt
# the version from HEAD.
$ git show :3:file.txt
# the version from MERGE_HEAD.
you ask git-diff(1) to show the conflicts, it runs a three-way diff
between the conflicted merge results in the work tree with stages 2 and
3 to show only hunks whose contents come from both sides, mixed (in
other words, when a hunk's merge results come only from stage 2, that
part is not conflicting and is not shown. Same for stage 3).
你用 git diff(1) 来显示冲突的时候,它将根据你当前工作目录中的版本与文件阶段 2 和 3
进行三路差异运算之后,向你显示一个差异内容块,此内容混合了来自两个方面的差异(换一个讲法,就是工作树中的内容与第二个文件阶段中的内容合并,再去合
并第三个文件阶段中的内容,但是冲突块仅仅是显示了这第二次合并中有冲突的地方,而没有冲突的地方则不显示)。
diff above shows the differences between the working-tree version of
file.txt and the stage 2 and stage 3 versions. So instead of preceding
each line by a single "+" or "-", it now uses two columns: the first
column is used for differences between the first parent and the working
directory copy, and the second for differences between the second
parent and the working directory copy. (See the "COMBINED DIFF FORMAT"
section of git-diff-files(1) for a details of the format.)
述的输出显示了 file.txt 文件在工作树中的版本对阶段2(stage 2)与阶段3(stage 3)中的差异,并且在每行中加上 "+"
或者 "-" 的前缀, 分两列排列: 第一列用于标记第一个父交付对工作树的差异,第二列用于表示第一个父交付对工作树的差异。(参考
git-diff-files(1) 中的 "COMBINED DIFF FORMAT" 段,取得详细信息)
After resolving the conflict in the obvious way (but before updating the index), the diff will look like:
解决了冲突之后(但未刷新索引之前), 差异输出类似这样:
$ git diff
diff --cc file.txt
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,1 @@@
- Hello world
++Goodbye world
shows that our resolved version deleted "Hello world" from the first
parent, deleted "Goodbye" from the second parent, and added "Goodbye
world", which was previously absent from both.
这个输出显示我们的解决方案是删除来自第一个父交付的 "Hello world",删除来自第二个父交付中的 "Goodbye",加入了 "Goodbye world",这是在两个父交付中都从来没有出现过的内容。
Some special diff options allow diffing the working directory against any of these stages:
下面是一个特殊的差异选项,比较工作树对其他的文件阶段的差异:
$ git diff -1 file.txt
# diff against stage 1
$ git diff --base file.txt
# same as the above
$ git diff -2 file.txt
# diff against stage 2
$ git diff --ours file.txt
# same as the above
$ git diff -3 file.txt
# diff against stage 3
$ git diff --theirs file.txt
# same as the above.
The git-log(1) and gitk(1) commands also provide special help for merges:
git-log(1) 与 gitk(1) 命令会有关于合并的专题帮助:
$ git log --merge
$ gitk --merge
These will display all commits which exist only on HEAD or on MERGE_HEAD, and which touch an unmerged file.
如此将显示所有仅存于 HEAD 或者是 MERGE_HEAD 中的所有涉及未合并的文件的交付。
You may also use git-mergetool(1), which lets you merge the unmerged files using external tools such as Emacs or kdiff3.
你还可以用 git-mergetool(1) 命令,它容许你使用第三方合并工具进行合并操作,譬如 Emacs 或者是 kdiff3。
Each time you resolve the conflicts in a file and update the index:
每当你解决了冲突之后就应刷新索引:
$ git add file.txt
different stages of that file will be "collapsed", after which git-diff
will (by default) no longer show diffs for that file.
之后,其他的差异阶段文件将被丢弃, git-diff 命令将显示没有任何差异。
Undoing a merge
If you get stuck and decide to just give up and throw the whole mess away, you can always return to the pre-merge state with
如果你在合并过程中遇到麻烦,并且打算放弃和离开混乱处境,你总是可以回到合并之前的状态
$ git reset --hard HEAD
Or, if you've already committed the merge that you want to throw away,
又或者,你已经将合并提交了,但是你想扔掉它,
$ git reset --hard ORIG_HEAD
this last command can be dangerous in some cases&never throw away a
commit you have already committed if that commit may itself have been
merged into another branch, as doing so may confuse further merges.
可是,最后一个命令在某些情况下是危险的,它是扔掉一个已经提交了的合并,如果这个合并交付本身是曾经合并过其他的分支的话,这样做将会给今后的合并带来混乱。
Fast-forward merges 快进合并
one special case not mentioned above, which is treated differently.
Normally, a merge results in a merge commit, with two parents, one
pointing at each of the two lines of development that were merged.
有一个特殊的情况上面没有提及到的,这被看作是一个特例。正常情况下,合并的结果是一个合并交付,带两个父交付,分别指向被合并的两个研发分支。
if the current branch is a descendant of the other&so every commit
present in the one is already contained in the other&then git just
performs a "fast forward"; the head of the current branch is moved
forward to point at the head of the merged-in branch, without any new
commits being created.
不过,要是当前分支的东西都是另外一个分支中的东西的后裔的时候,git 只会进行 &快进& 操作;也就是说,它只会将当前的分支头快进到合并过后的分支头,而不会创建一个新的交付。
Fixing mistakes 修复失误
messed up the working tree, but haven't yet committed your mistake, you
can return the entire working tree to the last committed state with
要是工作树已经被你搞得一团糟了,但是你还没有提交过错误的东西的话,你可以整体地将工作树撤回到最后一个交付的状态
$ git reset --hard HEAD
If you make a commit that you later wish you hadn't, there are two fundamentally different ways to fix the problem:
要是你做了一个交付,但是你后来又想放弃它,那么基本上有两个途径让你修复问题:
You can create a new commit that undoes whatever was done by the old
commit. This is the correct thing if your mistake has already been made
You can go back and modify the old commit. You should never do this if
you have already mad git does not normally expect
the "history" of a project to change, and cannot correctly perform
repeated merges from a branch that has had its history changed.
你可以创建一个新的交付来撤销你旧的交付的东西。这个才是正确的方法,如果你的错误已经发布出去了。
你可以回到那个老的交付中并修改它。可是当你的版本库历史已经发布出去之后,你绝对不应该这样做;通常地 git 不会设想项目的 &历史& 是会出现改变的。同时也不能够正确地对那些历史发生过改变的分支合并进行重新整合。
Fixing a mistake with a new commit 修复一个新的交付中的失误
a new commit that reverts an earlier just pass the
git-revert(1) command a referen for example, to
revert the most recent commit:
创建一个新的交付去逆转一个最近的交付的变更是很容易的;通过 git-revert(1) 命令指向一个坏交付就行;例如,逆转一个最新的交付:
$ git revert HEAD
will create a new commit which undoes the change in HEAD. You will be
given a chance to edit the commit message for the new commit.
这将创建一个新交付去撤销在 HEAD 中的变更。这样就给了你一个机会编辑新交付中的注释。
You can also revert an earlier change, for example, the next-to-last:
你可以一个接一个地逆转更早的变化,例如:
$ git revert HEAD^
this case git will attempt to undo the old change while leaving intact
any changes made since then. If more recent changes overlap with the
changes to be reverted, then you will be asked to fix conflicts
manually, just as in the case of resolving a merge.
在这种情况下,每当 git 离开过一个原封的变更时,它将试图将撤销的变更应用到其后的项目历史中。如果有多个变更重叠,你可能会被要求解决冲突,正如你要解决合并冲突那样。
Fixing a mistake by rewriting history 通过重写历史来修复失误
problematic commit is the most recent commit, and you have not yet made
that commit public, then you may just destroy it using git-reset.
如果一个有问题的交付是最新的交付,并且你还没有将它发布出去,那么你可以用 git-reset 来销毁它。
Alternatively,
you can edit the working directory and update the index to fix your
mistake, just as if you were going to create a new commit, then run
另一个途径是编辑工作目录并刷新索引来修复你的失误,就像你创建一个新的交付那样,运行
$ git commit --amend
will replace the old commit by a new commit incorporating your changes,
giving you a chance to edit the old commit message first.
它将用你更正后的新交付去覆盖旧的交付,首先你有机会改变旧的交付信息。
you should never do this to a commit that may already have been merged
use git-revert(1) instead in that case.
重申一次,你绝对不应该在这个交付已经并合并经其他的分支的情况下这样做; 此时你应该用 git-revert(1) 来处理失误。
is also possible to replace commits further back in the history, but
this is an advanced topic to be left for another chapter.
它还可以覆盖历史更久远的交付,不过这个是一个高级话题,留待其他的章节讨论。
Checking out an old version of a file 提取一个文件的旧版本
process of undoing a previous bad change, you may find it useful to
check out an older version of a particular file using git-checkout(1).
We've used git-checkout before to switch branches, but it has quite
different behavior if it is given a path name: the command
在处理撤销以前坏变更的过程中,你可能已经认识到 git-checkout(1) 用于提取一个具体的文件的旧版本的有用性。以前我们用 git-checkout 来在旧的版本之间切换,不过如果你给出路径的名称,那么这个命令的表现会完全不同。
$ git checkout HEAD^ path/to/file
path/to/file by the contents it had in the commit HEAD^, and also
updates the index to match. It does not change branches.
它将以交付 HEAD^ 中的内容来覆盖 path/to/file 文件,并且同时恰当地刷新索引。它不会改变分支。
you just want to look at an old version of the file, without modifying
the working directory, you can do that with git-show(1):
假如你只是想看看一个文件的旧版本是什么样子,而不想触动工作树的话,你可以用 git-show(1) 命令这样做:
$ git show HEAD^:path/to/file
which will display the given version of the file.
它会显示给定的版本的文件内容。
are in the middle of working on something complicated, you find an
unrelated but obvious and trivial bug. You would like to fix it before
continuing. You can use git-stash(1) to save the current state of your
work, and after fixing the bug (or, optionally after doing so on a
different branch and then coming back), unstash the work-in-progress
你正处于一个复杂的工作过程当中,但忽然发现一个与当前工作无关的,而又很明显的漏洞的时候。你也许希望先修复这个漏洞,再继续你手头上的工作。你可以用
git-stash(1)
将你当前工作树的状态先保存起来,待修复了那个漏洞之后(或者,在另外的分支上完成这件事之后再回来),再取回你刚才手头上的工作接着做。
$ git stash save "work in progress for foo feature"
command will save your changes away to the stash, and reset your
working tree and the index to match the tip of your current branch.
Then you can make your fix as usual.
这个命令将你当前工作树中的变更保存到临时的空间(stash)中,并以你当前的分支状态重置工作树和索引。那你就可以进行漏洞的修复工作了。
... edit and test ...
$ git commit -a -m "blorpl: typofix"
After that, you can go back to what you were working on with git stash apply:
之后,你就可以用 git stash apply 命令回到原来的工作状态:
$ git stash apply
Ensuring good performance 确保好的性能
repositories, git depends on compression to keep the history
information from taking up too much space on disk or in memory.
在大型项目中, git 依靠对历史信息进行压缩来利用磁盘空间和内存空间。
This compression is not performed automatically. Therefore you should occasionally run git-gc(1):
不过压缩不是自动的,你应该时不时运行一下 git-gc(1):
to recompress the archive. This can be very time-consuming, so you may prefer to run git-gc when you are not doing other work.
它会重新压缩项目。这可能是很费时的工作,你可以在完成其他的事情之后才做这件事。
Ensuring reliability 确保伸缩性
Checking the repository for corruption 检查版本的损坏
git-fsck(1) command r

我要回帖

更多关于 somethinglikeyou 的文章

 

随机推荐