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

一、完整的Git Workflow

1. ssh登录设置

设置用户名和邮箱

bash 复制代码
git config --global user.name "xxx"
git config --global user.email "xxxx@xx.xx"

生成密钥

bash 复制代码
ssh-keygen -t rsa -C "xxx@xxx.cn"

找到~/.ssh/id_rsa.pub并复制内容。 gitlab上创建ssh将刚才复制的内容粘贴上去,title随便取个名字。

2. git clone

有如下几种克隆代码的形式:

  1. 全量拉取所有代码和commit
markdown 复制代码
git clone git@xxx.git
  1. 我们只克隆下包含最近一次commit的一个分支,这样这个项目文件就不会很大。

使用场景:你只是想clone最新版本来使用或学习,而不是参与整个项目的开发工作

markdown 复制代码
git clone --depth 1 git@xxxxx.git
  1. 可以选择只拉取某个分支
markdown 复制代码
git clone -b feature-xxx  git@xxxxx.git

3. 创建并切换分支

创建 + 切换分支

bash 复制代码
git checkout -b feature-xxx

切换分支

bash 复制代码
git checkout feature-xxx

分支命名规范

  • 新需求和特性: feature-模块名-姓名缩写
  • bug修复(待确定): fix-模块名-姓名缩写

4. git add

bash 复制代码
git add 1.txt # 添加1.txt到暂存区

git add . # 添加所有文件到暂存区

5. git commit -m "xxx"

bash 复制代码
git commit -m "xxx" # 提交commit

6. git log

bash 复制代码
git log # 查看log日志

git log --stat # 查看大致改动,可以看到修改的文件

7. git show

bash 复制代码
git show 70f68aa8fcfcea1054fb790ab9879f48c2598aa4 # 查看commit详情

6. git push

bash 复制代码
git push # 上传commit

git push --force # 强制上传commit

7. git pull

bash 复制代码
git pull # 拉取当前分支的远程代码

git pull origin master # 拉取master的远程代码

8. 创建merge request

9. 解决冲突

(1)假设当前处于 feature-xxx 的分支, 你即将合并test分支 (2)创建merge request后发现有merge conflict (3)首先你需要 创建并切换 或 直接切换test-conflict这个解决冲突的分支

bash 复制代码
git checkout test-conflict

# 如果没有这个分支,就创建并切换过去
git checkout -b test-conflict

(4)当前处于test-conflict分支, 你需要如下操作

bash 复制代码
git pull # 拉取当前最新远程代码

git pull origin test # 拉取 test 的代码

git pull origin feature-xxx # 拉取你自己的代码

git add .

git commit -m "merge: reolve conflict" # 创建commit

git push

(5)创建Merge request, 此时是从test-conflict合并到test

相信到这里你已经明白如何处理了,其他环境同理。 简单理解下来,其实解决分支冲突,核心在于需要你为目标分支再切换出来一个分支,避免污染分支。

10. 删除分支

在开发完成后,可以考虑删除当前的分支

bash 复制代码
git checkout xxx # 先切换到别的分支,再删除
git push origin --delete [branch_name] # 删除远程
git branch -D [branch_name] # 删除本地分支

二、危险操作

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

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

bash 复制代码
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树如下:

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

(1)回退某一个commit

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

git revert 425e6dd10b86783 # 回退某个commit

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

(2)回退多个commit

有如下两个commitid, AB

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

bash 复制代码
git revert OLDER_COMMIT^..NEWER_COMMIT # 回退几个commit就产生几个新commit

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

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

bash 复制代码
git revert -n 82e9029759976b9bbba6d47adf68f6a2eeafea88^..64b4646ec1ff9e3d608e583563fefd834a23b062

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

bash 复制代码
git commit -m "revert: A, B"

(3)回退merge

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

bash 复制代码
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重叠的。

然后继续执行如下命令:

bash 复制代码
git revert -m 1 83e2776

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

3. 回退本地代码 ⚠️

(1)git reset

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

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

bash 复制代码
git reset --soft 3ffc7c6856e207d45ee71d4dd1fd53f215c9d008 # 先回退

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

bash 复制代码
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 分支中:

bash 复制代码
git checkout feature
git merge master

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

bash 复制代码
git merge feature master

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

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

2. git rebase

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

bash 复制代码
git checkout feature
git rebase master

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

bash 复制代码
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顺序

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

bash 复制代码
git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

第一条是最老的commit记录。最后一条是最新的。 然后交换位置后, :wq保存。

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

3. 回退commit

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

bash 复制代码
git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

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

4. 修改commit

bash 复制代码
git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

pick改成eedit。然后:wq保存和退出编辑。 控制台会打印如下内容: 此时你会进入编辑commit的状态,这时候你修改代码。 再执行:

bash 复制代码
git add .
git rebase --continue

然后会进入编辑commit message的状态, 在这一步你可以修改commit message 保存后,你的commit就被修改了。

5. 合并commit

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

bash 复制代码
git rebase -i 086cbb47628be91b3cc2407056d231fe8c75a120

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

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

bash 复制代码
pick xxx feat: A

# 改成

f xxx feat: A

五、git cherry-pick

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

bash 复制代码
git checkout feature-B
git cherry-pick 086cbb47628be91b3cc2407056d231fe8c75a120

也支持同时多个cmmit

bash 复制代码
git cherry-pick A B C

支持某个范围

bash 复制代码
git cherry-pick A^..B # A是最老的commit

六、git stash

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

git stash的用法相当简单:

bash 复制代码
git stash # 先临时存起来

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

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

bash 复制代码
git checkout feature-A # 切换回来

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

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

七、VSCode插件推荐

1. Gitlen

非常推荐安装

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

2. Gitlab Workflow

可以一键创建MR

并且支持在VSCode上看MR记录

相关推荐
catmes11 分钟前
Git开发常用命令总结
git
獨枭16 分钟前
CMake 构建项目并整理头文件和库文件
c++·github·cmake
蟾宫曲1 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心1 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
liuxin334455661 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
qq13267029401 小时前
运行Zr.Admin项目(前端)
前端·vue2·zradmin前端·zradmin vue·运行zradmin·vue2版本zradmin
魏时烟3 小时前
css文字折行以及双端对齐实现方式
前端·css
2401_882726484 小时前
低代码配置式组态软件-BY组态
前端·物联网·低代码·前端框架·编辑器·web
web130933203984 小时前
ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含
前端·github
胡西风_foxww4 小时前
【ES6复习笔记】迭代器(10)
前端·笔记·迭代器·es6·iterator