## 名称

gittutorial - Git 的教程介绍

## 概要

    git *

## 描述

本教程介绍了如何将新项目导入 Git，对其进行更改以及与其他开发人员共享更改。

如果您主要对使用 Git 获取项目感兴趣，例如，要测试最新版本，您可能更愿意从 “Git用户手册” 的前两章开始。

首先，请注意，您可以获取命令的文档，例如`git log --graph`：

    $ man git-log

或者：

    $ git help log

使用后者，您可以使用您选择的手动查看器; 请参阅 git-help [1] 了解更多信息。

在进行任何操作之前，向 Git 介绍自己的姓名和公共电子邮件地址是一个好主意。最简单的方法是：

    $ 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 为当前目录下的所有文件的内容创建一个快照（注意`.`）`git add`：

    $ git add .

此快照现在存储在 Git 称为“索引”的临时区域中。您可以使用`git commit`命令将索引的内容永久存储在存储库中：

    $ git commit

这会提示你输入提交信息。您现在已经将您的项目的第一个版本存储在 Git 中。

## 进行更改

修改一些文件，然后将其更新的内容添加到索引中：

    $ git add file1 file2 file3

您现在已准备好提交。您可以使用`git diff`--cached 选项查看要提交的内容：

    $ git diff --cached

（不使用 - 缓存，`git diff`会显示您已做出但未添加到索引的任何更改。）您还可以通过以`git status`方式获得情况的简要摘要：

    $ git status

    On branch master

    Changes to be committed:Your branch is up-to-date with 'origin/master'.  (use "git reset HEAD <file>..." to unstage)

            modified:   file1

            modified:   file2

            modified:   file3

如果您需要进一步调整，请立即执行此操作，然后将任何新修改的内容添加到索引中。最后，通过以下方式进行修改：

    $ git commit

这将再次提示您输入描述更改的消息，然后记录该项目的新版本。

或者，不要事先运行`git add`，您可以使用

    $ git commit -a

它会自动注意到任何已修改（但不是新增）的文件，将它们添加到索引中，然后全部一步完成。

关于提交消息的注释：虽然不是必需的，但最好先用一个简短（少于50个字符）的行开始提交消息，然后再总结一个空行，然后进行更全面的描述。直到提交消息中的第一个空行的文本被视为提交标题，并且该标题在整个 Git 中使用。例如， git-format-patch [1] 将提交转换为电子邮件，并使用主题行上的标题和正文中的其余提交。

## 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" 分支是您刚刚创建的分支，“主分支”分支是自动为您创建的默认分支。星号标记你当前所在的分支类型;

    $ git checkout experimental

切换到实验分支。现在编辑一个文件，提交更改并切换回主分支：

    (edit file)$ git commit -a

    $ git checkout master

检查您所做的更改是否不再可见，因为它是在实验分支上创建的，而您又回到了主分支上。

您可以在主分支上进行不同的更改：

    (edit file)$ git commit -a

在这一点上，两个分支已经发生了分歧，每个分支都有不同的变化。要将实验中所做的更改合并到 master 中，请运行

    $ git merge experimental

如果更改不冲突，则表示完成。如果有冲突，标记将留在显示冲突的有问题的文件中;

    $ git diff

会显示这一点。一旦你编辑了文件来解决冲突，

    $ git commit -a

将承诺合并的结果。最后，

    $ gitk

将显示最终的历史记录的一个很好的图形表示。

在这一点上，你可以删除实验分支

    $ git branch -d experimental

命令确保实验分支中的更改已经在当前分支中。

如果你在一个分支的思路发展，然后后悔了，你可以随时删除分支

    $ git branch -D crazy-idea

分支机构既便宜又容易，所以这是尝试一些东西的好方法。

## 使用git进行协作

假设 Alice 已经在 / home / alice / project 中使用 Git 存储库启动了一个新项目，并且在同一台机器上有一个主目录的 Bob 想要贡献。

Bob 从以下开始：

    bob$ git clone /home/alice/project myrepo

这会创建一个包含 Alice 存储库克隆的新目录 “myrepo” 。克隆与原始项目保持平等，拥有原始项目历史的副本。

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 会希望在启动此“拉”之前执行其本地更改。如果 Bob 的工作与爱丽丝自历史分手以来所做的工作相冲突，Alice 将使用她的工作树和索引来解决冲突，而现有的本地更改将干扰冲突解决过程（Git 仍将执行提取操作，但会拒绝合并 - - Alice 将不得不以某种方式摆脱她的本地变化，并在发生这种情况时再次pull）。

Alice 可以通过使用“获取”命令来查看 Bob 没有合并的情况，这允许 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 那里 pull 。如果 Bob的历史确实需要 Alice 立即需要的东西，艾丽斯可能会选择先搁置她正在进行的工作，做一次 “pull”，然后最终在最终的历史之外取消正在进行的工作。

当你在一个紧密团结的小团队中工作时，一次又一次地与同一个存储库进行交互并不少见。通过定义`remote`存储库速记，可以使其更容易：

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

有了这个，Alice 可以使用`git fetch`命令单独执行 “pull” 操作的第一部分，而不用将它们与自己的分支合并，使用：

    alice$ git fetch bob

与 longhand 形式不同的是，当 Alice 使用远程仓库快速设置从 Bob 获取时`git remote`，在这种情况下，获取的内容存储在远程跟踪分支中`bob/master`。所以在这之后：

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

显示了 Bob 从 Alice 的主分支中分支后所做的所有更改的列表。

在检查这些更改后，Alice 可以将更改合并到她的主分支中：

    alice$ git merge bob/master

`merge`也可以通过`pulling from her own remote-tracking branch`如下方式完成：

    alice$ git pull . remotes/bob/master

注意 git pull 总是合并到当前分支中，而不管命令行上给出的是什么。

之后，Bob可以使用Alice的最新更改更新其回购

    bob$ git pull

请注意，他不需要为 Alice 的存储库提供路径; 当 Bob 克隆 Alice 的存储库时，Git 将其存储库的位置存储在存储库配置中，并且位置用于提取：

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

（创建的完整配置`git clone`使用可见`git config -l`，而 git-config [1] 手册页解释每个选项的含义。）

Git 还以 “origin / master” 的名称保存了 Alice 主分支的原始副本：

    bob$ git branch -r

      origin/master

如果Bob后来决定从另一个主机上工作，他仍然可以使用 ssh 协议执行 clone 和 pull 操作：

    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 日志条目的第一行还提供了提交的名称：

    $ 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`一个“范围”的提交，其中第一个不一定是第二个的父类; 例如，如果分支机构的“稳定”和“主机”的提示早于一个普通的提交，那么

    $ git log stable..master

将列出在主分支中进行的提交，但不在稳定分支中进行提交

    $ git log master..stable

将显示稳定分支上的提交列表，但不显示主分支上的提交列表。

`git log`命令有一个弱点：它必须在列表中提交提交。当历史的发展路线发生分化，然后合并到一起时，`git log`呈现这些提交的顺序就没有意义了。

大多数具有多个贡献者的项目（如 Linux 内核或 Git 本身）经常合并，`gitk`更好地将其历史记录可视化。例如，

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

允许您浏览在 “drivers” 目录下提交修改文件的最后2周提交的任何提交。（注意：按住“ - ”或“+”键的同时按住控制键可以调整 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]：当你的项目出现回归时，追踪错误的一种方法是通过搜索历史记录来找到应该归咎于的确切提交。Git bisect 可以帮助您执行该提交的二进制搜索。即使在具有大量合并分支的复杂非线性历史的情况下，它也足够聪明地执行接近最优的搜索。

- gitworkflows [7]：概述推荐的工作流程。

- giteveryday [7]：每天 Git 与20个命令或者如此。

- gitcvs-migration [7]：CVS 用户的 Git。