Why Git?
1. 本地版本控制系统
- Why:
- 许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。 这么做唯一的好处就是简单,但是特别容易犯错。 有时候会混淆所在的工作目录,一不小心会写错文件或者覆盖意想外的文件。
- 为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。
- What:
- 其中最流行的一种叫做 RCS,现今许多计算机系统上都还看得到它的踪影。 RCS 的工作原理是在硬盘上保存补丁集(补丁是指文件修订前后的变化);通过应用所有的补丁,可以重新计算出各个版本的文件内容。
2. 集中化的版本控制系统
- Why:
- 接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?
- 于是,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应运而生。
- What:
- 诸如 CVS、Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。 多年以来,这已成为版本控制系统的标准做法。
3. 分布式版本控制系统 DRCS(Distributed Version Control System)
- Why:
- CVCS 最显而易见的缺点是中央服务器的单点故障。 如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。
- 如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据——包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。
- 于是分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了。
- What:
- 在这类系统中,像 Git、Mercurial 以及 Darcs 等,客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。
- 更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。 你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。
What is Git?
Git是一个 分布式版本控制
系统,用于跟踪文件的修改,可以允许多个开发人员协作开发项目,同时维护代码的完整性和历史记录。
1. 直接记录快照,而非差异比较
- 存储每个文件与初始版本的差异方式——非 Git
- 从概念上来说,其它大部分系统以文件变更列表的方式存储信息,这类系统(CVS、Subversion、Perforce 等等) 将它们存储的信息看作是一组基本文件和每个文件随时间逐步累积的差异 (它们通常称作 基于差异(delta-based) 的版本控制)。
- 存储项目随时间改变的快照方式——Git
- Git 不按照
存储每个文件与初始版本的差异
对待或保存数据。反之,Git 更像是把数据看作是对小型文件系统的一系列快照。 - 在 Git 中,每当你提交更新或保存项目状态时,它会对整个项目的当前状态生成一个快照并保存这个快照的索引。 为了效率,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。
- 快照:
- 文件对象(Blob):
- 存储文件的内容(而非文件名或位置)。
- 内容通过哈希(SHA-1 或其他)生成唯一标识,保证内容一致性。
- 树对象(Tree):
- 记录文件的结构(文件名、目录关系)。
- 每个目录对应一个树对象,树对象中包含指向文件对象或子树的指针。
- 提交对象(Commit):
- 指向一个树对象。
- 包含提交信息(如作者、时间、注释)以及指向父提交的指针。
2. 近乎所有操作都是本地执行
- 相比于集中式版本控制系统,Git 因为在本地磁盘就有项目的完整历史,所以大部分操作看起来是瞬间完成的。
- 意味着尽管离线或者无 VPN 时,也可以近乎做所有操作,直到有网络连接时再上传。
- 只有涉及远程仓库的操作(拉取、推送、克隆等)需要网络。
3. Git 保证完整性
- Git 如何使用 SHA-1(SHA-1(Secure Hash Algorithm 1) 是一种加密散列函数,可以将任意长度的数据(如文本或文件)通过特定算法,转化为一个固定长度的字符串。)?
- 数据完整性保证:
- Git 中所有的数据在存储前都计算校验和,然后以校验和来引用。 这个哈希值用来标识数据的“指纹”。
- 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。
- 这个功能建构在 Git 底层,若你在传送过程中丢失信息或损坏文件,Git 就能发现。
- 以哈希值为索引:
- 在 Git 的内部,文件名并不重要,文件内容的哈希值才是唯一标识符。Git 使用这些哈希值来存储和查找数据。
- 文件被存储在 Git 的对象库中,路径由哈希值决定。 为什么用哈希值而不是文件名?
- 为什么用哈希值而不是文件名?
- 防篡改:因为哈希值和内容直接相关,所以只要文件内容有任何改变,哈希值也会改变。这确保了 Git 可以检测到数据是否被篡改。
- 高效存储:
- 如果两个文件的内容相同,它们的哈希值就相同,Git 只需存储一次,避免了冗余。
- 即使文件名或路径变了,只要文件内容不变,Git 不会重复存储。
- 引用管理:
- Git 的提交、树对象等都是用哈希值来标识的,这使得整个版本控制体系结构清晰且一致。
- 总结
- Git 的底层存储基于 SHA-1 散列,以哈希值作为唯一标识符,而非文件名。
- 这种设计的好处是:
- 确保数据完整性和防篡改。
- 高效存储避免重复。
- 更灵活的版本管理和引用系统。
4. Git 一般只添加数据
- Git 几乎不会执行任何可能导致文件不可恢复的操作。
- 同别的 VCS 一样,未提交更新时有可能丢失或弄乱修改的内容。但是一旦你提交快照到 Git 中, 就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。
5. Git 文件的三种状态⭐
- 已提交(Committed)
- 文件已经被 Git 保存到本地仓库的数据库中——文件的某个版本已经被永久记录在 Git 历史中,不会丢失。
- Usually,只有通过
git commit
命令,文件才会变成“已提交”状态。 - 提交后的文件版本会被 Git 使用一个哈希值(SHA-1)标识,确保你可以随时回退到该版本。
- 已修改(Modified)
- 文件已经在工作区进行了修改,但还没有被暂存(即没有准备好被提交)。
- 已修改状态的文件,Git 会认为这些文件是变化过的,但他们还没有被标记为“已暂存”的状态
- 通过
git status
命令查看已修改状态的文件。
- 已暂存(Staged)
- 文件在工作区被修改后,使用
git add
命令将文件的当前版本放入暂存区,表示文件已准备好在下一次 commit 时被记录。 - 暂存区是 Git 用来保存即将提交的文件的区域,本质上是一个临时区域,我们可以选择性地添加某些修改(而不是修改全部)到暂存区。
- 通过
git status
命令查看已修改状态的文件。
文件状态总结:
状态 |
描述 |
操作命令 |
已修改 |
文件被修改,但还未暂存 |
修改文件 |
已暂存 |
文件被暂存,等待提交 |
|
已提交 |
文件已经提交并保存在 Git 仓库中 |
|
常见操作:
git status
:查看文件的当前状态(已修改、已暂存或已提交)。git add
:将修改添加到暂存区。git commit
:将暂存区的文件提交到 Git 仓库。git diff
:查看工作区和暂存区之间的差异,或查看暂存区和 Git 仓库的差异。
6. Git 的三个区域 ⭐
- 工作区——已修改(Modified)
- 实际开发和修改的地方,在该目录中,可以看到项目的源代码文件。
- 修改包括(新增、删除、修改)。
- 在工作区修改的文件处于“已修改”的状态。
- 暂存区(索引)——已暂存(Staged)
- 暂存区是一个文件,本质上是 Git 用来记录哪些修改将会在下次提交时被记录的地方。也称为索引,可以理解为指向 blob 和 tree 的一组指针。
- 在暂存区中的文件处于“已暂存”的状态。
- Git 仓库目录(Git Repository)——已提交(Commited)
- Git 存储项目历史和元数据的地方,存储了所有的提交(包括每次提交的快照)、分支、标签等。
- 这些提交记录存在
.git/
文件夹内。
7. Git 基本工作流程 ⭐
- 在工作区中修改文件。
- 暂存文件
- 使用
git add <file>
命令,选择性地将修改文件加入暂存区,让文件处于 Staged(准备提交)状态。
- 提交更新
- 使用
git commit
命令,将暂存区中的文件提交到 Git Repository——永久存储文件的快照,形成一个新版本。
- 更新 Working Directory,Staging Area,.Git Repository。
- 暂存后、提交后,工作区的文件仍然保留。
- 提交后暂存区的文件被清空。
8. 如何跳过暂存区直接提交
Git 允许你在某些情况下跳过暂存区,直接将文件提交到 Git 仓库。这种操作可以通过以下命令实现:
git commit -a
:这个命令会将所有已修改且已跟踪的文件(不包括新文件)直接提交,而不需要使用git add
先将它们暂存。- 注意:
git commit -a
只会提交已跟踪的文件,对于新创建的文件,你仍然需要使用git add
将它们添加到暂存区。
Git 配置
1. 初次运行 Git 前的配置
- 既然已经在系统上安装了 Git,你会想要做几件事来定制你的 Git 环境。 每台计算机上只需要配置一次,程序升级时会保留配置信息。 你可以在任何时候再次通过运行命令来修改它们。
- Git 自带一个
git config
的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:
/etc/gitconfig
文件: 包含系统上每一个用户及他们仓库的通用配置。 如果在执行git config
时带上--system
选项,那么它就会读写该文件中的配置变量。 (由于它是系统配置文件,因此你需要管理员或超级用户权限来修改它。)~/.gitconfig
或~/.config/git/config
文件:只针对当前用户。 你可以传递--global
选项让 Git 读写此文件,这会对你系统上 所有 的仓库生效。- 当前使用仓库的 Git 目录中的
config
文件(即.git/config
):针对该仓库。 你可以传递--local
选项让 Git 强制读写此文件,虽然默认情况下用的就是它。 (当然,你需要进入某个 Git 仓库中才能让该选项生效。)
- 每一个级别会覆盖上一级别的配置,所以
.git/config
的配置变量会覆盖/etc/gitconfig
中的配置变量。 - 在 Windows 系统中,Git 会查找
$HOME
目录下(一般情况下是C:\Users\$USER
)的.gitconfig
文件。 Git 同样也会寻找/etc/gitconfig
文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。 如果你在 Windows 上使用 Git 2.x 以后的版本,那么还有一个系统级的配置文件,Windows XP 上在C:\Documents and Settings\All Users\Application Data\Git\config
,Windows Vista 及其以后的版本在C:\ProgramData\Git\config
。此文件只能以管理员权限通过git config -f <file>
来修改。 - 你可以通过以下命令查看所有的配置以及它们所在的文件:
$ git config --list --show-origin
2. 用户信息
- 安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改:
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com
- 再次强调,如果使用了
--global
选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有--global
选项的命令来配置。 - 很多 GUI 工具都会在第一次运行时帮助你配置这些信息。
3. 文本编辑器
- 既然用户信息已经设置完毕,你可以配置默认文本编辑器了,当 Git 需要你输入信息时会调用它。 如果未配置,Git 会使用操作系统默认的文本编辑器。
- 如果你想使用不同的文本编辑器,例如 Emacs,可以这样做:
$ git config --global core.editor emacs
- 在 Windows 系统上,如果你想要使用别的文本编辑器,那么必须指定可执行文件的完整路径。 它可能随你的编辑器的打包方式而不同。
- 对于 Notepad++,一个流行的代码编辑器来说,你可能想要使用 32 位的版本, 因为在本书编写时 64 位的版本尚不支持所有的插件。 如果你在使用 32 位的 Windows 系统,或在 64 位系统上使用 64 位的编辑器,那么你需要输入如下命令:
$ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
Note |
Vim、Emacs 和 Notepad++ 都是流行的文本编辑器,通常程序员们会在 Linux 和 macOS 这类基于 Unix 的系统或 Windows 系统上使用它们。 如果你在使用其他的或 32 位版本的编辑器,请在 git config core.editor 命令 中查看设置为该编辑器的具体步骤。 |
Warning |
如果你不这样设置编辑器,那么当 Git 试图启动它时你可能会被弄糊涂、不知所措。 例如,在 Windows 上 Git 在开始编辑时可能会过早地结束。 |
4. 检查配置信息
- 如果想要检查你的配置,可以使用
git config --list
命令来列出所有 Git 当时能找到的配置:
$ git config --list user.name=John Doe user.email=johndoe@example.com color.status=auto color.branch=auto color.interactive=auto color.diff=auto ...
- 你可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:
/etc/gitconfig
与~/.gitconfig
)。 这种情况下,Git 会使用它找到的每一个变量的最后一个配置。 - 你可以通过输入
git config <key>
: 来检查 Git 的某一项配置:
$ git config user.name John Doe
Note |
由于 Git 会从多个文件中读取同一配置变量的不同值,因此你可能会在其中看到意料之外的值而不知道为什么。 此时,你可以查询 Git 中该变量的 原始 值,它会告诉你哪一个配置文件最后设置了该值: $ git config --show-origin rerere.autoUpdate file:/home/johndoe/.gitconfig false |
获取帮助
- 若你使用 Git 时需要获取帮助,有三种等价的方法可以找到 Git 命令的综合手册(manpage):
$ git help <verb> $ git <verb> --help $ man git-<verb>
- 例如,要想获得
git config
命令的手册,执行
$ git help config
- 这些命令很棒,因为你随时随地可以使用而无需联网。 如果你觉得手册或者本书的内容还不够用,你可以尝试在 Freenode IRC 服务器 https://freenode.net 上的
#git
或#github
频道寻求帮助。 这些频道经常有上百人在线,他们都精通 Git 并且乐于助人。 - ⭐此外,如果你不需要全面的手册,只需要可用选项的快速参考,那么可以用
-h
选项获得更简明的 ``help'' 输出:
$ git add -h usage: git add [<options>] [--] <pathspec>... -n, --dry-run dry run -v, --verbose be verbose -i, --interactive interactive picking -p, --patch select hunks interactively -e, --edit edit current diff and apply -f, --force allow adding otherwise ignored files -u, --update update tracked files --renormalize renormalize EOL of tracked files (implies -u) -N, --intent-to-add record only the fact that the path will be added later -A, --all add changes from all tracked and untracked files --ignore-removal ignore paths removed in the working tree (same as --no-all) --refresh don't add, only refresh the index --ignore-errors just skip files which cannot be added because of errors --ignore-missing check if - even missing - files are ignored in dry run --chmod (+|-)x override the executable bit of the listed files