Learn coding by playing: Learn git branch

我很喜欢跟着游戏学一些新上手的东西,比如学vim会找vim游戏来玩,这次发现了一个Git的游戏,所以也来试了一下。主要是之前学git其实学的并不好,有时候处理一些复杂的问题还是会粗暴地采用并不最优的方式。这次正好再来整理一下知识点。

本地操作

主要命令

提交内容

image-20190908111943756

  • git commit
  • C2 的父节点是 C1
  • 父节点是当前提交中变更的基础

分支

  • git 的分支非常轻量,它们只是简单地指向某个提交记录
  • 创建再多分支也不会造成储存或内存上的开销
  • `git

创建新分支`newImage` 指向提交记录 `C1`

基于C1创建新的分支newImage

image-20190908112521757

在新分支上提交内容 C2,但是当前master没有在新分支上

  • git checkout <name> 切换分支
  • git checkout -b <name>创建并切换到新分支

image-20190908112710648

切换到新分支上,星号表示当前分支

分支与合并

  • 在新分支上开发某些功能,开发完后再合并回主线
git merge
  • git merge 会产生一个特殊的提交记录,它有两个父节点。这个提交记录会把两个父节点本身及它们所有的祖先都包含进来

image-20190908113640032

合并bugFix分支到master上,从master开始沿着箭头向上看,master包含了对代码库的所有修改

image-20190908114551002

git checkout bugFix; git merge master

master已经继承了bugFix,所以Git只是把bugFix移动到master所指向的那个提交记录

现在每一个分支都包含了代码库的所有修改

git rebase
  • rebase 实际上是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个地放下去
  • rebase 的优势是可以创造更线性的提交历史

image-20190908115731428

  • bugFix 分支上git rebase master
    • bugFix分支上的工作转移到了master的最顶端
    • 提交记录C3依然存在,C3’是rebase到master分支上的C3的副本

image-20190908120925246

  • git checkout master; git merge bugFix
    • 由于bugFix继承自master,所以只是简单地把master分支的引用向前移动了一下

高级操作

在提交树上移动

  • HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录
  • HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的
  • HEAD 通常情况下是指向分支名的,当你提交时,改变了分支的状态,这一变化通过 HEAD 变得可见
  • cat .git/HEAD 查看 HEAD 的指向
  • 分离的 HEAD 是让其指向了某个具体的提交记录而不是分支名

image-20190908123001915

相对引用

  • 实际操作中需要使用 git log 查看提交记录的哈希值
  • 使用相对引用可以从易于记忆的地方开始计算
    • 使用 ^ 向上移动 1 个提交记录
    • 使用 ~<num> 向上移动多个提交记录

image-20190908123511516

*git checkout master^

master分支的最近一次提交向上移动一个节点

  • 也可以将 HEAD 作为相对引用参照

image-20190908123754631

git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^;

“~” 操作符

image-20190908124123345

git checkout HEAD~4

  • git branch -f master HEAD~3 可以让分支指向另一个提交(让master分支强制指向 HEAD 的第3级父提交)

image-20190908124438892

git branch -f master HEAD~3

撤销变更

  • 撤销变更由底层部分(暂存区的独立文件或者片段)和上层部分(变更到底是通过哪种方式被撤销的)组成
git reset

image-20190908125024971

git reset HEAD~1

  • master 分支移回到 C1,现在本地代码库不知道有 C2 这个提交了
  • reset后, C2 所做的变更还在,但是出于未加入暂存区状态
  • git reset 只对本地分支有效,对一起使用的远程分支无效
git revert

image-20190908125313350

git revert HEAD

  • revert后增加了C2’提交,C2’引入了更改,这些更改用于撤销C2这个提交,也就是说C2’的状态与C1是相同的

移动提交记录

git cherry-pick

  • 将一些提交复制到当前所在位置

image-20190908130503435

git cherry-pick C2 C4

交互式的 rebase

  • 如果不清楚想要的提交记录的哈希值,那么使用交互式的 rebase 更好
  • git rebase —interactive 也可以写作 git rebase -i
  • 增加这个选项后,git会打开一个UI界面并列出要被复制到目标分支的备选提交记录,以及每个提交记录的哈希值和提交说明
  • Rebase打开UI界面时,可以调整提交记录的顺序,删除不想要的提交,合并提交

image-20190908131136752

git rebase -i HEAD~4

技巧

只取一个提交记录

![image-20190908185736968](/Users/nikkkki/Library/Application Support/typora-user-images/image-20190908185736968.png)

git tags

  • 永远指向某个提交记录的标识
  • git tag v1 C1

image-20190908190918635

git describe

  • 用来描述离你最近的标签
  • git describe <ref>

多次 rebase

选择父提交记录

  • ^操作符后面也可以跟一个数字,用来指定合并提交记录的某个父提交
  • git checkout master^2

image-20190908192239237

image-20190908192613384

git checkout HEAD~^2~2


远程仓库

git clone

  • 创建一个远程仓库的拷贝

远程分支

  • 反映远程仓库的状态
  • 在你检出时自动进入分离 HEAD 状态
  • 格式是 <remote name>/<branch name>
  • 也可以切换到远程分支 git checkout o/master

image-20190908195655637

git fetch

  • git fetch 用于从远程仓库获取数据,它实现了两件事:
    • 从远程仓库下周本地仓库中缺失的提交记录
    • 更新远程分支指针
  • git fetch 不会更新本地仓库的状态,也不会更新master分支,也不会修改磁盘上的文件

image-20190908200059547

git pull

image-20190908200851797

git fecth; git merge o/master

  • git pull 就是 git fetch; git merge <just fetched branch>的缩写

git push

image-20190908201732634

偏离的工作

image-20190908202459517

git fetch; git rebase o/master; git push

image-20190908202610765

git fetch; git merge o/master; git push

推送主分支

跟踪远程分支

  • git checkout -b totallyNotMaster o/master 创建新分支,并跟踪远程分支o/master

image-20190908210826913

git checkout -b foo o/master; git pull

image-20190908210927266

git checkout -b foo o/master; git commit; git push

  • git branch -u