跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言大前端java

Git 版本控制系统入门教程

Git 版本控制系统的基础知识与核心操作。内容包括 Git 的安装配置、工作区与版本库概念、基本工作流程(add/commit/log)、分支管理(创建/切换/合并/冲突解决)、远程仓库操作(克隆/推送/拉取)以及多人协作流程。此外还涵盖了标签管理、版本回退及撤销修改等实用技巧,帮助开发者掌握代码版本控制技能。

刀狂发布于 2026/3/30更新于 2026/10/25105 浏览
Git 版本控制系统入门教程

文章配图

1. 初识 Git

1.1 Git 是什么?

Git 是一个开源的分布式版本控制系统,用于高效地跟踪和管理项目代码的变更历史(不仅仅是代码,还有其它格式也是可以的)。

1.2 为什么要有 Git

在学习或者是工作的时候,比如编写各种文档,为了防止文档丢失,更改失误,我们不得不复制出一个副本,保留历史记录,方便找回历史记录。例如:

'设计文档-v1'
'设计文档-v2'
'设计文档-v3'
'设计文档 - 确定版'
'设计文档 - 最终版'

每个版本有各自的内容,但最终会只有一份文档是需要被使用的,在此之前的工作都需要这些不同版本的报告,于是每次都是复制粘贴副本,文件就越来越多,不仅文件多,更重要的是,随着版本数量的不断增多,我们可能记不太清每一个版本具体修改了哪些内容,文档如此,我们编写的项目代码也如此!

那么,如何解决呢?

答:版本控制器,记录每次修改以及版本迭代的一个管理系统。目前,最主流的版本控制器就是 Git,可以控制电脑上所有格式的文件。

为了能够更方便管理这些不同版本的文件,便有了版本控制器!所谓的版本控制器,就是能让你了解到一个文件的历史,以及它的发展过程的系统。通俗的讲就是一个可以记录工程的每一次改动和版本迭代的一个管理系统,同时也方便多人协同作业。目前最主流的版本控制器就是 Git,Git 可以控制电脑上所有格式的文件,例如 doc、excel、dwg、dgn、rvt 等等,对于我们开发人员来说,Git 最重要的就是可以帮助我们管理软件开发项目中的源代码文件!

【注意事项】
所有的版本控制系统,Git 也不例外,其实只能跟踪文本文件的改动,比如 txt 文件,网页,所有的程序代码等等,版本控制系统可以告诉你每次的改动,比如在第 10 行加了"name",在第 12 行删除了一个"Windows",而图片、视频等这些二进制文件,虽然也能由版本控制系统管理,但没办法跟踪文件的变化,只能把二进制文件每次改动串起来,即只知道图片从 90KB 改成了 100KB,但到底改了啥,版本控制系统无法记录。

文章配图

2. 安装 Git

接下来,我们来进行实操!安装 Git。

Git 是开放源代码的代码托管工具,最早是在 Linux 下开发的,当然,最开始也只能应用于 Linux 平台,后面慢慢的被移植到 Windows 下,现在 Git 可以在 Linux、Unix、Mac 和 Windows 这几大平台上正常运行了。

2.1 Linux-Ubuntu 安装 Git

这里介绍 Ubuntu 下的安装。

在 Ubuntu 安装 git 相当简单,一起来看看!

  • 首先查看系统有没有安装过 Git,输入命令:git --version
  • 如果出现 git 版本号已经安装:

文章配图

  • 如果出现这类提示,则没安装
Command 'git' not found, but can be installed with: sudo apt install git 
  • 没有则进行安装,输入安装命令:sudo apt-get install git -y(在安装过程中,出现了图形化界面,回车即可)
    再次输入 git --version,就可以看到 git 版本号啦!此时,安装完成。
2.2 Windows 安装 Git

Git 官网直接下载:Git 下载官网

  • 选择 Windows 操作系统

文章配图

  • 根据自己的电脑选择相应的下载

文章配图

下载完成后,找到下载到的文件,进行双击进行安装

文章配图

  • 接着,按照指示,一步步安装~

非常简单的,按照指示点下一步就好。

  • 检测是否安装好 Git,打开 Git Bash

文章配图

输入:git --version,出现对应安装的 git 版本号,就是安装成功啦!

文章配图

3. Git 初始化与配置

Git 的安装是很简单的,现在我们来看看 Git 的初始化与配置。

3.1 创建 Git 本地仓库

可以将仓库理解成是进行版本控制的一个文件目录,如果我们想要对文件进行版本控制,就必须先创建一个仓库出来!

创建一个 Git 本地仓库对应的命令为 git init,注意命令要在文件目录下执行,例如:

文章配图

文章配图

3.2 配置 Git

当安装 Git 后首先要做的事情就是设置你的用户名称和 e-mail 地址,这是非常非常重要的,配置命令为:

git config [--global] user.name "Your Name"
git config [--global] user.email "[email protected]"
# 把 Your Name 改成你的用户名
# 把 [email protected] 改成你的邮箱的格式,只要格式正确即可 

注意 --global 是一个可选项,如果使用了该选项,就表示这台机器上所有的 Git 仓库都会使用这个配置,如果你希望在不同仓库中使用不同的 name 或 e-mail,即可以不要 --global 选项,但需要注意的是,执行命令时必须要在仓库里面。

查看配置命令为:

git config -l

删除对应的配置命令为:

git config [--global] --unset user.name
git config [--global] --unset user.email

4. Git 工作流程 - 认识工作区、暂存区、版本库

  • 工作区:是在电脑上要写的代码或者是文件的目录
  • 暂存区 (stage/index):一般存放在 .git 目录下的 index 文件(.git/index)中,把暂存区有时也叫作索引(index)
  • 版本库 (repository):也叫仓库,工作区有一个隐藏目录 .git,它不算工作区,而是 Git 的版本库,这个版本库里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以"还原"

文章配图

  • 左侧为工作区,右侧为版本库,Git 的版本库里存放了很多东西,其中最重要的是暂存区
  • 在创建版本库的时候,Git 会自动为我们自动创建一个唯一的 master 的分支,以及指向 master 的一个指针 HEAD(分支与 HEAD 后续介绍)
  • 当对工作区修改或者是新增的文件,执行 git add 命令,暂存区目录树的文件索引会被更新
  • 当执行提交操作 git commit 时,master 分支会做相应的更新,可以简单理解为暂存区的目录树才会被真正写到版本库中

由上述描述我们便能得知:通过新建或粘贴进目录的文件,并不能称之为向仓库中新增文件,而只是在工作区新增了文件。必须要通过使用 git add 和 git commit 命令才能将文件添加到仓库中进行管理!!!

添加文件

在包含 .git 的目录下新建一个 ReadMe 文件,我们可以使用 git add 命令可以将文件添加到暂存区:

• 添加一个或多个文件到暂存区:git add [file1] [file2] ...
• 添加指定目录到暂存区,包括子目录:git add [dir]
• 添加当前目录下的所有文件改动到暂存区:git add .

再使用 git commit 命令将暂存区内容添加到本地仓库中:
• 提交暂存区全部内容到本地仓库中:git commit -m "message"
• 提交暂存区的指定文件到仓库区:git commit [file1] [file2] ... -m "message"

注意: git commit 后面的 -m 选项,要跟上描述本次提交的 message,由用户自己完成,这部分内容绝对不能省略,并要好好描述,是用来记录你的提交细节,是给我们人看的。

例如:

文章配图

我们还可以多次 add 不同的文件,而只 commit 一次便可以提交所有文件,是因为需要提交的文件是通通被 add 到暂存区中,然后一次性 commit 暂存区的所有修改。如:

文章配图

Git 工作流程:

  1. 工作区:开发者实际编辑代码的目录
  2. 暂存区:通过 git add 将修改添加到暂存区,准备提交
  3. 本地仓库(Local Repository):通过 git commit 将暂存区的修改保存到本地仓库,生成一个提交记录(上述介绍的是本地仓库)
  4. 远程仓库(Remote Repository):通过 git push 将本地提交推送到远程仓库,如 Gitee、GitHub(后续介绍如何连远程仓库)

截至目前为止,我们已经能够将代码直接提交至本地仓库了。我们可以使用 git log 命令,来查看下历史提交记录:

文章配图

该命令显示从最近到最远的提交日志,并且可以看到我们 commit 时的日志消息。

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline 参数:

文章配图

需要说明的是,我们看到的一大串类似 5a250e...2111e0 的是每次提交的 commit id(版本号),Git 的 commit id 不是 1,2,3……递增的数字,而是一个 SHA1 计算出来的一个非常大的数字,用十六进制表示。

查看.git 文件

先来看看我们的 .git 的目录结构:

文章配图

  1. index 就是我们的暂存区,add 后的内容都是添加到这里的。
  2. HEAD 就是我们的默认指向 master 分支的指针。

文章配图

而默认的 master 分支,其实就是:

文章配图

打印的 5a250e9e1895753939dfcf9cba0719ee6d2111e0 是什么东西呢?保存的就是当前最新的 commit id。

  1. objects 为 Git 的对象库,里面包含了创建的各种版本库对象及内容。当执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,就位于 ".git/objects" 目录下,让我们来看看这些对象有何用处:

文章配图

查找 object 时要将 commit id 分成 2 部分,其前 2 位是文件夹名称,后 38 位是文件名称。

找到这个文件之后,一般不能直接看到里面是什么,该类文件是经过 sha(安全哈希算法)加密过的文件,好在我们可以使用 git cat-file 命令来查看版本库对象的内容:

文章配图

其中,还有一行 tree c9b796e175c00c170f3e2b54ce4e2dd73cf43af9,我们使用同样的方法,看看结果:

文章配图

再看 ReadMe 对应的 a0423896973644771497bdc03eb99d5281615b51:

文章配图

总结一下,在本地的 git 仓库中,有几个文件或目录很特殊

• index: 暂存区,git add 后会更新该内容。
• HEAD: 默认指向 master 分支的一个指针。
• refs/heads/master: 文件里保存当前 master 分支的最新 commit id。
• objects: 包含了创建的各种版本库对象及内容,可以简单理解为放了 git 维护的所有修改。

文章配图

修改文件

Git 比其他版本控制系统设计得优秀,因为 Git 跟踪并管理的是修改,而非文件。

什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。

让我们将 ReadMe 文件进行一次修改:

文章配图

此时,仓库中的 ReadMe 和我们工作区的 ReadMe 是不同的,如何查看当前仓库的状态呢?git status 命令用于查看在你上次提交之后是否有对文件进行再次修改。

文章配图

上面的结果告诉我们,ReadMe 被修改过了,但还没有完成添加与提交。

文章配图

目前,我们只知道文件被修改了,如果能知道具体哪些地方被修改了,就更好了。有人会说,我刚改的我知道呀!可是,你还记得你三天前写了什么代码吗?或者没写?

git diff [file] 命令用来显示暂存区和工作区文件的差异,显示的格式正是 Unix 通用的 diff 格式。也可以使用 git diff HEAD -- [file] 命令来查看版本库和工作区文件的区别。 知道了对 ReadMe 做了什么修改后,再把它提交到本地仓库就放心多了。

文章配图

git add 之后,就没有看到上面 no changes added to commit (use "git add" and/or "git commit -a") 的消息了。接下来让我们继续 git commit 即可:

文章配图

版本回退

执行 git reset 命令用于回退版本,可以指定退回某一次提交的版本。要解释一下'回退'本质是将版本库中的内容进行回退,工作区或暂存区是否回退由命令参数决定:

git reset 命令语法格式为:git reset [--soft | --mixed | --hard] [HEAD]

• HEAD 说明:
◦ 可直接写成 commit id,表示指定退回的版本
◦ HEAD 表示当前版本
◦ HEAD^ 上一个版本
◦ HEAD^^ 上上一个版本
◦ 以此类推...
• 可以使用 ~ 数字表示:
◦ HEAD0 表示当前版本
◦ HEAD
1 上一个版本
◦ HEAD^2 上上一个版本
◦ 以此类推...

值得说的是,Git 的版本回退速度非常快,因为 Git 在内部有个指向当前分支(此处是 master)的 HEAD 指针,refs/heads/master 文件里保存当前 master 分支的最新 commit id。当我们回退版本的时候,Git 仅仅是给 refs/heads/master 中存储一个特定的 version,可以简单理解成如下示意图:

文章配图

文章配图

【操作一】 提交 version3 后,发现 version3 编写有误,想回退到 version2,重新基于 version2 开始写,这里希望工作区的内容也回退到 version2 版本,因此需要 --hard 参数,如下:

文章配图

可以看到 Read 文件的内容,已经回退到 version2 了,使用 git log 查看提交日志,也发现 HEAD 指向了 version2。

【操作二】 后悔回退到 version2,想再回到 version3

可以继续使用 git reset 命令,回退到 version3 版本,but 我们必须要拿到 version3 的 commit id 去指定回退的版本,从上图中,看到 git log 并不能打印出 version3 的 commit id,如果运气好的话,可以在终端找之前的记录,运气不好的话,commit id 已经被我们搞丢啦,不过不用担心!Git 提供了一个 git reflog 命令,可以补救一下,该命令用来记录本地的每一次命令!!!

文章配图

【操作三】 在实际开发中,由于长时间开发,导致 commit id 早就找不到了,但是又想回到 version3,貌似现在不可能~

我们要知道 Git 版本回退速度非常快,因为 Git 在内部有个指向当前分支,这里是 HEAD 指针默认指向 master 分支,在.git 隐藏文件中 refs/heads/master 文件里面保存了当前 master 分支的最新 commit id,当我们在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储一个特定的 version,可以简单理解为下图:

文章配图

可以查看 refs/heads/master 文件内容,保存了最新的 commit id,如下:

如果是操作二,回退到 version3 版本,则保存的 commit id 为 version3 的

撤销修改

情况一:对于工作区的代码,还没有 add

文章配图

万幸!才写了一行内容,就发现需要删除了,万一写了很多,一直都没有提交,可能都忘记自己新增的哪些内容了,那如何删除呢?

Git 为我们提供了更好的方式!!!

我们可以使用 git checkout -- [file] 命令让工作区的文件回到最近一次 add 或 commit 时的状态。要注意 git checkout -- [file] 命令中的 -- 很重要,切记不要省略,一旦省略,该命令就变为其他意思了

文章配图

情况二:已经 add,但没有 commit

add 后还是保存到了暂存区呢?怎么撤销呢?

让我们来回忆一下学过的 git reset 回退命令,该命令如果使用 --mixed 参数,可以将暂存区的内容退回为指定的版本内容,但工作区文件保持不变。那我们就可以回退下暂存区的内容了!!

文章配图

我们可以将版本回退到当前版本库版本
git reset --mixed HEAD File
git reset --hard HEAD File

情况三:已经 add,并且也 commit 了
不要担心,我们可以 git reset --hard HEAD^ 回退到上一个版本!不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程。

文章配图

删除本地仓库中的文件

在 Git 中,删除也是一个修改操作

下面演示删除 file4 文件:

使用 rm file4?

文章配图

这样直接删除是没有用的,此时只是删除了工作区的 file4,git status 会告诉你哪些文件被删除了,但是,这个时候,工作区和版本库就不一致了,要删除文件,除了要删除工作区的文件,还要清除版本库的文件

到这里,有两种情况:

【情况一】确实需要从版本库删除该文件

使用 git rm [文件名],将文件从工作区和暂存区中删除,并且 commit ~

文章配图

【情况二】删错了

使用 git checkout -- file4 来恢复,删除也是修改哦,这是刚刚学过的命令~

文章配图

文章配图

5. Git 分支管理

在版本回退里,每次提交,Git 都把它们串成一条时间线,这条时间线就可以理解为一个分支。截止目前为止,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。

再来理解一下 HEAD,HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分支。

文章配图

每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长,而 HEAD 只要一直指向 master 分支即可指向当前分支。

通过查看当前的版本库,我们也能清晰的理出思路:

cat .git/HEAD ---》ref: refs/heads/master
cat .git/refs/heads/master ----》5476bdeb12510f7cd72ac4766db7988925ebd302

创建分支

Git 支持我们查看或创建其他分支,在这里我们来创建第一个自己的分支 dev,对应的命令为:

git branch #查看当前本地所有分支 ----》* master
git branch dev #新建分支 dev
git branch ---》dev ---》* master 

当我们创建新的分支后,Git 新建了一个指针叫 dev,* 表示当前 HEAD 指向的分支是 master 分支。另外,可以通过目录结构发现,新的 dev 分支:

ls .git/refs/heads/ ---》dev master
cat .git/refs/heads/* -》5476bdeb12510f7cd72ac4766db7988925ebd302 -》5476bdeb12510f7cd72ac4766db7988925ebd302 

发现目前 dev 和 master 指向同一个修改。并且也可以验证下 HEAD 目前是指向 master 的。

cat .git/HEAD ---》ref: refs/heads/master

文章配图

切换分支

那如何切换到 dev 分支下进行开发呢?使用 git checkout 命令即可完成切换,示例如下:

git checkout dev -》Switched to branch 'dev'
git branch -》* dev -》master
cat .git/HEAD -》ref: refs/heads/dev 

文章配图

我们发现 HEAD 已经指向了 dev,就表示我们已经成功的切换到了 dev 上!

接下来,在 dev 分支下修改 ReadMe 文件,新增一行内容,并进行一次提交操作:

vim ReadMe
cat ReadMe -》hello bit -》write aaa for new branch
git add .
git commit -m"modify ReadMe" -》[dev 3740dce] modify ReadMe -》1 file changed, 1 insertion(+)

现在,dev 分支的工作完成,我们就可以切换回 master 分支:

git checkout master -》Switched to branch 'master'
cat ReadMe -》hello bit 

切换回 master 分支后,发现 ReadMe 文件中新增的内容不见了!!

但是在 dev 分支上,内容还在。为什么会出现这个现象呢?我们来看看 dev 分支和 master 分支指向,发现两者指向的提交是不一样的:

因为我们是在 dev 分支上提交的,而 master 分支此刻的提交点并没有变,此时的状态如图如下所示:

文章配图

当切换到 master 分支之时,HEAD 就指向了 master,当然看不到提交了!

合并分支

为了在 master 主分支上能看到新的提交,就需要将 dev 分支合并到 master 分支,示例如下:

git branch -》* dev -》master
git checkout master # 切换到 master 上进行合并 -》Switched to branch 'master'
git merge dev # 合并 dev 分支 -》Updating 16623e1..3740dce -》Fast-forward -》ReadMe | 1 + -》1 file changed, 1 insertion(+)
cat ReadMe -》hello bit -》write aaa for new branch 

git merge 命令用于合并指定分支到当前分支。合并后,master 就能看到 dev 分支提交的内容了。此时的状态如图如下所示。

文章配图

Fast-forward 代表'快进模式',也就是直接把 master 指向 dev 的当前提交,所以合并速度非常快。 当然,也不是每次合并都能 Fast-forward。 删除分支 合并完成后,dev 分支对于我们来说就没用了,那么 dev 分支就可以被删除掉,注意如果当前正处于某分支下,就不能删除当前分支,如:

git branch -》* dev -》master
git branch -d dev -》error: Cannot delete branch 'dev' checked out at '/home/user/gitcode' 

而可以在其他分支下删除当前分支,如

git checkout master
Switched to branch 'master'
git branch -d dev Deleted branch dev (was bdaf528). 

文章配图

因为创建、合并和删除分支非常快,所以 Git 鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在 master 分支上工作效果是一样的,但过程更安全。 合并冲突 可是,在实际分支合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。为了演示这问题,创建一个新的分支 dev1,并切换至目标分支,我们可以使用 git checkout -b dev1 一步完成创建并切换的动作,示例如下

git checkout -b dev1 Switched to a new branch 'dev1'
git branch * dev1 master 

在 dev1 分支下修改 ReadMe 文件,更改文件内容如下,并进行一次提交,如:

cat ReadMe hello bit write bbb for new branch # 将 aaa 该为 bbb
git add .
git commit -m"modify ReadMe" [dev1 0854245] modify ReadMe 1 file changed, 1 insertion(+), 1 deletion(-) 

切换至 master 分支,观察 ReadMe 文件内容:

git checkout master
Switched to branch 'master'

cat ReadMe
hello bit
write aaa for new branch

我们发现,切回来之后,文件内容由变成了老的版本,这种现象很正常,我们现在也完全能理解。

此时在 master 分支上,我们对 ReadMe 文件再进行一次修改,并进行提交,如下:

[user@server repo]$ git branch dev1 * master [user@server repo]$ vim ReadMe [user@server repo]$ cat ReadMe hello bit write ccc for new branch [user@server repo]$ git add . [user@server repo]$ git commit -m"modify ReadMe" [master c10f6d0] modify ReadMe 1 file changed, 1 insertion(+), 1 deletion(-) 

现在,master 分支和 dev1 分支各自都分别有新的提交,变成了这样:

文章配图

这种情况下,Git 只能试图把各自的修改合并起来,但这种合并就可能会有冲突,如下所示:

[user@server repo]$ git merge dev1 Auto-merging ReadMe CONFLICT (content): Merge conflict in ReadMe Automatic merge failed; fix conflicts and then commit the result. [user@server repo]$ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: ReadMe no changes added to commit (use "git add" and/or "git commit -a") 

发现 ReadMe 文件有冲突后,可以直接查看文件内容,要说的是 Git 会用 <<<<<<<,=======,>>>>>>> 来标记出不同分支的冲突内容,如下所示:

文章配图

此时我们必须要手动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘记)

文章配图

到这里冲突就解决完成,此时的状态变成了:

文章配图

分支管理策略 通常合并分支时,如果可能,Git 会采用 Fast forward 模式。还记得如果我们采用 Fast forward 模式之后,形成的合并结果是什么呢?

文章配图

在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。 但在合并冲突部分,我们也看到通过解决冲突问题,会再一次进行新的提交,得到的最终状态为:

文章配图

那么这就不是 Fast forward 模式了,这样的好处是,从分支历史上就可以看出分支信息。例如我们现在已经删除了在合并冲突部分创建的 dev1 分支,但依旧能看到 master 其实是由其他分支合并得到

文章配图

Git 支持我们强制禁用 Fast forward 模式,那么就会在 merge 时生成一个新的 commit,这样,从分支历史上就可以看出分支信息

git merge --no-ff -m "msg" branch_name

bug 分支 假如我们现在正在 dev2 分支上进行开发,开发到一半,突然发现 master 分支上面有 bug,需要解决。在 Git 中,每个 bug 都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。 可现在 dev2 的代码在工作区中开发了一半,还无法提交,怎么办?

Git 提供了 git stash 命令,可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。

[user@server repo]$ git stash
Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
[user@server repo]$ git status
On branch dev2
nothing to commit, working tree clean

用 git status 查看工作区,就是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复 bug。 储藏 dev2 工作区之后,由于我们要基于 master 分支修复 bug,所以需要切回 master 分支,再新建临时分支来修复 bug,示例如下:

[user@server repo]$ git checkout master # 切回 master Switched to branch 'master' [user@server repo]$ git checkout -b fix_bug # 新建并切换到 fix_bug 分支 Switched to a new branch 'fix_bug' [user@server repo]$ vim ReadMe [user@server repo]$ cat ReadMe hello bit write bbb for new branch a,b,c,d,e # 修复 bug--忘记写 e [user@server repo]$ git add ReadMe # 重新 add,commit [user@server repo]$ git commit -m"fix bug" [fix_bug 4bbc0c4] fix bug 1 file changed, 1 insertion(+), 1 deletion(-) 

修复完成后,切换到 master 分支,并完成合并,最后删除 fix_bug 分支。 至此,bug 的修复工作已经做完了,我们还要继续回到 dev2 分支进行开发。切换回 dev2 分支

[user@server repo]$ git checkout dev2 Switched to branch 'dev2' [user@server repo]$ git status On branch dev2 nothing to commit, working tree clean 

工作区是干净的,刚才的工作现场存到哪去了?用 git stash list 命令看看

[user@server repo]$ git stash list stash@{0}: WIP on dev2: 41b082f modify ReadMe

工作现场还在,Git 把 stash 内容存在某个地方了,但是需要恢复一下,如何恢复现场呢?我们可以使用 git stash pop 命令,恢复的同时会把 stash 也删了,示例如下:

[user@server repo]$ git stash pop On branch dev2 Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: ReadMe no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (4f873250b3503695efd26976676767676767676767) 

再次查看的时候,我们已经发现已经没有现场可以恢复了。 但我们注意到了,修复 bug 的内容,并没有在 dev2 上显示。此时的状态图为:

文章配图

Master 分支目前最新的提交,是要领先于新建 dev2 时基于的 master 分支的提交的,所以我们在 dev2 中当然看不见修复 bug 的相关代码。 我们的最终目的是要让 master 合并 dev2 分支的,那么正常情况下我们切回 master 分支直接合并即可,但这样其实是有一定风险的。 是因为在合并分支时可能会有冲突,而代码冲突需要我们手动解决(在 master 上解决)。我们无法保证对于冲突问题可以正确地一次性解决掉,因为在实际的项目中,代码冲突不只一两行那么简单,有可能几十上百行,甚至更多,解决的过程中难免手误出错,导致错误的代码被合并到 master 上。此时的状态为:

文章配图

解决这个问题的一个好的建议就是:最好在自己的分支上合并下 master,再让 master 去合并 dev,这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响 master。此时的状态为:

文章配图

文章配图

6. Git 远程操作

下面演示在 gitee 上创建远程仓库

创建远程仓库

文章配图

文章配图

上面的.gitignore 是为了在上传时过滤掉不重要的文件,分支模型选单分支模型就够用了,或者选生产/开发模型。 当然,如果创建仓库的时候没有添加.gitignore 文件,可以在本地仓库创建.gitignore 文件

文章配图

文章配图

将远程仓库克隆到本地

下面仅介绍两种方式:HTTPS,SSH

文章配图

文章配图

文章配图

SSH

文章配图

文章配图

然后查看是否有 id_rsa 和 id_rsa.pub 这两个文件

文章配图

如果没有的话,需要创建 ssh.key

ssh-keygen -t rsa -C "[email protected]"

注意:上面的邮箱要和 gitee 上绑定的邮箱一致

如果有的话,打开看一下

文章配图

将上面的内容全部复制下来,然后再打开 gitee 的设置

文章配图

配置 SSH 公钥

文章配图

文章配图

文章配图

三板斧

git add
git commit -m "XXX"
git push

当我们从远程仓库克隆后,实际上 Git 会自动把本地的 master 分支和远程的 master 分支对应起来,并且,远程仓库的默认名称是 origin。在本地我们可以使用 git remote 命令,来查看远程库的信息,如:

git remote

或者,用 git remote -v 显示更详细的信息:

git remote -v origin

提交时要注意,如果我们之前设置过全局的 name 和 e-mail,这两项配置需要和 gitee 上配置的用户名和邮箱一致,否则会出错。或者从来没有设置过全局的 name 和 e-mail,那么我们第一次提交时也会报错。这就需要我们重新配置下了,同样要注意需要和 gitee 上配置的用户名和邮箱一致。如何配置已讲过,在这里就不再赘述。 到这里我们已经将内容提交至本地仓库中,如何将本地仓库的内容推送至远程仓库呢,需要使用 git push 命令,该命令用于将本地的分支版本上传到远程并合并,命令格式如下:

文章配图

拉取远程仓库内容

文章配图

给命令配置起别名

在我们使用 Git 期间,有些命令敲的时候着实让人头疼(太长了。。),幸运的是,git 支持对命令进行简化!

举个例子,将 git status 简化为 git st,对应的命令为:

git config --global alias.st status

--global 参数是全局参数,也就是这些命令在这台电脑的所有 Git 仓库下都有用。如果不加,那只针对当前的仓库起作用。

标签管理

标签 tag,可以简单的理解为是对某次 commit 的一个标识,相当于起了一个别名。例如,在项目发布某个版本的时候,针对最后一次 commit 起一个 v1.0 这样的标签来标识里程碑的意义。 这有什么用呢?相较于难以记住的 commit id,tag 很好的解决这个问题,因为 tag 一定要给人容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使用标签就能很快定位到。

创建标签
在 Git 中打标签非常简单,首先,切换到需要打标签的分支上
然后,敲命令 git tag [name] 就可以打一个新标签
可以用命令 git tag 查看所有标签
可以用 git show [tagname] 查看标签信息。

文章配图

当然,并非只能给最新的提交打标签,使用如下命令查看 commit id,然后在 git tag [版本] [commit id]

文章配图

Git 还提供可以创建带有说明的标签,用-a 指定标签名,-m 指定说明文字,格式为:

git tag -a [name] -m "XXX" [commit_id]

删除标签

文章配图

因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。

推送标签

如果要推送某个标签到远程,使用命令

git push origin <tagname>

当然,如果你本地有很多标签,也可以一次性的全部推送到远端:

git push origin --tags

本地删除远程标签

git push origin --delete <标签名>

7. 多人协作一

目标:远程 master 分支下 file.txt 文件新增代码'aaa','bbb'
实现:由开发者 1 新增 aaa,开发者 2 新增 bbb
条件:在一个分支下协作完成

我们创建一个分支 dev,在分支 dev 上完成这些操作

git branch 查看本地分支,只有一个 master;git branch -r 查看远程分支,我们可以看到远程里面也只有 master,没有新创建的 dev

文章配图

将 dev 分支从远程拉取下来

文章配图

在 windows 上面模拟开发者 2,首先需要将仓库克隆到 windows 下,随便选取一个目录,shift + 右键

文章配图

文章配图

此时我们准备工作完成,接下来我们让开发者 1 新增 aaa,开发者 2 新增 bbb

文章配图

我们可以分别用 Linux 机器和 Windows 机器来模拟开发者 1 和开发者 2,依旧是采用我们上面已经创建的仓库 remote-repo。

1. 开发者 1 创建一个分支 dev

开发者 1 创建一个分支 dev,然后开发者 1 和开发者 2 都同时在这个分支上进行操作。

文章配图

👉 你在哪个分支上工作,就从那个分支 push 自己:

文章配图

2. 开发者 2 拉取远程仓库

打开 bash 进行 clone 远程仓库:

文章配图

当 clone 的时候,本地仓库就只有 master 分支,那么就要获取 dev 分支。如果本地还没有 dev,Git 会自动从远程的 origin/dev 创建一个对应的本地分支,并自动追踪它。

git checkout -b dev origin/dev 

文章配图

将本地 dev 分支和远程的 dev 分支进行建立链接,开发者 2 的本地也具有 dev 分支了。

3. 开发者 1 对远程仓库进行推送

文章配图

文章配图

切换到开发者 2 中,可以看到正常的进行对 file.txt 文件进行修改,可是 push 的时候却发生错误,提示当前的本地与远程仓库有区别!

文章配图

我们应该先进行 pull 来更新本地仓库!

git pull origin dev 

再次 push 又会发现失败,出现合并冲突问题,需要手动进行解决!!!

文章配图

解决完冲突后,这里要特别注意,要重新进行 add . 和 commit -m 来重新进行推送,再次进行 push 就可以上传成功,开发者 2 新添加的 bbb 内容成功推送。 此时可以在远程的 dev 分支上看到我们想要得到的结果:file.txt 文件内有开发者 1 添加的'aaa',有开发者 2 添加的 bbb。 接下来就可以用 master 来合并 dev 分支!!!

文章配图

可以看到 master 分支上没有这两行代码!

4. 将内容合并至 master
4.1 提交 Pull Request

开发者 1 和开发者 2 在远程仓库创建一个 Pull Request,提交合并请求。

文章配图

文章配图

4.2 本地操作:
  • 在 dev 分支和 master 分支上,执行如下命令:
git checkout master
git merge dev
git push origin master 

由于在 master 上进行 merge dev,可能会导致冲突,因此应该在本地 dev 上进行 merge master。这样就算有冲突,也可以在本地解决。解决完冲突后,再用 master 来 merge dev,就不会有问题。 步骤如下:

文章配图

文章配图

这样就可以看到 master 分支上的 file.txt 被同步更新了。

在这里插入图片描述

完成后,可以同时让开发者 1 和开发者 2 对 dev 分支进行删除。

在这里插入图片描述

8. 多人协作二

文章配图

1. 本地创建分支

要保证本地的 master 是最新的,先 pull 操作,然后再次创建 dev 分支。

开发者 1 操作

文章配图

文章配图

开发者 2 操作

文章配图

可以看到每次开发都是自己创建的分支,然后进行 push,每次都能成功,不会遇到冲突的问题。因为我们是在最新的 master 上创建的分支,然后自己创建的分支只有自己开发的时候能够用上,所以不会出现 push 冲突的问题。

2. 拉取远程的 feature-2 分支

突然,开发者 2 生病了,开发者 1 需要担起开发 feature-2 分支的重任!这时需要从远程拉取 feature-2 分支进行开发。此时,我们又回到了多人开发一中的情形,开发者 1 和开发者 2 在同一个分支开发。

拉取远程分支内容

使用如下命令拉取远程 feature-2 分支的内容:

git pull origin feature-2 

拉取到远程的 origin/feature-2 分支后,本地没有这个分支,所以需要创建并切换至 feature-2 分支。

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

文章配图

文章配图

此时,开发者 1 就能够在 feature-2 分支上继续开发

文章配图

3. 合并 feature-1 和 feature-2 至 master

现在就是又遇到了合并 feature-1 的问题,为了避免冲突 我们就还是再 feature-1 分支上来合并 master

文章配图

每次 feature-1 合并 master 之前 就要先保证 master 是最新的,所以要切换到 master 进行 pull 再用 master 进行合并 merge

文章配图

文章配图

当我们 merge master 的时候跳转到当前页面就说明没用任何问题,没用产生冲突,ctrl + x 就会退出该页面!

在这里插入图片描述

最后,开发者 1 和开发者 2 将各自的 feature-1 和 feature-2 分支合并到 master 分支上。

文章配图

文章配图

4. 删除远程分支

删除远程分支后,本地仍然可以看到已删除的远程分支。此时,可以使用以下命令移除远程已删除的分支记录:

文章配图

git remote prune origin 

目录

  1. 1. 初识 Git
  2. 1.1 Git 是什么?
  3. 1.2 为什么要有 Git
  4. 2. 安装 Git
  5. 2.1 Linux-Ubuntu 安装 Git
  6. 2.2 Windows 安装 Git
  7. 3. Git 初始化与配置
  8. 3.1 创建 Git 本地仓库
  9. 3.2 配置 Git
  10. 把 Your Name 改成你的用户名
  11. 把 [email protected] 改成你的邮箱的格式,只要格式正确即可
  12. 4. Git 工作流程 - 认识工作区、暂存区、版本库
  13. 5. Git 分支管理
  14. 6. Git 远程操作
  15. 创建远程仓库
  16. 将远程仓库克隆到本地
  17. 三板斧
  18. 给命令配置起别名
  19. 标签管理
  20. 推送标签
  21. 本地删除远程标签
  22. 7. 多人协作一
  23. 1. 开发者 1 创建一个分支 dev
  24. 2. 开发者 2 拉取远程仓库
  25. 3. 开发者 1 对远程仓库进行推送
  26. 4. 将内容合并至 master
  27. 4.1 提交 Pull Request
  28. 4.2 本地操作:
  29. 8. 多人协作二
  30. 1. 本地创建分支
  31. 开发者 1 操作
  32. 开发者 2 操作
  33. 2. 拉取远程的 feature-2 分支
  34. 拉取远程分支内容
  35. 3. 合并 feature-1 和 feature-2 至 master
  36. 4. 删除远程分支

更多推荐文章

查看全部
  • 深入解析 AI 大模型:概念、技术架构与产业现状
  • Java 数据结构实战:二叉树与哈希表详解
  • OpenAI 回击马斯克骚扰指控;微软清华提出 Diff Transformer
  • Java 面试核心知识点总结:Spring、MySQL、并发编程等
  • Vue 3 实战:10 个提升开发体验的核心技巧
  • GESP C++一级认证考点解析与备考策略
  • Rust 与 WebAssembly 实战:浏览器与 Node.js 高性能应用
  • 构建 Java 镜像的 10 个最佳实践
  • 2026 年毕业论文 AI 检测标准及各高校红线汇总
  • Reachy Mini:桌面机器人开源硬件设计与实现
  • Ubuntu 403 软件包下载错误解决方法
  • 如何成为一名职业黑客:核心技能与成长路径
  • Python 列表基础:创建、操作与切片详解
  • C++与Go匿名函数编程对比
  • 基于 Redis 与 Caffeine 的图片系统性能优化及分布式 Session 实践
  • 程序员职场进阶:除代码外需掌握的关键技能
  • 使用 Docker 部署 n8n 并启用 Python Native 节点
  • 提示词工程(Prompt Engineering)全面指南
  • Trae 集成 Vizro:低代码构建数据可视化仪表板
  • 算法设计与分析:贪心算法

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online