git高级命令: reset/merge/rebase 图形化手把手教学

| 2.3k字 | 8分钟

git 常用命令速查表

git-601637982348.png

上篇文章 git 基本操作,一篇文章就够了,介绍了日常使用 git 的一些操作,接下来介绍下 git 的一些高级用法,提升你对 git 新的认识。

消除最近的几次提交

已经 push 的代码,有些 commit 确确实实是不想要的,暂存区和工作区都恢复成你指定的那个 commit 的内容了 如图所示,我需要将代码恢复到 cbb25868ec9ef 这个 commit 所在的位置。

git-20211127111935.png
// 执行回退指令
git reset --hard cbb25868ec9ef

reset 执行成功之后, git log --graph 查看提交记录。

git-20211127112216.png
这样就可以删掉之前的提交,将其恢复到你当前执行的 commit hash 那个位置。因为此命令具有不可恢复性,所以在执行此条命令前,请确定你之前的提交是确确实实不想要的。
  1. git revert 是用一次新的 commit 来回滚之前的 commit,git reset 是直接删除指定的 commit。
  2. git reset 是把 HEAD 向后移动了一下,而 git revert 是 HEAD 继续前进,只是新的 commit 的内容和要 revert 的内容正好相反,能够抵消要被 revert 的内容。

提交暂存区后如何查看 diff

diff 暂存区 也就是 git add . 后,还想查看 diff, 执行git diff --cached 后面可以跟具体要 diff 的文件,不写就默认 diff 的是所有在暂存区的文件。
比较不同分支,不同文件的差异,如何用命令行进行操作查看呢?

// 比如 我们想对比 main 和 temp 分支的所有改动文件的diff差异
git diff main temp

// 如果只想对比其中的某个文件 在不同分支上的diff差异, 后面根据题的文件名就可以了
git diff main temp -- index.html

修改最新 commit 的 message

git commit --amend

修改老旧 commit 的 message

git-20211127112913.png
// 就要用到变基操作,既然是变基,就要找到当前你需要更改message的父级提交
git rebase -i cbb25868

此时会有一个交互的信息出来,如下图:

git-20211127113123.png
此时根据提示,执行 `Commands`相应的操作,这里可以在第一个 `pick a4f74a5 refactor: edit text`

中更改第一个 pickr 或 rewordr a4f74a5 refactor: edit text,然后保存退出。退出后,又将进入到具体你更改的那个 commit message 中.

git-20211127113326.png

这个时候 重新修改你的 message 信息,然后保存退出就可以了,退出后,此时就会告知你修改已经成功了。

【detached HEAD commitHash】分离头指针,步骤:git 会先分离头指针,然后在上面做调整,调整完毕之后,他还把最新的 commit 产生之后呢,又用一个指针指向他,也就是我们当前工作的这个 main 分支。

git-20211127113406.png

对比下修改前后的区别:

git-20211127113553.png

把连续多个 commit 整理成1个

前提是:此分支尚未推送至远程,只修该提交记录,对提交文件内容不做修改。
找到操作提交记录的父提交 commitId(如:cbb25868ec ,也可以理解为上一次提交记录 git rebase -i cbb25868ec
1、找到像合并的那几个提交信息
2、想合并的几次提交前面的 pick 保留一个,其余想合并的提交将 pick 更新为 s,然后在 git 弹出的命令窗口中,添加修改提交记录信息,最后保存退出即可

比如 我当前的 commit 记录中 这里的这两个记录都是关于编辑修改文字相关的提交

git-20211127113920.png
git rebase -i cbb25868ec

git-20211127164246.png

git-20211127164024.png

保持第一个前一个为 pick, 后面想要合并的 commit 使用 s 或者 squash 这样,就会把所有 s 标记的 commit 都合并到前一个第一个以 pick 开头的 commit。
上图 :wq! 保存退出后,进入到 commit 信息修改页面,对你需要合并后的 commit 编写具体的文案即可。

git-20211127164422.png

git-20211127164503.png

执行 git log --graph 前后对比。

git-20211127164653.png
这个时候,连续的多个 commit 整理成 1 个 commit 就完成了。 你可以会有疑惑 如果是不连续的呢,那接下来,我们尝试操作下不连续的。

把间隔几个 commit 整理成1个

如何将 间隔的几个commit整理成一个的操作其实和 连续的多个commit整理成1个 操作其实差不多,只是在 rebase 交互的时候,移动其位置就可以了,话不多说,直接上代码。

git-20211127164955.png
这里我新提交了三个 commit,对应下图红色框框中的部分,其中橙色框框中的部分为同一类修改,但是不是连续的,我想将这两个合并成一个 commit。
// 先找到操作提交记录的父提交为依据,这里以feat:create http server提交为依据,commitId 为 cbb25868
git rebase -i cbb25868

git-20211127165058.png

调整 commit 的位置,老样子,需要被合并的 commitId 用 s 或 squash

git-20211127165135.png

保存退出之后,可能会出现下面两种情况中的一种:

  1. 如果没有直接进入到交互页面,而是直接退出了。执行 git status 之后,查看提示,
    然后继续 git rebase --continue 执行此命令,就会继续进入到交互页面了。
  2. 如果没有直接退出,就会直接弹下面的 message 修改交互页面,直接做相应的修改就可以。

git-20211127165217.png

修改完之后,保存退出 出现 successfully 就说明修改成功了。

git-20211127165250.png

接下来 我们执行 git log --graph 再来看看合并后的 commit 的前后变化

git-20211127165413.png

这个时候,我们就把间隔的几个 commit 整理成 1 个了。


将某分支合并到另外一个分支

将一个分支的更改合并到另外一个分支中(一般是主分支同步更新到自己开发分支)
背景描述: main 分支是主分支,temp 和 test 是子分支,基于 main 分支

通常情况下,我们使用的是 merge 的操作:
git:(temp) > git merge main 此时,main 分支的代码将会被合并到 temp 分支(前提是 先要切换到 main 分支拉取最新的代码),这种方式的缺点有两个:

  1. 必须要切换到主分支拉取最新的代码,在切回自己的分支进行 merge
  2. 合并后的所有 commit 会按照提交时间从旧到新排列
  3. git 流程 会被打乱,直接上图

git-20211127165804.png

其次,还可以采用 rebase 的操作:
test 分支做了代码文件内容更改,合并到了 main 分支,此时我 temp 分支是落后于 main 分支的,此时我需要将远程主分支 main 的代码同步到 temp 分支。
主要命令:git pull origin main --rebase 此时 main 分支上最新的代码就全部被合并到 temp 分支上了

git-20211127165922.png

使用 rebase 的优点有:

  1. 改变当前分支从 master 上拉出分支的位置
  2. 没有多余的合并历史的记录,且合并后的 commit 顺序不一定按照 commit 的提交时间排列
  3. 可能会多次解决同一个地方的冲突(有 squash 来解决)
  4. 更清爽一些,master 分支上每个 commit 点都是相对独立完整的功能单元

git-20211127170023.png

那么 rebase 到底做了什么操作呢?
首先,git 会把 feature 分支里面的每个 commit 取消掉;
其次,把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;
然后,把 feature 分支更新到最新的 master 分支;
最后,把上面保存的 patch 文件应用到 feature 分支上;

git-rebase 存在的价值是:对一个分支做「变基」操作。 1.当我们在一个过时的分支上面开发的时候,执行 rebase 以此同步 master 分支最新变动; 2.假如我们要启动一个放置了很久的并行工作,现在有时间来继续这件事情,很显然这个分支已经落后了。这时候需要在最新的基准上面开始工作,所以 rebase 是最合适的选择


解决 rebase 过程中的冲突

关于冲突解决这块,使用以下几种方式处理这些冲突:

1. git rebase --abort (表示放弃之前的rebase)
  a. 会放弃合并,回到rebase操作之前的状态,之前的提交的不会丢弃;
  b. 执行之后,本地内容会回到提交之间的状态,也就是回到以前提交但没有pull是的状态,简单来说就是撤销rebase。
2. git rebase --skip (就是跳过这个rebase)
  a. 则会将引起冲突的commits丢弃掉(使用skip时请慎重、慎用!!);
3. git rebase --continue (就是继续rebase)
  a. 执行完 git pull --rebase 之后,如果有冲突,先是解决当前的页面的冲突
  b. 然后git add . --> git rebase --continue 如果再有,再解决,持续执行git add . --> git rebase --continue
4. 解决完冲突之后,控制台会一直提醒 git pull 不用去理会,一波强推 git push -f 就完事了