type
status
date
slug
summary
tags
category
icon
password
如果你是一枚 Coder,但是你不知道 Git,那么你就不是一个菜鸟级别的 Coder,因为你压根不是真正的 Coder,你只是一个 Code 搬运工。但是你如果已经在读这篇文章了,你就已经知道 Git 了。正是 Git & GitHub,让社会化编程成为现实。
版本控制系统
什么是版本控制系统?我为什么要关心它呢?
“版本控制系统是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。 在本书所展示的例子中,我们对保存着软件源代码的文件作版本控制,但实际上,你可以对任何类型的文件进行版本控制。” ——《Pro Git》
关于版本控制
在现实的开发场合中,我们常常会遇到数据文件的备份,保存,以及同步的问题。你可以想象这样的场合:
你在一个研究小组中,小组里的每个人都需要根据自己的分工完成同一份实验报告。一天前,A 同学给你发了一份他本地修改过的报告,你于是在他的基础上完成你的部分。第二天,C 同学把他的报告和 D 同学的报告合并之后又发给了 A 同学,A 同学修改完之后又发给了你,一来一回,你发现你又要重写你负责的部分……
或者,你正在参加一个比赛,时间还很多,你准备优化一部分代码,然后添加一些新功能。调着调着,比赛还剩下半小时,可是新的部分却依然没有调好……无奈之下,你依稀记得你给之前的代码做了备份,可是看着电脑里
新建文件夹 (1)
新建文件夹 (2)
新建文件夹 (3)
新建文件夹 (4)
新建文件夹 (5)
,你陷入了沉思……其实,在上面的例子中,我们就已经涉及到了最简单的本地版本控制系统,也就是手动复制文件夹备份的方法。
但是,这种方法往往显得不那么智能,虽然你可以为文件夹打上备注,但也特别容易犯错。比如一不小心删除了重要文件,混淆了当前的工作目录等。
但更大的问题是,当你和不同人共同完成一个项目时,项目的文件该如何以一种合理的方式保持同步?(显然 QQ 群传文件并不是一个好方法)
现代的版本控制系统可以帮助您轻松地(甚至自动地)回答以下问题:
- 当前模块是谁编写的?
- 这个文件的这一行是什么时候被编辑的?是谁作出的修改?修改原因是什么呢?
- 最近的 1000 个版本中,何时/为什么导致了单元测试失败?
基于快照的版本控制系统
我们首先来看看基于差异的版本控制系统。
- 相比于复制备份,基于差异的版本控制系统大大缩小了需要的储存空间。
- 回退版本时需要从头开始一步步回溯,如果文件在版本系统不知晓的情况下修改,所有备份将会损坏丢失。
而在 Git 所管理的项目中,Git 会保存每一个文件的镜像,同时管理一份指向修改前的文件和修改后的文件的索引(类似于指针)。我们在每次向 Git 提交文件时,Git 就会帮我们保存一份文件的镜像(压缩后)和指向它的索引,所以我们称 Git 是基于快照的版本控制系统(甚至可以说 Git 帮我们维护了一个小型的文件系统)。
这样做有很多好处,比如:
- 保留了差异式系统所需储存空间小的优点。
- 用户提交新快照时,若文件没有更改,Git 可以直接添加旧的镜像索引到新的提交中。
- 所有提交都可以在极短时间内完成回溯。
- 由于 Git 会给所有管理的对象计算 SHA1 校验和(SHA-1 算法特性),以保证文件的完整性。
- 在用户的所有操作中,几乎都只是向 Git 中添加数据,很少有可能造成数据丢失(所以建议在 Git 储存库中不要存入敏感信息)。
哈希算法示例:
一些 Git 概念
- blob:Git 的基本储存单元之一,是最简单的对象,一般是文本文件,但也可以是其他内容。
- tree:其引用 blob 形成目录,同时也可以引用其他 tree 作为子目录。
- commit:向 DAG 图中添加一个节点(快照),这个节点指向表示提交时文件状态的 tree。
- ref:类似于指针(便利贴)的作用(给节点的哈希值一个名字),指向当前 DAG 图的状态或者你处于的位置。
- HEAD:特殊的一个标签,用于指代你的当前储存库在 DAG 图中所处于的位置。
- master:Git 默认创建的分支名称。
- <remote>:用于指代远程 Git 服务器所处于的位置。
- <branch>:用于指代 DAG 图中分支的标签。
Git 实质上是一个含有所有历史快照的 DAG 图(有向无环图)。
一个常见的 Git 分支图,每个点代表了一个 commit,不同行代表所处的不同分支。
不难看出,Git 只是帮我们保存并维护了两样东西:对象和引用。
Git 的安装与配置
参考 Git 官方中文教程。
OR:
自带 Git 和一个非常美观的 GUI 😳
命令行操作与技巧
Git 流程
Add / Commit
Example:
Branch / Checkout / Switch
Example:
Merge / Rebase
Example:
Fast-forward:
当两个分支在同一条未分支的路径上时,Git 会尝试直接移动分支标签进行合并,而不是创建一个新的 commit。
Merge 和 Rebase
两种不同的合并方法,相比于 merge,rebase 在合并时相当于直接把待合并的分支嫁接在了主分支的顶部。
Oh my god it's a conflict!
有时候合并的两个分支含有冲突的内容,Git 会尝试帮我们自动合并,但在无法自动合并时,Git 就会提示我们手动解决冲突。
这是文件合并时遇到冲突时的样子,请不要害怕,这并不意味着我们的文件损坏了,他只是标记了我们需要手动解决冲突的位置。
这是一种标注文件内容差异的格式:GNU-diff。
有些比较智能的 IDE 或者编辑器会将它们标记出来,如 VSCode 会将其显示成这样子:
我们既可以手动删除不需要的部分,也可以通过 IDE 或者其他图形化的合并工具帮助我们解决冲突,再重新 merge。
Clone / Pull / Push
有时候我们需要和他人进行协作,我们就需要从远端获取我们的代码仓库,这时就需要使用 pull 和 push 了。
Example:
注意:如果你的仓库是由
git init
初始化的,则需要手动添加一下远程 Git 服务器的地址;如果是 git clone
下来的,则远程服务器名称默认为 origin,地址默认为你 clone 时的地址。Log
有时候你忘记了之前的操作,或者想要查看一下当前仓库的历史状态,则可以使用 Git 的 log 功能。
Example:
输出示例
其它
一些很有意思的命令:
git blame
git cherrypick
...进一步了解 Git:
Submodules
Git 的 submodule 功能允许你将一个 Git 仓库作为另一个 Git 仓库的子模块(submodule)包含进来。这在管理大型项目时非常有用,特别是当你需要将多个项目组合在一起时。
Git & GitHub 历史
Git 的历史始于 Linux 内核开源项目的发展需求。在 1991 年至 2002 年间,Linux 内核的维护工作非常繁琐,主要依赖于提交补丁和保存归档。到了 2002 年,Linux 内核项目开始使用一个名为 BitKeeper 的专有分布式版本控制系统来管理代码。然而,到了 2005 年,由于 Linux 内核社区与 BitKeeper 的开发公司 BitMover 的合作关系结束,BitMover 收回了对 Linux 社区的免费授权,这迫使 Linux 社区必须寻找新的版本控制系统。
Linux 的缔造者 Linus Torvalds 决定开发自己的版本控制系统,这就是 Git。Git 的开发目标包括速度、简单的设计、对非线性开发模式的支持、完全分布式,以及能够高效管理大规模项目的能力。Git 在 2005 年诞生,它的发展非常迅速,很快就成为了 Linux 内核的版本控制系统,并逐渐被广泛接受和使用。
Git 的核心理念是分布式版本控制,与传统的集中式版本控制系统不同,Git 允许开发者在本地工作,并且可以在不同的设备之间同步代码,而不需要依赖中央服务器。这种设计使得 Git 在处理大规模项目时更为高效,并且具有更好的网络连接稳定性。
Git 的成功部分归功于它解决了开发者在版本控制中遇到的问题,提供了简单可靠的备份,并允许生成私有的仓库,而不用担心中央仓库的权限问题。此外,Git 的分布式特性和高效的分支管理使得它非常适合大型项目和快速迭代的开发流程。
随着时间的推移,Git 不断成熟和完善,它的易用性不断提高,功能也不断增强。2008 年,GitHub 的上线进一步推动了 Git 的普及,GitHub 为开源项目提供了免费的 Git 存储服务,吸引了大量的开发者和项目迁移到 Git 平台。
GitHub 是一个基于 Git 的版本控制和协作平台,它允许用户托管和管理代码,以及跟踪任务和增强团队合作。GitHub 由 Chris Wanstrath、PJ Hyett 和 Tom Preston-Werner 在 2008 年创立,现在是微软的一部分。
参与开源项目
如何参与 GitHub 上的开源项目?
- Step 1. 把仓库 fork 到自己的账户下(获得对代码的修改权)。
- Step 2. 把自己 fork 的 repo 克隆到本地并进行修改(建议新建一个自己的分支)。
- Step 3. 推送自己的修改,并在原项目页面上提交一个
Pull Request
,附上自己修改的简要介绍,等待原作者合并你的修改。
- Step 4. 作者可能会提出一些问题或者修改建议,此时注意网上交流礼仪。
- Step 5. 等到作者认为合适之后,会将你的修改合并到主分支中,于是你就成功参与了一个开源项目啦!
通俗易懂的动画教程
- 作者:DrimTech
- 链接:https://drim.cc/git-tutorial
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。