Git和版本管理
参考
版本控制系统的基本需求
将版本控制比作一个时间机器,将项目放到这样一个时间轴上,我们可以随时回到任何一个特定的版本。

版本控制时间轴
为了实现这一点,需要记录每个版本的完整信息,方便快速回到对应版本,这种方式称为全量方案。

全量方案
对于代码和文本这类字符型内容,全量方案更为适用,因为它们占用的空间相对较小。而对于视频和大型二进制内容,增量方案能更好地节省空间。
Git选择将所有版本信息放在项目根目录的 .git
文件夹中。
Warning发布网站时,不要将.git
目录发布出去,因为.git
文件夹中包含着整个版本信息,包括源代码和可能存在的账号密码,都可以通过这个.git
目录访问到。
Git使用文件的 SHA1
值作为文件名,SHA1
和 MD5
都是哈希函数,通过计算文件内容提取较短的哈希值,保证版本库中所有相同内容的文件只保存一份。
tree结构和暂存区
tree 结构
在Git中,标记为 tree
的是目录,blob
是文件。

tree结构
如果子目录中的文件修改了,文件的 SHA1
值会发生变化,那么文件夹的 SHA1
值也会发生变化,这些值的变动会保存到新的文件中,从而完成更新内容的信息存储。

子目录变化
文件内容会保存到 Objects
目录中。对于内容非常大的文件,Git使用哈希值的前两位来管理文件。

Objects管理
如果自动提交会生成很多无用版本,因此建议使用手动操作。

手动操作
暂存区
git add . # 将目录添加到暂存区
git commit . # 将暂存区的文件提交到 .git 目录中

暂存区操作
文件状态判断:
- 如果文件在代码和暂存区中,但SHA1值不匹配,则文件已修改。
- 如果文件不在代码中但在暂存区中,则文件已删除。
- 如果文件在代码中但不在暂存区中,则文件是新增的。

文件状态判断
对比暂存区和 .git
也能知道文件的状态。

暂存区与 .git 对比
文件从暂存区提交到Git中会产生一个快照,描述当前文件夹下所有文件的状态。

快照生成
不断提交操作会产生多个快照,形成一个链表。使用指针 HEAD
指向最新快照,当需要某个快照时,将 HEAD
指针指向该快照,然后 checkout
即可恢复工作区内容。

指针与快照
协同和分支
网络问题
团队环境下,代码仓库应放在服务器上,集中访问。若网络出现问题,无法同步版本管理,可以在主机上放置一个Git版本管理软件,待网络恢复后再将本地版本上传至服务器。

网络问题
如果服务器上有不同部分需要分别修改,两个工程师将文件同步到本地仓库后,根据需求修改文件,服务器端可以很容易同步不同文件的修改。

文件同步
文件问题
若同时修改相同文件,会产生冲突。第一位同事先提交,服务器正常接受,第二位同事提交时,产生冲突,需手动解决冲突后再提交。

冲突解决
分支
为了管理不同功能或开发者的工作,可以使用分支。假设生产环境是 online
,开发环境是 dev
,在开发分支内测公测完后合并到 online
,保证线上代码的稳定性,同时能将测试代码 checkout
到分支环境。

分支管理
合并
Merge
找到两个分支的共同祖先,进行三方合并,合并后的提交叫 Merge。
git checkout wechat
git merge weibo

Merge
Rebase
git checkout weibo
git rebase wechat
Git会找到共同提交,撤销微博线的提交并保存到临时目录,将 wechat
的提交应用到 weibo
分支中,形成新的 weibo
分支。

Rebase
Cherry-pick
在 wechat
分支上只想合并 weibo
分支的某些特定提交,可以使用 cherry-pick
。
git checkout wechat
git cherry-pick 324e

Cherry-pick
回顾
Git采用全量存储方式保存历史文件,历史版本库中包含完整信息,存储在 .git
目录中。文件内容的 SHA1
值作为名称,相同文件只存储一份,通过内容寻址。Git定义了 tree
目录结构描述和容纳目录及文件的 SHA1
值,暂存区作为源代码和版本库之间的中间层,当暂存区内的代码上传到版本库时,会产生新的提交(commit
),多个提交形成链表,使用 checkout
对应的链表值,可以回到对应的版本。Git提供了分支概念,支持在不同分支下进行工作,最终合并到 master
上。在本地仓库和远程仓库之间,网络状态良好时提交到远程仓库中。对于合并,使用 Merge
和 Rebase
两种方式,Rebase
修改提交历史,建议在本地使用。通过分支管理,可以实现不同功能或开发者的独立工作,并在最终合并到主分支当中。

总结
Git 常用命令
本地仓库相关
git init #使用git初始化命令

image.png
git add a.txt # 将a.txt 添加到暂存区
git add . # 将当前目录添加到暂存区

image.png
git reset a.txt #将文件移出暂存区
cd .git && ls -lha
cd objects && ls -lha

image.png

image.png
#git 查看文件内容
git cat-file -p 7a22f4fd0865519b0abfeca803b051260866b5cd
#需要将文件名22f4fd0865519b0abfeca803b051260866b5cd 与上一级的文件目录 7a 拼接起来

image.png
#git 查看暂存区中的文件
git ls-files --stage

image.png
#git 通过commit 命令提交内容
git commit -m "first push"

image.png
#创建新分支
git branch dev
git checkout dev #切换到dev分支
git commit -m "dev"

image.png
# checkout 回master ,创建ops 分支,切换到ops分支
git checkout master && git branch ops && git checkout ops
# checkout 回master,合并dev分支
git checkout master && git merge dev

image.png
#放弃合并
git merge --about
# 再次提交
git add a.txt && git commit -m "merged"
# 查看日志
git log
# 这里面是完整的hash值,可以git checkout sha1值,来切换到对应的版本信息
git log sha1

image.png
远程仓库相关
#首先先在github上创建一个项目
git remote add origin url
# 上传到github上
git push -u origin main
# 从github上拉代码下来
git pull
# 查看远程仓库配置
git remote
git remote show origin
# 修改远程仓库配置
git remote remove origin
git remote add origin url
git push
# 将修改的内容缓存起来
git stash
git stash apply
git stash list
git stash show