前端工程化12-Git版本控制工具详解

2.1、Git知识概述

理解版本控制工具,聊下他的历史,之后会讲两种版本控制工具的区别(集中式|分布式)、他的基本环境搭建安装,如何初始化本地仓库,如何往仓库里提交一些东西,文件的话会有那些变化。学习git的远程仓库(这是多人协作开发,远程仓库是必须的)两种验证方式一种是https账号密码,一种是ssh密钥的方式,如何为我们的某个版本打上tag,git分支如何使用,git Flow如何使用?远程分支的管理?怎么理解git rebase 变基 和meger,git常见命令速查表。

2.2、认识版本控制(version control)

什么是版本控制?

  • 版本控制的英文是Version control

  • 是维护工程蓝图的标准作法,能追踪工程蓝图从诞生一直到定案的过程;

  • 版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确保由不同人所编辑的同一程序文件都得到同步;

简单来说,版本控制在软件开发中,可以帮助程序员进行代码的追踪、维护、控制等等一系列的操作。

image-20240728141701329

好处不需要手动进行控制、每个版本都手动存储一份。

2.3、版本控制的功能

对于我们日常开发,我们常常面临如下一些问题,通过版本控制可以很好的解决:

不同版本的存储管理:

  • 一个项目会不断进行版本的迭代,来修复之前的一些问题、增加新的功能、需求,甚至包括项目的重构;
  • 如果我们通过手动来维护一系列的项目备份,简直是一场噩梦;

重大版本的备份维护:

  • 对于很多重大的版本,我们会进行备份管理;

恢复之前的项目版本:

  • 当我们开发过程中发生一些严重的问题时,想要恢复之前的操作或者回到之前某个版本;

记录项目的点点滴滴:

  • 如果我们每一个功能的修改、bug的修复、新的需求更改都需要记录下来,版本控制可以很好的解决;

多人开发的代码合并:

  • 项目中通常都是多人开发,将多人代码进行合并,并且在出现冲突时更好的进行处理;

打一个标签git tag v1.0.0,代码回到对应的版本 git checkout v1.0.0

2.4、版本控制的历史

版本控制的史前时代(没有版本控制):

  • 人们通常通过文件备份的方式来进行管理,再通过diff命令来对比两个文件的差异;

CVS(Concurrent Versions System)

  • ==第一个被大规模使用的版本控制工具,==诞生于1985年;
  • 由荷兰阿姆斯特丹VU大学的Dick Grune教授实现的,也算是SVN的前身(SVN的出现就是为了取代CVS的)。

SVN(Subversion)

  • 因其命令行工具名为svn因此通常被简称为SVN;
  • SVN由CollabNet公司于2000年资助并发起开发,目的是取代CVS,对CVS进行了很多的优化;
  • SVN和CVS一样,也属于集中式版本控制工具;
  • SVN在早期公司开发中使用率非常高,但是目前已经被Git取代;

Git(Linus的作品)

  • 早期的时候,Linux社区使用的是BitKeeper来进行版本控制;
  • 但是因为一些原因,BitKeeper想要收回对Linux社区的免费授权;
  • 于是Linus用了大概一周的时间,开发了Git用来取代BitKeeper;
  • Linus完成了Git的核心设计,在之后Linus功成身退,将Git交由另外一个Git的主要贡献者Junio C Hamano来维护;

2.5、集中式版本控制

CVS和SVN都是是属于集中式版本控制系统(Centralized Version Control Systems,简称 CVCS)

  • 它们的主要特点是单一的集中管理的服务器,保存所有文件的修订版本;
  • 协同开发人员通过客户端连接到这台服务器,取出最新的文件或者提交更新;

image-20240728144947448

集中式版本控制工具容易出现单点故障,服务器不可用时就不能在提交东西,分布式的可以吗?可以分布式版本控制工具每个人都有一份本地仓库,每个人的电脑就相当于一台服务器。每个人的本地都有一份完整的项目。就算中央服务器完全宕机或者磁盘损坏,也不会发生提交记录丢死,版本文件丢失的情况。

2.6、分布式版本控制

Git是属于分布式版本控制系统(Distributed Version Control System,简称DVCS)

  • 客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录;
  • 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复;
  • 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份;

目前在公司开发中我们都是使用Git来管理项目的,所以接下来我们会重点学习Git的各种用法;

image-20240728150224725

2.7、Git安装

Git的官网:https://git-scm.com/downloads

根据自己的操作系统下载Git即可;

image-20240728184839157

在window操作系统按照默认配置全局安装即可;

2.8、Bash – CMD – GUI 区别

Bash,Unix shell的一种,Linux与Mac OS X都将它作为默认shell。

  • Git Bash 就是一个 shell,是 Windows 下的命令行工具,可以执行 Linux 命令;
  • Git Bash 是基于 CMD 的,在 CMD 的基础上增添一些新的命令与功能;
  • 所以建议在使用的时候,用 Bash 更加方便;

Git CMD

  • 命令行提示符(CMD)是 Windows 操作系统上的命令行解释程序;
  • 当你在 Windows 上安装 git 并且习惯使用命令行时,可以使用 cmd 来运行 git 命令;

Git GUI

  • 基本上针对那些不喜欢黑屏(即命令行)编码的人;
  • 它提供了一个图形用户界面来运行 git 命令;

上课演练的方式:

  • 在Git Bash中演练Git的常见操作;

3.0、Git的配置分类

既然已经在系统上安装了Git,你会需要做几件事来定制你的Git 环境

  • 每台计算机上只需要配置一次,程序升级时会保留配置信息;
  • 你可以在任何时候再次通过运行命令来修改它们;

Git自带一个git config的工具来帮助设置控制Git外观和行为的配置变量:

  • /etc/gitconfig 文件:包含系统上每一个用户及他们仓库的通用配置
    • 如果在执行 git config 时带上 --system 选项,那么它就会读写该文件中的配置变量;
    • 由于它是系统配置文件,因此你需要管理员或超级用户权限来修改它。(开发中通常不修改)
  • ~/.gitconfig 或 C/用户/coderwhy/.gitconfig 文件:只针对当前用户
    • 你可以传递 --global 选项让 Git 读写此文件,这会对你系统上 所有 的仓库生效;
  • 当前使用仓库的 Git 目录中的 config 文件(即 .git/config):针对该仓库
    • 你可以传递 --local 选项让 Git 强制读写此文件,虽然默认情况下用的就是它;

image-20240728191349467

3.1、Git的配置选项

安装Git后,要做的第一件事就是设置你的用户名和邮件地址。

  • 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改;
  • 如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息;

image-20240728192313039

检测当前的配置信息:git config --list

image-20240728192344973

3.2、Git的别名

Git 并不会在你输入部分命令时自动推断出你想要的命令:

  • 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。

    image-20240728192528216

    image-20240728192541422

3.3、获取Git仓库 – git init/git clone

我们需要一个Git来管理源代码,那么我们本地也需要有一个Git仓库

通常有两种获取 Git 项目仓库的方式:

  • 方式一:初始化一个Git仓库,并且可以将当前项目的文件都添加到Git仓库中(目前很多的脚手架在创建项目时都会默认创建一个Git仓库);
  • 方式二:从其它服务器 克隆(clone) 一个已存在的 Git 仓库(第一天到公司通常我们需要做这个操作);

方式一:初始化Git仓库

  • 该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的核心;

  • 但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪;

    git init

方式二:从Git远程仓库

git clone https://github.com/coderwhy/hy-react-web-music.git

image-20240728192952916

3.3、文件的状态划分

现在我们的电脑上已经有一个Git仓库:

  • 在实际开发中,你需要将某些文件交由这个Git仓库来管理;
  • 并且我们之后会修改文件的内容,当达成某一个目标时,想要记录下来这次操作,就会将它提交到仓库中

那么我们需要对文件来划分不同的状态,以确定这个文件是否已经归于Git仓库的管理:

  • ==未跟踪(Untracked):==默认情况下,Git仓库下的文件也没有添加到Git仓库管理中,我们需要通过add命令来操作;
  • ==已跟踪(Tracked):==添加到Git仓库管理的文件处于已跟踪状态,Git可以对其进行各种跟踪管理;

已跟踪的文件又可以进行细分状态划分:

  • staged(已暂存状态):暂缓区中的文件状态;
  • Unmodified(未修改状态):commit命令,可以将staged中文件提交到Git仓库
  • Modified(已修改):修改了某个文件后,会处于Modified状态;

在工作时,你可以选择性地将这些修改过的文件放入暂存区;

然后提交所有已暂存的修改,如此反复;

3.4、Git操作流程图

image-20240728195309197

3.5、检测文件的状态 - git status

我们在有Git仓库的目录下新建一个文件,查看文件的状态:

  • git status

image-20240728201242692

Untracked files:未跟踪的文件

  • 未跟踪的文件意味着 Git 在之前的提交中没有这些文件;
  • Git 不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”;

我们也可以查看更加简洁的状态信息:

  • git status –s
  • git status --short

image-20240728201334812

左栏指明了暂存区的状态,右栏指明了工作区的状态;

??:表示未跟踪状态

3.6、文件添加到暂存区 – git add

跟踪新文件命令:

  • git add aaa.js

  • 使用命令 git add 开始跟踪一个文件。

跟踪修改的文件命令:

  • 如果我们已经跟踪了某一个文件,这个时候修改了文件也需要重新添加到暂存区中;

image-20240728202017619

通过git add . 将所有的文件添加到暂存区中:

image-20240728202109519

3.7、git忽略文件

一般我们总会有些文件无需纳入Git的管理,也不希望它们总出现在未跟踪文件列表。

  • 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等;
  • 我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件的模式;

在实际开发中,这个文件通常不需要手动创建,在必须的时候添加自己的忽略内容即可;

  • 比如右侧是创建的Vue项目自动创建的忽略文件:
    • 包括一些不需要提交的文件、文件夹;
    • 包括本地环境变量文件;
    • 包括一些日志文件;
    • 包括一些编辑器自动生成的文件;

image-20240728204333690

github上不同语言的忽略文件模版 :https://github.com/github/gitignore

3.8、文件更新提交 – git commit

现在的暂存区已经准备就绪,可以提交了。

  • 每次准备提交前,先用 git status 看下,你所需要的文件是不是都已暂存起来了;

  • 再运行提交命令 git commit;

  • 可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行;

  • git commit –m “提交信息”

image-20240728213128606

如果我们修改文件的add操作,加上commit的操作有点繁琐,那么可以将两个命令结合来使用:

  • git commit -a -m “修改了bbb文件”

image-20240728213222586

3.9、Git的校验和

Git 中所有的数据在存储前都计算校验和,然后以 校验和 来引用。

  • Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希);
  • 这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来;

image-20240803213905555

3.1、查看提交的历史 – git log

在提交了若干更新,又或者克隆了某个项目之后,有时候我们想要查看一下所有的历史提交记录

  • 这个时候我们可以使用git log命令:
    • 不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面;
    • 这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明;

image-20240803214038265

3.2、版本回退 – git reset

如果想要进行版本回退,我们需要先知道目前处于哪一个版本:Git通过HEAD指针记录当前版本。

  • HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交;

  • 理解 HEAD 的最简方式,就是将它看做 该分支上的最后一次提交 的快照;

    image-20240803214330384

我们可以通过HEAD来改变Git目前的版本指向:

  • 上一个版本就是HEAD,上上一个版本就是HEAD^;
  • 如果是上1000个版本,我们可以使用HEAD~1000;
  • 我们可以可以指定某一个commit id;

git reset --hard HEAD^

git reset --hard HEAD~1000

git reset --hard 2d44982

3.3、什么是远程仓库?

什么是远程仓库(Remote Repository)呢?

  • 目前我们的代码是保存在一个本地仓库中,也就意味着我们只是在进行本地操作;
  • 在真实开发中,我们通常是多人开发的,所以我们会将管理的代码共享到远程仓库中;

那么如何创建一个远程仓库呢?

  • 远程仓库通常是搭建在某一个服务器上的(当然本地也可以,但是本地很难共享);
  • 所以我们需要在Git服务器上搭建一个远程仓库;

目前我们有如下方式可以使用Git服务器:

  • 使用第三方的Git服务器:比如GitHub、Gitee、Gitlab等等;
  • 在自己服务器搭建一个Git服务;

image-20240803214623694

3.4、远程仓库的验证

常见的远程仓库有哪些呢?目前比较流行使用的是三种:

  • GitHub:https://github.com/
  • Gitee:https://gitee.com/
  • 自己搭建Gitlab:http://152.136.185.210:7888/
  • 自己搭建Gogo类似于Gitlab

对于私有的仓库我们想要进行操作,远程仓库会对我们的身份进行验证:

  • 如果没有验证,任何人都可以随意操作仓库是一件非常危险的事情;

目前Git服务器验证手段主要有两种:

  • 方式一:基于HTTP的凭证存储(Credential Storage);
  • 方式二:基于SSH的密钥;

下面我们来具体讨论一下这两种方式的验证规则和过程;

3.5、远程仓库的验证 – 凭证

因为本身HTTP协议是无状态的连接,所以每一个连接都需要用户名和密码:

  • 如果每次都这样操作,那么会非常麻烦;
  • 幸运的是,Git 拥有一个凭证系统来处理这个事情;

下面有一些 Git Crediential 的选项:

  • 选项一:默认所有都不缓存。 每一次连接都会询问你的用户名和密码;
  • 选项二:“cache” 模式会将凭证存放在内存中一段时间。 密码永远不会被存储在磁盘中,并且在15分钟后从内存中清除;
  • 选项三:“store” 模式会将凭证用明文的形式存放在磁盘中,并且永不过期;
  • 选项四:如果你使用的是 Mac,Git 还有一种 “osxkeychain” 模式,它会将凭证缓存到你系统用户的钥匙串中(加密的);
  • 选项五:如果你使用的是 Windows,你可以安装一个叫做 “Git Credential Manager for Windows” 的辅助工具;
    • 可以在 https://github.com/Microsoft/Git-Credential-Manager-for-Windows 下载。

image-20240803215031690

3.6、远程仓库的验证 – SSH密钥

Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。

SSH以非对称加密实现身份验证。

  • 例如其中一种方法是使用自动生成的公钥-私钥对来简单地加密网络连接,随后使用密码认证进行登录;
  • 另一种方法是人工生成一对公钥和私钥,通过生成的密钥进行认证,这样就可以在不输入密码的情况下登录;
  • 公钥需要放在待访问的电脑之中,而对应的私钥需要由用户自行保管;

如果我们以SSH的方式访问Git仓库,那么就需要生产对应的公钥和私钥:

image-20240803215227940

3.7、远程仓库的交互

从远程仓库clone代码:将存储库克隆到新创建的目录中;

  • git clone http://152.136.185.210:7888/coderwhy/gitremotedemo.git

将代码push到远程仓库:将本地仓库的代码推送到远程仓库中;

  • 默认情况下是将当前分支(比如master)push到origin远程仓库的;

    git push

    git push origin master

从远程仓库fetch代码:从远程仓库获取最新的代码

  • 默认情况下是从origin中获取代码;

    git fetch

    git fetch origin

  • 获取到代码后默认并没有合并到本地仓库,我们需要通过merge来合并;

    git merge

从远程仓库pull代码:上面的两次操作有点繁琐,我们可以通过一个命令来操作

git pull

git fetch + git merge(rebase)

3.8、本地分支的上游分支(跟踪分支)

问题一:当前分支没有track的分支

image-20240803220150180

原因:当前分支没有和远程的origin/master分支进行跟踪

在没有跟踪的情况下,我们直接执行pull操作的时候必须指定从哪一个远程仓库中的哪一个分支中获取内容;

image-20240803220234292

如果我们想要直接执行git fetch是有一个前提的:必须给当前分支设置一个跟踪分支(上游分支):

image-20240803220309081

git branch --track dev origin/master 创建一个dev分支,让当前这个dev分支直接跟踪远程的master分支

3.9、拒绝合并不相干的历史

问题二:合并远程分支时,拒绝合并不相干的历史

image-20240803220828764

原因:我们将两个不相干的分支进行了合并:

https://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories-on-rebase

image-20240803220902530

简单来说就是:过去git merge允许将两个没有共同基础的分支进行合并,这导致了一个后果:新创建的项目可能被一个毫不

怀疑的维护者合并了很多没有必要的历史,到一个已经存在的项目中,目前这个命令已经被纠正,但是我们依然可以通过–

allow-unrelated-histories选项来逃逸这个限制,来合并两个独立的项目;

image-20240803220926676

3.1、入职公司做的操作

情况一:公司已经有远程仓库了

  • 1、账号密码验证
  • 2、git clone下来
  • 3、进行开发
    • git add .
    • git commit -m ‘提交’
    • 先git pull(防止冲突、有冲突在自己本地解决)
    • git push(东西推送到远程仓库)

情况二:开发一个全新的项目(由你来搭建的)

方案一:

  • 1、创建远程仓库
  • 2、git clone
    • 在clone下来的文件夹中开始搭建项目
    • git add.
    • git commit -m “”
    • git push

方案二:

  • 创建一个本地仓库和搭建本地项目
    • git remote add origin xxx
    • git branch --set-upstream-to=origin/master
    • git fetch
    • git merge --allow-unrelated-histories (合并是有问题的所以我们要加后边这个参数)
      • 当然我们可以直接用git pull (git fetch+git merge=git pull)
    • git push

3.2、常见的开源协议

image-20240803221238447

MIT的协议是一种非常宽松的协议,Apache相对于MIT来说他就必须在改代码的时候就必须在修改的时候放置对应版权说明

我们直接选MIT就可以了

3.3、怎么操作gitHub

注册登录、下载源码、ssh方式、http模式、看开源项目、有问题看下issues有没有对应的解决、正常提交代码push

3.4、怎么操作gitlab

偏好设置、设置中文语言(大约翻译了百分94)

3.5、git push的默认行为(小问题记录)

我们本地分支叫做master

git branch --set-upstream-to=orgin/main (设置当前master的上游分支)

git pull 拉取对应的代码是可以的

但是 git push推送的时候有问题,完整的push写法 git push origin master:main,也写一个git pus origin head:main

如果我直接写 git push origin maseter,这个操作是将本地的maseter分支推送到了远程仓库里面

那如果我全部都不跟呢?直接写 git push,默认行为到底是什么呢?我们会发现报错了

image-20240804140502035

为什么报错,这么因为他跟他的git配置有一定的关系,默认是如下

git config push.default simple

这个参数的行为是,默认是找到当前的分支 ,然后再去找到远程的master分支,但是远程没有这个master这个分支,所以他就给你报刚才那个错误了

我的想法是,想让你找我当前对应分支的上游分支,因为我已经设置过当前本地分支的上游分支了,

git config push.default upstream

查看当前仓库的git 配置文件

cat .git/config

image-20240804141408244

git checkout -b dev 本地创建并切换到dev分支上了

这时候我要再去推送这个分支的东西,就会发现报错如下。

image-20240804141629246

因为我从来没有对dev分支设置过什么上游分支

测试另一个参数

修改git push的默认行为 git config push.default current

git push 推送成功

current这个参数跟simple非常相似,只不过跟simple的区别在于simple会去找我们当前分支相同的远程分支,找不到就会报错,current这个东西他也会去找远程分支,只不过他找不到就会新创建一个远程分支

总结:simple upstream current

simple,找名称跟本地分支相同的远程分支,找不到报错

upstrean 找名称跟上游分支相同的远程分支,找到推送,找不到创建

current,找名称相同的远程分支,找不到就创建

3.6、Git标签(tag) - 创建tag

对于重大的版本我们常常会打上一个标签,以表示它的重要性:

  • Git 可以给仓库历史中的某一个提交打上标签;
  • 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等);

创建标签:

  • Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated);

  • 附注标签:通过-a选项,并且通过-m添加额外信息;

    image-20240804184852196

git show v1.4

默认情况下,git push 命令并不会传送标签到远程仓库服务器上

  • 在创建完标签后你必须显式地推送标签到共享服务器上,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签;

    image-20240804184930409

解读

如果我们在开发过程中你达到了自己的某个目标,就是本来我打算开发一个功能,这个功能差不多现在我已经准备就绪了,一般在准备就绪的时候我们会给当前这次比较重要的这个版本里面,会给他打上一个标签,意思是我标记下这个东西,其目的是方便我之后去查找到我曾经在哪里打过这样的标签,然后以后的话方便我进行版本的回退,或者通过这个东西的话给也可以给他新建一个分支,维护跟多的功能

3.7、Git标签(tag) - 删除和检出tag

删除本地tag:

要删除掉你本地仓库上的标签,可以使用命令 git tag -d

image-20240804185055380

删除远程tag:

  • 要删除远程的tag我们可以通过git push –delete

image-20240804185124075

检出tag:

  • 如果你想查看某个标签所指向的文件版本,可以使用 git checkout 命令
  • 通常我们在检出tag的时候还会创建一个对应的分支(分支后续了解);

image-20240804185227182

注意: 我通常切换到对应的tag标签中后一般是需要创建分支的,而是直接在tag标签上进行修改

3.8、Git提交对象(Commit Object)

几乎所有的版本控制系统都以某种形式支持分支

  • 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。

在进行提交操作时,Git会保存一个提交对象(commit object):

  • 该提交对象会包含一个指向暂存内容快照的指针;
  • 该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针;
  • 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象;
  • 而由多个分支合并产生的提交对象有多个父对象;

3.9、Git master分支

Git的分支,其实本质上仅仅是指向提交对象的可变指针。

  • Git 的默认分支名字是 master,在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支;
  • master 分支会在每次提交时自动移动;

Git 的 master 分支并不是一个特殊分支。

  • 它就跟其它分支完全没有区别;
  • 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它;

image-20240804222010609

3.1、Git创建分支

Git是怎么创建新分支的呢?

​ 很简单,它只是为你创建了一个可以移动的新的指针;

比如,创建一个testing 分支, 你需要使用git branch 命令:

git branch testing

image-20240804222439502

那么,Git又是怎么知道当前在哪一个分支上呢?

  • 也很简单,它也是通过一个名为 HEAD 的特殊指针;

    git checkout testing

image-20240804222625829

3.2、Git分支提交

如果我们指向某一个分支,并且在这个分支上提交:

image-20240804223008929

你也可以切换回到master分支,继续开发:

image-20240804223150467

3.2、创建分支同时切换

创建新分支的同时切换过去

  • 通常我们会在创建一个新分支后立即切换过去;
  • 这可以用 git checkout -b 一条命令搞定;

3.3、为什么需要使用分支呢?

让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流。

  • 开发某个项目,在默认分支master上进行开发;
  • 实现项目的功能需求,不断提交;
  • 并且在一个大的版本完成时,发布版本,打上一个tag v1.0.0;

继续开发后续的新功能,正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补, 你将按照如下方式来处理:

  • 切换到tag v1.0.0的版本,并且创建一个分支hotfix;

想要新建一个分支并同时切换到那个分支上,你可以运行一个带有 -b 参数的 git checkout 命令:

​ git checkout –b hotfix

image-20240804223520087

3.4、分支开发和合并

分支上开发、修复bug:

  • 我们可以在创建的hotfix分支上继续开发工作或者修复bug;
  • 当完成要做的工作后,重新打上一个新的tag v1.0.1;

切换回master分支,但是这个时候master分支也需要修复刚刚的bug:

  • 所以我们需要将master分支和hotfix分支进行合并;

git checkout master

git merge hotfix

image-20240804223808135

3.5、查看和删除分支

如果我们希望查看当前所有的分支,可以通过以下命令:

​ git branch # 查看当前所有的分支

​ git branch –v # 同时查看最后一次提交

​ git branch --merged # 查看所有合并到当前分支的分支

​ git branch --no-merged # 查看所有没有合并到当前分支的分支

image-20240804224021490

如果某些已经合并的分支我们不再需要了,那么可以将其移除掉:

​ git branch –d hotfix # 删除当前分支

​ git branch –D hotfix # 强制删除某一个分支

3.6、Git的工作流(git flow)

由于Git上分支的使用的便捷性,产生了很多Git的工作流:

  • 也就是说,在整个项目开发周期的不同阶段,你可以同时拥有多个开放的分支;
  • 你可以定期地把某些主题分支合并入其他分支中;

比如以下的工作流:

  • master作为主分支;
  • develop作为开发分支,并且有稳定版本时,合并到master分支中;
  • topic作为某一个主题或者功能或者特性的分支进行开发,开发完成后合并到develop分支中;

image-20240804224300589

3.7、比较常见的git flow

image-20240804224353785

3.8、Git的远程分支

远程分支是也是一种分支结构

  • 以 / 的形式命名的;

如果我们刚刚clone下来代码,分支的结构如下:

如果其他人修改了代码,那么远程分支结构如下:

  • 你需要通过fetch来获取最新的远程分支提交信息;

image-20240804224515555

3.9、远程分支的管理

操作一:推送分支到远程

  • 当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上;

  • 运行 git push ;

    git push origin

操作二:跟踪远程分支

  • 当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master 的 master 分支
  • 如果你愿意的话可以设置其他的跟踪分支,可以通过运行 git checkout --track /
  • 如果你尝试检出的分支 (a) 不存在且远程、刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支;

git checkout --track /

git checkout

操作三:删除远程分支

  • 如果某一个远程分支不再使用,我们想要删除掉,可以运行带有 --delete 选项的 git push 命令来删除一个远程分支。

git push origin --delete

3.1、Git rebase用法

在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。

image-20240804225134778

什么是rebase呢?

  • 在上面的图例中,你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次;
  • 在 Git 中,这种操作就叫做 变基(rebase);
  • 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样;
  • rebase这个单词如何理解呢?
    • 我们可以将其理解成改变当前分支的base;
    • 比如在分支experiment上执行rebase master,那么可以改变experiment的base为master

git checkout experiment

git rebase master

3.2、rebase的原理

rebase是如何工作的呢?

  • 它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2;

  • 然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件;

  • 然后将当前分支指向目标基底 C3;

  • 最后以此将之前另存为临时文件的修改依序应用;

我们可以再次执行master上的合并操作:

  • git checkout master
  • git merge experiment

image-20240804225544441

3.3、rebase和merge的选择

开发中对于rebase和merge应该如何选择呢?

事实上,rebase和merge是对Git历史的不同处理方法:

  • merge用于记录git的所有历史,那么分支的历史错综复杂,也全部记录下来;
  • rebase用于简化历史记录,将两个分支的历史简化,整个历史更加简洁;

了解了rebase的底层原理,就可以根据自己的特定场景选择merge或者rebase。

注意:rebase有一条黄金法则:永远不要在主分支上使用rebase

  • 如果在main上面使用rebase,会造成大量的提交历史在main分支中不同;
  • 而多人开发时,其他人依然在原来的main中,对于提交历史来说会有很大的变化;

image-20240804225725551

解读

merge做的操作是两次提交合并,并合成一次新的提交,弊端通过查看记录发现已经不是一个线性的历史记录了,有些人就喜欢看线性的结构,

如果我们想让他变成一种线性结果,就需要要用到rebase这个操作,rebase,中文意思变基的意思,切换到被何必的分支上然后再使用命令如下

git rebase master

此时我们还是在feature分支上

通过命令 git checkout master 切换到master上

然后再 命令 git merge把刚才变基过来的提交进行合并

3.4、git命令速查表

image-20240804225918266

3.5、git处理分支冲突

image-20240804195149469

保留当前改变,保留远程改变,保留两者,比较信息

3.6、实战远程仓库操作

远程分支操作,当我为本地项目添加远程仓库以后,如果直接使用 git branch --set-upstream-to=origin/main,会发现报错的,这是因为此时我的本地根本不知道远程有这个origin/main这个分支,我们需要先git fetch origin main,先把远程分支拿到本地。然后再使用git branch --set-upstream-to=origin/main 设定当前分支的远程分支,然后你发现我文件中并没有出现远程仓库里的那俩文件,我们需要进行手动合并 git merge,其实在这里我们是省略了一些东西。为什么能省略就是因为我们设置了他的上游分支,默认情况下merge的使用是需要详细指定的。比如git merge origin/main,但是经过命令实战也是不可以合并的,这是因为他们并没有共同的祖先,就是我们前面讲到的从git2.9版本所做的一个限制,禁止合并不想干的两个分支,我们可以通过命令来逃逸这个规则,git merge --allow-unrelated-histories,现在远程的代码跟我们本地的成功合并,但是我们此时使用git push命令时发现有报错了,这是因为git push有一定的默认行为,他会去远程仓库中找当前本地分支,找不到就会报错,默认行为参数为simple,我们可以修改这个push的默认行为使用命令,git config push.default upstream,参照于当前分支的上游分支,去远程仓库找分支。找不到就创建,找到就用。这是一种开发中常见的操作。

我在开发中的操作,上述出现的原因是,我的本地分支跟远程分支的名称并不相同,但是我想让我本地的master分支跟踪远程的main分支,就会出现很多的问题。其实每次push的时候,也是非常奇怪的,把master提送到main。并不符合我们开发习惯,怎么解决,我们可以使用 git checkout --track origin/main 这个操作意思。是我在本地创建了一个main分支的同时,也跟踪了远程的origin/main分支。

创建一个本地分支?

git branch 分支名称

创建并切换一个分支?

git checkout -b 分支名称

怎么提交本地的分支到远程?

git push? 可惜不可以

git push origin develop 可以

然后我切换到dev分支进行写代码开发

推送dev分支的内容

git push

失败

原因是本地分支名并没有设置上游分支

使用如下命令

git push --set-upstream origin develop

或者

git branch --set-upstream-to=origin/develop

然后再 git push

李四克隆项目

git clone 路径

李四查看本地分支

git branch

怎么让李四在本地的dev分支上进行开发?

git checkout --track origin/develop //直接切换到dev分支,并且让他跟踪这个分支,甚至我们可以直接写 git checkout develop,这个东西是上述命令的一个简写,他会自动检查下你本地有没有叫做develop的这个分支如果你本地没有,我会自动检测下我对应远程git仓库里面有没有这样的分支,如果有我就直接给你创建一个对应的本地分支

查看本地分支

git branch

开发代码

暂存区、提交本地库、提交远程库

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值