likes
comments
collection
share

那些你该了解的Git常用操作,如何优雅的回退代码?

作者站长头像
站长
· 阅读数 13

一、危险操作

1. 拉取work、test、ut环境分支代码 ❌

禁止拉取work、test、ut环境分支,如果合并到线上,可能会导致线上代码被污染出现Bug!

git pull origin test # 错误操作

2. 回退远程代码 ⚠️

通常我们在网上看到的回退操作,有不少是通过git reset进行完成的,但是这个操作是比较危险的,经常会出现你明明修改了代码,但是你merge上去之后,什么也没更改。 所以,在回退代码方面,推荐大家使用git revert操作。

回退代码的原理,其实就是把你之前的代码修改,再进行反向修改。例如你进行了如下操作:

  1. 基于master切了一个分支feature-test
  2. 删除一行代码,然后提交产生了Commit(C)
  3. 执行git revert xx之后,代码会自动反向修改,恢复那一行代码,产生Merge Commit(D)

此时的git树如下: 那些你该了解的Git常用操作,如何优雅的回退代码?

下面来介绍回退代码的几种操作

(1)回退某一个commit

git revert 产生新commit(推荐)
git log # 通过日志,找到你想回退代码的commitid

git revert 425e6dd10b86783 # 回退某个commit

那些你该了解的Git常用操作,如何优雅的回退代码?

在你执行git revert后,会产生一个新的commitId, 并且会出现一个message编辑器, 你可以修改revert产生的commit message

(2)回退多个commit

有如下两个commitid, AB

那些你该了解的Git常用操作,如何优雅的回退代码?

可通过如下命令回退多个commit

git revert OLDER_COMMIT^..NEWER_COMMIT # 回退几个commit就产生几个新commit

git -n revert OLDER_COMMIT^..NEWER_COMMIT # 回退的commit, 合并成一个

在上面的例子中,我们执行如下命令

git revert -n 82e9029759976b9bbba6d47adf68f6a2eeafea88^..64b4646ec1ff9e3d608e583563fefd834a23b062

然后你还需要重新commit, 这样你就回退了

git commit -m "revert: A, B"

(3)回退merge

如果你按照上面学习到的,git revert xxx回退一个merge, 那么一定会出现如下问题:

git revert 83e2776
error: commit 83e2776adb7a47617fbd181228906e52ada396ac is a merge but no -m option was given.
fatal: revert failed

为什么呢?因为此时git不知道要做什么。merge commit是两个分支的汇合点。本质上这两个分支地位是完全相等的。例如下面的图中,master在合并后,从Commit(B)移动到了Commit(Merge), 此时的指针是与feature-test重叠的。 那些你该了解的Git常用操作,如何优雅的回退代码?

然后继续执行如下命令:

git revert -m 1 83e2776

这里-m 1其实就是保留目标分支,回退feature分支上的代码。所以,一般来讲,我们都用-m 1即可。

3. 回退本地代码 ⚠️

(1)git reset

此处有三个commit, 如果我想回退掉前面两个commit

那些你该了解的Git常用操作,如何优雅的回退代码?

获取最下面的commitid, 然后执行:

git reset --soft 3ffc7c6856e207d45ee71d4dd1fd53f215c9d008 # 先回退

回退完成后,你会发现你的工作区多出了被回退的代码,此时如果你想push上去,是不行的,需要强制push。

git push --force

如果你后悔了刚才的回退操作, 就需要重新commit工作区的代码。

(2)git rebase 方式

请参考后面 git rebase的相关用法

二、git rebase VS git merge

不知怎么,git rebase 一直被认为初学者不应该学习它,但它实际上可以让开发团队在使用时更加轻松。我们将 git rebasegit merge 命令进行比较。在 Git 工作流中,说明所有可以使用 rebase 的场景

1. git merge

注意:一般我们合并代码,直接使用Gitlab可视界面即可。 最简单的方式是通过以下命令将 master 分支合并到 feature 分支中:

git checkout feature
git merge master

或者,你可以将其浓缩为一行命令:

git merge feature master

这会在 feature 分支中创建一个新的 merge commit,它将两个分支的历史联系在一起,请看如下所示的分支结构:

那些你该了解的Git常用操作,如何优雅的回退代码?

使用 merge 是很好的方式,因为它是一种 非破坏性的 操作。现有分支不会以任何方式被更改。这避免了 rebase 操作所产生的潜在缺陷(下面讨论)。 另一方面,这也意味着 feature 分支每次需要合并上游更改时,它都将产生一个额外的合并提交。如果master 提交非常活跃,这可能会严重污染你的 feature 分支历史记录。尽管可以使用高级选项 git log 缓解此问题,但它可能使其他开发人员难以理解项目的历史记录(此处仅做讨论,组内规范仍然使用merge流程)

2. git rebase

可以理解为“重新设置基线”(重新设置分支比较的起点commit),并将“新基线”以后的commit拷贝到指定的分支上。所有当前分支上在“新基线”以后的commit会被copy一份存储到一个临时区域,然后按顺序应用到指定分支上

git checkout feature
git rebase master

那些你该了解的Git常用操作,如何优雅的回退代码?

大家可能注意到了,master是落后于feature的,需要我们在master 上将feature分支合并过来。当然,你也可以使用Gitlab可视界面合并。

git checkout master

git merge feature

三、强大的git rebase

1. git rebase 注意事项 ⚠️

使用git rebase的注意事项,请一定遵守。

  1. 公共分支不rebase
  2. 已经push的部分不rebase

线上提交执行变基会导致什么结果: (1)你在本地对部分线上提交进行了变基,这部分提交我们称之为a,a在变基之后commit id 发生了变化 (2)你在本地改变的这些提交有可能存在于你的同事的开发分支中,我们称之为b,他们与a的内容相同,commit id 不同 (3)如果你把变基结果强行push 到远程仓库后,你的同事在本地执行git pull 的时候会导致a 和b 发生融合,且都出现在了历史提交中,导致你的变基行为无效

2. 修改commit顺序

那些你该了解的Git常用操作,如何优雅的回退代码?

如果你想处理从 commit A 到最新的commit, 你需要获取这个范围外的第一条,也就是图上的最后一条commit

git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

第一条是最老的commit记录。最后一条是最新的。 那些你该了解的Git常用操作,如何优雅的回退代码? 然后交换位置后, :wq保存。

那些你该了解的Git常用操作,如何优雅的回退代码?

可以看到,两条commit顺序变了。

那些你该了解的Git常用操作,如何优雅的回退代码?

3. 回退commit

注意:日常不推荐使用,会导致落后于master分支,你的更改将不会产生新的merge。

git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

那些你该了解的Git常用操作,如何优雅的回退代码?

与上面的操作一样,你需要把pick改成d或者drop, 你也可以直接删除这一行,保存之后就会回退commit, 但是这条commit会被删除,请谨慎操作。

4. 修改commit

git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

那些你该了解的Git常用操作,如何优雅的回退代码?

pick改成eedit。然后:wq保存和退出编辑。 控制台会打印如下内容: 那些你该了解的Git常用操作,如何优雅的回退代码? 此时你会进入编辑commit的状态,这时候你修改代码。 那些你该了解的Git常用操作,如何优雅的回退代码? 再执行:

git add .
git rebase --continue

然后会进入编辑commit message的状态, 在这一步你可以修改commit message 那些你该了解的Git常用操作,如何优雅的回退代码? 保存后,你的commit就被修改了。 那些你该了解的Git常用操作,如何优雅的回退代码?

5. 合并commit

如果你想让自己的commit好看一点,你可以把你这次需求所有的commit进行合并。有如下三个commit

那些你该了解的Git常用操作,如何优雅的回退代码?

git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

那些你该了解的Git常用操作,如何优雅的回退代码?

修改一下:

那些你该了解的Git常用操作,如何优雅的回退代码?

pick改成ssquash, 这个意思是把commit合并到前一个commit。在上面的例子中,都被合并到了commit A git会将三个commit 的message也进行合并, 你也可以编辑commit A的 message

那些你该了解的Git常用操作,如何优雅的回退代码?

最后只剩下一个 commit

那些你该了解的Git常用操作,如何优雅的回退代码?

如果你闲麻烦,想直接合并,省略掉编辑message的过程,可以这样:

pick xxx feat: A

# 改成

f xxx feat: A

四、git cherry-pick

git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支。 比如,你的feature-A分支上产生了一个commit (086cbb47628be91b3cc2407056d231fe8c75a120) 另一位同学feature-B也想用你的这份代码,但是其他的代码并不想要,可以这么操作

git checkout feature-B
git cherry-pick 086cbb47628be91b3cc2407056d231fe8c75a120

也支持同时多个cmmit

git cherry-pick A B C

支持某个范围

git cherry-pick A^..B # A是最老的commit

五、git stash

你可能会遇到这样的场景:在feature-A分支上开发,突然来了另一个需求,但是我不想 commit提交我的代码,想直接进入feature-B的开发。正常来讲这肯定是不行的,但是我们可以用git stash临时将代码存放起来。

git stash的用法相当简单:

git stash # 先临时存起来

git checkout feature-B # 切换到另外的分支

开发完成后,再恢复过来:

git checkout feature-A # 切换回来

git stash list # 可以查看stash 记录
git stash apply # 恢复代码

当然,你也可以用可视界面操作:

那些你该了解的Git常用操作,如何优雅的回退代码?

六、VSCode插件推荐

1. Gitlen

非常推荐安装

那些你该了解的Git常用操作,如何优雅的回退代码?

那些你该了解的Git常用操作,如何优雅的回退代码?

可以看到每一行,每一个文件的commit记录。鼠标放在代码上也可以看到最近谁更改了这一行

那些你该了解的Git常用操作,如何优雅的回退代码?

2. Gitlab Workflow

那些你该了解的Git常用操作,如何优雅的回退代码?

可以一键创建MR

那些你该了解的Git常用操作,如何优雅的回退代码?

并且支持在VSCode上看MR记录

那些你该了解的Git常用操作,如何优雅的回退代码?