版本控制——深入浅出git

版本控制简述

最简单的版本控制是什么

复制整个项目目录的方式并附加时间后缀

从 本地控制系统——RCS

  • 在硬盘上保存补丁集(补丁是指文件修订前后的变化)
  • 通过应用所有的补丁,可以重新计算出各个版本的文件内容

到 集中化版本控制(svn)

  • 单一的集中管理的服务器,保存所有文件的修订版本
  • 协同工作的人们都通过客户端连接

再到 分布式版本控制系统(git)

  • 客户端不同于只提取最新版本的文件快照,而是把代码仓库完整地镜像下来
  • 可以指定和若干不同的远端代码仓库进行交互

git和其他版本控制的区别

例如svn的很多系统,保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异

版本控制——深入浅出git - 图1


Git则是在保存时,对当时的全部文件制作一个快照并保存这个快照的索引

版本控制——深入浅出git - 图2

产生的优势

  • 近乎所有操作都是本地执行
    • 响应速度很快,无需等待
    • 无需联网即可本地工作
  • 保证完整性,不可能随意更改任何文件内容或目录内容

所有数据在存储前都进行SHA-1 散列(hash,哈希)计算校验

  • 操作只添加数据

git简介

三种状态

  1. 已提交(committed)———— 数据已经安全的保存在本地数据库中
  2. 已修改(modified)———— 修改了文件,但还没保存到数据库中
  3. 已暂存(staged)———— 对已修改文件的当前版本做了标记,使之包含在下次提交的快照中

这三种状态也对应了三个工作区域概念:Git 仓库、工作目录以及暂存区域

版本控制——深入浅出git - 图3

Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。

工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。

暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。

我们的日常git工作流

  1. 在工作目录中修改文件
  2. 暂存文件,将文件的快照放入暂存区域
  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录

对应的git生命周期

版本控制——深入浅出git - 图4

git基本操作

用户相关

安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址

  1. git config --global user.name "BugMaker"
  2. git config --global user.email "BugMaker@example.com"

这样以后每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改

最常用的文件提交操作


  1. # 添加文件至暂存区
  2. git add file
  3. # 添加所有文件至暂存区
  4. git add .
  5. # 移除暂存区的文件并删除目录
  6. git rm file
  7. # 移除暂存区的文件但保留文件
  8. git rm --cached file
  9. # 文件改名
  10. git mv file_from file_to
  11. # 提交暂存区更改
  12. git commit
  13. # 以-m参数的内容进行提交
  14. git commit -m "update file"
  15. # 跳过暂存区直接提交
  16. git commit -a -m "update"
  17. # 查看git状态
  18. git status

status的几种状态

  • new file
  • modified
  • deleted
  • renamed

常用辅助操作


  1. # 查看文件修改
  2. git diff
  3. # 查看提交历史
  4. git log
  5. # 附带参数
  6. # -p 附带文件修改记录
  7. # 通常搭配 -num 限制显示数量
  8. git log -p -2
  9. # 修正提交记录(可以补充文件)
  10. git add forgotten_file
  11. git commit --amend
  12. # 撤销文件
  13. git reset

危险操作 git reset —hard
会丢失当前所有所做的更改!

远程操作

  1. # 查看远程仓库
  2. git remote -v
  3. # 从远程仓库中拉取
  4. git fetch [remote-name]
  5. # 向远程仓库推送
  6. git push [remote-name] [branch-name]
  1. git fetch会访问远程仓库,从中拉取所有你还没有的数据
  2. 并不会自动合并或修改你当前的工作,需要手动合并更改

对于已经设定了远程跟踪的分支,git pull命令来自动的抓取然后合并远程分支到当前分支

  1. git pull => git fetch && git merge

git tag打标签操作,有兴趣的话可以访问git文档进行阅读

git分支

git 分支是什么?

回顾: git保存的是什么?

文件快照

git提交的是什么?

一个包含三部分的对象:

  1. 每一个文件的快照信息
  2. 一个记录着目录结构和索引的树对象
  3. 包含着指向前述树对象的指针和所有信息的提交对象

版本控制——深入浅出git - 图5

我们进行了多次提交后,会利用里面的指针进行索引

版本控制——深入浅出git - 图6

那么回到最初的问题,git的分支的本质是什么


git的分支就是指向提交对象的指针:

Git 的默认分支名字是 master
在多次提交操作之后,master 分支指向最后那个提交对象

  1. # 新建分支
  2. git branch testing

此时我们只是新建了一个可移动的指针

那么git是如何知道我们处在哪个分支上的呢?

git通过HEAD的特殊指针标识你所处分支

版本控制——深入浅出git - 图7

  1. # 分支切换
  2. git checkout testing

分支的合并

快进合并

版本控制——深入浅出git - 图8

  1. $ git checkout master
  2. $ git merge hotfix
  3. Updating f42c576..3a0874c
  4. Fast-forward
  5. index.html | 2 ++
  6. 1 file changed, 2 insertions(+)

在合并时我们看到了快进(Fast-forward),说明当前master分支所指向的提交是当前提交(有关 hotfix 的提交)的直接上游,所以 Git 只是简单的将指针向前移动

版本控制——深入浅出git - 图9

三方合并

我们更多遇到的是要合并的两个分支所做的修改已经产生不同的推进
版本控制——深入浅出git - 图10

  1. $ git checkout master
  2. Switched to branch 'master'
  3. $ git merge iss53
  4. Merge made by the 'recursive' strategy.
  5. index.html | 1 +
  6. 1 file changed, 1 insertion(+)

出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4 和 C5)以及这两个分支的工作祖先(C2),做一个简单的三方合并

版本控制——深入浅出git - 图11

合并后,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交

版本控制——深入浅出git - 图12

Git 会自行决定选取哪一个提交作为最优的共同祖先,并以此作为合并的基础

合并冲突

推荐使用vscode或其他IDE操作…

变基

整合不同的分支除了常用的merge以外,还有rebase操作
版本控制——深入浅出git - 图13

我们也可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次。 在 Git 中,这种操作就叫做rebase(变基)。 你可以使用rebase 命令将提交到某一分支上的所有修改都移至另一分支上

  1. $ git checkout experiment
  2. $ git rebase master
  3. First, rewinding head to replay your work on top of it...
  4. Applying: added staged command

版本控制——深入浅出git - 图14

原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用

  1. $ git checkout master
  2. $ git merge experiment

版本控制——深入浅出git - 图15

rebase命令可以让并行的工作历史记录变成串行一样,从而保证整个提交历史的整洁。这也是大多数开源项目贡献代码的方式。

储藏与清理

当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态,而这时你想要切换到另一个分支做一点别的事情。

问题是,你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。

针对这个问题的答案是 git stash 命令

该命令会处理工作目录的脏的状态 - 即,修改的跟踪文件与暂存改动 - 然后将未完成的修改保存到一个栈上,而你可以在任何时候重新应用这些改动

  1. # 查看储藏列表
  2. git stash list
  3. # 导出储藏记录
  4. git stash apply <index>
  5. # 清除储藏记录
  6. git stash drop <index>
  7. # 快速导出储藏并丢弃
  8. git stash pop

git 配置

git 协议

  1. http协议
    • 优点:只需要一个 URL 以及授权信息,简便(无+需配置ssh)
    • 缺点:授权信息的存储和输入
  2. ssh协议
    • 优点:访问安全,无需输入凭证
    • 缺点:不支持匿名访问

建议大家进行ssh配置,整体效率更高。

具体操作流程参考gitlab的ssh配置指引

多用户的ssh配置

可以在.ssh目录下建立config文件来进行多账户配置

  • Host: 别称,建议和hostName保持一致,不然会改变原始命令
  • User: 用户名
  • HostName: 真实域名
  • IdentityFile 对应的私钥路径
  1. Host code.zikuinfo.com
  2. User chengyupeng
  3. HostName code.zikuinfo.com
  4. IdentityFile ~/.ssh/id_rsa
  5. Host github.com
  6. User Username
  7. HostName github.com
  8. IdentityFile ~/.ssh/id_rsa_work
  9. # 配置完成进行ssh连接确认
  10. ssh -T git@<HostName>.com

gui工具(推荐)

最后为大家推荐git强大的gui工具sourcetree

跳过注册进入方式