一些零碎的知识

修改最后一次提交

实际开发中,你可能会遇到下边这两种情况:

Situation One:版本刚一提交(commit)到仓库,突然想起漏掉两个文件还没有添加(add)。就好比你是老司机,说开车就开车,到了半路发现还有俩乘客没上来……

Situation Two:版本刚一提交(commit)到仓库,突然想起版本说明写得不够全面,无法彰显你本次修改的重大意义……

辣么遇到上边这两种情况,你都避免不了要头疼。但记住一点,只要是在本地发生的事情,大多数情况下我们都是有办法恢复滴。

有鱼油猛地虎躯一震,似乎想起来什么

没错,在 Git实用教程6:回到过去 中我们讲到可以用 reset 命令回到过去。

但这有点像我们打游戏打不过 BOSS,退回最近存档重练的赶脚……对于希望“一次通关”的完美主义者来说多少有点不爽!那么有没有一步到位的方法呢?

答案是肯定的,可以执行带 --amend 选项的 commit 命令,Git 会“更正”最近的一次提交。

案例还是前边的 MyProject2(别问我为嘛不整点 niubi 轰轰的栗子,因为那样你就会忙着去看代码而忘了学 Git 了!就像你们去车展,难道是去看车的吗?)

回顾一下,上次经我们这么一折腾,仓库里总共提交了两个版本:

然后为了演示 diff 命令,我们将 README.md 文件改了又改,最后三棵树是酱紫:

这时,我们希望将暂存区域的 README.md 文件进行提交,但又没必要为此增加一个新的版本(你说是吧)。

怎么办呢?执行 git commit --amend 命令修改最后一次提交即可。

执行命令后会立刻跳转到下边界面:

看到没有,老外对我们满满的恶意

其实进入的界面是让你编辑提交说明而已,如果你 commit 的时候没有 -m 选项,都会进入这么一个窗口让你填写说明。

大家也看到了,这一块对中文的支持仍然是一个大写的不友善!

So,如果需要修改提交说明,那么可以执行 git commit --amend -m "新的提交说明" 命令。

如果不需要修改,请按下快捷键 Shift + z + z(其实就是连续两个大写 Z)来退出,或者可以按下冒号(:),然后输入 q! 退出。那么会 Git 会保留旧的提交说明。

这块就是vim的操作。

此时,Git 仓库中仍然只有两个版本:

暂存区域的内容也提交上去了:

这里其实说的不是很对,我觉得更好的说法是暂存区的内容被传递到了版本区。

暂存区目前还是有内容的。这样做我觉得很大程度上是为了节省空间,因为git存的是文件的全部内容而不是增量,多一个版本,如果是大的工程,空间就要耗费很多。

这个中文支持真让我头疼。

删除文件

“自从使用了 Git,妈妈再也不用担心我删错文件了!”—— 一个文件只要被 Git 盯上了,那么它就休想轻易地逃出魔掌!

比如我现在从工作目录中手动删除 README.md 文件,然后执行 git status 命令:

Git 马上意识到哪里不对劲,赶紧对比一下暂存区域……噢,原来你小子偷偷地把 README.md 删除了丫!哼,还想瞒天过海?

Git 同时提醒使用 checkout 命令可以将暂存区域的文件恢复到工作目录:

看,README.md 又回来了:

那现在问题来了:如何在 Git 中删除文件呢?

假如你不小心把小黄图下载到了工作目录,然后又不小心提交到了 Git 仓库:

这下肿么办?让老板看到了这鱿鱼就吃定了……

这时,小甲鱼祭出了 rm 命令救你于水深火热之中!

执行 git rm yellow.jpg 命令:

你会发现此工作目录中的小黄图(yellow.jpg)已经被删除……

但执行 git status 命令,你仍然发现 Git 还不肯松手:

(⊙o⊙) Git 的意思是说它在仓库的快照中发现有个叫 yellow 的东西,但似乎在暂存区域和当前目录不见了!

好吧,事实证明要从 Git 中真正删除一个文件是件非常麻烦的事儿!

此时,你可以执行 git reset --soft HEAD~ 命令将快照回滚到上一个位置,然后重新提交,Git 就不会再提小黄图的事儿了:

注意:rm 命令删除的只是工作目录和暂存区域的文件(即取消跟踪,在下次提交时不纳入版本管理)

你们别嫌我啰嗦,还有两种情况你们可能会遇到,比如我在工作目录中增加一个 test.py 文件,然后执行 git add test.py 命令将其添加到暂存区域,此时我修改 test.py 文件的内容,那么暂存区域和工作目录就是两个不同的 test.py 文件了:

此时如果我执行 git rm test.py 命令,Git 会下意识地阻止我:

因为两个不同内容的同名文件,谁知道你是不是搞清楚了都要删掉?还是提醒一下好,别等一下出错了又要赖机器……

根据提示,执行 git rm -f test.py 命令就可以把两个都删除。

还有另一种情况就是你可能只想删除暂存区域的文件(保留工作目录的),那么你可以执行 git rm --cached 文件名命令实现目的。这些我们前面都试过,不过和我理解的rm有些不一样。

这里我假如要删除README.md

这里还是我前面在第二讲里理解的有些问题,这里面的git rm也就是把文件从工作目录

和暂存区删除了,而并没有从版本库里面删除,并没有创建一个新的版本库,这个时候我们可以commit创建一个新的版本库,但是这样有点危险,因为如果有人回到上一个版本,岂不是就揭穿你了?

所以还是reset 一下比较好,这样最起码git log是无法看到有黄图版本的id,就恢复不过去,如果你了解前面的知识,就会知道其实git reflog还是可能有办法恢复回去右黄图的版本,不过这个安全性就高一些,这个可以说是最稳妥的办法了。

重命名文件

代码改着改着突然觉得文件的名字不合适了,于是重命名,这种情况平时不少见吧?

但你这么做,通常会把 Git 搞懵逼!

我们把 game.py 重命名为 wordgame.py,执行 git status 命令:

Git 说:OMG,仓库的快照中检查到有一个叫 game.py 的文件,你是不是删了(rm)?然后又整了个叫 wordgame.py 的新文件进来?

其实我们就只是改了一下名字……

好吧,先把名字改回来(你再执行 git status 又可以看到 clean 了)。

在 Git 里重命名,需要让 Git 来帮你做,这样它才便于跟踪。

执行 git mv game.py wordgame.py 命令:

mv是剪切的意思。

木有消息,因为在 Git 看来,这点儿小事不值得一提~~

但你执行 git status 命令可以看到操作记录:

其实,mv 命令相当于执行下边三条命令:ren gam.py wordgame.py

git rm game.py

git add wordgame.py

注:Windows在cmd里使用 ren 命令修改文件名,Linux 是使用 mv 命令……都说了,深深的文化入侵的恶意……

噢,对了,你应该还不知道如何让 Git 忽略一些指定的文件吧?

我的意思是让 Git 识别某些格式的文件,然后自主不跟踪它们(不要总提示 XXX 还没加入暂存区域,要不要加入啊?要不要跟踪啊?要不要?要不要嘛?!!)

现在在工作目录中添加 1.temp、2.temp 和 3.temp 三个文件。

我们不希望后缀名为 temp 的文件被追踪,可 Git 却像个烦人的小妖精:

(要不要嘛,要不要嘛,嗯,要嘛,要嘛~~~)

让 Git 闭嘴的办法是有的,需要你在工作目录创建一个名为 .gitignore 的文件。

然后你发现 Windows 压根儿不允许你在文件管理器中创建以点(.)开头的文件(Linux 和 Mac 我们都习惯在终端下工作,这里就不啰嗦):

Windows 需要在命令行窗口下才能创建以点(.)开头的文件,执行 echo *.temp > .gitignore 命令,创建一个 .gitignore 文件,并让 Git 忽略所有 .temp 后缀的文件:

(上面的内容是不是很熟悉啊,没错就是一个输出重定向而已)

再看看 Git 的状态:

好了,Git 已经忽略了所有的 *.temp 文件(你还可以把 .gitignore 文件也一并忽略)。

.gitignore 语法规范

.gitignore 可以使用标准的 glob 模式匹配(glob 模式是指 shell 所使用的简化了的正则表达式):所有空行或者以注释符号 # 开头的行都会被 Git 忽略;

星号(*)匹配零个或多个任意字符;

[abc] 匹配任何一个列在方括号中的字符;

问号(?)只匹配一个任意字符;

[a-z] 匹配所有在这两个字符范围内的字符;

匹配模式最后跟反斜杠(/)说明要忽略的是目录;

匹配模式以反斜杠(/)开头说明防止递归;

要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

正则的语法在python学习那里就介绍过了。

嗯嗯,这里有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,拿走,不谢

https://github.com/github/gitignore

我们看看python的:

和python相关的还真是有一堆呢。如果你想加入到原来的.gitignore而不是覆盖的话,用>>就好。

下面是这一讲的主角。

分支和分支管理

俗话说得好 —— 该来的总是会来的!

之前我们一直把分支挂在嘴边,好多鱼油胃口都给小甲鱼吊到嗓门眼上了,这一节开始小甲鱼就来给大家讲讲 Git 的分支和分支管理!分支无疑是 Git 最值得傲娇的技能,不信你看它的 LOGO

这不就是个大写的劈叉嘛~

分支是什么?

假设你的大项目已经上线了(有上百万人在使用呢),过了一段时间你突然觉得应该添加一些新的功能,但是为了保险起见,你肯定不能在当前项目上直接进行开发,这时候你就有另(创)起(建)炉(分)灶(支)的需要了。

放个大图先让你知道分支大概是咋回事:

如果没有分支,整个产品的迭代周期就会因为新功能的开发而被延误(因为还有补 bug 这样比较着急的任务)……可见分支对于版本控制系统来说是多么重要!

不过话说回来,目前几乎所有的版本控制系统都以某种形式支持分支,那么 Git 还有什么好嘚瑟的呢?

记得在第一讲介绍 Git 的时候跟大家分享过资深玩家对 SVN 的吐槽:克隆一份全新的目录以同样拥有 5 个分支来说,SVN 是同时复製 5 个版本的文件,也就是说重复 5 次同样的动作。而 Git 只是获取文件的每个版本的元素,然后只载入主要的分支(master)在我的经验,克隆一个拥有将近一万个提交(commit),5 个分支,每个分支有大约 1500 个文件的 SVN,耗了将近 1 小时!而 Git 只用了区区的 1 分钟!

“克隆一个拥有将近一万个提交(commit),5 个分支,每个分支有大约 1500 个文件的 SVN,耗了将近 1 小时!而 Git 只用了区区的 1 分钟!”……突然小甲鱼想起了一句话 —— 天下武功,唯快不破!

我们深入一点思考,到底是什么成就了 Git“秒男”的称号呢?

在第三讲中,我们介绍理论的时候,说 Git 采用一种看似“异端”的形式来处理版本迭代 —— 通常的版本控制系统是采用增量文件系统来管理版本迭代;而 Git 则是采用将每个版本都独立存储的方式 —— 看上去使用 Git 会耗费更多的空间,但来到分支管理这一块,却成了 Git 完胜其它版本控制系统的关键!

因为对于其它版本控制系统而言,创建分支常常需要完全创建一个源代码目录的副本,项目越大,耗费的时间就越多,因为它每次存储的都是增量,必须得回溯到最开始的那个版本才能合并成一个完整的版本;而 Git 由于每一个结点都已经是一个完整的项目,所以只需要创建多一个“指针”(像 master)指向分支开始的位置即可。

创建分支

下边小甲鱼给大家演示如何创建和切换分支,我们来到之前的 MyProject2(如果你已经删了,没关系,重新创建一个项目,然后随便写点东西,提交然后修改,再提交,即可):

MyProject2 现在仓库里的情况如下:

执行 git status 命令查看状态:

可以看到 README.md 文件被修改并添加到暂存区域(还没有提交),所以当前三棵树应该是这样:

好,现在我们开始创建分支!

创建分支,使用 git branch 分支名 命令:

没有任何提示说明分支创建成功(一般也不会失败啦,除非创建了同名的分支会提醒你一下),此时可以执行 git log --decorate 命令查看:

如果希望以“精简版”的方式显示,可以加上一个 --oneline 选项(即 git log --decorate --oneline),这样就只用一行来显示一个快照记录。

可以看到最新的快照后边多了一个 (HEAD -> master, feature)

它的意思是:目前有两个分支,一个是主分支(master),一个是刚才我们创建的新分支(feature),然后 HEAD 指针仍然指向默认的 master 分支。

所以目前仓库中的快照应该是这样:

切换分支

现在我们需要将工作环境切换到新创建的分支(feature)上,使用的就是之前我们欲言又止的 checkout 命令。

执行 git checkout feature 命令:

这样 HEAD 指针就指向 feature 分支了:

什么?!口说无凭!

好吧,你们要的证据在这里:

看到没有?HEAD 指针已经指向了 feature 分支:(HEAD -> feature)

现在我们进行一次提交(暂存区域还有一个更改的文件没有提交呢):

现在仓库中的快照应该是酱紫:

然后我们将 HEAD 指针切回 master 分支:

细心的朋友会发现上一次对 README.md 文件的修改已经荡然无存了,这是因为我们的工作目录已经回到 master 分支的状态中:

现在对 README.md 文件进行修改(随便改改),然后执行 git commit -m "再次修改说明文件":

好了,目前仓库中的快照应该变成了酱紫:

什么?!不相信?

好吧,让 Git 自己来告诉你!

执行 git log --oneline --decorate --graph --all 命令:

--graph 选项表示让 Git 绘制分支图,--all 表示显示所有分支

也就是在分支创建的节点也就是HEAD指向的快照,之前和创建时的master的快照是共享的,如果以后再修改的话,就不是共享的了,会进行分叉。git log查看的是当前分支上之间提交的快照。

Git 工作流程

Git 工作流使用一个中间仓库作为所有开发者的交流地点,开发程序的小伙伴在本地工作,然后将各自的分支推送到中间仓库。

开发分支(develop)

代替单一的 master 主分支,上图的工作流使用了两个分支来处理项目发布和日常开发。

master 主分支通常只是用于对外发布项目的新版本,日常开发应该在另一条分支上完成。我们把开发用的分支叫做 develop 分支。

功能分支(feature)

每一个新功能应该使用单独一个功能分支进行开发,功能分支应该从开发分支中分离出来,功能开发完成后合并到开发分支。

提示1:功能分支不应该跟 master 分支有任何交流。

提示2:功能分支可以采用 feature-* 的形式命名。

预发布分支(release)

在项目正式发布之前,你可能需要一个预发布的版本进行测试。于是你可以从开发分支中分离出预发布分支,用于内部或公开的测试。

提示1:预发布分支应该同时合并到主分支和开发分支中。

提示2:预发布分支可以采用 release-* 的形式命名。

维护分支(hotfix)

项目正式发布后难免会出现 bug,这时就需要创建一个分支,进行 bug 的修补。

提示1:维护分支应该从主分支中分离出来,bug 被修补后,再合并到主分支和开发分支中。

提示2维护分支可以采用 fixbug-* 的形式命名。

常设分支

常设分支就主分支(master)和开发分支(develop)两个即可,另外的功能分支(feature)、预发布分支(release)和维护分支(hotfix)属于临时分支,用完之后应该及时删除。

So,在正式开发中,Git 的分支管理如下:

虽然看起来比较复杂,不过都还是比较好理解的。

合并分支

当一个子分支的使命完结之后,它就应该回归到主分支中去。

上次经我们这么一折腾之后,分支的状态如下:

合并分支我们使用 merge 命令,执行 git merge feature 命令,将 feature 分支合并到 HEAD 所在的分支(master)上:

Holy crap!!

这就叫出师不利……

从 Git 提示的内容来看,我们知道这次的合并并没有成功,Git 说:合并 README.md 文件的时候出现冲突。

所以自动合并失败;请修改冲突的内容并重新提交快照。

意思是说现在你需要先解决冲突的问题,Git 才能进行合并操作。所谓冲突,无非就是像两个分支中存在同名但内容却不同的文件,Git 不知道你要舍弃哪一个或保留哪一个,所以需要你自己来决定。

此时执行 git status 命令也会显示需要你解决的冲突:

然后 Git 会在有冲突的文件中加入一些标记,不信你打开 README.md 文件看看:

以“=======”为界,上到“<<<<<<< HEAD”的内容表示当前分支,下到“>>>>>>> feature”表示待合并的 feature 分支,之间的内容就是冲突的地方。

现在我们将 README.md 统一修改如下(同时去掉了 <<<<<<< HEAD 等内容):《零础入门学习Python》第004讲

课后作业:文字游戏

Power by www.FishC.com

保存文件,然后提交快照:

执行 git log --decorate --all --graph --oneline 命令,可以看到此时的分支已经自动合并了:

当然,如果不存在冲突,就不用搞这么多了……

我再做一次给你看!

执行 git checkout -b feature2 命令(相当于 git branch feature2 和 git checkout feature2 两个命令的合体):

在工作目录随便创建一个文本文件(feature2.txt)并提交快照:

执行 git log--decorate --all --graph --oneline 命令:

可以看到,feature2 分支比 master 分支快了一步。现在我们切换回 master 分支,并将 feature2 分支合并进来:

这次 Git 只显示了 Fast-forward(快进)这词儿,这是因为 feature2 这个分支的父结点是 master 分支,而master在c5523f4之后又没有新的快照,所以 Git 只需要简单移动 master 的指向即可。

执行 git log --decorate --all --graph --oneline 命令:

删除分支

对于不再需要的分支,我们还是把它们删了吧!

删除分支,使用 git branch -d 分支名 命令:

执行 git log --decorate --all --graph --oneline 命令:

这时 feature 和 feature2 已经消失了……

由于 Git 的分支原理实际上只是通过一个指针记载,所以创建和删除分支都几乎是瞬间完成。删除的只是分支的名字而已,其实我们还是可以通过id找到删除分支的快照。

注意:如果试图删除未合并的分支,Git 会提示你“该分支未完全合并,如果你确定要删除,请使用 git branch -D 分支名 命令。

对于分支的合并,Git 又是领先业界好几年!

Git 使用自动三方合并的方式,就算在一段较长的时间内,反复把一个分支合并入另一个分支,也不是什么难事。因为通常情况下,Git 会自动解决一些它能够理解的“冲突”,不需要你来干预;但如果是 SVN 之流则需要你亲自处理每一次合并的冲突。

那你知道什么是三方合并(three-way merge)吗?

Fast-forward

所谓的 Fast-forward 就是当待合并的分支位于目标分支的直接上游时,Git 只需把目标分支的指针直接移动即可实现合并。

比如下面图片中 master 分支是位于 feature2 分支的直接上游:

将 feature2 分支合并到 master 分支,只需要移动 master 的指针即可:

Three-way merge

如果待合并的两个分支不在同一条线上,那么进行合并就需要解决一个根本的问题 —— 冲突!我想有鱼油可能就会问了:为何两个分支在同一条线上就不会冲突呢?

因为 Git 的快照是按时间顺序提交的,所以在同一条线上的两个快照,它们是有先后顺序的,尽管两者可能出现同名文件不同内容,Git 会认为这是“改变”而不是“冲突”。

对于冲突的处理,Git 相对来说是比较机智的。

举个例子:

合并 C3 和 C4 得到 C5,但 C5 应该如何处理“冲突”呢?

SVN 会把问题抛给用户,让用户自行解决;Git 则显得更为高明,它会找到第三个快照,然后综合三者特点自动解决冲突。

那第三个快照应该如何决定呢?

没错,应该找两者的共同“祖先”作为参照物,一比较就知道两个分支都干了些什么。

图片中 C3 和 C4 的共同祖先是 C1,可以看到 C3 和 C4 分别增加了 test2.py 和 test1.py 两个文件。因为对比之后发现三者并没有冲突,所以 C5 应该是三者的合体,即同时拥有 common.py、test1.py 和 test2.py 三个文件(有兴趣的鱼油不妨测试一下)。

另外,值得一提的是,Git 这种合并方式也适用于同名文件的不同更改。

举个例子:

这里 C3 和 C4 都只有一个文件(test.txt),但是内容却不一样。如果这样合并,你猜 Git 会不会报“冲突”?

答案是不会的!

因为 Git 找到它们的共同祖先 C1,可以看到 C3 和 C4 都是在 C1 的基础上进行添加(C4 在第 2 行添加了“I”,C3 在第 4 行增加了“FishC”,C1 第 3 行的“love”是它们共同拥有的),同时在每一行并没有产生冲突的地方,所以自动合并后的 C5 是这样的:# test.txt

I

love

FishC

注意:如果 Git 检测到同一行有不同的内容,还是会报冲突并让你自行决定谁去谁留的!

这个就是同一行内容不同,所以会有冲突。

git上传分支的原理_git系列教程四:分支和分支管理相关推荐

  1. 史上最详细的Android Studio系列教程四--Gradle基础

    史上最详细的Android Studio系列教程四--Gradle基础 转载于:https://www.cnblogs.com/zhujiabin/p/5125917.html

  2. git 上传项目到linux仓库_使用子模块和子树来管理 Git 项目 | Linux 中国

    使用子模块和子树来帮助你管理多个存储库中共有的子项目. 来源:https://linux.cn/article-12244-1.html 作者:Manaswini Das 译者:Xiaobin.Liu ...

  3. 使用git上传代码到github

    1.      github上创建项目 github是一个服务器托管商,我们写好的代码可以上传到github上面去 登录github的官方网站:http://github.com/ 注册一个自己的用户 ...

  4. git上传提交遇到问题

    git上传提交遇到问题 一. The local repository is out of date.Make sure all changes have been pulled from the r ...

  5. git 上传修改文件

    git 上传修改文件 git init git remote add superman https://gitee.com/li_jiazhao_1/ChangClass_examination.gi ...

  6. 如何用Git向GitHub上传送文件(从注册GitHub到用Git上传的每一步)

    文章目录 1.GitHub 1.1.GitHub注册(已经注册过的直接看1.2GitHub仓库的建立) 1.2 GitHub仓库的建立 2.Git 2.1Git 安装 2.2 Git 下载 2.3 G ...

  7. Git上传代码时报错 Warning: Permanently added ‘gitee.com,212.64.62.174‘ (ECDSA) to the list of known host...

    Git上传代码时报错 Warning: Permanently added 'gitee.com,212.64.62.174' (ECDSA) to the list of known host... ...

  8. git上传文件到gitee

     第一步:登录注册gitee,有一个gitee仓库  1.git上传思路 2.git第一次上传步骤 第二步:将创建好的仓库,pull(拉取)到本地(不是第一次上传的情况下)            方式 ...

  9. Git 上传代码到github上

    学会操作git和使用Github来管理代码是技术开发人员的必备基本功,在工作中越来越发现,熟练掌握好git这个利器对工作非常有帮助. 首先你得在github上有一个账号.然后在上面创建一个创建个人项目 ...

最新文章

  1. Windows窗体编程(二)
  2. css3的动画详解 html直接可以运行
  3. 经典C语言程序100例之九五
  4. 网络协议基础:“工作中模模糊糊的概念,这次终于理顺了!”
  5. python并行计算numpy_【Nature文章摘录】NumPy: 从单机到分布式并行计算
  6. 【软件测试】测试驱动开发
  7. linux中杀死指定进程,Linux中通过 kill命令 杀死指定进程
  8. linux中判断语句,Linux--shel的if判断语句--05
  9. 【机器学习】KNN回归
  10. std::sort使用
  11. Base64(电子邮件传输算法)
  12. 8.PMAC上位机-VC编程环境配置
  13. 使用带有响应的Hypermedia API来保留v6
  14. taro开发微信小程序配置全局appid
  15. 《第十一堂棒球课》:MLB棒球创造营·棒球名人堂
  16. 教你一招:Word中的文字转换成表格,把表格转换成文字
  17. 上海交大 计算机科学家,世界顶尖科学家论坛丨上海交大计算机系教授俞凯:科研经费支持应少些“风险意识”...
  18. java 像素矩阵_JAVA eclipse 中,已知灰度图像的像素矩阵怎么输出这个图像
  19. 访问swagger/Knife4j 接口文档报错:java.lang.NumberFormatException: For input string: ““
  20. 程序的循环结构(for循环)

热门文章

  1. Essential C++ chapter 02_2.1
  2. BUUCTF bbys_tu_2016xm_2019_awd_pwn2
  3. Android开发实战《手机安全卫士》——2.“设置中心”模块实现 自定义组件 Sp工具类 MD5加密
  4. esri的portal门户:无法访问分析服务、存在错误、图层 无法添加到地图中
  5. 实战!教你如何破解交换机的密码(转)
  6. python 列表 元祖 字典 集合_python基础知识之列表、元祖、字典、集合、字符串。...
  7. 关于Kali Linux的安装
  8. 2022年注册会计师考试(税法)练习题及答案
  9. 内网渗透-cobaltstrike之cs上线获取shell
  10. 生成常用验证码识别,基于PaddleOCR训练识别