当前位置: 首页 > news >正文

Git的基本操作以及原理介绍

文章目录

    • 基本操作
      • 创建git仓库
      • 配置name和email
    • .git目录的结构
    • git add & git commit
      • .git目录结构的变化
    • git追踪管理的数据
      • git的版本回退
        • 回退的原理
        • 回退的三种情况
    • 版本库中文件的删除
    • git分支管理
      • 分支的删除
      • 合并分支时的冲突
        • 分支的合并模式
        • 分支策略
        • git stash
        • 不要在master分支上解决冲突
    • git的远程操作
      • 将修改提交到远程仓库
      • push时忽略特殊文件
        • 配置命令的别名
    • git的标签管理
      • 推送标签
    • git实战
      • 同一分支下的多人协作(不推荐)
      • 不同分支下的多人协作
      • 为什么本地依然能看到远端已经删除的分支?
      • git flow模型

git作为目前最主流的版本控制器,可以控制电脑中所有格式的文件
对于开发人员来说,通常使用git维护项目的源文件

那么什么是版本控制器?版本控制器是一个管理系统,用来记录每次的修改以及版本迭代(每次的版本数据)

基本操作

创建git仓库

要想使用git的版本控制,就需要创建一个git仓库,只有在仓库中的文件才会被git追踪管理
将当前所在目录初始化成git仓库:

git init

此时目录下会多出一个.git文件
image.png

配置name和email

使用git config进行配置

git config user.name "用户名"
git config user.email "邮箱地址"

这两个配置项必须与git远程仓库对应
查看配置项

git config -l

image.png

删除配置

git config --unset user.name
git config --unset user.email

使用--global选项选项,将配置应用于本地的所有git仓库:

git config --global user.name "用户名"
git config --global user.email "邮箱地址"

相应的,要删除全局的配置,只需要在删除命令中加上--global选项

.git目录的结构

查看一下git的目录树
image.png
我们不能修改.git下的所有文件,也不能更改.git的目录结构,这将导致git出错

在.git所在目录下创建了文件,文件会受到git的版本控制吗?
image.png
解释之前先说明两个概念:

  1. 版本库(即仓库):当前目录下的.git被称为版本库
  2. 除了.git之外的其他文件被称为工作区。我们只能修改工作区中的内容,不能修改版本库中的内容

工作区与版本库的关系:
image.png
版本库中,stage被称为暂存区,也叫索引index。此外还有一个master分支,由HEAD指针指向

工作区中的修改(新增、修改、删除)不会受到git的追踪
执行add命令后,git会将工作区中的修改写入暂存区
执行commit后,git会将暂存区中的修改提交到master分支中,此时修改真正地被写入版本库,这些修改才会受到git的追踪控制

此外,版本库中还有一个分区:objects对象库。对象库中存在多个对象,所有对工作区的修改都会被写入到这些对象中(这些对象保存了工作区的修改)
可以注意到暂存区和master都是目录树的结构,其中存储了文件,而这些文件中存储了对象库中对象的指针。也就是说,暂存区和master通过保存对象库中的对象指针,以表示当前的状态

执行add将修改暂存区的目录树,使之索引到对象库中的对象
执行commit操也修改master的目录树,使之索引到对象库中的对象

git add & git commit

将工作区中的修改写入暂存区中

git add filename [filename]

可以使用git add .,表示将当前目录下的所有修改写入暂存区中

将暂存区中的修改写入master分支(本地仓库)中

git commit -m "描述此次提交的目的"

使用git commit时,需要带上-m选项并输入此次提交的目的
如果直接输入git commit,我们将进入vim编辑器并输入此次提交的目的。显然直接使用-m选项是更方便的

打印时间从近到远的commit记录,记录包含了每次提交的提交目的

git log

image.png

其中commit id是经过hash得到的定长字符串。对于git log命令,携带--pretty=oneline选项,将简化打印的内容为一行
image.png

.git目录结构的变化

再创建两个文件,将其commit到仓库中
image.png

此时观察.git的目录结构
image.png

其中新增了index文件,即暂存区。执行add操作后,暂存区保存了工作区的修改,所以此时出现了index文件

此外还有存在一个HEAD文件
cat一下HEAD文件,发现指向了仓库中的master文件,也cat一下master文件
image.png
发现master文件保存了commit id,该commit id为最近一次commit操作的id

首先,master和index中保存着对象指针,指针指向的对象存储了工作区中的修改信息
所以commit id是一个指针,前两位为目录名,剩下的数字为文件名,这些文件存储在.git的objects目录下,可以在objects目录中找到对应文件
使用命令,打印object的信息

git cat-file -p commit id

-p选项可以将打印信息简化
image.png
(似乎不使用-p还无法打印信息)
可以看到object中记录了执行commit操作的用户名与邮箱,以及上一次的commit id
第一行还有一串commit id,git cat-file下,看看是什么
image.png
可以看到,该对象似乎保存了工作区中每个文件的object指针,每个文件对应的object中保存了文件的修改信息
image.png
ReadMe文件中,确实只有"hello git"这串字符串

总结一下,object保存了每次的commit信息,以及工作区中每个文件的修改信息。如何获取object的指针?master文件保存了最近一次commit对应的object指针,也保存了上一次commit的object指针

注意:要想将工作区中的修改提交到版本库中,必须先执行add将修改提交到工作区,再执行commit将修改提交到版本库,这两个操作不能颠倒

git追踪管理的数据

git追踪管理的不是文件,而是每一次的修改
修改ReadMe文件,使用git status命令查看当前仓库的状态
image.png
打印信息说,我们修改了ReadMe文件,但是暂存区中没有文件(no changes added)需要被提交
因为我们没有执行add

使用以下命令,查看工作区与暂存区中[某个文件]的差异

git diff [filename]

image.png
打印的是unix通用的diff格式:
---a表示改动前,+++b表示改动后
-1表示第一行为改动前的内容,+1表示之后的一行为改动后的内容,2表示改动后的内容到第二行结束

使用以下命令,查看版本库与工作区中[某个文件]的差异

git diff HEAD [filename]

image.png

将当前工作区的修改add到暂存区中,执行git status
image.png
打印信息说,当前暂存区中的信息已经准备好被提交了(changes to be committed)
并且指明了暂存区中修改的文件为ReadMe

commit之后,再执行commit status
image.png
打印信息说,工作区与暂存区都没有发生修改

git的版本回退

版本回退本质上是回退版本库中的内容
使用以下命令,进行版本回退

git reset [--soft | --mixed | --hard] [HEAD] -- commit id
  • –soft:回退版本库中的内容
  • –mixed:回退版本库与暂存区中的内容,可以指定需要回退的文件
  • –hard:回退所有区域的内容

其中miexed为默认选项
之前说过,执行了git init后的目录下有三个区域,工作区、暂存区以及版本库(仓库),reset命令的不同选项将不同程度地回退这些区域中的内容
注意:hard选项需要慎用!因为它将回退工作区中的数据!

根据git log打印的commit id,进行hard选项的版本回退,使ReadMe中只有"hello git"
image.png
可以看到之前有的"appending…“消失,只剩下"hello git”,并且日志也进行了回退

如果你有回退之前的commit id,你甚至可以撤销回退,回退之前的回退
image.png
该commit id为回退之前的id,此时成功撤销了回退
同时日志的回退也被撤销了
image.png

如果想要撤销回退,执行git reflog可以查看所有add和commit的信息,其中就包含了commit id的前7个字符,使用commit id的前7个字符也能进行执行/撤销回退
image.png
而一旦找不到commit id,将无法执行/撤销回退的操作

回退的原理

为什么git的回退这么快?因为回退只是修改了master保存的指针
master存储了最近一次的commit id,也就是object指针。object对象记录了每一次的修改操作。版本回退本质上是在修改master的值,使master指向不同的object指针。此时仓库中最近一次的commit操作就被修改,最近一次的commit不同,仓库中的数据就不同

回退的三种情况

撤销操作的本质:防止错误的代码从版本库中被push到远程仓库
用code表示错误的代码,那么将出现以下三种情况

工作区暂存区版本库解决方法
codegit checkout –
codecodegit reset + git checkout --或者git reset --hard
codecodecodegit reset --hard,前提条件: commit之后没有push
  1. 工作区中开发了大量代码,但是没有add,此时要撤销工作区中的修改
  2. 工作区中开发了大量代码,add了但是没有commit,此时要撤销工作区与暂存区的修改
  3. 工作区中开发了大量代码,add并且commit了,此时要撤销工作区、暂存区与版本库的修改

情况一:只有工作区需要回退代码

执行命令,将工作区的文件回退到最近一次add的状态,也就是和暂存区一致

git checkout -- filename

注意,必须要加上--,否则命令的效果完全不一样!
image.png

情况二:工作区和暂存区都需要回退代码

先修改ReadMe中的内容,添加"code"并且add修改到暂存区中
image.png

两种解决方法:
执行hard回退命令,使工作区与暂存区中的代码和版本库一致

git reset --hard HEAD filename

image.png
注意,git reset --hard不能回退指定文件,只有mixed模式能回退指定文件!

另一种方法:将情况二转换成情况一
执行命令,使暂存区中的代码回退,与版本库中的代码一致

git reset HEAD filename

HEAD指针指向了master分支,而master分支保存版本库的最近一次修改,即最新版本
所以git reset HEAD将使版本库和暂存区回退到当前版本,而版本库本来就是当前版本,所以只有暂存区回退到了当前版本

git status验证:
image.png
此时git status说,暂存区中没有修改需要被提交,也就是暂存区的内容和工作区中的内容一致

此时执行git checkout -- ReadMe,使工作区中版本和暂存区中的版本一致即可
image.png

情况三:所有区域都需要回退代码

执行命令,将工作区、暂存区以及版本库中的代码回退到上一版本

git reset --hard HEAD^

(其中HEAD,表示上一次修改即当前版本,而HEAD^表示上一个版本,HEAD^^表示上两个版本…)
一般来说都是将代码回退到上一版本,但是具体来说是哪个版本,就需要根据情况决定了
image.png

版本库中文件的删除

第一种方式:

  1. 先删除工作区中的文件
  2. 再将修改提交到暂存区中
  3. 最后将暂存区中的修改提交到版本库中
rm file1
git add file1
git commit -m "delete file1"

image.png
可以看到当前版本库中已经没有file1文件了

第二种方式:

  1. 执行git rm,同时删除工作区与暂存区中对应文件
  2. 将暂存区中的修改commit到版本库中

其实就是git rm等价于rm+git add

git rm file2
git commit -m "delete file2"

image.png
可以看到当前目录只剩下了ReadMe文件

git分支管理

之前说过,HEAD指针指向master分支,master分支存储了一个对象指针,该对象保存了最近一次commit,查看该对象的数据
image.png
可以看到该对象中还保存了一个对象指针parent,分支下的每一次commit都有先后时间,根据时间顺序,保存每次修改的对象就形成了一条时间链。parent保存了时间链中,当前对象的上一个对象的指针
通过parent指针,我们就能不断地往前追溯历史commit

我们还可以在master主分支上创建分支,并对该分支提交修改,此时也将形成一条版本链

执行指令,查看当前git仓库中存在哪些分支

git branch -a

-a将显示本地分支与远程分支,默认只显示本地分支
image.png

除了master分支,HEAD也能指向其他分支,由HEAD指向的分支被称为工作分支,也就是当前分支
执行命令,创建新的分支:

git brach dev

image.png

创建新的分支后的目录结构:
image.png
此时.git目录下出现了dev文件,查看该文件中的内容
image.png
发现它和master文件的内容一样,由此证明新建分支的数据基于原分支

切换分支

git checkout 分支名

image.png
* 在dev之前,说明当前HEAD指针指向了dev分支

也能使用一行命令完成分支的创建与切换:

git ckeckout -b 分支名

在dev分支中,修改ReadMe文件,并切换到master分支,查看ReadMe文件
image.png
发现只有在dev分支中才能看见修改后的ReadMe文件,而在master分支中,无法看见修改后的ReadMe文件
说明此次的修改被提交到了dev分支上,对master分支不可见

同理,在dev分支上提交数据后,refs/heads/dev保存的对象指针和refs/heads/master保存的对象指针不再相同
image.png

如何合并分支?首先要切回master分支

git checkout master
git merge 分支名

image.png
合并分支后,打印信息说,master分支下的ReadMe文件新增了一行数据

分支的删除

不能删除当前所在分支(工作分支),只能删除其他的分支

git branch -d 分支名

合并分支与删除分支的速度非常快。因此,git鼓励我们在分支上完成任务,合并到master分支中再删除分支,这样将更加安全

如果分支执行了add或者commit,但是没有被合并,此时无法使用-d删除该分支(git认为创建出来的分支都是要被merge的,只有在merge分支后,才能删除该分支),只能使用-D强制删除该分支

git branch -D 分支名

合并分支时的冲突

在dev分支中修改ReadMe文件,也在master分支中修改ReadMe文件,使两份文件不同
修改完文件我们要进行add和commit,使仓库中两个分支下的文件内容不同
image.png

此时执行合并操作
image.png
打印信息说合并失败,此时查看ReadMe文件
其中<<<<<<HEAD=======之间为当前分支下的数据,========到dev之间为dev分支的数据,两者不相同所以产生了冲突

如何解决冲突?手动解决,在master分支中的冲突文件中保留想要的代码。解决冲突后执行add和commit,此时合并操作才算完成
image.png

查看当前日志
image.png

使用以下命令,可以以图表的形式看到master分支与dev分支之间的关系

git log --graph --abbrev-commit

image.png

分支的合并模式

如果执行命令

git merge 分支名

调试信息中有"fast-forward"字段时,说明这次的提交为ff模式
该模式的合并无法通过git log --graph --abbrev-commit查看,图中不会出现两个分支合并成一个分支的信息,因此我们无法得知master合并了哪个分支

ff模式的本质是将被合并分支的最近一次提交对象指针写入到master分支的最近一次提交对象指针
image.png

当合并没有发生冲突时,git默认使用ff模式
此外,还有一种模式: no-ff,这种模式的合并可以通过git log --graph --abbrev-commit知道两哪个分支发生了合并
使用no-ff模式的合并:

git merge -no-ff -m "此次合并的目的" 被合并的分支名

由于合并完分支后,还需要进行commit操作,所以需要-m提交信息

分支策略

master主分支对应着线上环境,必须是十分稳定的,所以提交的代码需要能稳定运行,没有重大的bug
而其他分支则是不稳定,存在bug的。开发人员在这些分支上进行开发,进行一系列测试验证后,就能将其他分支上的代码合并到master分支中
基于分支,我们就能进行同一项目的多人同时开发,同时也演变出了多种分支策略

git stash

如果在其他分支中修改了文件,未进行add和commit,此时的操作将不受到git的版本控制,只是单纯的对工作区的修改。切回master分支后,可以在本地看见其他分支对文件的修改

若其他分支修改文件后,进行了add和commit,此时的操作将受到git的版本控制。切回master分支后,无法看见其他分支对文件的修改

如果不进行add和commit,又不想让master分支看见其他分支对文件的修改,可以使用命令

git stash

该命令将保存分支对文件的修改到一个特殊文件中,也就是将修改后的文件添加到git的版本控制中,此时master分支无法看见其他分支对于文件的修改
image.png

此时.git的目录树中,多了一个stash文件,用来保存分支中的修改
image.png

执行命令,打印stash中保存的修改

git stash list

如果在dev分支中修改了文件,并执行git stash,切出该分支,再切回dev分支
此时分支中的数据和master分支相同,要想恢复之前所做的修改,就需要执行命令,将stash中的修改恢复到分支中

git stash pop

image.png

不要在master分支上解决冲突

项目上线后可能遇到的场景:存在一个小bug,此时基于master分支创建分支fix_bug进行bug修复,修复成功后在master分支中合并fix_bug分支,项目再次上线
同时,项目的开发也在不断进行中,在发现bug之前,创建了一个分支dev开发新的功能。等到功能开发好时,项目已经不再是当时创建分支时的项目,而是修改了bug后的项目。此时在master分支中合并dev分支将产生冲突
image.png
我们不能直接合并dev分支,并在master分支上手动修改文件,这可能导致使修改后的文件出现bug
正确做法应该是:在dev分支上合并master分支并且手动修改冲突,测试没有问题后,再到master分支中合并dev分支

git的远程操作

git的全程叫做分布式版本控制系统,版本控制很好理解,如何理解分布式?

一个项目的开发往往需要多人的分工协作,之前所说的git仓库:工作区、暂存区以及版本库都是在本地运行的。一个开发人员对项目进行了修改,另一个开发人员要如何获取到他的修改呢?或者说如何让其他人看到我对项目的修改?

显然只使用本地的git无法解决这个问题。git为我们提供了一个解决方案,使用中央服务器存储git仓库,我们也叫它远程仓库

每个开发人员都能访问到远程仓库,需要开发项目时,从远端仓库将整个仓库拉取下来进行开发。开发完成后,将本地的修改提交到远程仓库中。那么其他开发人员就能通过远程仓库看到你对项目的开发,并且也能拉取你对项目的修改,进一步进行开发

用https克隆远程仓库,注意:不能在拥有.git目录的路径下(已经初始化过本地仓库的地方)克隆仓库!
克隆也能理解为第一次拉取

在远程仓库中可以找到该仓库的链接,通常有https和ssh协议,先演示https协议的克隆,将URL复制下来,执行命令

git clone URL

image.png

查看远程仓库的信息

git remote [-v]

直接使用git remote将打印本地仓库中已经配置的远程仓库名字,通常是origin
image.png
git remote -v将查看已经配置的远程仓库列表,以及它们的URL。fetch表示本地拥有远程仓库的拉取权限,push则表示提交权限

用ssh克隆远程仓库:
需要先将本地服务器的公钥放到远端的git服务器中

如何配置git服务器的公钥?
找到个人设置中的相关配置项
image.png
点击添加公钥:
image.png

在本地服务器中生成公钥与私钥:
进入/~/.ssh目录,如果没有则创建目录
如果目录中没有id_rsa 和id_rsa.pub文件,则执行以下命令

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

其中-C选项表示添加注释信息,用来表示生成的密钥对的用途,将这个信息设置为自己的邮箱即可
输入命令后一直回车直到能够输入其他命令为止
image.png

此时目录下新增两个文件:id_rsa 和id_rsa.pub
image.png
生成后,将公钥(id_rsa.pub中的字符)写入git服务器中
image.png

此时执行命令,即可克隆仓库

git clone ssh链接

image.png

将修改提交到远程仓库

注意:不是将整个本地仓库的修改提交到远程仓库,而是将某个分支的修改提交到远程仓库
克隆完远程仓库后,需要配置user.name和user.email,这两个信息要和git服务器中的信息一致

首先在工作区中修改文件,并add与commit,最后执行push,将版本库中的修改提交到远程仓库

git push 仓库名 本地仓库的分支:远程仓库的分支

push其实做了两步操作:将本地仓库某个分支的修改提交到远程仓库中,将指定分支与远端分支进行合并

其中,仓库名是本地服务器配置的远程仓库的名字,一般是origin
同时指定要push哪个本地分支中的修改到远程仓库中的哪个分支,这两个分支名一般用:隔开,当两者相同时,可以只写一次分支名(github的master分支现在叫做main分支)
image.png

此时远程仓库中出现了分支的修改,新增了ReadMe文件
image.png

push操作的本质是本地分支与远端分支的交互,交互之前需要先建立连接。一般在克隆仓库时,本地仓库的master分支与远程仓库的master分支就自动建立了连接,可以直接使用git push。而其他分支没有建立连接,需要使用上面的长命令进行push操作

当本地仓库的版本领先于远程仓库的版本,此时进行push操作以推送更新
当远程仓库的版本领先于本地仓库的版本,此时要进行pull操作以同步与远程仓库的版本

假设远程仓库的hello.txt被其他人修改了并且push了,这是修改后的内容
image.png

此时我要进行下一步的开发,就必须与远程仓库的版本保持同步
使用pull命令完成同步

git pull 仓库名 本地仓库的分支:远程仓库的分支

pull和push的使用相同,pull其实也进行了两步操作:将远程仓库中指定分支的修改拉取到本地,与本地分支进行合并
image.png

push时忽略特殊文件

创建远程仓库中,可以勾选添加.gitignore文件的选项:指定一些不想被push的文件,这些文件的修改就不会被add到暂存区中,更不会被push到远程仓库中了
在.gitignore文件中的文件不会被git追踪管理,即忽略这些文件,.gitignore文件需要位于git工作区的根目录下

若新建仓库时没有勾选添加.gitignore文件的选项,后续想要添加该文件时,可以直接添加
image.png
该文件在工作区的根目录下
image.png

此时创建一个以so结尾的文件,并将当前目录下的所有文件add到工作区中,执行git status命令,查看哪些文件的修改需要被commit到版本库中
image.png

发现调试信息中,没有a.so文件只有.gitignore文件,说明.gitignore文件生效了

如何强制添加文件到暂存区中,就算该文件在.gitignore中出现?
为add添加-f选项,强制提交修改到暂存区中

git add -f filename

image.png
也可以在.gitignore文件中添加规则,使git不要不略某个文件的提交
image.png
!表示不忽略该文件的提交

如何判定某一文件是否被忽略?

git check-ignore -v filename

image.png
打印信息说,该文件被第三行的规则忽略了

配置命令的别名
git config --global alias.别名 '原名(不需要加git)'

给status起别名
image.png

git的标签管理

使用标签可以方便的查看信息,以及记录一些有意义的信息
执行命令,为最近的一次commit将被打上指定的标签

git tag 标签名

查看所有标签

git tag

image.png

.git的目录树中也出现了相应的目录,查看该文件
image.png
发现该文件存储了最近一次的commit id

为指定的commit打标签,先通过git log --pretty=oneline --abbrev-commit,列出所有commit id,找到想要打标签的commit id
image.png

执行

git tag 标签名 commitid 

执行命令,为commit打标签并添加注释:

git tag -a 标签名 -m "注释内容" commit id

执行命令,查看标签的注释:

git show 标签名

git show将显示对应commit的详细信息,如果该commit的标签有注释,那么也将一起展示,如果没有则只显示其他信息
image.png

删除标签:

git tag -d 标签名

推送标签

git push 仓库名 标签名

推送所有标签:

git push 仓库名 --tags

image.png

删除远端仓库的标签(首先要先删除本地仓库的标签)

git push 仓库名 :标签名

git实战

同一分支下的多人协作(不推荐)

开发者1在dev分支下的hello.txt文件中添加"111",开发者2在dev分支下的test文件中添加"222"

先在远端仓库中添加新的分支
image.png

接着在两个开发者的机器上执行git pull,获取最新的仓库版本(新的分支)
但是执行git branch后,无法看到新的分支。这是因为远端的分支与本地的分支没有关系,所以就算拉取了,也不会执行分支合并的操作。使用git branch -r选项就能看到远端的分支
image.png
此时我们要在本地手动创建名字相同的分支,并将本地分支与远端分支建立连接
执行命令建立连接

git checkout -b 本地分支名 仓库名/远端分支名

除此之外,使用其他命令也能达到同样效果(前提是dev分支不存在)

git branch 本地分支名 仓库名/远端分支名v
git checkout 本地分支名

若dev分支存在,则执行

git branch --set-upstream-to=仓库名/远端分支名 本地分支名
git checkout 本地分支名

image.png
执行git branch -vv可以查看本地仓库与远端仓库的连接
为什么要建立连接?这样可以直接使用git pushgit pull这样的短命令,而不使用git push origin main这样的长命令

开发者1完成操作,修改文件后add、commit、push三板斧
image.png

开发者2执行相同的操作
image.png
而开发者2修改完hello.txt却无法提交,原因是此时的远端仓库中hello.txt和开发者2本地仓库最近一次pull的版本不同(开发者1的提交导致版本的不同),此时提交将产生冲突
解决方法是:执行git pull,此时hello.txt文件产生冲突,手动修改冲突并重新add、commit、push即可

image.png

最后一步:将dev分支合并到master分支中
有两种方法:

  1. 将本地的dev分支合并到master分支中,再将master分支push到远端
  2. 在git服务器上提交pr(pull request)申请,由管理员审批后,合并将被执行

如何提交pr申请?
image.png
选择选项,将dev分支合并到main分支中,添加标题和内容后选择reviewers和addignees,点击新建pr
关于reviewers和addignees的区别,可以看这篇博客Git GitHub上的Reviewers和Assignees之间有什么区别|极客笔记 (deepinout.com)image.png
相关人员审查没问题后,就会进行合并操作了

另一种方法是在本地执行merge操作,推荐使用pr合并方式,经过审查员的审查,合并操作会更加安全

首先,执行合并操作的开发人员的本地仓库中,dev分支可能不是最新,此时需要先pull拉取最新版本

git checkout dev
git pull

由于无法保证main分支也是最新的,所以也需要pull

git checkout main
git pull

由于无法保证将dev分支合并到main分支是否会发生冲突,所以先到dev分支下,将main分支合并到dev分支。若发生冲突则手动解决冲突

git checkout dev
git merge main

解决完冲突后,再回到main分支下,合并dev分支

git checkout main
git merge dev

最后进行push操作即可

git push

删除dev分支(可选)

git branch -d dev

可以看到同一分支下的多人协作非常麻烦,产生冲突的概率极大,需要不停的pull解决冲突
所以开发中的多人协作一般是在不同分支下进行的

不同分支下的多人协作

每个开发者(开发项目的不同功能)对应不同分支,在属于自己的分支上提交自己开发的代码
最后这些代码将合并到main分支下
如:开发者1在feature-1分支下提交file1文件,开发者2在feature-2分支下提交file2文件
开发者1:首先pull更新本地的master分支,然后在本地master分支下,创建feature-1分支,编辑文件file1并进行add和commit操作

git pull
git checkout -b feature-1

此时的push操作比较特殊,不能直接git push,而要执行

git push 远端仓库名 本地分支名

因为此时的远端仓库中没有feature-1分支,我们只是在本地创建了feature-1分支,所以这次的提交需要将整个分支进行提交
总结下:可以在本地创建新分支,也可以在远端创建新分支

  1. 在本地创建新分支后,需要将整个分支进行提交
  2. 而在远端创建新分支后,需要先pull获取远端的分支,再创建本地的同名分支并建立连接
    image.png
    此时远程仓库下已经存在feature-1分支了
    image.png

开发者2执行与开发者1相同的操作:基于master分支创建新的分支feature-2,在该分支上编写文件file2,并执行add、commit以及push操作,在执行push操作之前需要先pull获取最新的远程仓库

开发过程中可能遇到的场景:开发者1需要帮助开发者2完成后续开发
此时开发者1的本地仓库中没有featrue-2分支,所以需要将该分支拉取下来
image.png
解释一下这时的pull为什么只需要使用短链接?
pull操作其实有两种:1. 拉取某一分支下的内容,此时需要使用长连接,如果本地分支与远端分支建立连接后即可使用短连接 2. 拉取仓库中的内容,如新的分支,此时使用短连接即可,但是拉取到的新分支不会和本地分支建立连接

但是拉取操作只是将远端的分支拉取下来,本地没有相应的分支,打印的信息提示我们要在本地创建相同的分支并与其链接

git checkout -b feature-2 origin/feature-2

此时处于feature-2分支下,继续编写该分支下的文件,完成开发者2未完成的代码

最后:将feature-1分支和feature-2分支合并到main分支下
在git服务端分别提交两次pr申请即可
在提交pr申请前,推荐先用其他分支合并main分支,解决可能存在的冲突,再用main分支合并其他分支,此时将不会产生冲突

为什么本地依然能看到远端已经删除的分支?

将远端分支删除后,本地使用git branch -a依然能看到远端分支,如何解决?
image.png
image.png

使用命令清理远端无用分支即可

git remote prune origin

image.png
此时远端分支只有main分支,剩下的本地分支用git branch -d删除即可

git flow模型

git flow模型是企业级常用的一种git分支设置规范,这只是一种常用的开发模型,并不适合于所有的开发团队。了解它有助于我们理解软件开发的流程
image.png

分支名称适用环境
master主分支生产环境
release预发布分支预发布/测试环境
develop开发分支开发环境
feature需求开发分支本地
hotfix紧急修复分支本地
master分支
  • master为主分支,该分支唯一且只读,用于部署正式发布环境,一般由合并release分支得到
  • master分支为稳定的代码库,任何时候都不能直接在master分支上修改代码
  • 产品的功能全部实现后,最终在master分支上对外发布。并且master分支上的所有提交都应该打标签(tag)做记录,方便追溯
  • master分支不可删除

feature分支

  • feature为新功能或新特性的开发分支,以develop分支为基础创建feature分支
  • 命名通常为feature/user_createtime_feature,表示开发人员,开发时间以及所开发的特性
  • 新特性开发完成后需要将feature分支合并到develop分支中,且删除feature分支

develop分支

  • develop为开发分支,基于master分支创建的唯一且只读分支,始终保持最新完成以及bug修复后的代码。可部署到对应开发集群
  • 通常用来合并feature分支,也可直接在develop分支上开发

release分支

  • release分支为预发布分支,基于develop分支创建,可以部署到测试或者预发布集群
  • 通常的命名规则:release/version_publishtime,表示发布的版本以及发布时间
  • release分支通常用于提交给测试人员进行测试,若出现问题则需要验证develop是否出现问题,测试完成后可以删除release分支

hotfix分支

  • hotfix为bug修复分支或补丁分支,主要用于线上版本的bug修复
  • 命名规则通常为hotfix/user_createtime_hotfix,表示相关人员,创建时间以及具体的bug
  • 问题修复完成,将其合并到master分支后删除

相关文章:

Git的基本操作以及原理介绍

文章目录 基本操作创建git仓库配置name和email .git目录的结构git add & git commit.git目录结构的变化 git追踪管理的数据git的版本回退回退的原理回退的三种情况 版本库中文件的删除git分支管理分支的删除合并分支时的冲突分支的合并模式分支策略git stash不要在master分…...

2023安全与软工顶会/刊中区块链智能合约相关论文

2023安全与软工顶会/刊中区块链智能合约相关论文 前言软工顶会ISSTAFSEASEICSE 软工顶刊TOSEMTSE 安全顶会S&PUSENIX SecurityCCSNDSS 前言 主要整理了2023年四大安全顶会、四大软工顶会和两个软工顶刊中&#xff0c;有关区块链智能合约的相关论文。 搜索方式是&#xff1…...

word文档转换为ppt文件,怎么做?

大家是否会遇到需要将word文档转换为ppt文件的情况&#xff1f;除了反反复复粘贴复制以外&#xff0c;还有其他方法可以转换文件格式&#xff0c;今天给大家分享word转换ppt方法。 首先我们先将word文件打开大纲模式 然后我们将文中的大标题设置为1级标题&#xff0c;副标题设…...

机器视觉选型-什么时候用远心镜头

物体厚 当被检测物体厚度较大&#xff0c;需要检测不止一个平面时&#xff0c;典型应用如食品盒&#xff0c;饮料瓶等。 物体位置变化 当被测物体的摆放位置不确定&#xff0c;可能跟镜头成一定角度时。 物体上下跳动 当被测物体在被检测过程中上下跳动&#xff0c;如生产线上下…...

quartz笔记

Quartz-CSDN博客 上面是Quartz的一些基本知识,如果对quartz的基本API不是很了解的话,建议先看下上面的 和Linux Crontab对比 1.执行粒度: Linux Crontab是进程级 quart是线程级 2.跨平台性: Crontab只能在Linxu运行 quart是java实现,可以跨平台 3.调度集上 Crontab的…...

ER 图是什么

文章目录 前言什么是 ER图ER 图实例简化的 ER 图总结 前言 产品经理在梳理产业业务逻辑的过程中&#xff0c;非常重要的一项工作就是梳理各个业务对象之间的关系。如果涉及对象很对的时候&#xff0c;没有工具支持的话很难处理清楚。今天我们就来介绍一个梳理业务对象关系的工…...

PLC电力载波通讯,一种新的IoT通讯技术

前言: PLC-IoT 是 PLC 技术应用在物联场景的创新实践,有效解决电力线路信号干扰、衰减问题,支持 IP 化通信能力,使能终端设备智能化,构建智慧边缘联接。PLC让传统IoT有了更多的连接可能: 电力线通信技术适用的场景包括电力配用电网络、城市智慧路灯、交通路口信号灯、园…...

Elasticsearch:通过摄取管道加上嵌套向量对大型文档进行分块轻松地实现段落搜索

作者&#xff1a;VECTOR SEARCH 向量搜索是一种基于含义而不是精确或不精确的 token 匹配技术来搜索数据的强大方法。 然而&#xff0c;强大的向量搜索的文本嵌入模型只能按几个句子的顺序处理短文本段落&#xff0c;而不是可以处理任意大量文本的基于 BM25 的技术。 现在&…...

OpenCV图像纹理

LBP描述 LBP&#xff08;Local Binary Pattern&#xff0c;局部二值模式&#xff09;是一种用来描述图像局部纹理特征的算子&#xff1b;它具有旋转不变性和灰度不变性等显著的优点。它是首先由T. Ojala, M.Pietikinen, 和D. Harwood 在1994年提出&#xff0c;用于纹理特征提取…...

自媒体写手提问常用的ChatGPT通用提示词模板

如何撰写一篇具有吸引力和可读性的自媒体文章&#xff1f; 如何确定自媒体文章的主题和受众群体&#xff1f; 如何为自媒体文章取一个引人入胜的标题&#xff1f; 如何让自媒体文章的开头更加吸引人&#xff1f; 如何为自媒体文章构建一个清晰、逻辑严谨的框架&#xff1f;…...

分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测

分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测 目录 分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1…...

3GPP TS38.201 NR; Physical layer; General description (Release 18)

TS38.201是介绍性的标准&#xff0c;简单介绍了RAN的信道组成和PHY层承担的功能&#xff0c;下图是PHY层相关标准的关系。 文章目录 结构信道类型调制方式PHY层支持的过程物理层测量其他标准TS 38.202: Physical layer services provided by the physical layerTS 38.211: Ph…...

【GitLab】-HTTP 500 curl 22 The requested URL returned error: 500~SSH解决

写在前面 本文主要介绍通过SSH的方式拉取GitLab代码。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.生成秘钥3.GitLab添加秘钥4.验证SSH方式4.更改原有HTTP方式为SSH 三、参考资料写在后面系列文章 一、场景描述 之前笔者是通过 HTTP Personal access token 的方式拉取…...

【如何学习Python自动化测试】—— 自动化测试环境搭建

1、 自动化测试环境搭建 1.1 为什么选择 Python 什么是python&#xff0c;引用python官方的说法就是“一种解释型的、面向对象、带有励志语义的高级程序设计语言”&#xff0c;对于很多测试人员来说&#xff0c;这段话包含了很多术语&#xff0c;而测试人员大多是希望利用编程…...

在通用jar包中引入其他spring boot starter,并在通用jar包中直接配置这些starter的yml相关属性

场景 我在通用jar包中引入 spring-boot-starter-actuator 这样希望引用通用jar的所有服务都可以直接使用 actuator 中的功能&#xff0c; 问题在于&#xff0c;正常情况下&#xff0c;actuator的配置都写在每个项目的yml文件中&#xff0c;这就意味着&#xff0c;虽然每个项目…...

Seaborn 回归(Regression)及矩阵(Matrix)绘图

Seaborn中的回归包括回归拟合曲线图以及回归误差图。Matrix图主要是热度图。 1. 回归及矩阵绘图API概述 seaborn中“回归”绘图函数共3个&#xff1a; lmplot&#xff08;回归统计绘图&#xff09;&#xff1a;figure级regplot函数&#xff0c;绘图同regplot完全相同。(lm指lin…...

nginx学习(1)

一、下载安装NGINX&#xff1a; 先安装gcc-c编译器 yum install gcc-c yum install -y openssl openssl-devel&#xff08;1&#xff09;下载pcre-8.3.7.tar.gz 直接访问&#xff1a;http://downloads.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz&#xff0c;就…...

CLEARTEXT communication to XX not permitted by network security policy 报错

在进行网络请求时&#xff0c;日志中打印 CLEARTEXT communication to XX not permitted by network security policy 原因&#xff1a; Android P系统网络访问安全策略升级&#xff0c;限制了非加密的流量请求 Android P系统限制了明文流量的网络请求&#xff0c;之下的版本…...

91.移动零(力扣)

问题描述 代码解决以及思想 class Solution { public:void moveZeroes(vector<int>& nums) {int left 0; // 左指针&#xff0c;用于指向当前非零元素应该放置的位置int right 0; // 右指针&#xff0c;用于遍历数组int len nums.size(); // 数组长度while …...

PatchMatchNet笔记

PatchMatchNet笔记 1 概述2 PatchmatchNet网络结构图2.1 多尺度特征提取2.2 基于学习的补丁匹配 3 性能评价 PatchmatchNet: Learned Multi-View Patchmatch Stereo&#xff1a;基于学习的多视角补丁匹配立体算法 1 概述 特点   高速&#xff0c;低内存&#xff0c;可以处理…...

实时人眼追踪、内置3D引擎,联想ThinkVision裸眼3D显示器创新四大应用场景

11月17日&#xff0c;在以“因思而变 智领未来”为主题的Think Centre和ThinkVision 20周年纪念活动上&#xff0c;联想正式发布了业内首款2D/3D 可切换裸眼3D显示器——联想ThinkVision 27 3D。该产品首次将裸眼2D、3D可切换技术应用在显示器领域&#xff0c;并拓展了3D技术多…...

SELinux零知识学习十四、SELinux策略语言之客体类别和许可(8)

接前一篇文章&#xff1a;SELinux零知识学习十三、SELinux策略语言之客体类别和许可&#xff08;7&#xff09; 一、SELinux策略语言之客体类别和许可 4. 客体类别许可实例 &#xff08;2&#xff09;文件客体类别许可 文件客体类别有三类许可&#xff1a;直接映像到标准Lin…...

Unity——URP相机详解

2021版本URP项目下的相机&#xff0c;一般新建一个相机有如下组件 1:Render Type(渲染类型) 有Base和Overlay两种选项&#xff0c;默认是Base选项 Base:主相机使用该种渲染方式&#xff0c;负责渲染场景中的主要图形元素 Overlay&#xff08;叠加&#xff09;:使用了Oveylay的…...

CRUD-SQL

文章目录 前置insertSelective和upsertSelective使用姿势手写sql&#xff0c;有两种方式 一、增当导入的数据不存在时则进行添加&#xff0c;有则更新 1.1 唯一键&#xff0c;先查&#xff0c;后插1.2 批量插1.2.1 批次一200、批次二200、批次三200&#xff0c;有一条数据写入失…...

【C语言 | 数组】C语言数组详解(经典,超详细)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

第三十三节——组合式API生命周期

一、基本使用 组合式api生命周期几乎和选项式一致。注意组合式api是从挂载阶段开始 <template><div></div> </template> <script setup> import {onBeforeMount, onMounted,onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, } from …...

【Linux】Alibaba Cloud Linux 3 安装 PHP8.1

一、系统安装 请参考 【Linux】Alibaba Cloud Linux 3 中第二硬盘、MySQL8.、MySQL7.、Redis、Nginx、Java 系统安装 二、安装源 rpm -ivh --nodeps https://rpms.remirepo.net/enterprise/remi-release-8.rpm sed -i s/PLATFORM_ID"platform:al8"/PLATFORM_ID&q…...

【容器化】Kubernetes(k8s)

文章目录 概述Docker 的管理痛点什么是 K8s云架构 & 云原生 架构核心组件K8s 的服务注册与发现组件调用流程部署单机版部署主从版本Operator来源拓展阅读 概述 Docker 虽好用&#xff0c;但面对强大的集群&#xff0c;成千上万的容器&#xff0c;突然感觉不香了。 这时候就…...

stm32 HSUSB

/ stm32f407xx.h #define USB_OTG_HS_PERIPH_BASE 0x40040000UL #define USB_OTG_HS ((USB_OTG_GlobalTypeDef *) USB_OTG_HS_PERIPH_BASE) // // 定义全局变量 USBD_HandleTypeDef hUsbDeviceHS;并默认全零初始化/* USB Device handle structure */ typedef struct _USB…...

C# String.Trim 方法

String.Trim()方法定义&#xff1a; 命名空间&#xff1a;System 程序集&#xff1a;System.Runtime.dll 返回结果&#xff1a;返回一个新字符串&#xff0c;它相当于从当前字符串中删除了一组指定字符的所有前导匹配项和尾随匹配项。 Trim方法有三个重载的方法&#xff0c;…...

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 4》(8)

《Linux操作系统原理分析之Linux 进程管理 4》&#xff08;8&#xff09; 4 Linux 进程管理4.4 Linux 进程的创建和撤销4.4.1 Linux 进程的族亲关系4.4.2 Linux 进程的创建4.4.3 Linux 进程创建的过程4.4.4 Linux 进程的执行4.4.5 Linux 进程的终止和撤销 4 Linux 进程管理 4.…...

RT-Thread STM32F407 PWM

为了展示PWM效果&#xff0c;这里用ADC来采集PWM输出通道的电平变化 第一步&#xff0c;进入RT-Thread Settings配置PWM驱动 第二步&#xff0c;进入board.h&#xff0c;打开PWM宏 第三步&#xff0c;进入STM32CubeMX&#xff0c;配置时钟及PWM 第四步&#xff0c;回到R…...

idea中把spring boot项目打成jar包

打jar包 打开项目&#xff0c;右击项目选中Open Module Settings进入project Structure 选中Artifacts&#xff0c;点击中间的加号&#xff08;Project Settings->Artifacts->JAR->From modules with dependencies &#xff09; 弹出Create JAR from Modules&#…...

levelDB之基础数据结构-Slice

Slice是levelDB中用于操作字符串的数据结构&#xff0c;以字节为单位。 定义与实现 namespace leveldb {class LEVELDB_EXPORT Slice {public:// Create an empty slice.Slice() : data_(""), size_(0) {}// Create a slice that refers to d[0,n-1].Slice(const c…...

上位机模块之通用重写相机类

在常用的视觉上位机中&#xff0c;我们通常会使用单个上位机匹配多个相机或者多品牌相机&#xff0c;所以在此记录一个可重写的通用相机类&#xff0c;用于后续长期维护开发。 先上代码。 using HalconDotNet; using System.Collections.Generic;namespace WeldingInspection.M…...

机器人导航+OPENCV透视变换示例代码

透视变换又称四点变换&#xff0c;所以不能用于5边形这样的图形变换&#xff0c;不是真正的透视变换&#xff0c;但是这个方法可以把机器人看到的图像转换为俯视图&#xff0c;这样就可以建立地图&#xff0c;要不然怎么建立地图呢。 void CrelaxMyFriendDlg::OnBnClickedOk()…...

KofamScan-KEGG官方推荐的使用系同源和隐马尔可夫模型进行KO注释

文章目录 简介安装使用输入蛋白序列输出detail-tsv格式输出detail格式输出mapper格式 输出结果detail和detail-tsv格式mapper格式常用命令tmp目录 与emapper结果比较其他参数参考 简介 KofamScan 是一款基于 KEGG 直系同源和隐马尔可夫模型&#xff08;HMM&#xff09;的基因功…...

代码随想录算法训练营第五十五天丨 动态规划part16

583. 两个字符串的删除操作 思路 #动态规划一 本题和动态规划&#xff1a;115.不同的子序列 (opens new window)相比&#xff0c;其实就是两个字符串都可以删除了&#xff0c;情况虽说复杂一些&#xff0c;但整体思路是不变的。 这次是两个字符串可以相互删了&#xff0c;这…...

【Linux】kernel与应用消息队列的一种设计

Linux进程间通讯的方式有很多种&#xff0c;这里介绍一种通过消息队列的方式来实现kernel与APP之间的消息收发实现方式&#xff0c;这种方式特别适用于&#xff0c;kernel中发送消息&#xff0c;应用层收取消息。 消息队列设备驱动 该方法的设计思路即是创建一个消息队列的设…...

我们常说的网络资产,具体是如何定义的?

文章目录 什么叫网络资产&#xff1f;官方定义的网络资产网络资产数字化定义推荐阅读 什么叫网络资产&#xff1f; 通过百度查询搜索什么叫网络资产&#xff1f;大体上都将网络资产归类为计算机网络中的各类设备。 基本上会定义网络传输通信架构中用到的主机、网络设备、防火…...

WPF中可冻结对象

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;"可冻结对象"指的是那些在创建之后可以被设置为不可更改状态的对象。这种特性允许这些对象更有效地被共享和复制&#xff0c;并且可以增加性能。 例如&#xff0c;Brushes&#xff0c;P…...

【人工智能实验】A*算法求解8数码问题 golang

人工智能经典问题八数码求解 实际上是将求解转为寻找最优节点的问题&#xff0c;算法流程如下&#xff1a; 求非0元素的逆序数的和&#xff0c;判断是否有解将开始状态放到节点集&#xff0c;并设置访问标识位为true从节点集中取出h(x)g(x)最小的节点判断取出的节点的状态是不…...

Kafka学习笔记(二)

目录 第3章 Kafka架构深入3.3 Kafka消费者3.3.1 消费方式3.3.2 分区分配策略3.3.3 offset的维护 3.4 Kafka高效读写数据3.5 Zookeeper在Kafka中的作用3.6 Kafka事务3.6.1 Producer事务3.6.2 Consumer事务&#xff08;精准一次性消费&#xff09; 第4章 Kafka API4.1 Producer A…...

Typora for Mac:打造全新文本编辑体验

Typora for Mac是一款与众不同的文本编辑器&#xff0c;它不仅拥有直观易用的界面&#xff0c;还融合了Markdown语法和富文本编辑的功能&#xff0c;为用户带来了前所未有的写作和编辑体验。 一、简洁明了的界面设计 Typora for Mac的界面简洁明了&#xff0c;让用户可以专注…...

TikTok与媒体素养:如何辨别虚假信息?

在当今数字时代&#xff0c;社交媒体平台如TikTok已经成为信息传播和社交互动的主要渠道之一。然而&#xff0c;随之而来的是虚假信息的泛滥&#xff0c;这对用户的媒体素养提出了严峻的挑战。本文将探讨TikTok平台上虚假信息的现象&#xff0c;以及如何提高媒体素养&#xff0…...

Spring Boot 中使用 ResourceLoader 加载资源的完整示例

ResourceLoader 是 Spring 框架中用于加载资源的接口。它定义了一系列用于获取资源的方法&#xff0c;可以处理各种资源&#xff0c;包括类路径资源、文件系统资源、URL 资源等。 以下是 ResourceLoader 接口的主要方法&#xff1a; Resource getResource(String location)&am…...

1688往微信小程序自营商城铺货商品采集API接口

一、背景介绍 随着移动互联网的快速发展&#xff0c;微信小程序作为一种新型的电商形态&#xff0c;正逐渐成为广大商家拓展销售渠道、提升品牌影响力的重要平台。然而&#xff0c;对于许多传统企业而言&#xff0c;如何将商品信息快速、准确地铺货到微信小程序自营商城是一个…...

QStatusBar开发详解

一、QStatusBar接口说明 QStatusBar 类是 Qt 中用于创建和管理状态栏的类。它继承自 QFrame 类&#xff0c;提供了在主窗口底部显示消息、进度等信息的功能。以下是一些 QStatusBar 类的重要接口&#xff1a; 1.1 QStatusBar构造函数 QStatusBar(QWidget *parent nullptr);…...

后端接口性能优化分析-程序结构优化

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&…...

【SpringBoot3+Vue3】三【实战篇】-后端(优化)

目录 一、登录优化-redis 1、SpringBoot集成redis 1.1 pom 1.2 yml 1.3 测试程序&#xff08;非必须&#xff09; 1.4 启动redis&#xff0c;执行测试程序 2、令牌主动失效&#xff08;代码优化&#xff09; 2.1 UserController设置token到redis 2.2 登录拦截器Log…...