Learn Git Branching 记录

Learning Git Branching 可以说是目前为止最好的教程了,地址

在这里插入图片描述
点击右下角问号显示常用命令

1.提交

Learn Git Branching 记录_第1张图片

git commit

提交内容,并把这些修改保存成了一个提交记录 C3,C3 的父节点是 C2

修改提交信息

Learn Git Branching 记录_第2张图片

git commit --amend

每次 git commit 后都会产生一条提交记录,使用 git commit --amend 会把当前的修改追加到最新的提交里,而不会产生新的提交记录
例如,这里提交了 C2,追加了修改到 C2,形成 C2’,但是没有产生新的提交记录,C2 和 C2’ 的提交注释一样,但 hash 值不一样

2.创建,切换分支

Learn Git Branching 记录_第3张图片

git branch newImage

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

Learn Git Branching 记录_第4张图片

git checkout newImage
git commit

切换到 newImage 分支,提交C2,*表示当前分支
注意:在 Git 2.23 版本中,引入了一个名为 git switch 的新命令,最终会取代 git checkout,因为 checkout 作为单个命令有点超载(它承载了很多独立的功能)

git checkout -b bugFix 

创建一个新的分支bugFix,同时切换到这个分支,可以通过 git checkout -b your-branch-name 来实现

3.合并 merge

Learn Git Branching 记录_第5张图片

git merge bugFix

把 bugFix 分支合并到当前的 main 分支
在 Git 中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。翻译成自然语言相当于:“我要把这两个父节点本身及它们所有的祖先都包含进来。”,main 现在指向了一个拥有两个父节点的提交记录 C4

Learn Git Branching 记录_第6张图片

git checkout bugFix
git merge main

再把 main 分支合并到 bugFix,因为 main 继承自 bugFix,Git 什么都不用做,只是简单地把 bugFix 移动到 main 所指向的那个提交记录

4.合并 rebase

第二种合并分支的方法是 git rebase。rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去
Learn Git Branching 记录_第7张图片

git rebase main
// 等价于 git rebase main bugFix

C3’ 是 C3 的副本,复制后两个分支是并行开发的

Learn Git Branching 记录_第8张图片

git rebase bugFix

切换到了 main 上。把它 rebase 到 bugFix 分支上,由于 bugFix 继承自 main,所以 Git 只是简单的把 main 分支的引用向前移动了一下而已

在开发社区里,有许多关于 merge 与 rebase 的讨论。以下是关于 rebase 的优缺点:
优点:
rebase 使你的提交树变得很干净, 所有的提交都在一条线上
缺点:
rebase 修改了提交树的历史
比如, 提交 C1 可以被 rebase 到 C3 之后。这看起来 C1 中的工作是在 C3 之后进行的,但实际上是在 C3 之前。
一些开发人员喜欢保留提交历史,因此更偏爱 merge。而其他人可能更喜欢干净的提交树,于是偏爱 rebase

5.分离 HEAD

HEAD 是一个对当前所在分支的符号引用,分离的 HEAD 就是让其指向了某个具体的提交记录而不是分支名
Learn Git Branching 记录_第9张图片

git checkout C1 //这里的C1表示提交记录的哈希值

在命令执行之前的状态:HEAD -> main -> C1
HEAD 指向 main, main 指向 C1
执行后变成了:HEAD -> C1

6.相对引用

通过哈希值指定提交记录很不方便,所以 Git 引入了相对引用
使用 ^ 向上移动 1 个提交记录
使用 ~num 向上移动多个提交记录,如 ~3

Learn Git Branching 记录_第10张图片

git checkout main^

Learn Git Branching 记录_第11张图片

git checkout HEAD~4

强制修改分支位置,可以直接使用 -f 选项让分支指向另一个提交
Learn Git Branching 记录_第12张图片

git branch -f main HEAD~3

上面的命令会将 main 分支强制指向 HEAD 的第 3 级父提交

一个更复杂的例子
Learn Git Branching 记录_第13张图片

git branch -f main C6
git checkout HEAD^
git branch -f bugFix HEAD^

7.撤销变更

撤销变更由底层部分(暂存区的独立文件或者片段)和上层部分(变更到底是通过哪种方式被撤销的)组成。这里主要关注的是后者
Learn Git Branching 记录_第14张图片

git reset HEAD~1

git reset 通过把分支记录回退几个提交记录来实现撤销改动,在reset后,C2 所做的变更还在,但是处于未加入暂存区状态,reset 主要用于自己管理的分支

虽然在本地分支中使用 git reset 很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的!
为了撤销更改并分享给别人,我们需要使用 git revert
Learn Git Branching 记录_第15张图片

git revert HEAD

新提交记录 C2’ 引入了更改 —— 这些更改刚好是用来撤销 C2 这个提交的。也就是说 C2’ 的状态与 C1 是相同的

8.复制提交记录到当前分支(遴选)

Learn Git Branching 记录_第16张图片

git cherry-pick C2 C4

复制 C2 和 C4 并提交到当前 main 分支

9.交互式的 rebase

如果你想从一系列的提交记录中找到想要的记录,可以利用交互式的 rebase,它指的是用带参数 --interactive 的 rebase 命令, 简写为 -i
如果你在命令后增加了这个选项, Git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,所谓的 UI 窗口一般会在文本编辑器(如 Vim)中打开一个文件。 课程里使用一个对话框来模拟这些操作

当 rebase UI界面打开时, 你能做3件事:
调整提交记录的顺序(通过鼠标拖放来完成)
删除你不想要的提交(通过切换 pick 的状态来完成,关闭就意味着你不想要这个提交记录)
合并提交,它允许你把多个提交记录合并成一个

Learn Git Branching 记录_第17张图片
Learn Git Branching 记录_第18张图片

git rebase -i HEAD~4

这里打开 UI 界面对 HEAD 上面4个提交进行修改,删除 C3 这个提交,修改 C4,C5 的顺序

10.标签

分支很容易被改变,大部分分支还只是临时的,并且还一直在变。tag 可以(在某种程度上 —— 因为标签可以被删除后重新在另外一个位置创建同名的标签)永久地将某个特定的提交命名为里程碑,然后就可以像分支一样引用了
Learn Git Branching 记录_第19张图片

git tag V1 C1

建立一个标签V1,指向提交记录 C1,如果你不指定提交记录,Git 会用 HEAD 所指向的位置

最近的标签

由于标签在代码库中起着“锚点”的作用,Git 还为此专门设计了一个命令用来描述离你最近的锚点(也就是标签),它就是 git describe
git describe 的​​语法是:

git describe <ref>

ref 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会使用你目前所在的位置(HEAD)。
它输出的结果是这样的:

<tag>_<numCommits>_g<hash>

tag 表示的是离 ref 最近的标签, numCommits 是表示这个 ref 与 tag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位
当 ref 提交记录上有某个标签时,则只输出标签名称

Learn Git Branching 记录_第20张图片

git describe main
v1_2_gC2 //输出
git describe side
v2_1_gC4 //输出

11.选择父提交记录

操作符 ^ 与 ~ 符一样,后面也可以跟一个数字num
一个合并提交有两个父提交,num指代某个父提交,默认选择合并提交的“第一个”父提交
Learn Git Branching 记录_第21张图片

git checkout main^

默认会回到第一个父提交记录,在示例图中,第一个父提交记录是指合并提交记录正上方的那个提交记录

Learn Git Branching 记录_第22张图片

git checkout main^2

回到了另外一个父提交上

这些操作符还支持链式操作
Learn Git Branching 记录_第23张图片

git checkout HEAD~^2~2

12.远程仓库

git clone 地址

在本地创建一个远程仓库的拷贝

Learn Git Branching 记录_第24张图片
o/main 表示远程分支,其中o表示origin,远程分支有一个特别的属性,在你切换到远程分支时,自动进入分离 HEAD 状态。Git 这么做是出于不能直接在这些分支上进行操作的原因, 你必须在别的地方完成你的工作, (更新了远程分支之后)再用远程分享你的工作成果
当我们从远程仓库获取数据时, 远程分支也会更新以反映最新的远程仓库

fetch

Learn Git Branching 记录_第25张图片

git fetch

C2,C3 被下载到了本地仓库,git fetch 完成了仅有的但是很重要的两步:

  1. 从远程仓库下载本地仓库中缺失的提交记录
  2. 更新远程分支指针(如 o/main)

git fetch 并不会改变你本地仓库的状态。它不会更新你的 main 分支,也不会修改你磁盘上的文件,可以将 git fetch 的理解为单纯的下载操作,如果远程仓库有多个分支,它会下载所有的提交记录到各个远程分支

pull

当远程分支中有新的提交时,你可以像合并本地分支那样来合并远程分支。也就是说就是你可以执行以下命令:

git cherry-pick o/main
git rebase o/main
git merge o/main

由于先抓取更新再合并到本地分支这个流程很常用,因此 Git 提供了一个专门的命令来完成这两个操作

git pull

Learn Git Branching 记录_第26张图片

git fetch
git merge o/merge

用 fetch 下载了 C3,然后 C2 和 C3 合并成 C4,现在我们的 main 分支包含了远程仓库中的更新
而 git pull 就是 git fetch 和 git merge 的简写,使用 git pull 可以代替上面两条命令,类似的 git pull --rebase 就是 fetch 和 rebase 的简写
pull 操作时, 提交记录会被先下载到 o/main 上,之后再合并到本地的 main 分支

push

Learn Git Branching 记录_第27张图片

git push

git push 将你的变更上传到远程仓库,远程仓库接收了 C2,远程仓库中的 main 分支也被更新到指向 C2 了,我们的远程分支 (o/main) 也同样被更新了,所有的分支都同步了
注意 —— git push 不带任何参数时的行为与 Git 的一个名为 push.default 的配置有关。它的默认值取决于你正使用的 Git 的版本

Learn Git Branching 记录_第28张图片
这种情况执行 git push 会失败,因为你最新提交的 C3 基于远程分支中的 C1。而远程仓库中该分支已经更新到 C2 了,所以 Git 拒绝了你的推送请求,所以实际开发中必须先 git pull 更到最新才能提交

Learn Git Branching 记录_第29张图片

git fetch
git rebase o/main
git push

用 git fetch 更新了本地仓库中的远程分支,然后用 rebase 将我们的工作移动到最新的提交记录下,最后再用 git push 推送到远程仓库

git pull --rebase
git push

也可以使用 git pull --rebase 简化命令
Learn Git Branching 记录_第30张图片

git fetch
git merge o/main
git push

用 git fetch 更新了本地仓库中的远程分支,然后合并了新变更到我们的本地分支(为了包含远程仓库的变更),最后我们用 git push 把工作推送到远程仓库

git pull
git push

使用 git pull 简化命令

13.远程服务器拒绝!(Remote Rejected)

如果你是在一个大的合作团队中工作,很可能是main被锁定了,不能直接提交到main,需要一些Pull Request流程来合并修改。如果你直接提交(commit)到本地main,然后试图推送(push)修改,你将会收到这样类似的信息:
! [远程服务器拒绝] main -> main (TF402455: 不允许推送(push)这个分支; 你必须使用pull request来更新这个分支.)

远程服务器拒绝直接推送(push)提交到main, 因为策略配置要求 pull requests 来提交更新
你应该按照流程,新建一个分支,推送(push)这个分支并申请pull request

Learn Git Branching 记录_第31张图片

git reset --hard o/main
git checkout -b feature C2
git push origin feature

先 reset 保证main分支和远程服务器保持一致,这里使用 --hard 硬重置,可以尽情省略掉那个选项以避免麻烦!但是要记录 Git 中默认的是 --mixed

14.远程跟踪

当你克隆时, Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/main)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 main,main 被设定为跟踪 o/main —— 这意味着为 main 分支指定了推送的目的地以及拉取后合并的目标。
这也解释了为什么会在克隆的时候会看到下面的输出:
local branch “main” set to track remote branch “o/main”

有两种方法设置这个跟踪属性,第一种就是通过远程分支切换到一个新的分支,执行:

git checkout -b totallyNotMain o/main

就可以创建一个名为 totallyNotMain 的分支,它跟踪远程分支 o/main

Learn Git Branching 记录_第32张图片

git checkout -b foo o/main
git pull

切换到一个名叫 foo 的新分支,让其跟踪远程仓库中的 main,使用了隐含的目标 o/main 来更新 foo 分支,需要注意的是 main 并未被更新

第二种方法是使用:git branch -u 命令,执行:

git branch -u o/main foo

这样 foo 就会跟踪 o/main 了。如果当前就在 foo 分支上, 还可以省略 foo:

git branch -u o/main

15.git push 的参数

可以为 push 指定参数,语法是:

git push <remote> <place>
git push origin main

把这个命令就是:切到本地仓库中的“main”分支,获取所有的提交,再到远程仓库“origin”中找到“main”分支,将远程仓库中没有的提交记录都添加上去,实际就是要同步的两个仓库的位置

Learn Git Branching 记录_第33张图片

git checkout C0
git push origin main

通过指定参数, 远程仓库中的 main 分支得到了更新
如果上面的 git push 不指定参数,则命令会失败了,因为我们所切换的 HEAD 没有跟踪任何分支

指定 place 参数为 main 时,我们同时指定了提交记录的来源和去向,如果来源和去向分支的名称不同,使用如下命令

git push origin <source>:<destination>

Learn Git Branching 记录_第34张图片

git push origin foo^:main

source 可以是任何 Git 能识别的位置,foo^ 解析为一个位置,上传所有未被包含到远程仓库里 main 分支中的提交记录

Learn Git Branching 记录_第35张图片

git push origin main:newBranch

如果你要推送到的目的分支不存在会,Git 会在远程仓库中根据你提供的名称帮你创建这个分支

Learn Git Branching 记录_第36张图片

git push origin :foo

还可以不指定 source,通过给 push 传空值 source,会删除远程仓库中的分支

16.git fetch 的参数

git push 的 place 参数,还有用冒号分隔的 source:destination,这些参数也可以用于 git fetch,只是方向相反罢了(因为现在是下载,而非上传)

Learn Git Branching 记录_第37张图片

git fetch origin foo

只下载了远程仓库中 foo 分支中的最新提交记录,并更新了 o/foo
为何 Git 会将新提交放到 o/foo 而不是放到我本地的 foo 分支呢?因为你可能在 foo 分支上的工作还未完成,你也不想弄乱它

也可以指定 source:destination,注意:source 指的是远程仓库中的位置,而 destination 才是要放置提交的本地仓库的位置。它与 git push 刚好相反,开发人员很少这么做,这里就不演示了

Learn Git Branching 记录_第38张图片

git fetch origin :bar

如果 fetch 空 到本地,会在本地创建一个新分支

17.git pull 参数

以下命令在 Git 中是等效的:

git pull origin foo 相当于:
git fetch origin foo
git merge o/foo

还有…

git pull origin bar~1:bugFix 相当于:
git fetch origin bar~1:bugFix
git merge bugFix

pull 也可以用 source:destination
Learn Git Branching 记录_第39张图片

git pull origin main:foo

先在本地创建了一个叫 foo 的分支,从远程仓库中的 main 分支中下载提交记录,并合并到 foo,然后再 merge 到我们的当前所在的分支 bar 上

参考

B站最全Git进阶课程

你可能感兴趣的:(git,git)