版本控制

什么是版本控制

版本控制(Version Control)是一种记录文件内容变化,以便将来查阅特定版本修订情况的系统。它可以帮助我们:

  • 追踪文件的修改历史,查看谁在何时做了什么更改

  • 恢复到之前的版本,当出现错误时可以快速回滚

  • 多人协作时管理代码,避免文件冲突和覆盖

  • 并行开发不同功能,最后再合并到一起

简单来说,版本控制就像给你的项目创建了一系列"快照",你可以随时回到过去的任何一个状态。

版本控制系统的类型

1.本地版本控制系统

  • 在本地磁盘上保存文件的不同版本

  • 例如:RCS(通过补丁集记录文件差异)

2.集中式版本控制系统

  • 所有版本数据存储在中央服务器

  • 开发者从中央服务器拉取代码,完成后再推回

  • 例如:SVN、CVS

  • 缺点:中央服务器故障时无法协作,数据有丢失风险

3.分布式版本控制系统

  • 每个开发者的本地都有完整的版本库副本

  • 无需联网即可提交、查看历史

  • 拥有更强的分支管理能力

  • 例如:Git、Mercurial、Bazaar

  • 优势:容错性高,协作灵活,支持离线工作

版本控制系统区别

对比维度

本地版本控制 (Local VCS)

集中式版本控制 (CVCS)

分布式版本控制 (DVCS)

代表工具

RCS, SCCS

SVN, CVS, Perforce

Git, Mercurial, Bazaar

核心架构

单机单库:版本数据库仅存在于本地单台机器上。

单点中心:所有版本数据集中存储在中央服务器,客户端仅检出当前版本。

多节点全量:每个客户端都拥有完整的版本历史仓库,无强制中心节点。

网络依赖

完全离线:无需网络,纯本地文件操作。

强依赖网络:提交、查看历史、分支等操作均需连接中央服务器。

离线可用:提交、查看历史、创建分支等均在本地完成,仅推送/拉取需网络。

容灾与安全性

极高风险:硬盘损坏即丢失所有版本历史,无备份机制。

单点故障:中央服务器宕机或损坏会导致全员停工;需额外备份策略。

天然高可用:任一客户端的完整克隆均可作为恢复源,无单点故障风险。

分支与合并

极其困难:通常不支持或仅支持简单的文件级复制,合并需手动处理。

支持但较重:支持分支,但创建和切换分支涉及服务器IO,合并冲突解决较繁琐。

轻量且高效:分支仅是轻量级指针,创建/切换/合并均在本地瞬间完成,鼓励频繁分支。

性能表现

极快:仅读取本地文件,无网络开销。

受网络限制:操作延迟取决于网络带宽和服务器负载;大仓库检出极慢。

本地极速:绝大多数操作在本地磁盘完成,仅网络同步受带宽影响。

协作模式

无法协作:仅适用于单人开发或简单的文件归档。

中心化协作:所有人向同一服务器提交,权限控制集中在服务器端。

去中心化协作:支持点对点推送、多远程仓库、工作流灵活(如 Fork/Pull Request)。

典型适用场景

个人脚本备份、遗留系统维护、无需协作的单机环境。

传统企业内网开发、强权限管控需求、硬件/固件开发(大二进制文件)。

现代软件开发、开源项目、微服务架构、跨地域团队协作。

Git了解

什么是Git

Git是目前最流行的分布式版本控制系统,设计目标是:

  • 速度快

  • 支持非线性开发(强大的分支能力)

  • 完全分布式

  • 能高效处理大型项目(如Linux内核)

Git与其他版本控制系统的主要区别在于:它对待数据的方式更像是一个"快照流",而不是文件变化的列表。每次提交,Git都会对当时的全部文件创建一个快照并保存引用,而不是只记录差异。

对比维度

传统增量流 (如 SVN)

Git 快照流

记录方式

记录每次提交与上一次提交的差异(Diff)

记录每次提交时整个项目的完整状态(Snapshot)

回退操作

需要逆向应用差异(Rollback),容易出错

直接切换到目标快照的指针(Reset/Checkout),瞬间完成

分支操作

复制整个目录或应用复杂差异,耗时较长

仅创建一个指向特定快照的轻量级指针,瞬间完成

存储效率

依赖差异计算,大文件频繁修改时体积膨胀快

底层基于 SHA-1 哈希去重,未修改的文件零冗余

Git核心概念

1.工作区(Working Directory)

  • 你当前正在编辑的文件目录

  • 这些文件可能处于未跟踪或已修改状态

2.暂存区(Staging Area)

  • 一个文件(通常位于.git/index),用于临时保存你打算提交的修改

  • 可以理解为待提交内容的缓冲区

3.本地仓库(Local Repository)

  • 存储所有版本历史的数据库

  • 位于工作区的.git目录中

  • 包含所有提交记录、分支信息等

4.远程仓库(Remote Repository)

  • 托管在网络上的仓库(如GitHub、GitLab)

  • 用于多人协作时同步代码

5.提交(Commit)

  • 对工作区修改的一次永久记录

  • 每个提交都有一个唯一的哈希值作为标识

6.分支(Branch)

  • 指向某个提交的指针

  • 默认分支通常名为main或master

  • 可以创建多个分支并行开发不同功能

工作流程

1.修改文件:在工作区编辑文件

2.暂存修改:将需要提交的修改添加到暂存区(git add

3.提交修改:将暂存区的内容提交到本地仓库(git commit

4.同步远程:将本地仓库的修改推送到远程仓库(git push),或从远程拉取他人的修改(git pull

Git优点

  1. 性能卓越:Git的所有操作几乎都是本地执行,速度极快

  2. 强大的分支管理:创建和合并分支非常高效,支持复杂的工作流

  3. 分布式架构:每个开发者都有完整副本,不怕数据丢失

  4. 广泛采用:几乎成为行业标准,大量开源项目和企业使用

  5. 丰富的生态:有GitHub、GitLab等平台提供托管服务,以及众多工具支持

Git工作流

  1. 集中式工作流:类似SVN,所有人在同一个分支上工作

  2. 功能分支工作流:每个功能在单独分支开发,完成后合并到主分支

  3. GitFlow工作流:有严格的分支模型,区分功能开发、发布准备和bug修复

  4. Forking工作流:适合开源项目,通过Fork和Pull Request协作

对比维度

集中式工作流 (Centralized)

功能分支工作流 (Feature Branch)

Gitflow 工作流

Forking 工作流 (Forking)

核心思想

类似 SVN 模式,所有人共用一个主分支(main/master),直接在主干上提交。

围绕主分支,为每个新功能、Bug修复创建独立的短期分支,完成后合并回主分支。

严格区分主分支(main)、开发分支(develop)、功能分支、发布分支和热修复分支。

每个开发者 Fork 一份完整的独立仓库,在自己的仓库提交后,向原仓库发起 Pull Request。

分支模型

main 分支。

main + 多个 feature/* 分支。

main + develop + feature/* + release/* + hotfix/*

上游 main + 个人 Fork 仓库的 main + 个人功能分支。

协作模式

强中心化,开发者直接推送到中央仓库。

团队共享中央仓库,通过功能分支隔离开发,合并前进行代码审查(Code Review)。

团队共享中央仓库,通过多层分支严格控制代码流转和发布周期。

去中心化,开发者向自己的仓库推送,通过 PR 机制请求合并到上游中央仓库。

权限与安全

较低。容易误推代码破坏主干,依赖开发者自觉。

较高。主分支受保护,必须通过合并请求(MR/PR)合入,支持代码审查。

极高。严格的分支保护,发布和热修复都有专属流程,适合强合规要求。

最高。中央仓库完全只读,只有维护者有合并权限,杜绝了误操作。

适用场景

极小团队(1-2人)、个人项目、或从 SVN 迁移的过渡期。

中小型团队、敏捷开发、绝大多数现代互联网项目(最推荐)。

具有明确版本发布周期、需要严格测试和发版流程的中大型传统企业项目。

大型开源项目、跨公司/跨团队协作、对安全性要求极高的闭源核心项目。

优缺点

:极简,零学习成本。 :极易冲突,历史混乱,无容错空间。

:主干始终稳定,并行开发互不干扰,易于回滚。:分支过多时需注意清理。

:流程规范,发布路径清晰,历史极其整洁。 :过于繁琐,分支多,不适合持续交付(CI/CD)。

:绝对安全,贡献者无需上游仓库权限。 :同步上游代码较繁琐,维护成本高。

Git常用命令

一、基础配置(首次使用必做)

Git 首次安装后需配置用户信息(关联提交记录),可通过 --global 配置全局(所有仓库生效),或不加该参数配置当前仓库。

命令

说明

git config --global user.name "用户名"

配置全局用户名(与 GitHub/GitLab 账号一致)

git config --global user.email "邮箱"

配置全局邮箱(与远程仓库账号绑定)

git config --list

查看当前 Git 配置(全局+当前仓库)

git config user.name

查看当前生效的用户名

git config --global core.editor "编辑器"

配置默认提交编辑器(如 VS Code

二、仓库操作(初始化/克隆/查看状态)

包括本地仓库初始化、从远程克隆仓库,以及查看仓库文件状态。

1. 初始化与克隆

命令

说明

例子

git init

在当前目录初始化本地 Git 仓库(生成 .git 隐藏目录)

cd /home/zhangsan/my-project # 进入项目目录 git init # 初始化仓库

git clone <远程仓库地址>

从远程仓库克隆到本地(自动创建仓库目录)

git clone https://github.com/vuejs/vue.git 克隆一个名为 vue 的仓库

git clone <远程地址> <自定义目录名>

克隆时指定本地目录名

git clone https://github.com/vuejs/vue.git my-vue-project 将远程仓库克隆到 my-vue-project 目录

2. 查看仓库状态

命令

说明

git status

查看当前工作区/暂存区文件状态

git log

查看提交历史(详细格式)

git log --oneline

简化提交历史(仅哈希前7位+提交信息)

git log --graph

以图形化显示分支合并历史

三、分支管理(核心操作)

Git 分支是并行开发的核心,常用命令包括创建、切换、合并、删除分支等。

命令

说明

git branch

查看本地所有分支(* 标记当前分支)

git branch -r

查看远程所有分支

git branch -a

查看本地+远程所有分支

git branch <分支名>

创建新分支(基于当前分支)

git checkout <分支名>

切换到指定分支

git checkout -b <分支名>

创建并立即切换到新分支

git merge <分支名>

将指定分支合并到当前分支

git branch -d <分支名>

删除已合并的本地分支

git branch -D <分支名>

强制删除未合并的本地分支

git push origin --delete <分支名>

删除远程分支

四、提交与撤销(代码暂存/提交/回滚)

代码从“工作区”到“暂存区”再到“本地仓库”的流程,以及错误操作后的撤销方法。

1. 暂存与提交

命令

说明

git add <文件名>

将指定文件从工作区添加到暂存区

git add .

将当前目录所有修改/新增文件添加到暂存区

git add -p

交互式暂存(按块选择文件内容)

git commit -m "提交信息"

将暂存区内容提交到本地仓库

git commit -am "提交信息"

跳过暂存区,直接提交已跟踪文件的修改

git commit --amend

补充提交(合并到上一次提交,修改提交信息)

交互式暂存:按“代码块”选择文件内容进行暂存,适合只提交文件中部分修改的场景(如同一文件修改了两个功能,只想提交其中一个)。执行后会逐块显示修改内容,按提示操作:

  • y:暂存当前块

  • n:跳过当前块

  • q:退出交互

补充提交 若上一次提交遗漏了文件或需修改提交信息:

git add 遗漏的文件.js # 先暂存遗漏的文件 git commit --amend # 合并到上一次提交

2. 撤销操作

命令

说明

git restore <文件名>

撤销工作区修改(未暂存的文件)【修改会丢失,执行前确定一下是否保留】

git restore --staged <文件名>

将暂存区文件撤回工作区【取消暂存保留修改】

git reset --soft <提交哈希>

回滚到指定提交(保留暂存区和工作区)

git reset --mixed <提交哈希>

回滚到指定提交(清空暂存区,保留工作区)

git reset --hard <提交哈希>

强制回滚(清空暂存区+删除工作区修改)

git revert <提交哈希>

生成撤销提交(保留原历史,适合已推送的代码)

四种回滚的区别

类型

本地库

暂存区

工作区

适用场景

Soft

回退

保留

保留

撤销提交,重新修改或合并提交

Mixed (默认)

回退

清空

保留

撤销提交,重新修改后再 add

Hard

回退

清空

清空

彻底丢弃当前修改,一键恢复

Keep

回退

保留

保留未冲突部分

回退但保留本地未提交的改动

⚠️ 核心避坑:代码已推送到远程时,禁用 reset,改用 git revert(生成新提交来抵消旧修改)。

五、远程协作(与远程仓库交互)

团队协作中,需与 GitHub/GitLab 等远程仓库同步代码(拉取/推送/关联)。

命令

说明

git remote

查看已关联的远程仓库列表

git remote -v

查看远程仓库的详细地址

git remote add <远程名> <远程地址>

关联远程仓库

git pull

拉取远程分支代码并合并到本地当前分支

git pull <远程名> <远程分支>:<本地分支>

拉取指定远程分支到本地指定分支

git push

推送本地当前分支到远程对应分支(首次需 -u 绑定)

git push <远程名> <本地分支>:<远程分支>

推送本地分支到远程指定分支

git fetch

拉取远程仓库信息(不合并,仅更新本地跟踪分支)

git remote set-url <远程名> <新地址>

修改远程仓库地址

常用命令实例

git status/git status -s

查看状态

 # 查看状态
 [root@zuolaoshi git_data]# git status
 位于分支 master
 尚无提交
 无文件要提交(创建/拷贝文件并使用 "git add" 建立跟踪)
 ​
 # 创建三个空文件分别命名为a b c
 [root@zuolaoshi git_data]# touch a b c
 ​
 # 查看是否有这三个文件
 [root@zuolaoshi git_data]# ls
 a  b  c
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚无提交
 未跟踪的文件:
   (使用 "git add <文件>..." 以包含要提交的内容)
     a
     b
     c
 提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪) 

git add

暂存内容

 # 将当前工作目录下的所有更改一次性全部添加到暂存区
 [root@zuolaoshi git_data]# git add a
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚无提交
 要提交的变更:
   (使用 "git rm --cached <文件>..." 以取消暂存)
     新文件:   a
 未跟踪的文件:
   (使用 "git add <文件>..." 以包含要提交的内容)
     b
     c
  
 # 查看当前目录下 .git 文件夹内部的内容
 [root@zuolaoshi git_data]# ll .git/
 总用量 16
 drwxr-xr-x 2 root root   6 4月   3 05:34 branches
 -rw-r--r-- 1 root root  92 4月   3 05:34 config
 -rw-r--r-- 1 root root  73 4月   3 05:34 description
 -rw-r--r-- 1 root root  23 4月   3 05:34 HEAD
 drwxr-xr-x 2 root root 301 4月   3 05:34 hooks
 -rw-r--r-- 1 root root  96 4月   5 06:05 index
 # 你会发现index的时间产生了变化,这意味着,我们使用git add命令将文件提交到了暂存区域
 drwxr-xr-x 2 root root  21 4月   3 05:34 info
 drwxr-xr-x 5 root root  40 4月   5 06:05 objects
 # Git 会把 a、b、c 这三个文件的内容压缩打包,变成一个个“对象(Objects)”存入 .git/objects 文件夹中,并生成一个哈希值(Hash)来作为它们的唯一身份标识
 drwxr-xr-x 4 root root  31 4月   3 05:34 refs
 ​
 # 查看 Git 仓库的底层数据库(对象库)中实际存储了哪些数据
 [root@zuolaoshi git_data]# ll .git/objects/
 总用量 0
 drwxr-xr-x 2 root root 52 4月   5 06:05 e6
 drwxr-xr-x 2 root root  6 4月   3 05:34 info
 drwxr-xr-x 2 root root  6 4月   3 05:34 pack
 ​
 # 查看e6 这个文件夹里面的东西
 [root@zuolaoshi objects]# ls e6
 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
 # 上边这个乱码本质上是一个哈希值,但在文件系统里,Git 把它当成了文件名来用
 ​
 [root@zuolaoshi objects]# cat e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 
 # 在objects目录中可以看到已元数据形式存储的a文件,这个我们看不懂,我们可以将数据都添加
 ​
 # 将当前目录及所有子目录下的所有更改,一次性添加到暂存区
 [root@zuolaoshi git_data]# git add .  #可以使用.也可以使用*
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status
 位于分支 master
 尚无提交
 要提交的变更:
   (使用 "git rm --cached <文件>..." 以取消暂存)
     新文件:   a
     新文件:   b
     新文件:   c

git rm

将文件从暂存区撤回到工作区(变成未跟踪的)、然后再删除文件;也可以直接从暂存区删除

 # 将文件 c 从 Git 的暂存区(版本控制)中移除,但保留你电脑本地硬盘上的这个文件
 [root@zuolaoshi git_data]# git rm --cached c
 rm 'c'
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚无提交
 要提交的变更:
   (使用 "git rm --cached <文件>..." 以取消暂存)
     新文件:   a
     新文件:   b
 未跟踪的文件:
   (使用 "git add <文件>..." 以包含要提交的内容)
     c
     
 # 强制删除c文件
 [root@zuolaoshi git_data]# rm -fr c
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚无提交
 要提交的变更:
   (使用 "git rm --cached <文件>..." 以取消暂存)
     新文件:   a
     新文件:   b
     
 # 将文件 b 从 Git 的暂存区(版本控制)中移除,同时把你电脑本地硬盘上的文件 b 也彻底删除
 [root@zuolaoshi git_data]# git rm -f b
 rm 'b'
 ​
 # 查看状态 是否删除成功
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚无提交
 要提交的变更:
   (使用 "git rm --cached <文件>..." 以取消暂存)
     新文件:   a
     
 # 将暂存区中所有准备好的更改(比如你之前添加的文件 a)正式提交到本地 Git 仓库中,并附带一条提交说明
 [root@zuolaoshi git_data]# git commit -m " new a"  
 # 成功后显示
 [master(根提交) 6ac34be] a
  1 file changed, 0 insertions(+), 0 deletions(-)
  create mode 100644 a
  
  
 # 查看提交后的状态
 [root@zuolaoshi git_data]# git status
 位于分支 master
 无文件要提交,干净的工作区

git mv

将暂存区里的数据改名或移动

 1.使用mv命令配合git
 # 将文件 a 重命名为 a.txt
 [root@zuolaoshi git_data]# mv a a.txt
 ​
 # 查看是否修改成功
 [root@zuolaoshi git_data]# git status
 位于分支 master
 尚未暂存以备提交的变更:
   (使用 "git add/rm <文件>..." 更新要提交的内容)
   (使用 "git checkout -- <文件>..." 丢弃工作区的改动)
 ​
     删除:     a
 ​
 未跟踪的文件:
   (使用 "git add <文件>..." 以包含要提交的内容)
 ​
     a.txt
 ​
 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
 ​
 # 从暂存区删除a 【但是还有这个文件】
 [root@zuolaoshi git_data]# git rm --cached a    
 rm 'a'
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 要提交的变更:
   (使用 "git reset HEAD <文件>..." 以取消暂存)
 ​
     删除:     a
 ​
 未跟踪的文件:
   (使用 "git add <文件>..." 以包含要提交的内容)
 ​
     a.txt
 ​
 ​
 # 将新文件 a.txt 添加到 Git 的暂存区(Staging Area),准备在下一次提交时将其纳入版本控制
 [root@zuolaoshi git_data]# git add a.txt
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status
 位于分支 master
 要提交的变更:
   (使用 "git reset HEAD <文件>..." 以取消暂存)
 ​
     重命名:   a -> a.txt   ########识别到a和a.txt是重命名的文件
     
 # 将刚才在暂存区准备好的“重命名操作”正式、永久地保存到本地 Git 仓库中
 [root@zuolaoshi git_data]# git commit -m "rename a to a.txt"
 # 提交后显示
 [master 47a267c] a.txt
  1 file changed, 0 insertions(+), 0 deletions(-)
  rename a => a.txt (100%)
 ​
 ​
 2.使用git mv直接重命名
 # 将文件 a.txt 重命名回 a,并且自动将这次重命名操作加入暂存区
 [root@zuolaoshi git_data]# git mv a.txt a   
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status
 位于分支 master
 要提交的变更:
   (使用 "git reset HEAD <文件>..." 以取消暂存)
 ​
     重命名:   a.txt -> a
 ​
 # 将刚才使用 git mv 准备好的“重命名操作”正式、永久地保存到本地 Git 仓库中
 [root@zuolaoshi git_data]# git commit -m "rename a.txt to a"
 # 提交后显示
 [master a714e37] a
  1 file changed, 0 insertions(+), 0 deletions(-)
  rename a.txt => a (100%)

git diff

git status 只能查看区域状态的不同 ,不能查看文件内容的变化。

git diff 查看内容的不同

 # 查看文件差异
 [root@zuolaoshi git_data]# git diff #没有变化时不显示内容
 ​
 # 修改a文件
 [root@zuolaoshi git_data]# vim a
 hello
 abc
 ​
 # 将文件 a 当前的修改状态添加到 Git 的暂存区
 [root@zuolaoshi git_data]# git add a
 ​
 # 修改文件a
 [root@zuolaoshi git_data]# vim a
 hello
 test
 test1
 ​
 # 调整完成文件后,对比本地工作目录和暂存区文件的差异【主要看自己改了那些 决定是否加入暂存区】
 [root@zuolaoshi git_data]# git diff a   
 diff --git a/a b/a
 # git格式的diff命令,进行比较的是a版本的a文件和b版本的a文件
 index e69de29..ce01362 100644
 # 两个版本的哈希值,100644表示是对象是普通文件,权限是644
 --- a/a         #---表示变动前,也就是a版本的a文件
 +++ b/a         #+++表示变动后,也就是b版本的a文件
 @@ -1,2 +1,3 @@ ## 以@符号开始和结束“-1,2”表示前一个文件从第一行开始的连续两行;“+1,3”表示后一个文件的从第一行开始连续的3行(-表示前一个文件,+表示后一个文件)
 hello           
 -abc            #-表示去掉的内容
 +test
 +test1      #+表示新增的内容
 ​
 # 对比暂存区和最新一次提交的差异
 [root@zuolaoshi git_data]# git diff --cached a  
 diff --git a/a b/a
 index e69de29..0e3af97 100644
 --- a/a
 +++ b/a
 @@ -0,0 +1,2 @@
 +hello
 +abc

git commit -m

将暂存区内容提交到本地仓库-m后面是描述信息

 # 将a文件的最新修改提交到本地Git仓库中并标记为第二个版本
 [root@zuolaoshi git_data]# git commit -m "version2 a"
 # 显示如下
 [master 8f01c62] version2 a
  1 file changed, 2 insertions(+)
  
 # 查看文件 a 在“暂存区”与“最新一次提交”之间的差异
 [root@zuolaoshi git_data]# git diff --cached a
 ​
 # 打开一个文本编辑器,让你编写详细的提交信息
 git commit 
 # 相当于虚拟机的镜像、任何操作都被做了一次快照 ,可恢复到任意一个位置

git commit -am

快速提交到本地仓库

 # 查看当前文件内容
 [root@zuolaoshi git_data]# cat a
 haha
 ​
 # 确认一下工作区是否有文件
 [root@zuolaoshi git_data]# git diff
 ​
 # 追加内容到a文件
 [root@zuolaoshi git_data]# echo hello >> a
 ​
 # 查看差异报告【前面的加号表示新增】
 [root@zuolaoshi git_data]# git diff
 diff --git a/a b/a
 index 5ad28e2..5c06d49 100644
 --- a/a
 +++ b/a
 @@ -1 +1,2 @@
  haha
 +hello
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚未暂存以备提交的变更:
   (使用 "git add <文件>..." 更新要提交的内容)
   (使用 "git checkout -- <文件>..." 丢弃工作区的改动)
 ​
     修改:     a
 ​
 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
 ​
 # 将a文件放入暂存区
 [root@zuolaoshi git_data]# git add a
 ​
 # 提交到本地仓库
 [root@zuolaoshi git_data]# git commit -m "add hello"
 # 提交后显示
 [master 2add75e] add hello
  1 file changed, 1 insertion(+)
  
 # 确认工作区是否有文件
 [root@zuolaoshi git_data]# git diff
 ​
 # 在a文件中添加haha
 [root@zuolaoshi git_data]# echo haha >> a
 ​
 # 将文件 a 的最新修改自动加入暂存区,并直接提交到本地仓库
 [root@zuolaoshi git_data]# git commit -am "add haha"
 # 也可以使用-am直接提交到仓库,相当于先git add再git commit -m,但必须是跟踪状态的文件,参数a必须在m前面,否则会报错,无法提交。
 # 提交后显示
 [master f3d6391] add haha
  1 file changed, 1 insertion(+)
  
 # 查看工作区状态
 [root@zuolaoshi git_data]# git diff
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 无文件要提交,干净的工作区
 ​
 # 查看提交历史
 [root@zuolaoshi git_data]# git log --oneline 
 f3d6391 (HEAD -> master) add haha
 2add75e add hello

git checkout –

检出,重写工作区数据

 # 在a文件中添加haha
 [root@zuolaoshi git_data]# echo haha >> a
 ​
 # 查看a文件的内容
 [root@zuolaoshi git_data]# cat a
 hello
 test
 test1
 123
 haha
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 尚未暂存以备提交的变更:
   (使用 "git add <文件>..." 更新要提交的内容)
   (使用 "git checkout -- <文件>..." 丢弃工作区的改动)
 ​
     修改:     a
 ​
 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
 ​
 # 将文件 a 恢复到暂存区(或最新一次提交)的状态,直接丢弃你在本地工作区对它做的所有修改
 [root@zuolaoshi git_data]# git  checkout -- a
 ​
 # 查看状态
 [root@zuolaoshi git_data]# git status 
 位于分支 master
 无文件要提交,干净的工作区
 ​
 # 查看文件
 [root@zuolaoshi git_data]# cat a
 hello
 test
 test1
 123

git reset HEAD

本地仓库覆盖暂存区域

 # 将a的内容清空
 [root@zuolaoshi git_data]# echo "" > a 
 ​
 # 提交到暂存区
 [root@zuolaoshi git_data]# git add a   
 ​
 # 提交到仓库
 [root@zuolaoshi git_data]# git commit -m "test head"   
 提交后显示
 [master dd7925f] test head
  1 file changed, 1 insertion(+), 1 deletion(-)
  
 # 添加内容到a
 [root@zuolaoshi git_data]# echo haha > a 
 ​
 # 提交到暂存区
 [root@zuolaoshi git_data]# git add a  
 ​
 # 确认没有差异
 [root@zuolaoshi git_data]# git diff a 
 ​
 # 用本地仓库的数据将暂存区数据覆盖
 [root@zuolaoshi git_data]# git reset HEAD a
 重置后取消暂存的变更:
 M   a
 ​
 # 比较工作区和暂存区的数据差异
 [root@zuolaoshi git_data]# git diff a  
 diff --git a/a b/a
 index 8b13789..5ad28e2 100644
 --- a/a
 +++ b/a
 @@ -1 +1 @@
 -
 +haha

git reset --hard 哈希头名

Git服务程序中有一个叫做HEAD的版本指针,当用户申请还原数据时,其实就是将HEAD指针指向到某个特定的提交版本,但是因为Git是分布式版本控制系统,为了避免历史记录冲突,故使用了SHA‐1计算出十六进制的哈希字串来区分每个提交版本,另外默认的HEAD版本指针会指向到最近的一次提交版本记录,,注意恢复版本后代表的是在这个版本之前的内容全在(包括工作目录和暂存),本版本之后的都没了

 # 以极其简洁的“单行格式”查看 Git 提交历史记录
 [root@zuolaoshi git_data]# git log --oneline 
 f3d6391 (HEAD -> master) add haha
 2add75e add hello
 ff77333 aaa
 dd7925f test head
 e2e2131 head test
 644d678 test head
 326e57a v2 a
 8f01c62 version2 a
 a714e37 a
 47a267c a.txt
 6ac34be a
 ​
 # 将当前分支的指针强制回退到哈希值以 e2e2 开头的那个提交版本,并彻底丢弃该版本之后的所有修改和提交记录。
 [root@zuolaoshi git_data]# git reset --hard e2e2
 HEAD 现在位于 e2e2131 head test
 ​
 # 查看 Git 提交历史记录
 [root@zuolaoshi git_data]# git log --oneline 
 2add75e (HEAD -> master) add hello
 ff77333 aaa
 dd7925f test head
 e2e2131 head test
 644d678 test head
 326e57a v2 a
 8f01c62 version2 a
 a714e37 a
 47a267c a.txt
 6ac34be a
 ​
 # 查看文件内容
 [root@zuolaoshi git_data]# cat a
 test
 ​
 ​
 # git reset --mixed:此为默认方式,不带任何参数的git reset,即是这种方式,移动head指针,改变暂存区内容,但不会改变工作区
 # git reset  --soft:回退到某个版本,仅移动当前Head指针,不会改变工作区和暂存区的内容  
 # git reset --hard:彻底回退到某个版本,head指针、工作区和暂存区内容全部改变
 ​
 --soft用处不是很多;当执行git commit之后想撤回,但还不想覆盖工作区内容时,使用--mixed;当想完全回滚时,使用--hard来覆盖工作区。

git reflog

 # 查看文件内容,发现恢复错了,本来是想恢复到“add haha”这个位置的
 # 查看文件内容
 [root@zuolaoshi git_data]# cat a       
 test
 ​
 # 使用log查看,发现没有“add haha”的内容了
 # 查看 Git 提交历史记录
 [root@zuolaoshi git_data]# git log --oneline 
 e2e2131 (HEAD -> master) head test
 644d678 test head
 326e57a v2 a
 8f01c62 version2 a
 a714e37 a
 47a267c a.txt
 6ac34be a
 # 原因很简单,因为我们当前的工作版本是历史的一个提交点,这个历史提交点还没有发生过add bbb更新记录,所以当然就看不到了 ,要是想”还原到未来”的历史更新点 ,可以用git reflog命令来查看所有的历史记录
 ​
 # 查看 HEAD 指针的“所有移动历史”
 [root@zuolaoshi git_data]# git reflog 
 # 使用git reflog 可查看总历史内容(注意这里面也是所有的commit之后,也就是放到本地仓后的记录)再结合git reset --hard 哈希头部恢复版本快照 ,所有的数据根本就不可能丢失,随便删除,随便恢复(前提是已提交仓库的的内容)
 ​
 e2e2131 (HEAD -> master) HEAD@{0}: reset: moving to e2e2
 2add75e HEAD@{1}: reset: moving to 2add75e
 f3d6391 HEAD@{2}: commit: add haha
 2add75e HEAD@{3}: commit: add hello
 ff77333 HEAD@{4}: commit: aaa
 dd7925f HEAD@{5}: commit: test head
 e2e2131 (HEAD -> master) HEAD@{6}: commit: head test
 644d678 HEAD@{7}: commit: test head
 326e57a HEAD@{8}: commit: v2 a
 8f01c62 HEAD@{9}: commit: version2 a
 a714e37 HEAD@{10}: commit: a
 47a267c HEAD@{11}: commit: a.txt
 6ac34be HEAD@{12}: commit (initial): a
 ​
 # 使用reset恢复到“add haha”的版本
 [root@zuolaoshi git_data]# git reset --hard f3d6    
 HEAD 现在位于 f3d6391 add haha
 ​
 # 查看
 [root@zuolaoshi git_data]# cat a
 haha
 hello
 haha