文章目录
- 一、前言
- [二、Git 的特点](#二、Git 的特点)
- [三、Git 的工作流程](#三、Git 的工作流程)
- 四、基本操作
- [五、Git 远程仓库](#五、Git 远程仓库)
- 六、常见面试题
一、前言
在真实的软件开发过程中,我们常常会面临以下挑战:
- 备份:代码随时可能因为误操作或硬件故障丢失,需要一个安全的远程存储点。
- 代码还原:新功能开发到一半发现方向错了,需要回退到之前某个稳定的版本。
- 协同开发:多人同时修改同一项目,如何有条不紊地合并各自的工作成果。
- 追溯问题:线上出了 Bug,需要快速定位是谁、在什么时间、出于什么目的修改了哪一行代码。
为了解决这些问题,版本控制系统(VCS, Version Control System) 应运而生。
目前常用的版本控制工具主要有 SVN(Subversion)、CVS 和 Git。
- 最早期的 CVS 和 SVN 都是集中式版本控制系统:所有代码托管在一个中央服务器,开发者本地只保留工作副本,每次提交、更新、查看历史都需要和中央服务器通信。此时中央服务器一旦宕机,整个团队都无法提交代码或回滚版本,如果服务器硬盘损坏且没有备份,项目历史将永久丢失。

Git 则是一种分布式版本控制系统。它没有"中央服务器"的概念------每个开发者本地都有一份完整的仓库镜像(包含完整的版本历史),可以在本地完成提交、回退、分支等日常操作,即使没有网络也能高效工作。当需要协作时,再通过推送和拉取与远程仓库同步。

二、Git 的特点
- 极致的速度:大部分操作在本地完成,无需网络请求,提交、分支切换等操作几乎瞬间响应。
- 简洁的设计:一切皆为数据对象,分支和标签的底层结构干净统一。
- 对非线性开发的强力支持:创建、合并、毁灭上千个分支也毫不费力,鼓励平行开发再合并的工作流。
- 完全分布式:每个参与者的本地机器上都保存着完整的代码库历史,不仅是生成当前版本所需的最新快照,而且在服务器无法访问时可以独立查阅任何历史版本的完整变更记录。
- 高效管理超大规模项目:Linux 内核拥有百万级提交记录和数千名贡献者,Git 依然能保持稳定的速度和合理的数据量
三、Git 的工作流程
工作区 (Working Directory) → 暂存区 (Staging Area) → 本地仓库 (Local Repository) → 远程仓库 (Remote Repository)

- clone(克隆):从远程仓库中克隆代码到本地仓库
- checkout(检出):从本地仓库中检出一个仓库分支然后进行修订
- add(添加):在提交前先将代码提交到暂存区
- commit(提交):提交到本地仓库。本地仓库中保存修改的各个历史版本
- fetch(抓取): 从远程库,抓取到本地仓库,不进行任何的合并动作,一般操作比较少。
- pull(拉取): 从远程库拉到本地库,自动进行合并(merge),然后放到到工作区,相当于fetch+merge
- push(推送): 修改完成后,需要和团队成员共享代码时,将代码推送到远程仓库
四、基本操作
1.获取本地仓库
在目标文件夹中打开 Git Bash,执行 git init 初始化当前目录为一个 Git 仓库。
初始化完成后,使用 ll 命令可以看到目录下多了一个隐藏的 .git 文件夹。这个文件夹就是 Git 的"资料库",记录着版本历史、暂存区、分支信息等所有元数据。

2.提交到本地仓库
Git 的文件流转遵循以下路径:

- git init:初始化本地仓库,即在当前目录创建 .git 文件夹
- git status:查看修改状态,即显示哪些文件被修改、哪些在暂存区
- git add 文件名|通配符:工作区 → 暂存区,可使用 git add . 添加所有文件
- git commit -m "注释" :暂存区 → 本地仓库 为本次提交添加描述信息
- git log [option] :查看提交日志 显示历史版本信息,option的取值如下
- --all 显示所有分支
- --pretty=oneline 将提交信息显示为一行
- --abbrev-commit 使得输出的commitId更简短
- --graph 以图的形式显示
- git reset --hard <commitID>:版本回退到commitID
- git reflog:查看所有操作记录 可以看到已被 git log 忽略的"已删除"提交记录
操作示例
① 创建新文件并提交:在工作目录下创建 file01.txt,此时执行 git status,会看到该文件处于 Untracked(未跟踪) 状态

② 添加到暂存区并提交:git add . 将所有修改加入暂存区,git commit -m "add file01" 将文件提交到本地仓库


③ 查看提交日志:git log 查看提交日志,每一行 commit 的第二行 Author 记录着该次提交的作者;第三行 Date 记录着提交的具体时间。

④ 修改文件后再次提交:
使用 vi file01.txt 编辑文件内容后,再执行 git add . 和 git commit -m "update file01",日志中便会多出第二条提交

⑤ 版本回退:git reset --hard commitID 回退版本,hard 模式表示工作区、暂存区、仓库全部回退。

⑥ 找回"已删除"的提交:git reflog 指令查看所有 HEAD 移动记录,包括已被 reset 去除的提交,然后再次使用 git reset --hard <commitID> 即可恢复(这里删除的commitID为 edd9996)

3. 忽略文件列表
某些文件无需纳入 Git 管理,比如日志、临时文件、编译产物等。在项目根目录创建 .gitignore 文件,将想忽略的文件名或模式写入即可。例如:
.gitignore
*.log
*.class
target/
.idea/
常见模式规则如下,
| 模式 | 说明 | 示例 |
|---|---|---|
| *.后缀 | 忽略所有以指定后缀结尾的文件 | *.log 忽略所有日志文件 |
| 目录名/ | 忽略整个目录及其下所有内容 | target/ 忽略 Maven 编译输出目录 |
| 文件名 | 忽略特定文件 | secret.txt 忽略根目录下的 secret.txt |
| * | 通配任意多个字符(包括 0 个) | *.tmp 匹配 a.tmp、b.tmp |
| ? | 通配单个字符 | temp?.txt 匹配 temp1.txt、tempa.txt |
| /**/ | 匹配任意中间路径 | logs/**/*.log 忽略 logs/ 目录下所有子目录中的 .log 文件 |
| ! | 取反,重新包含之前被忽略的文件 | !important.log 让 important.log 不被忽略 |
4.分支管理
每个人在自己的分支上独立开发,完成后再合并到主干,互不干扰。此时需要用到分支管理。
常见的基本命令如下:
- git branch:查看本地分支
- git branch 分支名:创建本地分支
- git checkout 分支名:切换到指定分支
- git checkout -b 分支名:创建并切换到该分支
- git merge 分支名:将指定分支合并到当前分支
- git branch -d 分支名:删除分支(需检查是否已合并)
- git branch -D 分支名:强制删除分支(不做任何检查)
操作示例
① 创建分支并查看:git branch dev01表示创建 dev01 分支并查看

②提交后查看分支信息:git commit -m 'add ignore file'进行提交后查看信息如下,此时是在master分支上进行的提交。

③切换分支:git checkout dev01命令切换到dev01分支,git checkout -b dev02 命令创建并切换到该分支


④合并分支:在dev01分支下创建file02.txt并提交到仓库,此时输出的结果如下。此时需要将分支合并回 master。需要先git checkout master切换到master分支,再git merge dev01将dev01分支合并到master。

git branch -d dev02对dev02分支删除后方便观察 合并后的结果

(1)合并冲突
两个分支修改了同一个文件的同一行 ,Git 无法判断以哪个版本为准,会标记出冲突区域并暂停合并,等待开发者手动处理。
如下例所示,
①创建新分支并进行修改:创建并切换到 dev 新分支,修改file01.txt第一行为" update count=2 ",查看内容如下(为方便观察已经删除dev01)

② 此时再切换到master分支,修改file01中的值为" update count=3 ",修改后进行提交,此时显示信息如下,此时master分支上为count-3,dev分支上为count-2。

② 在 master 上执行 git merge dev,Git 会提示冲突

③此时的file01.txt文件如下。====之前表示当前分支做的修改,后面表示另一个分支上改成2.这个时候需要手动更改到底需要哪一个版本的文件,(此时手动修改为update count=4)
txt
<<<<<<< HEAD
update count=3 ← 当前分支 (master) 的修改
=======
update count=2 ← 被合并分支 (dev) 的修改
>>>>>>> dev
④保存文件 → git add . → git commit -m "resolve conflict",冲突解决

(2)开发中的常用分支
企业项目通常采用以下分支管理模型

- master (生产) 分支:线上分支,主分支,中小规模项目作为线上运行的应用对应的分支
- develop(开发)分支:是从master创建的分支,一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线要求,都可以在此版本进行开发,阶段开发完成后,需要是合并到master分支,准备上线。
- feature/xxxx分支:从develop创建的分支,一般是同期并行开发,但不同期上线时创建的分支,分支上的研发任务完成后合并到develop分支。
- hotfix/xxxx分支:从master派生的分支,一般作为线上bug修复使用,修复完成后需要合并到master、test、develop分支。
- 其他分支,例如test分支(用于代码测试)、pre分支(预上线分支)等
五、Git 远程仓库
Gitee(码云)是常用的国内代码托管平台,这里以 Gitee 为例。
1.配置SSH公钥
为了让本地 Git 安全地与 Gitee 通信,需要配置 SSH 密钥。
首先运行 ssh-keygen -t rsa 命令生成 SSH 密钥对(一路回车即可),然后 cat ~/.ssh/id_rsa.pub 命令查看生成的公钥内容。将输出的公钥内容复制到 Gitee → 设置 → SSH 公钥中保存。

ssh -T git@gitee.com 命令查看是否配置成功
2.操作远程仓库
首先添加远程仓库,添加命令如下,例如git remote add origin git@gitee.com:czbk_zhang_meng/git_test.git(远端名称默认叫 origin)
git
git remote add <远端名称> <仓库路径>
- 远端名称,默认是origin,取决于远端服务器设置
- 仓库路径,从远端服务器获取此URL
可以使用 git remote 命令查看已关联的远程仓库
推送代码到远程仓库的命令如下,例如git push origin master 表示推送到origin的master分支下
git
git push [-f] [--set-upstream] [远端名称] [本地分支名[:远端分支名]]
- -f 表示强制覆盖
- --set-upstream 推送到远端的同时并且建立起和远端分支的关联关系。git push --set-upstream origin master:master表示将本地master绑定到远程仓库的master分支。
如果当前分支已经和远端分支关联,则可以省略分支名和远端名。直接 git push 将master分支推送到已关联的远端分支。
3.本地分支与远程分支的关联关系
查看关联关系可以使用 git branch -vv 命令

git push --set-upstream origin master:master 表示将本地的 master 分支绑定到远程的 master 分支。下一次直接执行 git push,Git 就知道要推送到 origin 的 master 分支。
4.从远程仓库克隆
如果已经有一个远端仓库,可以直接clone到本地。命令如下,例如git clone git@gitee.com:username/repository.git
git
git clone <仓库路径> [本地目录]
- 本地目录名可省略,Git 会自动创建与仓库同名的目录。git clone 会自动将远程仓库命名为 origin,并新建一个与远程默认分支同名的本地分支。
5.从远程仓库中抓取和拉取
远程仓库的更新不会自动同步到本地,需要手动拉取。这涉及两个命令:
- git fetch:**将远程的更新下载到本地仓库,但不会合并到工作区。**适合先看看别人推送了什么,再决定是否合并。
git pull:git fetch + git merge 的合体,直接把远程更新拉下来并合并到当前分支。
合并冲突
当 A、B 两个用户修改了同一个文件的同一行,且推送时间有先后时,后推送的用户会先经历远程冲突:Git 会拒绝推送,并提示先拉取。B 用户执行 git pull 拉取最新代码后,Git 将自动尝试合并,一旦发现冲突,会在文件中标记出双方修改的差异,B 用户需手动解决、重新提交、再推送。如下图所示,

解决方式与本地分支冲突完全一致:手动编辑冲突文件 → git add . → git commit → git push。
六、常见面试题
1.git pull 和 git fetch 有什么区别?
- git fetch 是把远程仓库的最新提交下载到本地仓库,但不合并到工作区。它只是"看一看",让你先了解远端有哪些更新再做决定。
- git pull 是 git fetch + git merge 的组合操作------直接拉取远端最新代码并自动合并到当前工作分支。
2.git merge 和 git rebase 有什么区别?
- git merge 保留分支历史原貌,产生一个新的"合并提交"(merge commit),非线性但真实完整。
- git rebase 将当前分支的修改"移植"到目标分支的末尾,提交历史会变成一条直线,更整洁,但可能产生冲突需要逐个解决。适合个人分支整理,避免在公共分支上使用。
3.什么是 Git flow?master 和 develop 分支的作用是什么?
- Git flow 是一种经典的 Git 分支管理策略,定义了多个固定角色分支:
- master:随时可部署到生产环境,通常打上 tag 标记版本号。
- develop:日常开发的集成分支,所有功能都在此分支上合并。
- feature/xxx:功能分支,从 develop 分出,完成后合并回去并删除。
- hotfix/xxx:紧急修复分支,从 master 分出,修复后合并回 master 和 develop。
4.如何解决 Git 合并冲突?
- 冲突发生时,Git 会在文件中用 <<<<<<<、=======、>>>>>>> 标记双方修改的内容。开发者需手动决定采用哪个版本(或合并两者),删除标记符号 → git add → git commit 即可完成解决。
5.git reset 和 git revert 有什么区别?
- git reset 是"回退"到某个历史版本,后面的提交会被移除(不可恢复,除非用 reflog)。
- git revert 是"撤销"某次提交,但通过创建一个新的"反向提交"来抵消目标提交的修改,历史完整性不受影响。线上分支推荐用 revert,本地分支用 reset。