%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# 分支管理——git branch
`git branch`——列出、创建、或删除分支。
### 查看分支
- `git branch`:查看所有**本地分支**:
- `-v`:显示**各分支所指向的提交**——**哈希值、提交摘要**
- `-vv`:显示**各分支详细信息**——"**所指向的提交**、**上游跟踪的远程分支**、**提交摘要**"
- 跟踪的远程分支的显示格式:`[远程仓库/分支名:同步状态]`,同步状态为 `"ahead n"` 或 `"behind n"`
- `-r` :仅查看**远程分支**
- `-a` :查看**所有本地&远程分支**
- `--merged [branch]`:显示所有==**已合并**== 到 **当前分支**(或指定分支)的分支
- `--no-merged [branch]`:显示所有==**尚未合并**== 到 **当前分支**(或指定分支)的分支
> [!example] `git branch` 的 `-v` 与 `-vv`
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-27D64BA9AA70442D2FFCC9A66EB65DAE.png|274]]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-F6513E830C17FC9A1A14BD272782B7C0.png]]
> [!example] `git branch` 的 `-r` 与 `-a`
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-FCEE5A9501D7D097004FDACBF36A7E7C.png|408]]
>
> [!example] `git branch --merged`
>
> 该命令常见用途是 "**找出可以安全删除的分支**"——由于这些分支的更改**已被合并到当前分支**中,因此删除掉也不会丢失任何更改。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-0A0728163B3799C17172903880B6F53D.png|499]]
>
>
### 创建分支
两种方式:
- (1)`git branch [<oldbranch>] <newbranch>` 基于**当前分支**或**指定分支**创建新分支
- (2)`git switch -c <newbranch>` **创建并切换**到新分支
### 删除分支
- `git brach (-d | -D) [-r] [<branch>]`
- `-d`:**删除指定分支**(未指定时删除当前分支)
- `-D`:**强制删除**
- `-r`:指示为删除 "**远程跟踪分支**"
```shell
# 删除"远程跟踪分支" origin/todo, origin/html
git branch -d -r origin/todo origin/html
# 强制删除本地分支test
git branch -D test
```
> [!danger] 强制删除分支
> 如果指定分支存在 "**尚未合并到当前分支**" 的内容,则无法通过 `-d` 选项删除。
> 可使用`-D`强制删除,但将**丢失掉这一分支上的所有修改**!该分支的 **其它后继提交** 都将 **丢失该分支的提交历史!**
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-01608FF20311231127E64F3BBD1AEC2B.png|586]]
>
### 修改分支
- `git brach (-m | -M) [<oldbranch>] <newbranch>`:
- `-m`:**修改指定分支名称**(省略`<oldbranch>` 时表示修改 “**当前分支名**”)
- `-M`:**强制修改**
> [!NOTE] 修改**远程分支名**的方式
>
> 1. 先修改本地分支名
> 2. 删除远程分支
> 3. 推送本地分支到远程仓库
>
### 复制分支
- `git branch (-c | -C) [<oldbranch>] <newbranch>`:
- `-c`:**复制指定分支**
- `-C`:**强制复制**
### 设置本地分支 "跟踪" 的远程分支
为**本地分支** 关联 "**远程分支**"
- `git branch (-u <upstream> | --set-upstream-tp=<upstream>) [<branch>]`
> [!example] `git branch -u` 示例
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-2BEF563FB78AC7BFAECBA6C4C9820F91.png]]
>
> - `git bracnh -u origin/main main` 本地 main 分支关联远程 origin/main 分支
> - `git branch --set-upstream-to=origin/main` 本地当前分支关联远程 origin/main 分支
> - `git branch --set-upstream-to=origin/main main` 本地 main 分支关联远程 origin/main 分支)
> - **`git branch --set-upstream-to douglas/pa1 pa1` 本地分支 `p1` 跟踪远程分支 `douglas/pa1`**
>
> ^pcnp23
### 查看本地分支 "跟踪" 的远程分支
- `git branch -vv`:查看**所有本地分支详细信息**——**指向的提交**、**上游跟踪的远程分支(及同步状态)**、**提交信息摘要**
![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-1BAEDA726607ADC95584C16429DCCB78.png|503]]
### 取消本地分支 "跟踪" 远程分支
- `git branch --unset-upstream [<branch]>`: **取消本地分支 branch 跟踪关联的远程分支**
<br><br><br>
# 分支切换——git switch / checkout
> `git switch` 命令自 Git 2.23 引入
切换到**指定分支**,两种方式:
- (1)`git switch <branch>`
- (2)`git checkout <branch>`
**创建并切换**到指定分支:
- (1)`git switch -c <branch>`
- (2)`git checkout -b <branch>`
> [!example]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-91824252E500F1626E1BEF078B566AD3.png|400]]
>
> [!caution]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-90EB1F8C23D2C77B32DCFD71FE5EB8A8.png|575]]
>
> [!caution]
>
> 1. 切换分支时,如果两个分支所指的是同一提交版本,则**工作区中未暂存的修改以及暂存区中未 commit 的修改会保留**,这意味从 A 切换到 B 时,对分支 A 的改动将会带给分支 B。<br>由于切换前后 HEAD 指向的都是同一个 commit,因此未暂存的修改以及暂存区中未提交的修改才能得以保存。
> 2. 如果两个分支所指的不是同一 commit,则无法进行切换,会报错切换分支后,local changes 将被覆盖。
>
> 情况一: matser 与 testCheck 分支指向同一 commit
> 切换时将 master 分支中暂存的修改带入了 testCheck 分支
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-F1D3488D3E3AC34895DAFB891FD24317.png|454]]
>
> 情况二: master 分支与 testcheck 分支指向不同的 commit
> 无法进行切换,报错。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-2A36D51D8A1153514EA095A27FF985D4.png|475]]
>
>
<br><br><br>
# 分支合并——git merge ⭐
## 合并概念说明
执行 `git merge` 时有两种可能的合并情况:**快速合并**、**三路合并**:
| | 说明 |
| ---------------------------- | ------------------------------ |
| **快进合并**(Fast-Farword Merge) | **不产生合并提交**,仅**移动==分支引用==的指向** |
| **三路合并**(Three-Way Merge) | **产生一个新的合并提交** |
![[Excalidraw/Excalidraw-Solution/git 分支管理.excalidraw.md#^group=SSj0olZO|479]]
##### 快进合并
当进行合并的两个分支存在 "**==直接后继关系==**",即**顺着一个分支向后走可以抵达另一个分支**时,两个分支没有分歧,
此时 git 令**靠前的分支引用**直接后移指向 **靠后的分支引用**,**==不产生合并提交==**。
> [!example]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-E405F2FE9F46B947B1892149C53EE062.png|721]]
>
##### 三路合并
三路合并:基于 "**==两个被合并的 commit 及二者最近公共祖先==**" 三方进行合并。
(**将两个 commit 分别与这一最近公共祖先进行"比较",从而知道两个 commit 分别修改了什么位置**)
当两个分支有 **独立的提交历史时**,无法快速合并,**Git 在合并时将产生一个==新的合并提交==**。
未指定**提交 message** 时,默认生成 "Merged branch xxx"。
> [!example] 三方合并示例:`git checkout master && git merge topic`
>
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-454FCC3AD502E8C2C817D5AF98F8FE09.png|475]]
>
>
> [!example] 三方合并示例:`git checkout master && git merge bc1`
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-98D809043D030E9C4627B0DF2E882150.png|251]]
>
>
<br>
## 命令说明
`git merge <branch>`:合并**指定分支**到 **==当前分支==**:
- `-e | --edit`:成功合并后打开编辑器,**供指定提交 message**
- `-m <msg>`:**指定提交 message**
- `--no-ff`:禁用**快进合并**,保证**产生一个新的==合并提交==**;
- `--ff-ony`:**只允许快进合并**,若不能快进合并则 **拒绝合并**。
- `--abort`: **取消合并,恢复到合并前的状态**(仅当合并过程中报告 "**报告合并冲突**" 时可使用)
- `--squash`:将 **==目标分支==** 合并到**当前分支的 "==工作区&暂存区=="**,但 **==不产生合并提交==**。
- 该选项可用于 "**在当前分支上创建一个==单一的后继 commit==,但其效果等价于 "==合并两分支=="**。
- `--allow-unrelated-histories` :**强制合并另一个与当前分支 "历史无关" 的分支到当前分支**
- git 要求**被合并的两个分支**必须具有 "**公共提交祖先**",否则拒绝执行。该选项用于**强制实现这类合并**。
- `-s <strategy>`:**选择合并策略**,可选项为:
- `recursive`:默认策略,用于**三方合并**;
- `ours`:**保留当前分支的所有内容**,只将另一分支的**提交合并**(只产生合并 commit,但不更改当前分支内容)
- `-X <option>`:**选择 "合并冲突" 解决策略**,可选项为:
- `ours`:在发生冲突时,保留当前分支的内容。
- `theirs`:在发生冲突时,保留目标分支的内容。
> [!NOTE] 关于 `--squash` 选项
>
> 该选项使得**将另一个分支 "合并" 到当前分支**时,
> **合并 commit 只作为当前分支上的单一后继 commit**,丢弃另一分支的所有提交历史(不产生具有两个父提交的合并提交)
> 保证了**当前分支==干净的提交历史==**。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-47CEF771BBCE064B3EDEBDF3A1D22FFD.png|811]]
>
>
<br>
## 合并冲突处理
当**执行 `git merge` 命令后报告存在 ==合并冲突==** 时,可应用下列命令进行处理:
- `git status`:在合并过程中,使用此命令**检查当前合并的状态,以及冲突文件**。
- `git merge --abort`: **中断合并,恢复到合并前的状态**;
- `git merge --quit`:**停止合并过程**,**但保留所有更改**。
#### 手动处理冲突
> [!NOTE] git status 查看存在冲突的文件
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-9BA4169A2118C3CCC4A30D6B403A036F.png|483]]
>
> 手动处理冲突以后,通过 `git add` 来**将文件标记为冲突已解决**,然后再手动 git commit 进行提交。
> [!info] git 会在冲突位置自动插入**冲突标记**:
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-D52CF4D2A3AD272173E6C18FBF2DDC62.png|683]]
>
>
<br><br><br>
# 分支变基——git rebase⭐
## rebase 含义
`rebase` 含义——将一系列提交**从一个基点转移到另一个基点**:
即从==**两分支共有的最近祖先提交**==起,将**当前分支**位于该 "**祖先提交**"之后的**所有提交**按照**原有次序==依次==** 应用到 **==指定分支的最新提交==**(基底)之后,相对于基底**产生对应次数的==新提交==**(并且保留附注,除非产生合并冲突)。
> [!example] `git rebase master` 示例
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-33546ECA2C682B5E42401462B5253B63.png|603]]
>
> 如上图,若 `master` 分支在你创建当前分支 topic 后有新提交,则执行 `git rebase master` 表示将当前分支变基到 `master` 上——即**将 topic 分支上==原先分叉于 master 的所有提交==,基于 ==master 最新提交==全部应用一遍**。
> [!NOTE] `git rebase` 可用于将多条分叉的 "**并行分支**" 整合为 "**单条的线性分支**",而**不产生合并提交**。
> [!caution]
> ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-777B7C2EB8E7E5030A9D8BAE7F4F3BA8.png|613]]
>
> 团队协作开发时,通常全员采用 `git pull --rebase` 来**合并远程分支更新**而不是以 `merge`的方式,
> 由此**为该分支保持干净的提交历史——一条直线而没有大量冗余的分叉以及合并提交**
>
> ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-5BDD5B6E4A8690BDD1E839B24349842A.png|562]] ^otyima
<br>
## 命令说明
`git rebase [<options>] [<upstream> [<branch>]]`:**将 `<branch>` 分支变基到 `<upstream>` 分支末端之上**
- `[<branch>]` 省略时,表示将 "**==当前分支==**" 变基到 `<upstream>` 分支;
- 指定时,命令**等价于 `git checkout <branch> && git rebase <upstream>`**
- `[--onto <newbase>]`:指定作为 "**==基底==" 的分支**(默认是 `<upstream>`)
- 使用该选项后,命令含义变为 "**将 `<branch>` 分支中==不同于 `<upstream>` 的提交==变基到 `<newbase>` 分支末端之上**"
- `-i`:使用**交互模式**进行变基,允许在变基过程中修改、合并、删除、重排提交。
- `-r | --rebase-merges`: 保留**分支结构**,处理 "**==分支合并提交==**"
- `rebase` 默认用于得到 "**==线性历史==**",因此在 `-i` 下默认不会显示 "**合并提交**",只会**同时罗列 "合并提交" 的两个父 commit(相当于将另一分支上的 commit 进行 cherry-pick)**,故**最终变基得到的是 "线性提交历史"**。
- 启用该选项后,将 **==保留分支合并历史==**(会对涉及到的另一分支合并也进行 rebase)
- `--abort`:**取消当前变基**,恢复变基前(针对 rebase 过程中出现**合并冲突**而暂停的情况,应用 `git rebase --abort` 撤销)
### `--onto` 选项使用示例
`git rebase --onto <newbase> <upstream> [<branch>]` 的作用
> [!example] 示例一:以下图场景为例
>
> - 执行 `git rebase master topic`,是将 "**topic 分支上与 master 分支分歧的部分**" 变基到 master;
> - 执行 `git rebase --onto master next topic`,是将 "**topic 分支上与 next 分支分歧的部分**" 变基 master。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-30A34514C886F48D89D3A453A4516D3B.png|666]]
>
> 类似示例:
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-5D7E4785BA922065162FABE7335898BF.png|673]]
> [!example] 示例二
>
> 执行`git rebase --onto master topicA topicB` 将 "**topicB 分支上与 topicA 分支分歧的部分**" 变基 master。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-CB60EC529D909590C47F600E84591BDD.png|654]]
>
>
> [!example] 示例三:用以 "移除一段 commit 历史"
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-2FEBF7CB1CF4F21143FBD993991F6824.png|718]]
>
>
> [!example] **`git rebase -i -r <commit>` 示例——rebase 时保留分支合并历史** ⭐
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-4CF41771D014F32467377187069B80F4.png|980]]
>
>
<br><br>
## 以交互模式进行变基
`-i` 指定在交互式模式下进行 rebase,随后 git 将**启动编辑器**,
**列出将进行 rebase 的提交列表(按==提交先后==从上至下排列)**,**允许对其中 commit 进行修改、合并、删除、重排**。
![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-0C55157ADAE93216554A671B4535AA65.png|562]]
##### 修改历史记录提交顺序
直接交换各行顺序即可,rebase 时是**对各个 commit 从上至下按序逐个执行**。
> [!danger] 在 commit 之间有依赖关系时,谨慎调整顺序!
>
> 例如提交历史 A--B--C,其中 **B 引入一个文件**而 **C 进一步修改该文件内容**,则调整为 A--C--B 将导致冲突!
> 执行过程将是,**commit C 相较于 A 引入 C 修改后的文件版本**,然后又再 **相较于 C 应用 commit B**,尝试**合并最初 B 引入的文件版本**,由此导致 **==合并冲突==**。
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-2903162A0D98A944B5A995AEBBBBCAC4.png|523]]
>
##### 修改某次提交信息——标注 `r`
![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-D7F7373CC8422B6E640AAF37FBA6243F.png|154]]
##### **删除某个 commit**——将 `pick` 改为 `d` 或者直接在编辑器中移除这一行即可
![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-FC5782577D307E60C67E9B2B720AF1DC.png|148]]
> [!danger] 某个 commit 被删除后,**其中的变更不会被保留**,务必确保**其后 commit 不依赖其中的更改**。
>
> 假设存在提交历史 A--B--C--D--E (HEAD),
> 若 commit C 加入了一个函数定义,而 D 和 E 中均使用了该函数,则**删除 commit C 会导致该函数定义丢失**。
>
> 因为 rebase 的原理是**在指定的 upstream commit 之上 "==重新应用==" 其后所有 commit**。
> 例如 `git rebase -i B`,标记删除 C,意味着**仅将基于 B ==重新提交 D 和 E==**(引入 diff),而 **D 和 E 中并没有引入该函数**。
##### 压缩合并多个 commit
(1)方式一:标注 `s`(squash)
被标注的 commit 将**被合并进其==上方最近的 pick commit==**,并启动编辑器指定**合并提交消息**。
>![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-8EDE07F6491EFC8403EC03E2398FBCF3.png|440]]
(2)方式二:标注 `f`(fixup)
效果同 `s`,但**丢弃被合并 commit 的提交消息**,**沿用上方 pick commit 的提交消息**
>![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-DAED6A040FFF160B34D39B5BFF6CC30A.png|612]]
<br><br>
## 合并冲突处理
rebase 会将一系列 commit **依次 "变基" 到指定分支最新提交**之上。
在 rebase 过程中,当**某一 commit 存在==合并冲突==** 时,可应用下列命令进行处理:
- `git status`:检查**当前合并状态,冲突文件**;
- `git rebase --continue`:需**手动消除冲突后通过git add添加到暂存**区,再通过该命令**指示继续进行变基过程**。
- `git rebase --skip`:**直接跳过当前冲突的 commit**;
- `git rebase --abort`:**中止 rebase,恢复到 rebase 前的状态**;
> [!example] rebase 合并冲突解决示例
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-EB5C9E25CC06E46CC1BD95FB23BBB1BE.png|581]]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-E1BBB2AB149037E5A90A42DB1692421A.png|586]]
>
> ![[_attachment/05-工具/git 使用/git 分支管理.assets/IMG-git 分支管理-C076F35E018B7D27BF17077A7B179D32.png|584]]
>
>
# 分支合并总结 🌠
<br><br><br>
# 参考资料
# Footnotes