1. git commit
用来提交修改。
初始分支状态:

执行命令:
1 | git commit; |
分支前移

2. git branch
用来切换分支。
初始分支状态:

执行命令:
1 | git branch newImage; |
创建新的分支newImage指向当前的提交记录C1

当再次执行git commit后,main分支前移,newImage分支保持不动

星号*表示目前在main分支上,因此所有的操作都是基于main分支进行,newImage分支保持不动。
git branch -f main HEAD~3:将main分支强制指向HEAD的第3级父提交。
3. git checkout
切换分支操作。
初始分支状态:

执行命令:
1 | git checkout newImage; |

将对newImage分支进行操作。
git checkout -b newBranch,快速创建新分支并切换到新分支。
4. git merge
用来合并分支。
分支初始状态:

执行命令:
1 | git merge bugFix; |

该操作表示将bugFix分支合并到main分支,若是想将main分支合并到bugFix分支,则需要先切换分支再进行合并,即
1 | git checkout bugFix; |
执行过后分支状态图:

由于main继承自bugFix,git什么都不做,只是简单地把bugFix移动到main所指向的提交记录。
5. git rebase
与git merge功能相似,也是用来合并分支。
分支初始状态:

执行命令:
1 | git rebase main; |
分支状态图变为

将当前的分支bugFix合并到分支main上。
bugFix为分支上的工作在main的最顶端,同时能得到一个更线性的提交序列。
切换分支到main上,再将main进行rebase到bugFix上,
1 | git checkout main; |

git rebase -i branchA:交互式rebase,将指定的提交记录复制并添加到分支branchA,同时当前分支移动到复制后的分支上。
初始分支状态:

执行命令:
1 | git rebase -i main; |
弹出对话框,选择需要复制的提交记录节点,如C4
状态改变为:

此时目前所在的分支bugFix也会跟着移动到复制后的分支节点C4’上。
执行命令:
1 | git checkout main; |
将main分支合并到bugFix分支。
6. HEAD
HEAD总是指向当前分支上最近一次提交记录。
分离的HEAD是指让其指向某个具体的提交记录而不是分支名。
原始分支状态:

执行命令:
1 | git checkout C1; |
状态变为:

7. 相对引用
- 使用^向上移动1个提交记录
- 使用~num向上移动多个提交记录,如~3
初始状态:

执行命令:
1 | git checkout main^; |
状态变为:

8. 撤销变更
主要用git reset和git revert来进行撤销变更。
git reset
git reset 通过把分支记录回退几个提交记录来实现撤销改动,向上移动分支,原来指向的提交记录就跟从来没有提交过一样。
分支初始状态:

执行命令:
1 | git reset HEAD~1 |
状态变为:

这样本地代码库就不知道有C2这个提交,C2所做的变更还在,但是处于未加入暂存区状态。
git reset这种改写历史的方法对大家一起使用的远程分支无效,为了撤销更改并分享给别人,则需要使用git revert
git revert
初始分支状态:

执行命令:
1 | git revert HEAD; |
分支状态变为:

新提交记录C2’ 引入了更改,这些更改刚好用来撤销C2这个提交,此时C2’与C1是相同的。revert之后就可以把更改推送到远程仓库与别人分享。
9. git cherry-pick
用来对提交进行整理。
分支初始状态:

执行命令:
1 | git cherry-pick C2 C4 |
状态变为:

这样就将side分支上的工作复制到main分支。
10. 场景一
初始状态图如下:

该状态表示在main分支上新建了一个分支newImage,并进行一次提交,在提交后的newImage上新建了一个caption分支并进行一次提交,此时需要对之前的提交记录进行调整修改。
处理方案一(rebase -i):
- 先用git rebase -i将提交重新排序,然后将想要修改的提交记录挪到最前
- 用git commit –amend进行一些小修改
- 用git rebase -i调回原来顺序
- 最后将main移到修改的最前端。
依次执行:
1 | git rebase -i HEAD~2 |
此时调整C2和C3的顺序,状态图变为:

接着修改代码,并执行:
1 | git commit --amend |
此时状态变为:

接着再进行rebase,改变顺序
1 | git rebase -i HEAD~2 |

最后将main合并到caption分支并切换回main分支:(main是caption的父节点)
1 | git rebase caption main |

处理方案二(cherry-pick):
- 首先checkout到分支main
- 在main上进行cherry-pick分支newImage
- 进行修改后commit
- 最后再cherry-pick分支caption
1 | git checkout main |

修改代码并commit
1 | git commit --amend |

最后再进行cherry-pick操作
1 | git cherry-pick C3 |

11. 多次rebase
按顺序合并多个分支,分支初始状态:

首先将bugFix合并到main上:(main不是bugFix的父节点)
1 | git rebase main bugFix |

同理,将side分支和another分支合并
1 | git rebase bugFix side |
最后更新main分支(main是another的父节点)
1 | git rebase another main |

12. git fetch
从远程仓库下载本地仓库中缺失的提交记录,并更新远程分支指针。
该操作并不会改变本地仓库的状态,不会更新本地的main分支,也不会修改磁盘文件。
分支原始状态:

执行命令
1 | git fetch |

13. 提交偏离
在周一拉了代码进行修改,周五的时候远程仓库别人更新了,需要合代码才能入远程仓库。
分支初始状态:

本地提交一次
1 | git commit |

在将本地更新到远程仓库时需要先获取远程更新,再进行合并
1 | git pull --rebase |
最后提交
1 | git push |

14. 场景二
首先克隆了一份代码到本地开发,远程仓库被别人提交了代码并更新分支;
在本地有三个需求分别建立三个不同的分支,开发完之后需要将三个需求合并到远程仓库。
初始状态:

首先拉取远程仓库的更新
1 | git fetch |

进行本地分支的合并
1 | git rebase o/main side1 |

合并main分支
1 | git rebase side3 main |

最后直接push
1 | git push |
