Git 版本控制

195 阅读9分钟

1. 集中式版本控制与分布式版本控制

1.1 集中式版本控制

早期使用的是 CVS 和 SVN,这两个都属于集中式版本控制(Centralized Version Control Systems,简称 CVCS)

好处:

    1. 单一的集中管理的服务器,保存所有的修订版本
    1. 协同开发人员通过客户端连接到这台服务器,取出最新的文件或者提交更新

缺点:

    1. 中央服务器出现故障,所有的开发人员都无法工作;
    1. 如果中心数据库所在的磁盘发生损坏,又没有做适当备份,毫无疑问你将丢失所有数据。

1.2 分布式版本控制

Git 是属于分布式版本控制系统(Distributed Version Control System,简称 DVCS)

特点:

  • 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来,包括完整的历史记录;
  • 任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复;
  • 每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

2. Git 的使用

2.1 Git 的别名(alias)

如果不想每次都输入完整的 Git 命令,可以通过 git config 文件轻松地为每一个命令设置一个别名。

git config --global alias.co checkout

git config --global alias.br branch

git config --global alias.ci commit

git config --global alias.st status

2.2 文件的划分状态

  1. 未跟踪:默认情况下,Git 仓库下的文件也没有添加到 Git 仓库管理中,我们需要通过 add 命令来操作;
  2. 已跟踪:添加到 Git 仓库管理的文件处于已跟踪状态,Git 可以对其进行各种跟踪管理;
  • staged: 暂缓区的文件状态;
  • UNmodified: commit 命令,可以将 staged 中文件提交到 Git 仓库;
  • Modified: 修改了某个文件后,会处于 Modified 状态;

2.3 Git 操作流程

image.png

2.4 Git 校验和

Git 所有的数据在存储前都计算校验和,然后以校验和来引用。

  • Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希);
  • 这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来;

image.png

2.5 查看提交的历史 - git log

git log --pretty=oneline --graph

image.png

git log --pretty=oneline

image.png

2.6 版本回退 - git reset

如果想要进行版本回退,我们需要先知道目前先处于哪个版本:Git 通过 HEAD 指针记录当前版本。

  • HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交;

image.png

可以通过 HEAD 来改变目前的版本指向:

  • 上一个版本就是 HEAD^,上上一个就是 HEAD^^;
  • 如果是上 1000 个版本,我们可以使用 HEAD~1000;
  • 我们还可以指定某一个 commit id;

git reset --hard HEAD^

git reset --hard HEAD~1000

git reset --hard 2D44982

  • 如果想要返回上一次的提交状态,即将刚提交过的内容恢复到 staged 中,此时可以使用 soft

git reset --soft HEAD^

2.7 远程仓库的验证

  1. 基于 HTTP 的凭证存储(Credential Storage)
  • 因为本身 HTTP 协议是无状态的连接,所以每一个连接都需要用户名和密码:
    • 如果每次这样操作,就会显得很麻烦
    • 幸运的是,Git 拥有一个凭证来处理这个事情
  • Git Credential 的选项:
      1. 默认所有都不缓存。每一次连接都会询问你的用户名和密码;
      1. “cache” 模式会将凭证存放在内存中一段时间。密码永远不会被存储在磁盘中,并且在 15min 后从内存中清除;
      1. “store” 模式会将凭证用明文的形式存放在磁盘中,并且永远不会过期;
      1. 如果使用的是 Mac,Git 还有一种 “osxkeychain” 模式,它会将凭证缓存到系统用户的钥匙串中(加密的);
      1. 如果使用的是 Windows,可以安装一个叫做 “Git Credential Manager for Windows” 的辅助工具,这个再安装 Git 的时候附带安装即可。

        image.png

  1. 基于 SSH 的密钥

Secure Shell(安全外壳协议,简称 SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。

SSH 以非对称实现身份验证。

  • 例如其中一种方式就是使用自动生成的公钥-私钥对来简单地加密网络链接,随后使用密码认证进行登录;
  • 另一种方式是人工生成一对公钥和私钥,通过生成的密钥进行认证,这样可以在不输入密码的情况下登录;
  • 公钥需要放在待访问的电脑中,而对应的私钥需要由用户自行保管;

如果我们以 SSH 的方式访问 Git 仓库,那么就需要生产对应的公钥和私钥:

ssh-keygen -t ed25519 -C "your email"

ssh-keygen -t rsa -b 2048 -C "your email"

image.png

2.8 管理远程服务器

  • 查看远程地址:

git remote

git remote -v

  • 添加远程地址:我们也可以继续添加远程服务器(让本地的仓库可远程服务器仓库建立连接):

git remote add shortname url

git remote add origin github.com/xxx

  • 重命名远程地址:

git remote rename gitlab glab

  • 移除远程地址:

git remote remove gitlab

2.9 远程仓库实操

  1. 到公司后已经有项目,并且有远程仓库:
  • git clone xxxxxxx
  • 进行开发
    • git add .
    • git commit -m '提交' (第一二步可以合并 git commit -a -m '提交')
    • git pull(相当于 git fetch/git merge)
    • git push
  1. 开发一个全新的项目
  • 创建一个远程仓库
  • 方案一:
    • git clone xxxx
    • 在 clone 下来的文件夹中开始搭建整个项目
    • git add .
    • git commit -m ''
    • git push
  • 方案二:
    • 创建一个本地仓库和搭建本地项目
      • git remote add origin xxxx
      • git branch --set-upstream-to=origin/master
      • git fetch
      • git merge --allow-unrelated-histories
      • git config push.default upstream
      • git push
    • 创建其他分支
      • git checkout develop
      • git branch --set-upstream-to=origin/develop
      • git push(其中,以上两步可以简写为 git push -u origin develop

2.10 Git 标签

对于重大的版本我们常常会打上一个标签,以表示它的重要性。

  • 创建标签

    • Git 支持两种标签:轻量标签(lightweight)和附注标签(annotated);
    • 附注标签:通过 -a 选项,并且通过 -m 添加额外信息

      git tag v1.0

      git tag -a v1.1 -m '附注标签'

  • 默认情况下,git push 命令并不会传送标签到远程仓库服务器上。

    • 在创建完标签后必须显示地推送标签到共享服务器上,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签

      git push origin v1.0

      git push origin --tags

  • 删除 tag:

git tag -d tagname

git tag -d v1.1

  • 删除远程 tag:

git push 《remote》 -delete 《tagname》

git push origin --delete v1.1

  • 检出 tag:
    • 如果想要查看某个标签所指向的文件版本,可以使用 git checkout 命令;
    • 通常我们在检出 tag 的时候还会创建一个对应的分支,在其他分支上修改代码;

    git checkout v1.0

2.11 Git 分支

  • 创建分支:

    git branch name

    git branch testing

Git 通过一个名为 HEAD 的特殊指针来判断目前处于哪个分支

image.png

  • 创建分支并切换:

    • git checkout -b 《newbranchname》
  • 分支开发和合并:

    • 分支上开发、修复 bug:

      • 我们可以在新创建的分支(hotfix)上继续开发工作或者修复 bug;
      • 当我们完成要做的工作后,重新打上一个新的 tag v1.0.1;
    • 切换到 master 分支,但是这个时候 master 分支也需要修复刚刚的 bug:

      • 我们需要将 master 分支和 hotfix 分支进行合并;

      git checkout master

      git merge hotfix

      image.png

  • 查看和删除分支:

    • 查看分支:

    git branch # 查看当前所有的分支

    git branch -v # 同时查看最后一次提交

    git branch --merged # 查看所有合并到当前分支的分支

    git branch --no-merged # 查看所有没有合并到当前分支的分支

    • 删除分支

    git branch -d hotfix # 删除当前分支 git branch -D hotfix # 强制删除某一个分支

  • Git Flow

    • master 主分支;

    • develop 开发分支,并且有稳定版本时,合并到 master 分支中;

    • topic 某一个主体或者功能或者特性的分支进行开发,开发完成后合并到 develop 分支中;

      image.png

  • 比较常见的 Git flow

image.png

2.12 远程分支

  1. 推送分支到远程
  • 当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上;
  • git push remote branch

git push origin branch

  1. 跟踪远程分支
  • 当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master 的 master 分支;
  • 如果愿意的话可以设置其他的跟踪分支,可以通过运行 git checkout --track [remote]/[branch]
  • 如果你尝试检出的分支(a)不存在且(b)刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支;

git checkout --track [remote]/[branch]

git checkout [branch]

  1. 删除远程分支
  • 如果一个远程分支不再使用,我们你想要删除,可以运行带有 --delete 选项的 git push 命令来删除一个远程分支。

git push origin --delete [branh]

2.13 Git rebase

Git rebase 变基,Git merge 合并后的结构是树状结构的,rebase 合并后所得的结构是线性结构

git checkout experiment

git rebase master

image.png

image.png

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

我们可以再次执行 master 上的合并操作:

git checkout master

git merge experiment

image.png

  • rebase 和 merge 的选择
    • merge 用于 记录 git 的所有历史,那么分支的历史错综复杂,也全部记录下来;
    • rebase 用于简化历史记录,将两个分支的历史简化,整个历史更加简洁。

PS:rebase 有一条黄金法则:永远不要在主分支上使用 rebase。 如果在 main 上面使用 rebase,会造成大量的提交历史在 main 分支中不同;而多人开发时,其他人任然在原来的 main 中,对于提交历史来说会有很大的变化。

image.png

2.14 Git 速查表

image.png