Git 之旅

AndroidRain

共 3609字,需浏览 8分钟

 ·

2020-12-24 19:04

初期形态

代码管理的最早形态是使用类似现在百度同步盘的方式同步、管理代码。但是代码冲突问题时有发生,只能人工解决。

之后出现了改善工具:

diff:比较文本文件、目录差异patch:相当于 diff 反向操作

# 生成差异文件diff -u hello1 hello2 > diff.txt
# 根据 hello1、diff 生成 hello2cp hello1 hello3patch hello3 < diff.txt
# 根据 hello2、diff 生成 hello1cp hello2 hello4patch -R hello4 < diff.txt

Linus 在 1991~2002 年使用 diff、patch 维护 Linux 代码差异。

diff、patch 缺陷:无法处理二进制文件。Git 解决了此问题。

开山鼻祖 CVS Concurrent Versions System

CVS(ConcurrentVersionsSystem)诞生于1985年,是由荷兰阿姆斯特丹 VU 大学的 DickGrune 教授实现的。当时 DickGrune 和两个学生共同开发一个项目,但是三个人的工作时间无法协调到一起,迫切需要一个记录和协同开发的工具软件。于是 DickGrune 通过脚本语言对 RCS(Revision Control System)(一个针对单独文件的版本管理工具)进行封装,设计出有史以来第一个被大规模使用的版本控制工具。

—— 蒋鑫. Git权威指南 (Chinese Edition) (Kindle 位置 559-562). 机械工业出版社. Kindle 版本.

CVS 存在的问题:

创建 tag、branch 效率低tag、branch 分散在 RCS 文件中,不可见缺乏对合并的追踪,会导致重复合并不支持原子提交,会导致提交数据不完整

CVS 成功地为后来的版本控制系统确立了标准,像提交说明(commitlog)、检入(checkin)、检出(checkout)、里程碑(tag)、分支(branch)等概念在CVS中早就已经确立。

—— 蒋鑫. Git权威指南 (Chinese Edition) (Kindle 位置 578-579). 机械工业出版社.

SVN Subversion

SVN 优化了很多特性,如:

实现了原子提交:SVN 不会像 CVS 那样出现文件的部分内容被提交而其余的内容没有被提交的情况全局版本号:和 CVS 每个文件都拥有一个版本号相比,便捷许多文件轻拷贝:里程碑和分支创建速度加快很多

这些优化也使得它在版本控制工具中成为最佳选择之一。但 SVN 本质上是一种集中式版本管理工具,这种版本控制太依赖于服务器,如果服务器出现问题,版本控制将不可用;如果网络较差,提交代码将变得十分漫长。

除了以上集中式版本控制系统固有问题之外,再加上 SVN 本身设计的一些问题,使用其进行版本管理也并存在很多不如意之处。比如:

项目文件在版本库中必须按照一定的目录结构进行部署,否则就可能无法建立里程碑和分支创建里程碑和分支会破坏精心设计的授权分支太随意从而导致混乱。SVN 的分支创建非常随意:可以基于 /trunk 目录创建分支,也可以基于其他任何目录创建分支,因此 SVN 很难画出一个有意义的分支图。再加上一次提交可以同时包含针对不同分支的文件变更,使得事情变得更糟

Git

BitKeeper 和 Git 由来

BitKeeper 是一种分布式版本控制系统。分布式版本控制系统优势:不要中央版本库,每个人都可以自己本地查看提交日志、提交、创建里程碑和分支、合并分支、回退等操作,而不需要网络连接。

分布式版本控制系统和集中式版本控制系统区别粗略的讲,就像是分封制和郡县制的区别。

假设现在要书写史书,集中式即郡县制,郡县制背后是强大的中央集权,相当于中央的史书绝对权威,各个郡县对史书进行修改后必须上报中央才能生效。距离首都近的城市还好,提交修改十分便捷,如果海南要提交对史书的修改,得数月才能跑到首都,进行修改。要想拉取新的分支,写写野史,必须先上报中央,批准后才能进行。这里的离首都的距离,就相当于网速,任何修改、提交、拉分支必须经过网络和中央仓库交互后才能进行。

分布式则相当于春秋战国时期,诸侯做大,诸侯每个人都有一份史书,都可以在自己的国家进行修改。任何修改的提交,甚至想要创建新的分支,写写野史,也无须上报周天子,在自家就可以完成。想同步到周天子时再派人去周天子那里同步一下即可。

这就是集中式和分布式版本控制系统的根本区别。

2005 年发生的一件事最终导致了 Git 的诞生。在 2005 年 4 月,AndrewTridgell[1](即大名鼎鼎的 Samba - Wikipedia[2] 的作者)试图对 BitKeeper 进行反向工程,以开发一个能与 BitKeeper 交互的开源工具。这激怒了 BitKeeper 软件的所有者 BitMover 公司,要求收回对 Linux 社区免费使用 BitKeeper 的授权。迫不得已,Linus 选择了自己开发一个分布式版本控制工具以替代 BitKeeper。

—— 蒋鑫. Git权威指南 (Chinese Edition) (Kindle 位置 663-666). 机械工业出版社. Kindle 版本.

基本知识

工作区 Workspace暂存区 Index/Stage仓库 Repository远程仓库 Remote

目录结构

mkdir democd demogit initls -l .git
# output# # config# description# HEAD# hooks/# info/# objects/# refs/

description 文件仅供 GitWeb 程序使用,我们无需关心config 文件包含项目特有的配置选项info 目录包含一个全局性排除(global exclude)文件, 用以放置那些不希望被记录在 .gitignore 文件中的忽略模式(ignored patterns)hooks 目录包含客户端或服务端的钩子脚本(hook scripts)

剩下的四个文件很重要,是 Git 的核心组成部分:

HEAD 文件:指向目前被检出的分支index 文件:保存暂存区信息objects 目录:存储所有数据内容refs 目录:存储指向数据(分支 heads、远程仓库 remotes/origin 和标签 tags 等)的提交对象的指针

接下来通过拆解 git addgit commitgit checkout 命令,结合 HEADrefs/heads/masterobjects/ 文件变化,探索一下 Git 的背后。

实践操作

git checkout : HEAD

cat .git/HEAD# output# ref: refs/heads/master
git checkout -b test
cat .git/HEAD# output# ref: refs/heads/test

git add filename : 工作区文件添加到暂存区


# 生成 objectgit hash-object -w filename
# 添加到暂存区git update-index --add filename
# 上述两个命令相当于git add filename
# 查看暂存区git ls-files --stage
# 上述命令相当于git status

git commit : 将暂存区文件提交


# 保存当前目录结构git write-tree
# 保存快照 commit,-p 可指定父快照echo "first commit" | git commit-tree 90f3b20385d2b20cf85477a65e4ef7e2eff71353 [-p id]
# git log 无内容,因为当前 HEAD 没有绑定到刚刚提交的快照git log
# HEAD 对应 refs/head/master,将快照 id 放到该文件即可echo 785f188674ef3c6ddc5b516307884e1d551f53ca > .git/refs/heads/master
git log
# 以上命令相当于git commit -m "first commit"

总结

objects/ 中的对象类型

浏览 10
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报