简体中文 ▾ 主题 ▾ 最新版本 ▾ gittutorial 上次更新于 2.46.1

名称

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

您现在可以提交了。您可以使用带有 --cached 选项的 git diff 来查看即将提交的内容

$ git diff --cached

(如果没有 --cachedgit 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] 将提交转换为电子邮件,并在主题行上使用标题,并在正文中使用提交的其余部分。

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 可以先使用 fetch 命令查看 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

这意味着“显示可以从两者中的任何一个访问的所有内容,但排除可以从两者访问的任何内容”。

请注意,这些范围表示法可以与 gitkgit 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 分支创建分支以来,Bob 所做的所有更改的列表。

在检查这些更改后,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 将她的仓库位置存储在仓库配置中,该位置用于拉取操作

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

git clone 创建的完整配置可以使用 git config -l 查看,并且 git-config[1] 手册页解释了每个选项的含义。)

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 一个“范围”的提交,其中第一个不一定是第二个的祖先;例如,如果分支 stablemaster 的提示从一段时间前的公共提交中分离出来,则

$ 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/

允许您浏览过去 2 周内修改了 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]:当您的项目中出现回归时,查找错误的 一种方法是通过搜索历史记录来找到应受责备的确切提交。git bisect 可以帮助您对该提交执行二进制搜索。即使在具有大量合并分支的复杂非线性历史记录的情况下,它也足够智能,可以执行接近最佳的搜索。

  • gitworkflows[7]:概述了推荐的工作流程。

  • giteveryday[7]:使用 20 个左右的命令的日常 Git。

  • gitcvs-migration[7]:面向 CVS 用户的 Git。

GIT

git[1] 套件的一部分

scroll-to-top