设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.46.2 → 2.52.0 无更改
-
2.46.1
2024-09-13
- 2.43.1 → 2.46.0 无更改
-
2.43.0
2023-11-20
- 2.41.1 → 2.42.4 无更改
-
2.41.0
2023-06-01
- 2.33.1 → 2.40.4 无更改
-
2.33.0
2021-08-16
- 2.23.1 → 2.32.7 无更改
-
2.23.0
2019-08-16
- 2.16.6 → 2.22.5 无更改
-
2.15.4
2019-12-06
- 2.13.7 → 2.14.6 无更改
-
2.12.5
2017-09-22
- 2.9.5 → 2.11.4 无更改
-
2.8.6
2017-07-30
- 2.3.10 → 2.7.6 无更改
-
2.2.3
2015-09-04
- 2.1.4 无更改
-
2.0.5
2014-12-17
描述
本教程解释了如何将新项目导入 Git、对其进行更改以及与其他开发人员共享更改。
如果您主要对使用 Git 获取项目感兴趣,例如,要测试最新版本,您可以选择从The Git User’s Manual的前两章开始。
首先,请注意,您可以通过以下方式获取类似 git log --graph 命令的文档:
$ man git-log
或
$ git help log
对于后者,您可以使用您选择的手册查看器;有关更多信息,请参阅 git-help[1]。
在进行任何操作之前,最好先用您的姓名和公开电子邮件地址介绍自己。最简单的方法是:
$ git config --global user.name "Your Name Comes Here" $ git config --global user.email you@yourdomain.example.com
导入新项目
假设您有一个包含您初步工作的 tarball 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
您现在已准备好提交。您可以使用带 --cached 选项的 git diff 命令查看将要提交的内容:
$ git diff --cached
(不带 --cached,git diff 会显示您已进行但尚未添加到索引的任何更改。)您还可以使用 git status 命令获得当前情况的简要摘要:
$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: file1 modified: file2 modified: file3
如果您需要进行任何进一步的调整,请立即进行,然后将任何新修改的内容添加到索引中。最后,使用以下命令提交您的更改:
$ git commit
这将再次提示您输入一条描述更改的消息,然后记录项目的新版本。
或者,您可以先不运行 git add,而是使用:
$ git commit -a
该命令将自动识别任何已修改(但非新增)的文件,将它们添加到索引,然后一次性提交,全部一步完成。
关于提交消息的说明:虽然不是必需的,但最好在提交消息开头写一个简短的(不超过 50 个字符)单行摘要,后面跟一个空行,然后是更详细的描述。提交消息中第一个空行之前的所有文本都被视为提交标题,Git 在整个过程中都使用这个标题。例如,git-format-patch[1] 会将一个提交转换为电子邮件,它会将标题用在 Subject 行,而提交的其余部分放在正文中。
Git 跟踪内容而不是文件
许多版本控制系统提供一个 add 命令,用于告知系统开始跟踪新文件的更改。Git 的 add 命令作用更简单、更强大:git add 用于处理新增和已修改的文件,在这两种情况下,它都会对给定的文件内容进行快照,并将其暂存到索引中,为下一次提交做好准备。
查看项目历史
在任何时候,您都可以使用以下命令查看更改历史:
$ git log
如果您还想在每一步都看到完整的差异,请使用:
$ git log -p
通常,对更改的概述有助于了解每一步的进展。
$ git log --stat --summary
管理分支
一个 Git 仓库可以维护多个开发分支。要创建一个名为 experimental 的新分支,请使用:
$ git branch experimental
如果您现在运行:
$ git branch
您将获得一个现有分支列表。
experimental * master
experimental 分支是您刚刚创建的,而 master 分支是自动为您创建的默认分支。星号标记着您当前所在的分支;输入:
$ git switch experimental
切换到 experimental 分支。现在编辑一个文件,提交更改,然后切换回 master 分支:
(edit file) $ git commit -a $ git switch 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 在 /home/alice/project 中创建了一个新的 Git 仓库,而 Bob 在同一台机器上有自己的主目录,并希望贡献代码。
Bob 开始时执行:
bob$ git clone /home/alice/project myrepo
这将创建一个名为 myrepo 的新目录,其中包含 Alice 仓库的一个克隆。这个克隆与原始项目处于同等地位,拥有原始项目历史的副本。
Bob 接着进行一些更改并提交:
(edit files) bob$ git commit -a (repeat as necessary)
当他准备好时,他告诉 Alice 从 /home/bob/myrepo 的仓库拉取更改。她通过以下命令完成:
alice$ cd /home/alice/project alice$ git pull /home/bob/myrepo master
这将把 Bob 的 master 分支的更改合并到 Alice 当前所在的分支。如果 Alice 此期间自己也进行了更改,那么她可能需要手动解决任何冲突。
pull 命令因此执行两个操作:它从远程分支获取更改,然后将它们合并到当前分支。
请注意,通常情况下,Alice 希望在发起此 pull 命令之前提交她的本地更改。如果 Bob 的工作与 Alice 在他们的历史分叉后所做的更改发生冲突,Alice 将需要使用她的工作树和索引来解决冲突,而现有的本地更改会干扰冲突解决过程(Git 仍会执行获取操作,但会拒绝合并——此时 Alice 必须以某种方式丢弃她的本地更改,然后重新拉取)。
Alice 可以在不先合并的情况下查看 Bob 所做的更改,使用 fetch 命令;这允许 Alice 使用一个特殊的符号 FETCH_HEAD 来检查 Bob 所做的更改,以确定他是否有值得拉取的内容,如下所示:
alice$ git fetch /home/bob/myrepo master alice$ git log -p HEAD..FETCH_HEAD
即使 Alice 有未提交的本地更改,此操作也是安全的。HEAD..FETCH_HEAD 的范围表示法意味着“显示所有可从 FETCH_HEAD 可达但排除任何可从 HEAD 可达的内容”。Alice 已经知道所有导致她当前状态(HEAD)的内容,并使用此命令查看 Bob 的状态(FETCH_HEAD)中她尚未看到的内容。
如果 Alice 想可视化 Bob 在他们的历史分叉后所做的更改,她可以发出以下命令:
$ gitk HEAD..FETCH_HEAD
这使用了我们之前在 git log 中看到的相同的两个点范围表示法。
Alice 可能想查看他们分叉后各自所做的更改。她可以在两个点表示法中使用三个点表示法:
$ gitk HEAD...FETCH_HEAD
这意味着“显示从任一分支可达的所有内容,但排除从两个分支都可达的内容”。
请注意,这些范围表示法可以与 gitk 和 git log 一起使用。
在检查完 Bob 的工作后,如果没有紧急事项,Alice 可能决定继续工作而不拉取 Bob 的更改。如果 Bob 的历史确实有 Alice 立即需要的内容,Alice 可能选择先暂存她的未完成工作,执行 pull,然后在由此产生的历史之上最后恢复她的未完成工作。
当您在一个小型紧密协作的团队中工作时,频繁地与同一个仓库交互是很常见的。通过定义远程仓库的简写,您可以使其更容易。
alice$ git remote add bob /home/bob/myrepo
有了这个,Alice 可以单独使用 git fetch 命令执行 pull 操作的第一部分,而不将其与她自己的分支合并,使用:
alice$ git fetch bob
与长格式不同,当 Alice 使用 git remote 设置的远程仓库简写从 Bob 那里获取时,所获取的内容将存储在远程跟踪分支中,在本例中是 bob/master。因此,在此之后:
alice$ git log -p master..bob/master
显示了 Bob 自从从 Alice 的 master 分支分叉以来所做的所有更改的列表。
检查完这些更改后,Alice 可以将更改合并到她的 master 分支:
alice$ git merge bob/master
这个 merge 也可以通过从她自己的远程跟踪分支拉取来完成,如下所示:
alice$ git pull . remotes/bob/master
请注意,git pull 始终合并到当前分支,无论命令行中还提供了什么。
稍后,Bob 可以使用以下命令更新他的仓库以包含 Alice 的最新更改:
bob$ git pull
请注意,他不需要提供 Alice 仓库的路径;当 Bob 克隆 Alice 的仓库时,Git 将 Alice 仓库的位置存储在仓库配置中,该位置用于拉取操作。
bob$ git config --get remote.origin.url /home/alice/project
(通过 git config -l 可以看到 git clone 创建的完整配置,并且 git-config[1] man 页解释了每个选项的含义。)
Git 还保留了一个 Alice 的 master 分支的原始副本,名为 origin/master。
bob$ git branch -r origin/master
如果 Bob 后来决定从不同的主机工作,他仍然可以使用 ssh 协议执行克隆和拉取操作:
bob$ git clone alice.org:/home/alice/project myrepo
或者,Git 有一个本地协议,或者可以使用 http;有关详细信息,请参阅 git-pull[1]。
Git 也可以在类 CVS 模式下使用,有一个中央仓库供不同用户推送更改;请参阅 git-push[1] 和 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。如果您打算与他人共享此名称(例如,用于标识发布版本),您应该创建一个“标签”对象,也许还要对其进行签名;有关详细信息,请参阅 git-tag[1]。
任何需要知道提交的 Git 命令都可以接受这些名称中的任何一个。例如:
$ 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 grep 命令可以搜索您项目任何版本中的字符串,因此:
$ git grep "hello" v2.5
将在 v2.5 中搜索“hello”的所有出现。
如果省略提交名称,git grep 将搜索您当前目录中它管理的任何文件。所以:
$ 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
将列出在 master 分支中提交但不在 stable 分支中的提交,而:
$ git log master..stable
将显示在 stable 分支中提交但不在 master 分支中的提交列表。
git log 命令有一个弱点:它必须以列表的形式呈现提交。当历史发展线分叉然后合并在一起时,git log 呈现这些提交的顺序是没有意义的。
大多数有多位贡献者参与的项目(例如 Linux 内核或 Git 本身)都有频繁的合并,而 gitk 在可视化其历史方面做得更好。例如:
$ gitk --since="2 weeks ago" drivers/
允许您浏览过去两周内修改了 drivers 目录下文件的任何提交。(注意:您可以通过按住 Control 键同时按“-”或“+”来调整 gitk 的字体。)
最后,大多数接受文件名的命令可以选择在任何文件名之前加上一个提交,以指定文件的特定版本:
$ git diff v2.5:Makefile HEAD:Makefile.in
您也可以使用 git show 来查看任何此类文件:
$ git show v2.5:Makefile
下一步
本教程应该足以对您的项目执行基本的分布式版本控制。但是,要完全理解 Git 的深度和强大功能,您需要理解它所基于的两个简单概念:
-
对象数据库是一个相当优雅的系统,用于存储您项目的历史——文件、目录和提交。
-
索引文件是目录树状态的缓存,用于创建提交、检出工作目录以及保存合并中涉及的各种树。
本教程的第二部分将解释对象数据库、索引文件以及您需要了解的其他一些零散知识,以便充分利用 Git。您可以在 gittutorial-2[7] 找到它。
如果您不想立即继续学习,以下是一些可能在此刻引起您兴趣的其他内容:
-
git-format-patch[1], git-am[1]:这些命令可以将 Git 提交序列转换为电子邮件补丁,反之亦然,对于像 Linux 内核这样高度依赖电子邮件补丁的项目很有用。
-
git-bisect[1]:当您的项目出现回归时,一种查找 bug 的方法是搜索历史记录,找到导致问题的确切提交。
gitbisect可以帮助您对该提交进行二分查找。即使在复杂的非线性历史以及大量合并分支的情况下,它也足够智能,能够执行接近最优的搜索。 -
gitworkflows[7]:概述了推荐的工作流程。
-
giteveryday[7]:日常 Git 使用,包含大约 20 个命令。
-
gitcvs-migration[7]:Git for CVS users (CVS 用户迁移到 Git)。