简介

git是免费开源的分布式版本控制系统,版本控制系统分为集中式和分布式,集中式依赖中央服务器,但出现问题就会无法工作,分布式是每个人电脑上都有一个完整的版本库,可以在本地修改不需要考虑网络问题。

安装配置

https://git-scm.com/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
安装的时候看到这个(NEW!) Add a Git Bash Profile to Windows Terminal也推荐选择上

安装了vscode可以选择Use Visual Studio Code as Git's default editor,

然后选main,

然后Git from the command line and also from 3rd-party software,

然后Use bundled OpenSsH,

然后Use the openssL library,

然后Checkout Windows-style,

然后 Use MinTTY (the default terminal of MSYS2),

然后fast-forward or merge,

然后Git Credential Manager

Enable file system caching

安装完输入这个

1
2
#查看版本信息,有就是成功
git -v

Windows的话 安装完Git之后会自动安装Git Bash,鼠标右键有

git的使用方式有三种:命令行 图形化界面 和 IDE插件

命令行的方式是最基本和最常用的方式,就是在终端中输入Git命令的方式来使用Git。图形化界面也叫GUI,就是通过一些专用的图形化工具软件来使用Git,在Git官网上也可以找到常用的GUI工具。

image-20251021035518780IDE插件就是在常用的IDEA或者vscode这些IDE工具中,通过插件或者扩展的方式来使用git

为了区分Linux操作系统中的命令,Git的所有命令都以git开头,后面跟着具体的命令,比如 git init 就是初始化一个仓库

image-20251021035753626

蓝色背景的部分是当前所在目录的位置,波浪线表示的是用户的主目录,比如我们现在所在的目录就是主目录下的directory这个目录下。绿色背景这里可以显示Git的分支名称和当前仓库的状态等信息,这个不配置也不影响使用

在开始使用Git之前第一步就是先使用 git config 命令配置一下用户名和邮箱,这样在提交的时候 才能够识别出来是谁提交的内容。这里的 –global参数表示的是全局配置,也就是说这个配置对所有的Git仓库都有效,不加这个参数就表示只对当前的Git仓库有效,还有一个就是 –system 参数表示系统级别的配置,对所有的用户都有效,一般不会使用–system

image-20251021040104117

1
2
git config --global user.name "Liu Qi"
git config --global user.email 1830191738@qq.com

这里因为用户名中间存在空格,所以需要使用双引号把它括起来,如果没有空格的话 这个双引号是可以省略的。配置完用户名之后 我们再来配置一下邮箱,那因为邮箱中间是没有空格的 所以就可以省略掉这个双引号。这两个命令只需要执行一次,执行过就可以省略

我们还可以使用下面这个命令来保存用户名和密码,这样就不用每次都输入了

1
git config --global credential.helper store

我们也可以使用下面这个命令来查看Git的配置信息,可以看到刚刚我们配置的用户名和邮箱,配置完成之后 我们就可以使用Git来管理我们的代码了

1
git config --global --list

新建版本库

版本库又叫仓库,英文名叫Repository简称Repo,大家可以把仓库理解成一个目录,这个目录里面所有的文件都可以被Git管理起来,每个文件的修改 删除 添加等操作Git都能够跟踪到,以便任何时候都可以追踪历史或者还原到之前的某一个版本。

创建仓库:方式1,git init。方式2,,git clone

​ 只需要把一个目录变成Git可以管理的仓库就可以了,一种是在自己电脑本地直接创建一个仓库,另 一种是从远程服务器上克隆一个已经存在的仓库

  1. 首先需要找到一个合适的位置来创建一个空目录,比如这里我们就创建一个叫做 learn-git 的目录,后面课程中的所有操作也都会在这个目录下进行,然后输入git init就可以创建一个仓库了,然后提示我们已经初始化了一个空的仓库和位置,命令行前面提示符的部分也变成了main,这个 main 就是当前所在的分支的名称,表示当前这个目录已经是一个被Git管理的仓库,然后ls -a来看一下这个目录下到底有没有一个叫.git 的目录,因为.git是隐藏文件所以加-a
1
2
3
4
mkdir learn-git
cd learn-git
git init(输出Initialized empty Git repository in F:/learn-git/.git/
ls -a

git 这个目录存放了Git仓库的所有数据,用下面两个命令可以看到很多文件和目录,这里都是重要文件不要随意修改,删除这个目录等于删除仓库

1
2
cd .git
ls -altr

git init 后面还可以指定目录的名称,如果指定了就会在当前目录下面创建一个新的目录作为Git仓库,比如我们可以创建一个叫做my-repo的Git仓库,会在learn-git后面的 my-repo 里面生成了一个.git目录,也就是说 my-repo 才是我们创建的仓库

1
git init my-repo
  1. 使用 git clone 命令来从Github 或者 Gitee这种远程服务器上来克隆一个已经存在的仓库,直接在命令行中输入 git clone 后面加上仓库的地址。可以看到除了 my-repo 这个仓库以外又多了一个remote-repo 这样的目录,进入后它也是显示了一个绿色的main 分支,再-a看一下也是有一个.git 的目录
1
2
3
git clone https://github.com/geekhall-laoyang/remote-repo.git
ls -ltr(按大小排序的长格式列表,降序
cd remote-repo

Git的工作区域和文件状态

Git的本地数据管理分为工作区 暂 存区和本地仓库,工作区域英文名叫 Working Directory,也叫工作目录或者本地工作目录,暂存区英文名叫 Staging Area,也称为索引index,是一种临时存储区域,用于保存即将提交到Git仓库的修改内容,暂存区域是在Git进行版本控制时非常重要的一个区域,本地仓库就是我们上一节课通过 git init 命令创建的那个仓库,它包含了完整的项目历史和元数据,是Gi存储代码和版本信息的主要位置

当你修改完工作区的文件之后需要将它们添加到暂存区,然后再将暂存区的修改提交到本地仓库中,这个过程中我们可以使用Git提供的命令来查看 比较或者撤销修改,来保证版本控制的准确性和完整性

举个例子,我们可以把仓库理解成工厂里面的仓库,这个仓库里面有很多的货物和产品,这些货物和产品就是我们的文件,比如说我们的代码文件 文本文件 图片文件等等,工作区就是生产这些货物的车间,对我们的货物进行生产 加工和修改,车间生产完这些产品之后需要运送到仓库里面保管起来。那车间和仓库之间需要有一个运输工具,比如我们使用小货车来运输的话,那这个小货车里面就是暂存区,车间生产完产品之后把产品放到小货车上,然后运输到仓库里面保存起来

联系到工作中,当我们的代码完成了一个阶段想存档备份的时候,就可以把这个版本放到本地仓库里面保存起来,在版本控制系统中,这个保存到仓库中的过程就叫做提交。但是如果我们每次文件修改之后都需要进行一次提交的话会比较麻烦,git提供一种方式:可以将修改的文件先添加到暂存区中,然后再把所有暂存区中的文件统一执行一下提交操作。联想到我们刚刚的例子的话,就是我们的车间生产完货物之后,并不是每次都需要运送到仓库里面,而是先把这些货物放到小货车上,然后一次性的运送到仓库里面保存起来。

相应的 Git中的文件也存在几种状态,分别是未跟踪 未修改 已暂存 已提交

未跟踪就是我们新创建的还没有被Git管理起来的文件,未修改就是我们已经被Gt管理起来但是文件的内容没有发生变化,还没有被修改过。已修改就是我们修改了文件,但是还没有添加到暂存区里面。已暂存就是我们修改后并且已经添加到了暂存区域内的文件,联想到刚刚的例子也就是已经放到小货车里面的货物

image-20251021224351090

添加提交仓库

git status

status这个单词本身就是状态的意思,用于查看仓库的状态,比如可以查看当前仓库处在哪个分支、有哪些文件以及这些文件当前处在怎样的一个状态,使用后可能会看到自己的分支名称是 master 而不是main,这是由于Git的版本不同导致的,没什么事

首先创建一个文件,创建文件有很多种方式,用熟悉的就行,这里直接使用 Linux 下的 echo 命令,将回显的内容输出到一个文件里面,比如输出一个“这是第一个文件”,可以看到 本地已经多一个file.txt的文件,看一下这个文件里面的内容可以看到刚刚输入的内容已经被写入到这个文件里面了

1
2
cd my-repo
echo "这是第一个文件" > file.txt

再来看一下仓库的状态,可以看到命令的回显中比刚才多了一红色的文件,就是刚刚新建的文件,这个文件现在就是处在一个未被跟踪的状态,接下来就可以使用 git add 命令来把文件放到小货车里面,这个命令的作用就是将文件添加到暂存区,等待后续的提交操作。

再来看一下仓库的状态,可以看到刚刚红色的 filext已经变成了绿色,表示这个文件现在已经被添加到了暂存区等待被提交,提示符里面也多了一个加号(我这里没显示),表示我们的仓库中存在已经修改了但是没有提交的文件,下面括号里面还有这样一行提示 (use “git rm –cached …” to unstage),他告诉我们可以使用这样的命令来把添加到暂存区的文件再取消暂存,也就是可以把刚刚放到小货车里面的货物再拿回来

1
2
3
4
git status
git add file.txt

git status

git commit

commit就是提交的意思,我们的文件只有被提交到仓库中才算真正的被保管起来,这里有一个需要注意的地方就是 git commit 这个命令只会提交暂存区中的文件而不会提交工作区中的其他文件,比如我们现在再来创建一个新的文件,然后再来看一下仓库的状态,可以看到刚刚创建的这个 file2是红色的未跟踪的状态,然后提交一下,注意git commit 这个命令在提交的时候需要使用 -m 参数来指定提交的信息,这个信息会被记录到仓库中,如果不指定 -m 这个参数,那么git commit 命令会进入一个交互式的界面,默认会使用:vim 来编辑提交信息。提交完成之后再看看仓库状态,刚刚绿色的 filetxt已经不见了,这是因为我们已经把file提交到仓库里面保管起来

1
2
3
4
echo "这是文件2的内容" > file2.txt
git status
git commit -m "第一次提交"
git status

git add 命令还可以使用通配符来添加多个文件,为了演示通配符的使用 我们再来多添加几个文件,然后可以看到仓库里面有四个txt文件和一个以sh结尾的shell脚本文件,执行git status可以看到除了file己经被仓库保管起来之外下面四个新建的文件都处于一个未跟踪的状态,可以使用 git add *.txt来把所有以txt结尾的文件都添加到暂存区里面

1
2
3
4
5
6
echo "file3" > file3.txt
echo "file4" > file4.txt
echo "file5" > file5.sh
ls
git status
git add *.txt

git add 命令还可以接受文件夹作为参数,比如想要添加所有文件的话可以使用 git add.这个命令来把当前文件夹下的所有文件都添加到暂存区里面,这里的点就表示当前目录,这次我们不输入-m参数,Git就会自动地进入一个交互式界面,默认会使用vim来编辑提交信息,可以使用方向键来移动光标,t使用i键进入编辑模式,安装的时候好像设置成了vscode启动了,输入这是第二次提交然后保存退出提交,再看一下状态提示我们所有的文件都提交完成了

git log

可以使用 git log 命令来查看提交记录。每次提交都有一个唯一的提交ID,就是 commit 后面这个16进制的字符串,还有每次提交的作者和邮箱以及提交的时间和刚刚提交时编写的注释信息等等内容,这里的名字和邮箱就是我们使用 git config 命令配置的,git log 后面还可以接收一些参数,比如说可以使用 git log 后面加上 –oneline来查看简洁的提交记录,这样就只显示每次提交的 ID 和提交信息了

1
2
3
4
5
git add .
git commit
git status
git log
git log --oneline

git reset回退版本

reset 命令用于回退版本,可以退回到之前的某一个提交的状态

git reset的三种模式:git rese –soft、git rese –hard、git rese –mixed,也就是软的 硬的和混合的

soft 参数表示回退到某一个版本并且保留工作区和暂存区的所有修改内容,hard 的参数表示回退到某一个版本并且丢弃工作区和暂存区的所有修改内容,mixed 这个参数就是介于 soft 和 hard 这两个参数之间,它表示回退到某一个版本并且只保留工作区的修改内容而丢弃暂存区的修改内容,mixed 也是 reset 命令的默认参数

image-20251022031628912

例子:首先来新建一个仓库 并且添加几次提交内容,提交完来使用 git log 查看一下提交历史,然后这个时候如果我们想要回退到上一个版本的话就可以使用 git reset 命令

1
2
3
4
5
6
7
8
9
10
11
12
git init repo
cd repo
echo 111 > file1.txt
echo 222 > file2.txt
echo 333 > file3.txt
git add file1.txt
git commit -m "commit1"
git add file2.txt
git commit -m "commit2"
git add file3.txt
git commit -m "commit3"
git log --oneline

为了方便演示再打开一个终端,然后把这个仓库目录复制三份,分别来执行三种不同的参数

首先我们来看一下 soft 参数,直接在命令行输入 git reset –soft,后面加上要回退的版本ID就可以了,回车之后再来使用 git log 查看一下提交历史,可以看到现在提交历史只有两次了,HEAD 指针也指向了第二个版本,那再来看一下工作区和暂存区的内容,使用ls命令查看一下工作区的内容,可以看到 file3 这个文件还在,cat 命令查看一下 file3 的内容也是没有问题的,file3在暂存区里面也是存在的

再来看一下仓库的状态,提示我们 file3 是一个新文件,因为我们使用的是 soft 参数,所以回退到上一个版本的时候,工作区和暂存区的内容都不会被清空,所以file3这个文件还是存在的,但是因为回退到了第二个版本,而file3这个文件是在第三个版本才添加的,所以对于第二个版本来说i这个file3文件就是一个新文件,这个时候我们就可以修改一下file3的内容,然后重新添加暂存和提交一下就可以了

1
2
3
4
5
6
7
8
9
10
11
cd f:/learn-git
cp -rf repo repo-soft
cp -rf repo repo-hard
cp -rf repo repo-mixed

cd repo-soft
git reset --soft 7f644ae
git log --oneline
clear
ls
cat file3.txt

hard参数,这里我们也是回退到上一个版本,使用 HEAD 加上尖角号来表示上一个版本,回车之后再使用 git log 查看一下提交历史,可以看到现在提交历史也是只有两次了,这个和 soft 参数是一样的,再来看一下工作区和暂存区的内容,ls命令查看一下工作区的内容,能够看到file3这个文件已经不存在了,再来查看一下暂存区的内容也没有了

就是说如果我们使用 hard 参数回退到上一个版本的时候,工作区和暂存区的内容都会被清空

1
2
3
4
5
6
7
cd learn-git
ls
cd repo-hard
git reset --hard HEAD^
git log
ls (file3不存在
git ls-files(暂存区没有

最后再来看一下默认的 mixed 参数,同样回退,这次我们不加任何参数直接输入 git reset,回车之后再来使用 git log 查看一下提交历史,可以看到现在提交历史也是只有两次,在工作区和暂存区file3这个文件还是存在的,cat命令查看内容也是没有问题的,然后再查看一下暂存区的内容,可以看到暂存区里面已经没有file3这个文件了

1
2
3
4
5
6
7
cd learn-git
cd repo-mixed
git reset HEAD^
git log --oneline
ls
cat file3.txt
git ls-files

在使用场景方面soft和 mixed 的作用基本相似,区别就在于是否保留暂存区的内容,一般来说当我们连续提交了多个版本,但是又觉得这些提交没有太大意义可以合并成一个版本的时候,就可以通过这两个参数来进行回退之后再重新提交

那它们主要的区别就是在重新提交之前,混合模式需要执行一下get add操作来将变动的内容重新添加到暂存区,而soft模式就不需要了,因为暂存区并没有被清空,而hard参数的使用场景则一般是真的要放弃目前本地所有修改内容的时候,建议大家谨慎使用,hard.这个参数,因为它会删除这两个版本之间的工作区和暂存区的所有修改内容

如果不小心误操作的话也不用太担心,Git中的所有操作都是可以回溯的,可以使用git reflog 命令来查看一下我们操作的历史记录,然后找到误操作之前的版本号再使用 git reset 命令来回退到这个版本就可以了

git diff

它可以用来查看文件在工作区 暂存区以及版本库之间的差异,它还可以查看文件在两个特定版本之间的差异,或者文件在两个分支之间的差异,平时我们开发的时候更多的是使用一些图形化的工具,但是需要了解一下这个,因为有的时候我们需要在一些没有图形化工具的服务器上来使用Git

git diff 后面如果什么都不加的话,会默认比较的是工作区和暂存区之间的差异内容,它会显示发生更改的文件以及更改的详细信息

演示:还是使用上面创建的仓库,这个仓库目前有三次提交,每次提交都新增了一个文件,比如第一次提交新增了一个file1.txt 里面是三个1以此类推,然后来修改一下file3这个文件,把文件内容改成 一键三连了吗,然后保存退出,能够看到现在终端的命令提示符已经变成了黄色,表示我们修改了一些仓库中的内容。那现在我们使用 git diff 命令来查看一下

第一行提示了我们发生变更的文件,第二行解释:Git会将文件的内容使用哈希算法生成一个40位的哈希值,这里只显示了哈希值的前七位,后面的100644表示的是文件的权限,再往下就是刚刚修改的内容了,红色是删除内容绿色是添加,现在比较的是工作区和暂存区之间的差异,因为我们修改的内容还没有被添加到暂存区,我们添加一下 ,然后再来使用 git diff 看一下输出结果,可以看到没有任何内容了,表示我们的工作区和暂存区的内容是相同的

image-20251023035448689

access.log
git status

echo “other log” > other.log
git status

echo access.log > .gitignore
cat .gitignore(输出access.log
git status

git add .
git status
git commit -m “ignore file sample”
git ls-files

1
2
3
4
5
6
7
8
9
10

我们也可以使用*.log这样的通配符来匹配所有以log结尾的文件,那我们现在来修改一下点 .gitignore文件,我们在下面加上一行\*.log表示我们忽略所有的以log结尾的文件,然后我们再来添加一个日志文件,使用 git status 来看一下状态,我们现在只能看到,gitignore这个文件的修改,而 hello.log 的修改被我们忽略掉了,然后再提交一下,然后我们再来看一下我们版本库中的文件,可以看到 hello.log 这个文件也是没有被添加进来的,表示我们\*.log 成功的适配了所有的 \*.log结尾的文件

~~~bash
vi .gitignore
*.log
echo hell0 > hello.log
git status(只有.gitignore)
git commit -m "test ignore log"
git ls-files

小知识点:如果对已经添加到仓库的other.log 这个文件做一些修改的话,Git还会不会监测到它的版本变化呢?

比如我们在other.log文件里面追加一些内容,两个右箭头在Linux 命令里面表示追加到这个文件的后面,那我们现在使用 git status 来看一下它的状态,Git还是提示我们other.log 这个文件发生了变化,而且我们使用 gitdiff这个命令也是可以看到它的变化内容的

.gitignore文件生效需要有一个前提,就是这个文件不能是已经被添加到版本库中的文件,那这个时候我们就需要把other.log 这个文件先从版本库中先删除掉,使用git rm 命令会把文件从工作区和暂存区同时删除,如果我们只是想把它从版本库里面删除而不想删除本地文件的话,就可以在后面加上–cached的这个参数,然后我们来看一下仓库的状态,它提示我们 other.log这个文件已经被删除了,然后我们再来看一下本地文件,可以看到在本地没有被删除。然后再提交一下,这样以后无论这个文件发生了什么变化就都不会被纳入到版本控制中了

1
2
3
4
5
6
7
echo " modified " >> other.log
git status
git diff
git rm --cached other.log
git status
ls
git commit -am "delete other.log"

.gitignore文件中还可以配置文件夹的名称,比如这里我们创建一个 temp 文件夹,用来存放一些临时文件,小知识点:如果temp文件夹下面什么都没有的话,这个文件夹是不会被纳入到版本控制中的,因为Git默认是不会将空的文件夹添加到仓库里面的,这个时候如果我们使用 git status 命令也是看不到任何变化的,temp文件夹下面有文件的话就会被纳入到版本控制中

比如我们来添加一个hello 到temp/hello,再来使用git status -s这个命令来看一下仓库的状态,-s是 short 的缩写,表示查看状态这个命令的简略模式,这个命命的回显最前面有两个问号,这里的两个间号第一列表示是暂存区的状态,第二列表示工作区的状态,然后我们在 .gitignore文件中添加 temp 文件夹的名称,这样我们就忽略了 temp 文件夹,注意文件夹的格式是以斜线结尾的,保存退出然后再来看一下仓库的状态,可以看到temp文件夹已经被忽略掉 不显示了,那这里的 M 表示.gitignore文件被修改过,然后提交,我们看一下仓库的文件内容,可以看到 temp 文件夹以及它下面的所有文件并没有被提交到我们的仓库里面

1
2
3
4
5
6
7
8
9
10
11
mkdir temp
git status

echo "hello" > temp/hello.txt
git status -s(输出?? temp/)
vi .gitignore
temp/
:wq
git status -s(输出 M.gitignore)
git commit -am "test ignore folder"
git ls-files

.gitignore文件的匹配规则:gitignore 这个配置文件是按行从上到下进行规则匹配的,忽略文件的匹配规则在Git官网上有详细的说明https://git-scm.com/docs/gitignore

  • 空行或者以#开头的行会被Git忽略。一般空行用于可读性的分隔,#一般用作注释

  • 使用标准的Blob模式匹配,所谓的 glob 模式就是指 she!ll所使用的简化了的正则表达式,例如:

    • 星号*通配任意个字符
    • 问号 ?匹配单个字符
    • 中括号[]表示匹配列表中的单个字符,比如:[abc] 表示a/b/c
  • 两个星号 **表示匹配任意的中间目录

  • 中括号可以使用短中线连接,比如:

    • [0-9] 表示任意一位数字,[a-z]表示任意一位小写字母
  • 感叹号 ! 表示取反,要忽略指令模式以外的文件或者目录可以在模式前加上感叹号就可以了

例子:

hello.txt
git add .
git commit -m “first commit”
git ls-files

1
2
3
4
5

这里稍微解释一下,Git是一种分布式的版本控制系统,我们的本地仓库和远程仓库是两个仓库,它们之间是相互独立的,我们可以在本地仓库中做任何修改,但是这些修改并不会影响到远程仓库,反之亦然。因此我们需要一种机制来同步本地仓库和远程仓库的修改内容,让他们的状态保持一致,pull和push,一个表示拉取 一个表示推送。push就是把本地仓库的修改推送给远程仓库,pull就是把远程仓库的修改拉取到本地仓库,刚刚我们在本地仓库新建了一个文件,但是这个文件并没有同步给远程仓库,下面就使用push命令来把本地仓库的修改内容推送给远程仓库

~~~bash
git push

推送命令执行成功了,打开页面Ctr+shit+R刷新一下,可以看到 hello.txt 这个文件已经推送到了GtHub上

关联本地仓库和远程仓库

上节课是远程克隆到本地,如果我们本地已经有了一个仓库的话怎样才能把它放到远程仓库里面呢

首先我们还是需要在GitHub上创建一个新的仓库,叫first-repo,之前我们创建过一个叫做my-repo的本地仓库,那现在我们就来把my-repo这个本地仓库和刚刚在GitHub上创建的远程仓库关联起来,新创建的时候github已经提示了我们需要使用 git remote add 这个命令,它的意思就是添加一个远程仓库,这里的orgin就是我们远程仓库的别名,.一般默认的别名都是这个,也可以自己指定一个其他的名字,复制第一行到终端,再使用 git remote -v这个命令来查看一下,这个命令可以查看我们当前仓库所对应的远程仓库的别名和地址,可以看到我们现在本地仓库所对应的远程仓库别名叫做origin

image-20251025183411408

image-20251025184223858

1
2
3
cd my-repo
git remote add origin git@github.com:shelterlq77-bit/first-repo.git
git remote -v

那第二行的最会的意思是指定分支的名称为main,因为我们这里默认的分支名称就是main,所以这一行的命令我们可以省略掉,最后一行就是把我们本地的main分支和远程的origin仓库的main分支关联起来,其实这个命令的全称应该是这样写的,-u是upstream的缩写,它的意思就是把我们本地仓库和别名为origin的远程仓库关联起来,后面的main:main就是把本地仓库的main分支推送给远程仓库的main分支。如果本地分支的名称与远程分支的名称相同的话我们就可以省略只写一个main就可以了,回车之后它会提示我们输入密码,回到页面就成功推送了

1
2
#git push -u origin main:main
git push -u origin main

同样地 如果我们在远程仓库修改了一些内容,那么就需要使用pull命令来把远程仓库的修改拉取到本地,GitHub上的文件是可以直接在线编辑的,比如我们可以在这里添加一个新的文件来模拟一下远程仓库的修改,添加一个readme,当我们访问一个仓库地址的时候这个仓库的首页就会显示这个README文件中的内容,这样可以添加一些介绍

然后使用pull来拉取一下远程仓库的修改内容,这里面仓库的名称和分支的名称可以省略,如果省略的话默认就是拉取仓库别名为origin的main分支,它的作用就是把远程仓库的指定分支拉取到本地再进行合并,我们可以cat一下这个文件的内容和远程仓库的内容是一样的。

main1.txt
git add .
git commit -m “main:1”

git branch dev

1
2
3
4
5
6
7
8
9
10

![image-20251026001715724](./images/git/image-20251026001715724.png)

那现在我们可以看到这个新的分支已经创建完成了,可以在这个分支上进行开发和测试,这里需要注意的是git branch 命令只是创建了一个新的分支,并没有切换到这个新的分支上,可以使用 git checkout,后面加上分支的名称来切换到不同的分支,可以看到我们的命含提示符已经变成了dev。

使用git checkout命令来切换分支的时候存在的潜在问题:因为除了切换分支和状态之外git checkout命令还可以用来恢复文件或者目录到之前的某一个状态,恢复的时候如果分支名称和文件名称相同的话就会出现歧义,git checkout 命令会默认切换分支而不是恢复文件,Git官方在2.23版本开始为我们提供了一个新的命令git switch,它是专门用来切换分支的,语义更加明确,我们可以使用 git switch 来试一下,可以看到也成功地切回到了main分支

~~~bash
git checkout dev
git switch dev

那现在假如测试完成没有问题之后我们就需要把这个dev功能的分支合并到主线代码中,我们可以使用git merge命令来将不同的分支合并到当前分支中,merge后面的分支名称是将要被合并的分支,而我们当前所在的分支就是合并后的目标分支,比如说我们要把dev分支合并到main分支中的话,就需要首先切换到main分支,然后执行git merge dev命令,这样就可以把dev分支合并到main分支中了

1
git merge dev

回车之后Git会自动为我们产生一次提交,我们需要输入提交的消息,直接使用默认的提交信息保存,在GitKraken的分支图上可以看到dev分支和main分支已经合并了,它也非常形象地展示了分支合并的过程,其实这个分支图就是我们提交记录的一个可视化的展示,在命令行中也可以通过 ,gitlog 来查看我们的分支图

1
git log --graph --oneline --decorate --all

合并完成之后我们再来使用git branch 命令来看一下,可以看到这个dev分支还是存在的,这里有的同学可能会有一些误解,认为分支被合并之后就会消失掉,其实如果我们不手工删除这个分支的话还是会存在,如果分支不再需要,就可以使用 git branch -d 命令来删除这个分支,这里的 -d 参数表示删除已经完成合并的分支,意思就是如果一个分支已经被合并到其他分支中了,那么我们就可以使用这个命令来删除这个分支

1
2
git branch
git branch -d dev

但是如果没有被合并的话是不能使用这个小d参数来删除的,这个时候就需要使用 git branch 后面加上大写字母的 -D 命令来强制删除这个分支
image-20251026003143947

解决合并冲突

如果两个分支修改了同一个文件的同一行代码,Git就不知道应该保留哪个分支的修改内容了,这个时候就需要我们手动来解决冲突

我们还是使用上一节课的仓库,新建一个分支feat,分支的命名其实也是有一定规则和含义的,feat就是feature的缩写,一般用来表示开发某一个功能的分支,然后我们切换到feat分支,我们来修改-下main1.txt文件中的内容,添加一行“这是feat分支中添加的内容”,保存之后我们来提交一下,提交信息我们使用 feat:1表示这是feat分支的第一次提交,技巧:就是在提交命令后面加上-a参数,就可以一个命令完成添加暂存和提交两个动作

1
2
3
4
git branch feat
git switch feat
vi main1.txt
git commit -a -m "feat:1"

然后我们切换回main分支,我们在main分支里面也同样修改一下这个文件中的内容,当切换回main分支之后,工作区的文件内容也自动发生了变化,刚刚在feat分支添加的内容就消失不见了,因为在main分支中我们还没有对这个文件进行修改,所以切换回main分支之后Git自动为我们把工作区域的内容也恢复了,同样也在第二行加上一句话“xxxx”,然后同样也来保存提交一下,这里 -a -m 也可以省略成-am,这个时候就可以看到feat分支和main分支的修改内容产生了分歧

1
2
3
4
git switch main
ls
vi main1.txt
git commit -am "main:6"

那现在我们来尝试合并一下分支,输入 git merge 来把feat分支的内容合并到main分支,回车之后 Git就会提示我们产生了冲突,自动合并失败了,需要解决冲突之后再提交,现在我们也可以使用 git status 命令来查看一下冲突文件的列表,也可以使用 git diff 命令来查看冲突的具体内容,Git会把两个分支的修改内容全都显示出来

然后Git会使用左箭头 等号和右箭头分别来表示两个分支的修改内容,其中等号上面的部分表示我们刚刚main分支中的修改内容,而等号下面到右箭头之间的部分是我们刚刚在feat分支中添加的内容

1
2
git merge feat
git status

<img src=”./images/git/image-20251026025650819.png”

那现在我们需要做的就是需要手工编辑这个文件,留下我们想要的内容之后然后再重新提交,我们把左箭头 等号和右箭头都去掉,把第二行的内容合并到第一行后面,然后添加一个逗号,这样我们就把两个分支的修改内容合在了一起,然后保存退出,然后添加暂存提交,可以看到提交之后就自动完成了我们合并的过程

image-20251026030013097

1
2
3
vi main1.txt
git add .
git commit -m "merge conflict"

在提交之前如果想中断这次合并的话,我们也可以使用 git merge –abort 这个命令来终止合并

回退和rebase

除了merge以外还有另外一个方法可以将不同分支的修改内容整合到一起,就是rebase,中文意思是变基

image-20251026030422878

之前因为上一范课演示合并冲突的时候新建了一个feat分支,那我们先将这个feat分支删除掉,避免它干扰我们的演示,执行 git branch -d feat 命令就可以了,还有在之前合并完成之后我们已经把dev分支删除掉了,那么现在就需要把它恢复回来,执行gie checkout -b dev,后面加_dev:2这次提交的提交ID,这样就可以恢复到这个分支的这一时间点的状态,那这个提交ID可以在GitKraken中看到,如果没有的话 就在标题中点一下右键然后选中这个Sha,也可以在命令行中使用 git log 命令来查看

这个命令太长了可以使用alias命令来将它定义成一个别名,比如这里我们将它定义成graph,这样以后我们就可以直接使用graph命令来查看图形化的提交记录了

1
2
3
4
git branch -d feat
gie checkout -b dev
git log --oneline --graph --decorate --all
alias graph="git log --oneline --graph --decorate --all"

然后我们再切换回main分支