Git:掌握版本控制的指南
Git 是一个分布式版本控制系统。Linux 的创建者 Linus Torvalds 仅用 5 天就编写了自己的版本控制系统 Git。多年来,它迅速传播开来,成为全球开发人员的首选版本控制工具。
在 Git 出现之前,Linus 和许多其他开源开发人员都使用过专有版本控制系统 BitKeeper。然而,当 BitKeeper 与开源社区的关系恶化时,Linus 决定创建自己的解决方案。因此,Git 诞生了,其设计目标是快速、可靠和开源。
Git 允许您使用命令轻松地搜索、操作和恢复历史记录。
Git 的效率和灵活性彻底改变了开发人员在软件项目中协作、管理代码和维护历史记录的方式。
瓷器和水管命令
Git 使用两种类型的命令进行操作:**porcelain** 和 **plumbing**。
瓷器命令示例:
管道命令示例:
虽然日常 Git 交互中会用到瓷器命令(它们占了你要使用的命令的 99%),但管道命令可以让开发人员和高级用户更好地控制系统的操作。我们将在这篇文章中讨论一些重要的命令。
要安装 Git,请访问 Git --distributed-even-if-your-workflow-isnt。
安装后,你可以使用以下命令检查 Git 的版本:
git --version
**RTFM**,即“阅读该死的/友好的手册”,是开发者社区中常见的一句话,鼓励您查阅文档以获取详细信息。在 Git 中,您可以通过运行以下命令来访问其手册:
man git
该手册提供了有关 Git 命令、选项和用法的全面信息,以帮助您更好地了解如何有效地使用 Git。
Linus 创建 Git 是因为与 BitKeeper 的许可协议禁止对该软件进行逆向工程,因为它是专有的。然而,Linux 组织中的某个人违反了此协议,导致 BitKeeper 撤销了许可证。作为回应,Linus 创建了 Git 作为替代方案。
配置 Git
Git 配置可以在多个级别进行:全局(适用于所有存储库)或本地(特定于存储库)。配置文件可以位于用户的主目录(`~/.gitconfig`)中,也可以位于特定存储库的 `.git` 文件夹中。
要设置和配置您的 Git 存储库,请按照以下步骤操作:
**检查当前配置:**
**添加全局配置(设置用户名和电子邮件):**
**设置默认分支名称:**
**检查全局配置文件:**
这些命令设置您的 Git 配置,以确保正确跟踪提交、所有存储库中的一致用户身份以及新存储库的默认行为设置。
Git 存储库
**Git 存储库** 是存储所有项目文件和版本历史记录的地方。项目文件夹内的 `.git` 目录包含所有内部跟踪和版本信息,例如提交、分支和配置。
git init
要初始化新的 Git 存储库,请使用:
git init
此命令创建“ .git”目录,将您的项目文件夹转变为 Git 存储库,并允许您开始跟踪更改。
Git 状态
在 Git 中,文件的生命周期可以分为几个阶段:
Working Directory +---------------------+ | | | Untracked Files | <-- Files not added to Git | | | Staged Files | <-- Files added with `git add` | | +---------------------+ | v +---------------------+ | | | Committed Files | <-- Files saved in Git history | | +---------------------+
要查看存储库的当前状态,包括所有文件的状态,您可以使用:
git status
此命令显示哪些文件未跟踪、暂存或有需要提交的更改。这是跟踪工作进度的有用方法。
分期
在 Git 中,暂存是指在提交文件之前将文件添加到暂存区的过程。暂存区就像是下一次提交将包含的内容的预览。
要暂存特定文件,您可以使用:
git add i-use-arch.btw
或者,如果您想要暂存所有修改过的或新的文件,您可以使用:
git add .
这会为下一次提交的更改做好准备,让您可以控制包含哪些更改。
承诺
在 Git 中,**提交** 是在特定时间点保存存储库快照的过程。每次提交都包含一条描述所做更改的提交消息。
要创建提交,请使用:
git commit -m "your message here"
这会将暂存区的当前状态存储为带有所提供消息的提交。
如果您想更改**最后一次提交**的消息,您可以使用:
git commit --amend -m "new message"
这使您可以更新最后的提交消息而无需创建新的提交。
你已经学习了 Git 的一半(有点)
到目前为止,您已经了解了管理本地存储库的核心命令。这些是独立开发的基本工具:
这些命令足以让您自己管理项目。但是,Git 还可以提供更多功能来增强协作和版本控制。
但是通过您目前所学的知识,您已经能够熟练使用 Git 进行单独开发了!
Git 日志
`git log` 命令对于查看存储库中的提交历史记录至关重要。它允许您查看每次提交的执行者、提交时间以及引入了哪些更改。以下是 `git log` 中使用的常用标志的概述:
每个标志都允许您自定义“git log”的输出以满足不同的需求,从而更容易查看提交历史记录并跟踪项目中的更改。
提交哈希 (SHA-1)
提交哈希是使用 SHA-1 哈希算法为 Git 中的每个提交生成的唯一标识符。它用于跟踪存储库中的提交及其更改。
例如:`5ba78624h4i5hslv831c01e71444b9baa2228a4f`
实际上,通常只需要提交哈希的前 7 个字符即可识别它。
提交哈希是以下函数:
由于这些因素,哈希冲突(两个不同的提交具有相同的哈希值)的概率极低,从而确保每个提交都可以被唯一地标识。
让我们看看管道
在 Git 中,**管道** 指的是处理存储库数据存储和组织的内部机制。所有 Git 数据都存储在 `.git` 目录中,该目录隐藏在项目文件夹中。
Git 的文件存储方法有助于确保高效的访问和检索,同时避免系统限制(例如传统文件系统中发现的限制)。
文件系统中的 Inode
为了避免 inode 破坏,Git 采用了一种巧妙的方法:
例子:
如果你查看特定对象,例如:
cat .git/objects/78/asfadfefj8e0r48...
它将打印一堆压缩的原始字节数据。这是对象的内容,Git 以压缩形式存储它以节省空间并缩小 `.git` 目录。
Git 使用这个对象存储系统来有效地管理和跟踪变化,同时保持高度优化的文件结构。
内置管道命令:git cat-file
Git 提供了内置的管道命令来访问存储库的原始内部数据。其中一个命令是 **git cat-file**,它允许您通过哈希值与 Git 对象进行交互。
git cat 文件 -p
git cat-file -p
这将以可读格式显示对象(提交、树或 blob)的内容。
文件的十六进制转储
要查看 Git 中文件对象的原始二进制内容,可以使用 `xxd` 将其转换为十六进制格式:
xxd path/to/file > /tmp/commit_object_hex.txt
这将生成指定文件的十六进制转储并将其保存到“/tmp/commit_object_hex.txt”文件中。
Git 对象的类型
提交、树、Blob 和内容之间的关系
**提交** 包含:
示例结构:
Commit → Tree → Blob → Contents (A) → (tree) → (blob) → contents.md
Git 日志中的父哈希
管道与瓷器命令
通过了解 **trees** 和 **blob** 的工作原理,您可以更深入地了解 Git 如何组织和存储数据。这种内部结构有助于 Git 高效地管理更改,同时保持存储库轻量级。
在 Git 中存储数据
Git 不仅仅存储更改;它还存储每次提交中所有文件的**完整快照**。每次提交都会捕获当时项目的完整状态,而不仅仅是差异。
通过压缩提高效率
Git 使用 **压缩** 来最小化 `.git` 目录的大小,这有助于减少存储需求。得益于 Git 的内部机制,即使是大文件也能高效存储。
树对象和 Blob
每次提交都会存储一个唯一的 **树对象**,它是目录的快照。虽然每次提交都会创建一个新树,但 Git 不会再次存储未更改的文件。相反,它会 **指向先前提交的现有 blob**(文件),从而减少重复并提高流程效率。
删除后续提交的文件
如果在后续提交中删除了文件,则这些文件的 **哈希值** 将指向 null。这会在历史记录中创建断开的链接。要清理这些引用,您可以 **修剪** 存储库以删除未使用的对象并减小大小。
修剪和清理
您可以使用以下命令修剪断开的链接并优化存储库:
git gc --prune=now
这有助于删除未引用的对象并保持存储库更小。
再次配置 Git
Git 提供多级配置,允许您全局、本地或针对特定工作树设置配置选项。以下概述了如何管理和与 Git 配置交互。
Git 配置命令
git config --list --local cat .git/config
git config --get
git config --unset
git config --unset-all example.key
(注意:Git 只会应用配置文件中键的最后一次出现,因此如果有重复,则最后一个键将优先。)
git config --remove-section section
配置文件位置
Git 配置文件可以存在于多个地方,每个地方都有不同的作用域:
Git 分支
Git 中的分支本质上是指向特定提交的 **命名指针**。创建分支时,实际上是在创建一个跟踪特定提交的新指针。分支指向的提交称为分支的 **尖端**。分支是轻量级的,因为它们只是指针,不需要复制整个项目,因此是一种资源节约型的创建方式。
常用命令
git branch -m oldname newname
git branch my_new_feature
git switch -c my_new_feature
git switch my_existing_feature
或者,按照老方法:
git checkout my_existing_feature
分支机构信息存储
Git 将有关分支的所有信息存储在项目根目录 `.git` 子目录中的文件中。分支的“heads”(或“tip”)专门存储在 `.git/refs/heads/` 目录中。
合并分支
为了找到两个分支之间最佳的共同祖先提交(合并基),Git 将使用 **合并基** 来识别要合并的共同提交点。例如:
git merge my_feature_branch
修改提交信息
如果你需要更改最后一次提交的消息,你可以使用 `--amend` 标志:
git commit --amend -m "Updated commit message"
快进合并
在**快速合并**中,如果功能分支具有基础分支的所有提交,则 Git 将简单地将基础分支的指针移动到功能分支的尖端。例如:
git merge my_feature_branch
删除分支
完成分支后,可以使用以下方法删除它:
git branch -d my_feature_branch
如果分支已合并,这将在本地删除该分支。如果分支尚未合并,请使用 `-D` 强制删除。
团队开发的常见 Git 工作流程
Git 中的 Rebase
变基是一种将一系列提交移动或合并到新的基准提交的方法。与合并相比,它有助于维护更清晰、更线性的历史记录。
考虑以下场景:
A - B - C main \ D - E feature_branch
您正在处理“feature_branch”,并且想要从“main”引入最新更改以避免使用过时的代码。您可以将“main”合并到“feature_branch”,但这会引入合并提交,从而可能使历史记录混乱。相反,**rebase** 会将“feature_branch”中的提交重新应用于“main”之上,从而创建线性历史记录。
运行以下 rebase 命令后:
git rebase main
历史将会像这样:
A - B - C main \ D' - E' feature_branch
请注意,提交“D”和“E”已被重写为“D'”和“E'”,因为“feature_branch”的历史记录现在基于“main”中的提交“C”。这就是提交哈希在重新定基后发生变化的原因——这些提交的基础已经转移。
为什么要使用 Rebase?
但是,变基会重写提交历史,因此应谨慎使用。
重要提示:
切换分支的示例:
如果您需要从历史记录中的特定提交分支,则可以使用以下命令:
git switch -c new_feature
这将从由以下标识的提交中创建一个名为“new_feature”的新分支:`。
在共享分支上使用 rebase 时要小心,因为它会改变提交历史。
您可能想知道的一些术语
Git Reset:撤消更改
`git reset` 命令用于撤消存储库中的更改。它将当前分支指针移动到不同的提交,并可能影响暂存区和工作目录。
重置类型
例子:
git reset --soft HEAD~2
git reset --hard abc1234
警告:
.gitignore
`.gitignore` 文件是一个**隐藏文件**(以点开头),用于告诉 Git 忽略项目中的哪些文件或目录。它用于防止在版本控制中跟踪不必要或敏感的文件(例如构建工件、日志或配置文件)。
工作原理:
例子:
*.log
logs/*.tmp
在这种情况下,存储库中所有位置的 `*.log` 文件将被忽略,但只有 `logs/` 目录中的 `*.tmp` 文件会被忽略。
要点:
示例结构:
/project-root .gitignore # ignores *.log globally /logs .gitignore # ignores *.tmp in the logs directory error.log # will be ignored because of the global .gitignore temp.tmp # will be ignored because of the subdirectory .gitignore
这种灵活性有助于管理哪些文件应该被跟踪以及哪些文件应该保留在开发环境中。
在向有经验的人询问之前,请务必**RTFM**(阅读手册)。了解基础知识并参考官方文档不仅可以节省您的时间,还可以帮助您更彻底地掌握概念。
每周复习一次 Git 以保持技能的敏锐,最好的方法是将 Git 集成到您正在从事的项目中。通过定期使用它,您将更加熟悉高级功能和工作流程,这将使版本控制成为您的第二天性。
这是本系列的第 1 部分,第 2 部分即将推出!请继续关注有关掌握 Git 的更多见解。