本文已收录在Github,关注我,紧跟本系列专栏文章,咱们下篇再续!
- 🚀 魔都架构师 | 全网30W技术追随者
- 🔧 大厂分布式系统/数据中台实战专家
- 🏆 主导交易系统百万级流量调优 & 车联网平台架构
- 🧠 AIGC应用开发先行者 | 区块链落地实践者
- 🌍 以技术驱动创新,我们的征途是改变世界!
- 👉 实战干货:编程严选网
0 下载安装及基本配置
安装成功后,打开,右击选择options进行个性化设置:

字体:

版本:

1 版本控制
1.0 简介
一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。开发中,我们仅对保存着软件源代码的文本文件作版本控制管理,但实际可对任何类型的文件进行版本控制。
采用版本控制系统,可将某个文件回溯到之前状态,甚至将整个项目都回退到过去某个时间点的状态。
可比较文件的变化细节,查出最后谁修改了啥地方,找出导致怪异问题出现的原因,又是谁在何时报告某功能缺陷等。
使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改的改删的删,你也照样可恢复如初,额外增加的工作量微乎其微!
1.1 本地版本控制系统
许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单。不过坏处也不少:有时候会混淆所在的工作目录,一旦弄错文件丢了数据就没法撤销恢复。
为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异

最流行的一种叫做 rcs,现今许多计算机系统上都还看得到它的踪影。甚至在流行的 Mac OS X 系统上安装了开发者工具包之后,也可以使用 rcs 命令。它的工作原理基本上就是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录着对应文件修订前后的内容变化。所以,根据每次修订后的补丁,rcs 可以通过不断打补丁,计算出各个版本的文件内容,像WPS也有类似功能。
1.1 集中化的版本控制系统
如何让在不同系统上的开发者协同工作? 于是,集中化的版本控制系统( Centralized Version Control Systems,CVCS )应运而生。 诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法

每个人都可以在一定程度上看到项目中的其他人正在做些什么。 管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。
缺陷
中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。 最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端偶然提取出来的保存在本地的某些快照数据就成了恢复数据的希望。但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。 本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。
于是分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世!
1.3 分布式版本控制系统
像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。
优势
任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份:

许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。
2 Git 发展史
Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。
到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds )不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统制订了若干目标:
- 速度
- 简单的设计
- 对非线性开发模式的强力支持(允许上千个并行开发的分支)
- 完全分布式
- 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)
自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,它还有着令人难以置信的非线性分支管理系统(见第三章),可以应付各种复杂的项目开发需求。
3 Git 命令
3.1 Git配置
bash
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
git config
命令的--global
参数,表明这台机器上的所有Git仓库都会使用这个配置,也可以对某个仓库指定不同的用户名和邮箱地址。
修改提交人
bash
git commit --amend --author="JavaEdge <JavaEdge@gmail.com>"
# 再
git push -f
3.2 分区

3.2.1 工作区
PC里能看到的目录。实际的文件目录,包含项目文件。
工作区有一个隐藏目录.git
,是Git的版本库。
3.2.2 版本库
包含完整的项目历史和分支信息。包括:
- stage(或称index)暂存区。git add就是把文件从工作区添加到暂存区
- Git自动创建的
master
(现已避嫌,改为main分支),默认的主分支,包含提交历史 - 指向
master
的指针HEAD
:指向当前分支的指针
git commit
把暂存区的所有内容提交到当前分支。
查看工作区状态
bash
$ git status
On branch feature/caict
Your branch is up to date with 'origin/feature/caict'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: src/main/java/com/javaedge/MqttClientConsumer.java
no changes added to commit (use "git add" and/or "git commit -a")
查看修改内容
bash
# 可以查看工作区(work dict)和暂存区(stage)的区别
$ git diff
diff --git a/src/main/java/com/javaedge/MqttClientConsumer.java b/src/main/java/com/javaedge/MqttClientConsumer.java
index 9c65ba5..89bffdd 100644
--- a/src/main/java/com/javaedge/MqttClientConsumer.java
+++ b/src/main/java/com/javaedge/MqttClientConsumer.java
@@ -348,7 +348,7 @@ public class MqttClientConsumer {
// 6. 关闭Producer
producer.shutdown();
} catch (Exception e) {
- System.err.println("发送消息到RocketMQ异常: " + e.getMessage());
+ log.error("发送消息到RocketMQ异常: " + e.getMessage());^M
e.printStackTrace();
}
}
bash
# 查看暂存区(stage)和分支(master)的区别
$ git diff --cached
bash
# 查看工作区和版本库里最新版区别
$ git diff HEAD -- <file>
保存工作现场
bash
$ git stash
查看工作现场
bash
$ git stash list
恢复工作现场
bash
$ git stash pop
发现工作现场
bash
$ git stash apply
3.3 仓库
初始化Git仓库
bash
$ git init
添加文件到Git仓库
bash
# 可反复多次使用,添加多个文件
$ git add <file>
# 可一次提交很多文件,-m后输入本次提交说明,可为任意内容
$ git commit -m "description"
3.4 日志
查看提交日志
bash
$ git log
commit a3a04a5c5c1f8a03ab70f7e69af61c2fc014630b (HEAD -> feature/caict, origin/feature/caict)
Author: JavaEdge <javaedge@gmail.com>
Date: Tue Jul 29 16:18:00 2025 +0800
feat:新增 rocketmq 客户端依赖并发送测试topic消息,但发送失败
简化日志输出信息
bash
$ git log --pretty=oneline
a3a04a5c5c1f8a03ab70f7e69af61c2fc014630b (HEAD -> feature/caict, origin/feature/caict) feat:新增 rocketmq 客户端依赖并发送测试topic 消息,但发送失败
查看命令历史
bash
$ git reflog
a3a04a5 (HEAD -> feature/caict, origin/feature/caict) HEAD@{0}: commit: feat:新增 rocketmq 客户端依赖并发送测试topic 消息
,但发送失败
ab64e5d HEAD@{1}: commit: perf:消息基本转换完毕
3.5 回退
版本回退
bash
$ git reset --hard HEAD^
返回到上一版本。
HEAD
当前版本HEAD^
上一版本HEAD^^
上上个版本HEAD~n
n 个版本之前
回退到指定版本
bash
$ git reset --hard commit_id
commit_id是版本号,SHA1计算出的序列值。
调整commit之间的顺序
先看当前提交历史:
bash
$ git log --oneline
208dff8 (HEAD -> feature/caict, origin/feature/caict) perf:发消息成功
a3a04a5 feat:新增 rocketmq 客户端依赖并发送测试topic 消息,但发送失败
ab64e5d perf:map消息基本转换完毕
将add N提交挪到c2提交之前:
css
$ git rebase -i b0aa963
b0aa963用来确定commit范围,表示从此提交开始到当前的提交(不包括b0aa963提交)。
运行此命令后,弹出VIM编辑器:
bash
# commit提交排列顺序与git log排列相反,最先提交的在最上面
# pick表示保留此次commit提交不做修改
pick e773755 C2
4f66467 C3
pick 7703131 add 1
O4643d add 2
pick f0cc6b6 add 3
# Rebase b0aa963..f0cc6b6 onto b0aa963 (5 commands)
# Commands: 底部给出所有可用的命令
# p, pick = use commit, but edit the commit message
# r, reword = use commit, but stop for amending
# e, edit = use commit, but stop for editing
# s, squash = use commit, but meld into previous commit
# f, fixup = Like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
手动调整一下对应提交的位置:
java
pick 7703136 add 1
O4643d add 2
pick f0cc6b6 add 3
pick e773755 C2
4f66467 C3
保存离开就可以自动完成,再看提交历史记录:
java
git log --oneline (HEAD -> master)
6c59aa9 c3
cd09550 add 3
68a5550 add 2
f5c53c0 add 1
471cafa c1
调整影响:无论调整commit顺序或删除commit,都有可能产生冲突或者错误。如后面的提交对前面的有依赖性,而删除前面的提交,势必出问题。好比穿越时空来到父母恋爱之时,这时候如果热恋中的父母分手,那自己又会从哪来?
提交
bash
git cherry-pick
3.6 撤销
丢弃工作区的修改
bash
$ git checkout -- <file>
将文件在工作区的修改全部撤销,两种case:
- file自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
- file已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态
总之,就是让这文件回到最近一次git commit或git add时的状态。
丢弃暂存区的修改
分两步: 第一步,把暂存区的修改撤销掉(unstage),重新放回工作区:
bash
$ git reset HEAD <file>
第二步,撤销工作区的修改
bash
$ git checkout -- <file>
小结:
-
当你改乱工作区某文件内容,想直接丢弃工作区的修改,用
git checkout -- <file>
-
不但改乱工作区某文件内容,还添加到了暂存区,想丢弃修改,分两步:
-
用
git reset HEAD <file>
,就回到了第一步 -
第二步按第一步操作
-
-
已提交不合适的修改到版本库,想撤销本次提交,就进行版本回退,但前提是没推送到远程库
3.7 删除
删除文件
bash
$ git rm <file>
git rm <file>
相当于执行
bash
$ rm <file>
$ git add <file>
Q:rm text.txt
误删,咋恢复? A:git checkout -- text.txt
,把版本库的东西重新写回工作区
Q:执行git rm text.txt
,发现工作区的text.txt也删除了,咋恢复? A:先撤销暂存区修改,重新放回工作区,然后再从版本库写回到工作区
bash
$ git reset head text.txt
$ git checkout -- text.txt
Q:真想从版本库里删除文件咋做? A:执行git commit -m "delete text.txt"
,提交后最新的版本库将不包含这个文件
git rm V.S git rm --cached
需删除暂存区或分支上的文件,同时工作区也不需要该文件了:
bash
git rm file_path
需删除暂存区或分支上的文件,但本地又需要使用,只是不希望该文件被版本控制:
bash
git rm --cached file_path
3.8 远程仓库
创建SSH Key
bash
$ ssh-keygen -t rsa -C "xxx@gmail.com"

bash
~ % cat /Users/javaedge/.ssh/id_rsa.pub
贴到github的ssh key即可开启ssh免密访问。
关联远程仓库
bash
$ git remote add origin https://github.com/username/repositoryname.git
【取消】关联远程仓库
取消 Git 仓库与远程仓库的关联:
bash
git remote remove https://github.com/Java-Edge/education-microservice.git
不确定远程仓库名称,就查看远程仓库列表:
bash
javaedge@JavaEdgedeMac-mini education-microservice % git remote -v
origin https://github.com/Java-Edge/education-microservice.git (fetch)
origin https://github.com/Java-Edge/education-microservice.git (push)
列出所有与你的本地仓库相关联的远程仓库及其 URL。再按需用第一个命令取消关联特定的远程仓库。
推送到远程仓库
bash
$ git push -u origin master
-u
表示第一次推送master分支的所有内容,此后,每次本地提交后,只要有必要,就可以使用命令git push origin master
推送最新修改。
坑
bash
fatal: The upstream branch of your current branch does not match
the name of your current branch. To push to the upstream branch
on the remote, use
git push origin HEAD:release/10.0
To push to the branch of the same name on the remote, use
git push origin HEAD
与本地建立联系的是远程的 release 分支,因此git 报错会提示应该这么把代码推到远程的特定分支
bash
git push origin HEAD:release/10.0
从远程克隆
为了得到一个项目的备份,需知该项目仓库地址(Git URL)。Git能在许多协议下使用,所以Git URL可能以ssh://、http(s)://、git://或只是以一个用户名(git 会认为这是一个ssh 地址)为前辍。有些仓库可通过不只一种协议访问。如Git本身源码可用:
git:// 协议访问:
bash
git clone git://git.kernel.org/pub/scm/git/git.git
也可通过http 协议来访问:
java
git clone http://www.kernel.org/pub/scm/git/git.git
git://协议较为快速和有效,但有时须用http协议,如你公司防火墙阻止非http访问请求。若执行上面两行命令中的任一,你会看到一个新目录: 'git',包含有所的Git源代码和历史记录。
Git会把"Git URL"里最后一级目录名的'.git'的后辍去掉,做为新克隆(clone)项目的目录名,如:
java
git clone http://git.kernel.org/linux/kernel/git/torvalds/linux-2.6.git
会建立一个目录叫'linux-2.6'。
若访问一个Git URL需用户名、密码,可在Git URL前加上用户名,并在它们之间加上@符合以表示分割,再执行git clone,git提示你输入密码。
示例
bash
git clone javaedge@http://www.kernel.org/pub/scm/git/git.git
将以作为 javaedge 用户名访问:
java
http://www.kernel.org/pub/scm/git/git.git
然后按回车键执行git clone命令,git会提示你输入密码。
可通过-b <name>
指定要克隆的分支名:
bash
$ git clone -b master2 ../server .
表示克隆名为master2的这个分支,如果省略-b 表示克隆master分支。
bash
$ git clone https://github.com/usern/repositoryname.git
删除远程仓库文件
可能某些不需要的目录上传到远程仓库去了,下面开始操作
预览将要删除的文件
bash
# 加上 -n 参数,执行命令时,不会删除任何文件,而是展示此命令要删除的文件列表预览
git rm -r -n --cached 文件/文件夹名称
确认后删除
bash
git rm -r --cached 文件/文件夹名称
提交到本地
bash
git commit -m "提交说明"
并推送到远程服务器
bash
git push origin master
3.9 分支
创建分支
bash
$ git branch <branchname>
查看分支
bash
# 列出所有分支,当前分支前面会标一个*号。
$ git branch
* feature/caict
main
master
查看远程分支
bash
$ git branch -a
* feature/caict
main
master
remotes/origin/HEAD -> origin/main
remotes/origin/feature/caict
remotes/origin/main
remotes/origin/master
查看本地分支和远程分支之间的映射关系:
bash
$ git branch -vv
* feature/caict 208dff8 [origin/feature/caict] perf:发消息成功
main 95f1bb6 [origin/main: ahead 1, behind 1] Initial commit
master 95f1bb6 [origin/master] Initial commit
切换分支
bash
$ git checkout <branchname>
bash
# 切换远程分支
git checkout -b release/10.0 origin/release/10.0
创建+切换分支
bash
$ git checkout -b <branchname>
合并某分支到当前分支
bash
$ git merge <branchname>
删除分支
bash
$ git branch -d <branchname>
查看分支合并图
bash
$ git log --graph
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。用git log --graph
命令可以看到分支合并图。
普通模式合并分支
bash
$ git merge --no-ff -m "description" <branchname>
因为本次合并要创建一个新的commit,所以加上-m
参数,把commit描述写进去。合并分支时,加上--no-ff
参数就可以用普通模式合并,能看出来曾经做过合并,包含作者和时间戳等信息,而fast forward合并就看不出来曾经做过合并。
丢弃一个没有合并过的分支
bash
$ git branch -D <branchname>
查看远程库信息
bash
$ git remote -v
在本地创建和远程分支对应的分支
bash
$ git checkout -b branch-name origin/branch-name,
本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联
bash
$ git branch --set-upstream branch-name origin/branch-name;
从本地推送分支 (将本地项目与远程仓库项目关联)
bash
$ git push origin branch-name
java
sssdeMacBook-Pro:ArticleSpider sss$ git push -u origin master
Counting objects: 18, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (18/18), 4.32 KiB | 2.16 MiB/s, done.
Total 18 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/Wasabi1234/Scrapy-Tutorial.git
1c84622..bc4cf9a master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
如果推送失败,先用git pull抓取远程的新提交;
从远程抓取分支
bash
$ git pull
如果有冲突,要先处理冲突。
3.10 标签
tag让人容易记住的有意义的名字,跟某commit绑在一起。
新建一个标签
bash
$ git tag <tagname>
默认为HEAD,也可指定一个commit id。
指定标签信息
bash
$ git tag -a <tagname> -m <description> <branchname> or commit_id
git tag -a <tagname> -m "blablabla..."
可以指定标签信息。
PGP签名标签
bash
$ git tag -s <tagname> -m <description> <branchname> or commit_id
git tag -s <tagname> -m "blablabla..."
可以用PGP签名标签。
查看所有标签
bash
$ git tag
推送一个本地标签
bash
$ git push origin <tagname>
推送全部未推送过的本地标签
bash
$ git push origin --tags
删除一个本地标签
bash
$ git tag -d <tagname>
删除一个远程标签
bash
$ git push origin :refs/tags/<tagname>
参考:
本文由博客一文多发平台 OpenWrite 发布!