Learn Git Branching 学习笔记
分支管理
Git branch
目的:“我想基于这个提交以及它所有的父提交进行新的工作。”
创建一个新分支的方法:
git branch <name>
切换分支的方法:
git checkout <name>
创建一个新分支并切换到该分支上:
git checkout -b <branch-name>
切换完以后,会在原地出现一个新分支,也就是基于当前所在提交的一个新分支出现了。
Git merge
目的:“我要把这两个父节点本身及它们所有的祖先都包含进来。”
合并分支:
在当前的分支上,执行:
git merge <name>
会将 name 分支合并入 main,生成一次新的提交,而 name 分支将保持在原地不动
Git rebase
目的:我们某个分支上的工作全部转移到另一个分支上, 执行 rebase 指令后,所在分支的一个复制的将直接以对应分支为父节点,且会切换到这个复制的分支上(原分支仍会存在)
rebase 分支:
git rebase <name>
即将当前分支转移到 name 分支上如果要使接受转移的分支上的原指针和复制来的被转移分支同步,只需再次执行:
git switch originbranch; git rebase newbranch
通常如果我们将附属分支转移到主分支上,我们就需要再次 rebase 将主分支与 rebase 的附属分支同步,保持主分支在最顶端。
提交树移动
Head 分离
定义:HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录。HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的。** 可以理解 head 为一个鼠标 **
分离 head 指针
未分离情况下,head 指针跟随用户所在分支,指向 该分支上的最近一次提交记录
使用以下指令分离 head 和分支:
git checkout <某提交记录的哈希值>
checkout 方法的实质更像是移动 head 指针,所以 checkout + 位置更广义地理解就是移动 head 指针到对应的位置,比如移动 head 指针到 main 分支上
注意,一个哈希值可能是
fed2da64c0efc5293610bdd892f82a58e8cbc5d8
, 所以这不是一个友好的方法注意,使用 checkout+hash 的方法,可以将 head 移动到任何哈希值所指定的提交记录上!
相对移动
相对移动操作符:
^
:向上移动一个提交记录
~<num>
向上移动多个提交记录, 默认为一次相对移动 HEAD 指针用途:
如上文所提,我们已经知道移动 head 指针的方法就是 checkout, 但是移动的位置表示不是很方便,所以使用相对位置可以更方便地移动。注意,相对的参考点可以是提交记录的哈希值,分支名,也可以 head 指针自己
git checkout bugFix^
git checkout HEAD^^
移动分支指向:
我们可以使用以下命令使分支强制指向某一个提交记录
git branch -f <branch_name> <record>
注意,提交记录可以是相对引用,而且相对引用可能会方便一点
撤销更改
git reset
git reset <record>
通过更改将分支记录倒退实现撤销改动,撤销到 record 记录。比如:git reset HEAD~1
这样,原来指向的提交就就像从来没有提交过的一样,我们可以当作这次提交从未发生过
git revert
git reset 只能在本地撤销本地修改,虽然这对于本地写代码已经足够了,但是不能分享给别人。或者说,如果操作对象是一个远程分支,那么远程记录中,被 reset 的提交不会消失,这不太妙。因此,我们可以新建一个分支,让这个分支的信息就是我们想要撤回到的信息。这个代码就是
git revert
git revert <record>
运行以后,会在当前工作分支下,新建一个新的提交,这个提交就是撤回了 record 提交记录后的新提交,可以理解为与 record 记录之前一个提交记录相同
远程管理
git clone
- 原理:从技术上来讲,
git clone
命令在真实的环境下的作用是在本地创建一个远程仓库的拷贝(比如从 github.com)
远程分支
原理:远程分支与本地创建的分支是不同的,它将反应最近一次你与远程仓库通信后的状态。git 不允许直接在远程分支上进行工作。因此远程分支会自动在检出的时候进入 head 的分离状态,意思是必须在别的分支上完成工作,然后更新远程分支,再分享自己的工作成果
远程分支的命名格式:
<remote_name>/<branch_name>
通常 git 默认的远程仓库的名字就是 origin,如果一个分支名字是 br,那么这个分支的远程分支名字就是
origin/br
注意,远程分支就是一个新的分支了,和原来的分支基本没有联系了
远程分支无法在本地 commit 提交而改变(因为当你 checkout 到它上面的时候,他会自动分离出 head,你无法尝试直接在它上面 commit)
每个分支都可以有对应的远程分支,都记录了最近一次远程仓库的状态
如上所言,远程分支是用来 ** 指示最近一次你与远程仓库通信后的状态的!**
Git Fetch
原理:
git fetch
是与远程仓库通信的指令,完成了仅有的但是很重要的两步:- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针 (如
o/main
),使远程分支指向最新的同步远程记录
注意,这说明 git 没有改动本地仓库的任何文件。需要另外的命令做到这一点
Git Pull
Git Pull 是 fetch 和 merge 的集合简写。意思就是拉去更新,然后做出一个新提交,这个提交是本地分支与远程分支的两个父节点的子节点
Git Push
Git push 和 pull 命令相反,它将本地仓库的提交上传到远程仓库,并且更改远程分支指针与本地分支相同
解决冲突
当本地仓库基于 提交一 做了提交三, 远程仓库中的版本是基于 提交一 做的提交二,这是会出现冲突,git 会拒绝直接的 push 请求。因此我们需要先解决冲突。
让我们先假设我们的提交三不会因为并入提交二而出错
我们需要让本地仓库包含远程仓库的提交,才能使用 push。数学地说,需要本地的提交有以远程仓库现有提交为父节点。
要打到这一点,其实只需要使用合并分支的各种方法就可以
方法一: 先 pull 后 push
pull 就是 fetch 和 merge 的集合简写。git 会先同步远程分支与远程仓库,然后将远程分支与本地分支合并,这样生成的新提交(如果合并没有出现问题的话)就可以 git push 了!
方法二: 先 pull –rebase 后 push
pull –rebase 就是 fetch 和 rebase 的集合简写。git 会先同步远程分支和远程仓库,然后将本地分支复制,接在远程分支下面,这样以后就可以用 git push 提交了
使用 pull request 的方法
pull request 的部分操作在 github 中进行,但是这之前,我们需要在本地提交代码。这部分需要执行 git 操作
我们最好 ** 新建一个带有我们代码的分支,将他推送到远程服务器 **。之后 ** 检查我们的主分支,让他保持和远程仓库的提交记录一致 **,防止之后我们的开发和远程仓库的开发不在同一起始点上,这虽然可能能用 pull + push 解决,但是不同起点的开发有可能会遇到 pull 后代码冲突的问题。
假设我们没有事先在分支上开发,而是不小心直接用 main 开发了(且远程仓库主分支就是 main),我们只需要以下三个命令:(假定我们的远程仓库就是对应的 PR 目标仓库)
1 | git checkout -b myFeature |