git_各种切换分支_回退

参考文章:一文讲透 Git 底层数据结构和原理 - 阿里开发者的文章 - 知乎 https://zhuanlan.zhihu.com/p/142289703

image-20220815154815483

简要说明

命令 描述
checkout Switch branches or restore working tree files
reset Reset current HEAD to the specified state
revert Revert some existing commits
rebase Reapply commits on top of another base tip
switch Switch branches
restore Restore working tree files

可以看出,checkout实际上是switch和restore的结合。

对应的场景

checkout

两个作用,一是切换分支,二是恢复工作区代码。如果checkout相同分支,则作用就是恢复工作区代码。因此,可以作用于,想要把未add的代码恢复到最新commit的状态。

reset

  1. git reset --mixed:此为默认方式,等同于不带任何参数的git reset。这种方式,只保留源码,回退commit和index信息
  2. git reset --soft:回退到某个版本,只回退了commit的信息,如果还要提交,直接commit即可(修改的内容变成未add的状态),索引(暂存区)和工作目录的内容是不变的,在三个命令中对现有版本库状态改动最小。
  3. git reset --hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,所有修改的内容都会丢失, (修改的代码 不会变成未add的状态)。索引(暂存区)内容和工作目录内容都会变给定提交时的状态。

revert

revert我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西

参考链接:https://www.jianshu.com/p/ef34fa4c8bf8

rebase

https://blog.csdn.net/weixin_42310154/article/details/119004977

git回退

只回退单个文件

https://zhuanlan.zhihu.com/p/267141048

Git在2.17中新增两个命令,restore和switch,分担checkout的职责;

1
2
# 放弃工作区的内容,使保持与暂存区一致
git restore src/index.js src/images/file.png

这里的默认参数是--worktree(工作区)

暂存区单个文件放弃修改:

1
2
# 放弃暂存区的内容,使与最近一次提交保持一致(HEAD)
git restore --stage src/index.js src/images/file.png

这里是暂存区的内容发生了变化,工作区的内容不会受影响

工作区单个文件恢复到某个提交版本

1
2
3
# 恢复工作区的某个文件到指定的某个版本,如果文件有修改也会被覆盖
git restore --source HEAD src/index.js src/images/file.png
git restore --source d68fsdf68s6df src/index.js src/images/file.png

恢复操作执行后需要add

暂存区单个文件恢复到某个提交版本

1
2
3
# 恢复暂存区的某个文件到指定的某个版本,如果暂存区文件有未提交也会被覆盖
git reset HEAD src/index.js src/images/file.png
git reset d68fsdf68s6df src/index.js src/images/file.png

如果需要将工作区与暂存区的某个文件都恢复到之前某个提交版本,则使用checkout来操作,简称co

1
2
3
# 同时将工作区与暂存区的某个文件恢复到指定版本
git co HEAD src/index.js src/images/file.png
git co d68fsdf68s6df src/index.js src/images/file.png

分布式和集群之间的对比

单机服务器

业务系统做了模块化设计,每一个模块都包含很多特定的业务。

拿聊天服务器举例子,一个server上,有若干个模块构成,比如,用户管理、好友管理、群组管理、消息管理、后台管理模块。每一个模块都包含特定的业务,比如用户管理模块就包含用户的登录(通常用一个方法来做登录业务),再如用户的注册、用户的注销。好友管理模块包含添加好友、删除好友;群组管理包含加群、创建群、删除群成员等等;消息管理包含离线消息、一对一聊天消息、群聊消息;后台管理包含广播消息等。

问题:单机服务器在性能、设计上有何瓶颈?

  1. 聊天服务器所能承受的用户的并发量受限于硬件资源。比如32位服务器,最多支持2w多人同时在线聊天,即直接受限于socket资源。
  2. 所有模块耦合在一个单体服务器上,如果修改任意一个模块,哪怕是几行代码,都会导致整个项目代码重新编译、部署。
  3. 各模块对于硬件资源的需求不一样。有些模块属于CPU密集型(计算量大),有些是属于IO密集型的。CPU密集型模块应当部署在CPU性能高的机器上,IO密集型则对CPU性能要求不高,而是需要内存资源多、带宽大的机器。

集群服务器

现在,把同一个服务器程序,独立地运行在三个服务器上,分别是server1、server2、server3,每一台服务器都是一套独立的聊天系统。

解决了单机服务器的问题1,提升了用户的并发量。但是没有解决问题2,如果需要修改代码,仍需重新编译,只不过只需要编译1份,但是仍需重新部署在多台服务器上。针对问题3,单纯的集群只是水平地扩展硬件机器,每一台机器上的程序并没有分模块去针对性地分配硬件资源。

比如,后台管理使用的用户并不多,只有极个别的管理员才能使用,因此此模块根本不需要高并发。如果将后台管理部署在每一台服务器上,可能会浪费硬件资源。

因此,可以想到,如果不能很好地分配集群环境中的机器资源,可能不能把整体系统的性能发挥到最大,即不分模块进行部署则不能充分利用全部资源。

优点是,部署很简单,因为没有过多的设计,每台机器的部署方式是一样的,直接运行同一个程序即可。

分布式服务器

现有三台服务器,server1部署用户管理、消息管理模块;server2部署好友管理、群组管理模块;server3部署后台管理模块。

相对于集群服务器,如果server2失效,整个系统仍可以正常运行。而如果分布式系统中,任何一个服务器失效,都会造成整个系统的失效。因此,分布式系统是所有服务器共同构成一个聊天系统,给客户端提供服务。因此也把每个服务器称为分布式节点。

解决了问题2,因为分模块部署,如果只修改了某一模块的代码,只需要部分编译,只需要对某一节点进行单独的部署。

解决了问题3,比如节点3后台管理模块包含CPU密集型业务,则其对应的机器可以针对性增加CPU性能,相对地减少内存资源、网络带宽资源。相反的,节点1的用户管理、消息管理模块对应的机器增加内存资源、网络带宽资源,而不需要过高的CPU性能。如此,可以有利于硬件资源的合理分配。

分布式+集群服务器

根据节点的并发要求,可以针对某一节点再做节点模块集群部署。

分布式节点1主要负责用户连接、信息传递的处理,对并发量要求大,所以此时我们需要针对此节点进行扩容,即增加服务器同样部署用户管理、消息管理模块。

而且,也可以灵活的调整不同节点的职责,比如,可以同样在节点2上部署用户管理模块,当节点1失效时,可以启用节点2的用户管理模块。

带来的挑战

  1. 软件设计:需要设计整个系统的软件模块划分,否则各模块可能会实现大量重复的代码
  2. 框架设计:各模块之间如何访问、通信?各模块都运行在不同的进程里,比如好友管理模块、群组管理模块。需要一个机制使函数调用透明化。

分布式系统框架解决的问题

比如,节点1负责完用户的登录后,需要获取好友列表,则需要一个机制访问节点2上的好友管理模块。节点1上的模块怎么调用机器2上的模块的一个业务方法?机器1上的一个模块进程1怎么调用机器1上的模块进程2里面的一个业务方法?

需要在网络上传递函数的标识,函数复杂的参数的数据给其他机器。其他机器执行完毕后,返回数据的过程也是需要在网络上传递给调用方机器。

这个过程很复杂,因为有可能每个传递过程都会存在网络异常问题,需要有机制去告诉调用方传输状态。所以,需要把整个过程封装到分布式网络通信框架之中。则在用户看来,调用远端的方法就和调用本地进程内的方法一样简单,不用关注具体细节。

总的来说,分布式是为了克服部署解耦化、资源分配最大化而生。而实现分布式框架需要封装网络通信的具体细节,尤其是,一,传递函数的标识,函数复杂的参数的数据给其他机器,二,需要有机制去告诉调用方每一个传递过程中的传输状态。