Git:Cherry-Pick 桃色陷阱

2023-12-15 09:36
文章标签 陷阱 git pick cherry 桃色

本文主要是介绍Git:Cherry-Pick 桃色陷阱,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/J2b130UVF0aPoHM9-U9Uuw

Cherry-Pick 咋一看这名字就很时髦,用来干啥呢?

Cherry-Pick 是什么?

假设在开发某些功能或者修复 bug 的时候把代码 commit 到了错误的分支 A,并且分支 A 最新版本已经覆盖了该 commit。看到这样你不会抓狂?被逼无奈之下,你可能会这样补救一番:

首先,切换到分支 A,找到需要备份的 commit 内容,逐个备份出来,并且保存 commit 描述,然后再切换回将要接收合并的目标工作分支,接着把备份的内容逐个更新到当前分支中,最后再提交新的 commit 并且填上前面保存下来的 commit 描述。

如果更新内容庞大,没有相关指令可以自动化实现上面的操作,全程靠手动操作,那么估计 Ctrl + C/V 都会罢工。

幸运的是,Git 其实提供了这样一个命令 cherry-pick 帮助我们一步实现上面的补救措施。其命令格式是

git cherry-pick <commit-hash>

上面的命令格式中,commit-hash 是在提交 commit 时 git 自动生成的 hash 串,代表每个独一无二的 commit。

Cherry-Pick 用于从其它分支提取某些 commit,并且合并到当前工作分支,同时还会把之前提交的描述也拷贝进来。这样大大简化了拉取其他分支某个 commit 的难度。

为何要用 Cherry-Pick

在多人合作的团队项目中,管理员通常会创建一个主线分支,比如命名为 develop,然后允许各个开发者基于主线分支分叉出特性分支,并在各自特性分支上进行特性功能的开发。在特性分支上,功能开发验证完毕后,开发人员再提交 merge 合并请求,将特性分支合并到主线分支,合并请求由管理员审核通过后才执行具体合并动作。

这里边,在合并分支内容时,有些情况需要分开讨论。

如果,特性分支最终开发完毕,并得到完整的认可,那么可以采用 merge 操作将特性分支新增的所有 commits 都合并到主线分支。

可是,如果在特性分支没有开发完毕又被遗忘很久远的时候,后来想想又需要用到其中的部分更新内容,比如,bug 补丁等,那么这个特性分支里的部分 commit 才是值得被拉取的内容,用 merge 明显不行,应该用 cherry-pick。

既然 cherry-pick 和 merge 都是用于合并 commit,那么区别在哪?

Cherry-Pick 只针对某个分支的某些指定 commit,而不是全部,而 merge 会把被选中分支的所有不同 commit 都拉取过来,这正是 cherry-pick 和 merge 的核心区别所在。

此外,类似合并功能的命令还有 rebase,后边有机会再撩她。

怎么使用 Cherry-Pick

多人开发的团队项目在代码管理上,很多麻烦的操作(例如合并分支代码等)都在类似 Gitlab 的平台上进行,平台能够尽最大限度规范化推行代码的合并。关于 Gitlab 的介绍,可以查看八戒以前写的文章《在局域网搭建一个带 web 操作页面的 git 版本服务器 - Gitlab》。

当然,如果接收合并内容的分支不受管控,完全可以自己在本地通过 git 命令合并或者用集成 git 功能的客户端可视化操作。带有 git 功能的可视化客户端也比较多,例如 TortoiseGit、SourceTree 和各大热门 IDE 等。

接下来选择使用 git 命令来简单做个示例。

准备一个本地代码仓库

$ cd ~
$ mkdir sample && cd sample
$ git init
Initialized empty Git repository in ~/sample/.git/

添加第一个改动,这里创建一个文本文件 index.txt 并写入字符串 index,然后提交到默认分支 master

$ echo index>index.txt
$ git add .
$ git commit -m "add index file"
[master (root-commit) e423b8c] add index file1 file changed, 1 insertion(+)create mode 100644 index.txt
$ git status
On branch master
nothing to commit, working tree clean

再准备两个特性分支 A 和 B

$ git branch A
$ git branch B
$ git branchAB
* master

git branch 命令只会创建新分支,但不会切换。

切换到特性分支 B 开始特性开发,这里为演示起见单纯创建一个文件 feature.txt 并写入字符串 feature,然后将工程更新提交到当前分支 B

$ git switch B
Switched to branch 'B'
$ echo feature>feature.txt
$ ll
total 2
-rw-r--r-- 1 Administrator 197121 8 Nov  8 19:22 feature.txt
-rw-r--r-- 1 Administrator 197121 6 Nov  8 19:10 index.txt
$ git add .
$ git commit -m "create feature"
[B a827145] create feature1 file changed, 1 insertion(+)create mode 100644 feature.txt
$ git log --oneline
a827145 (HEAD -> B) create feature
e423b8c (master, A) add index file

可以看到本地工作目录,在只有 index.txt 文件的基础上,多了个 feature.txt 文件。

除了 git switch 可以切换分支,还有 git checkout 也可,两者作用基本一样,但是建议统一使用 switch,避免记忆负担。

使用 git log 查看当前分支的提交日志,后边的选项 --oneline 会将日志信息简化到一行,方便查看提交记录比较多的情况。

当特性开发到这个阶段时,突然发现工程代码其实有个 bug,自己发现—高兴坏了。既然分支 B 和 分支 A 都是从主线分支分叉而来,那么分支 A 的代码中也会存在同样的 bug。

着手修复分支 B 的 bug,这里简单起见只是创建一个文件 fix.txt 并写入字符串 fix,然后提交更新到仓库

$ echo fix>fix.txt
$ git add .
$ git commit -m "fix bug"
[B 797dfa4] fix bug1 file changed, 1 insertion(+)create mode 100644 fix.txt
$ git log --oneline
797dfa4 (HEAD -> B) fix bug
a827145 create feature
e423b8c (master, A) add index file

那么怎么把分支 B 里刚刚修复的 bug 更新应用到分支 A 中呢?如果使用 merge 合并,那么分支 B 中还未开发完成的特性功能也会被一起同步到分支 A 中,这样不是我们想要的结果,于是可以针对某些已提交的 commit 执行 git cherry-pick。

在执行 cherry-pick 时需要已提交 commit 的 hash。从上面分支 B 的提交日志可以找到这串 hash

...
797dfa4 (HEAD -> B) fix bug
...

797dfa4 就是我们需要的 commit hash,虽然它不是一串完整的 hash,但是 git 只对比前面一部分就够了。

切换到分支 A 中,然后 cherry-pick

$ git switch A
Switched to branch 'A'
$ git log --oneline
e423b8c (HEAD -> A, master) add index file
$ git cherry-pick 797dfa4
[A e27c778] fix bugDate: Wed Nov 8 19:48:36 2023 +08001 file changed, 1 insertion(+)create mode 100644 fix.txt$ ll
total 2
-rw-r--r-- 1 Administrator 197121 4 Nov  8 20:01 fix.txt
-rw-r--r-- 1 Administrator 197121 6 Nov  8 19:10 index.txt
$ git log --oneline
e27c778 (HEAD -> A) fix bug
e423b8c (master) add index file

可以看到执行 git cherry-pick 后,本地目录下也有了 fix.txt 文件,也即是分支 B 中做了修复 bug 的更新内容已经同步到分支 A 中,合并结果成功。

陷阱

上面的合并过程是很理想化的顺利,但是现实往往有些棘手。

比如,在分支 B 中,如果当时开发特性功能时刚好修改了有几行主线分支的原有代码,而修复 bug 时同样改动了这几行代码,那么在 cherry-pick 时有极大可能会出现合并冲突,导致合并失败,这时需要手动再处理冲突的代码段,保留符合修复 bug 意图的代码。

这种冲突,在 merge 操作中也很常见,原因基本类似。

所以说,cherry-pick 虽然很强大,但不是万能的,不要过度使用,使用时应该谨慎。

一般在 merge 合并操作能满足使用需求的情况下,优先建议使用 Merge,而不是 cherry-pick,只有在两个分支不是可以完全合并的前提下,再考虑使用 cherry-pick。因为 cherry-pick 在设计时就是为了解决某些指定 commit 的合并,而非全部。

这就是 cherry-pick 的桃色陷阱,你说呢?

这篇关于Git:Cherry-Pick 桃色陷阱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/495985

相关文章

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

git ssh key相关

step1、进入.ssh文件夹   (windows下 下载git客户端)   cd ~/.ssh(windows mkdir ~/.ssh) step2、配置name和email git config --global user.name "你的名称"git config --global user.email "你的邮箱" step3、生成key ssh-keygen

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

忽略某些文件 —— Git 学习笔记 05

忽略某些文件 忽略某些文件 通过.gitignore文件其他规则源如何选择规则源参考资料 对于某些文件,我们不希望把它们纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常它们都是些自动生成的文件,比如日志文件、编译过程中创建的临时文件等。 通过.gitignore文件 假设我们要忽略 lib.a 文件,那我们可以在 lib.a 所在目录下创建一个名为 .gi

取得 Git 仓库 —— Git 学习笔记 04

取得 Git 仓库 —— Git 学习笔记 04 我认为, Git 的学习分为两大块:一是工作区、索引、本地版本库之间的交互;二是本地版本库和远程版本库之间的交互。第一块是基础,第二块是难点。 下面,我们就围绕着第一部分内容来学习,先不考虑远程仓库,只考虑本地仓库。 怎样取得项目的 Git 仓库? 有两种取得 Git 项目仓库的方法。第一种是在本地创建一个新的仓库,第二种是把其他地方的某个

Git 的特点—— Git 学习笔记 02

文章目录 Git 简史Git 的特点直接记录快照,而非差异比较近乎所有操作都是本地执行保证完整性一般只添加数据 参考资料 Git 简史 众所周知,Linux 内核开源项目有着为数众多的参与者。这么多人在世界各地为 Linux 编写代码,那Linux 的代码是如何管理的呢?事实是在 2002 年以前,世界各地的开发者把源代码通过 diff 的方式发给 Linus,然后由 Linus

集中式版本控制与分布式版本控制——Git 学习笔记01

什么是版本控制 如果你用 Microsoft Word 写过东西,那你八成会有这样的经历: 想删除一段文字,又怕将来这段文字有用,怎么办呢?有一个办法,先把当前文件“另存为”一个文件,然后继续改,改到某个程度,再“另存为”一个文件。就这样改着、存着……最后你的 Word 文档变成了这样: 过了几天,你想找回被删除的文字,但是已经记不清保存在哪个文件了,只能挨个去找。真麻烦,眼睛都花了。看

C++学习笔记----6、内存管理(四)---- 通常的内存陷阱(2)

3、Windows环境下使用Visual C++发现并修复内存渗露         内存渗露很难跟踪是因为你无法很容易地看着内存并且看到什么对象处于使用中,一开始在哪儿分配的内存。然而,是有程序可以为你做到这一点的。内存渗露检测工具有昂贵的专业软件包,也有免费下载的工具。如果你是在Microsoft Visual C++环境下工作,它的排错工具库有内建的对于内存渗露检测的支持。该内存检测默认没有

如何删除不小心上传到git远程仓库中的.idea .iml文件

如果在开始的时候不配置,gitignore文件或者文件配置不正确,初始化上传的时候就会有一些不必要的信息上传上去 如果已经存在了一些文件在git远程仓库中,如。idea,.iml文件等。 首先在项目中定义一个  .gitignore文件,简单的实例如下也可以用idea中的gitignore插件 .DS_Storeclasses/*.settings/target/.classpath