前言
都说互联网的本质就是迭代!那我们如何保证代码可以快速迭代、回滚呢?所以版本控制工具就应运而生了。
一、git是什么?
git 是一款分布式的版本控制软件,在学习git之前我们先来看下版本控制工具发展的历程;
1.版本控制工具发展历程
1.1 手工保存文件
就像我们在大学里写论文从最开始----->版本1----->版本2----->版本3.........导师认可版,这个不断修正、反复修改的过程就是手工版本控制;
当然我们写的这些毕业论文是使用 N个文件得以实现版本控制的。
1.2.版本控制工具出现
使用软件实现本地版本控制后我们只能看到1文件,而其他的增量/减量软件自动帮我们管理起来,我们通过命令实现版本间的切换,
这就我们就实现了集中式本地版本控制(local computer versin control)。
1.3.集中式版本控制工具
本地版本控制的缺陷是只能1个人在自己的电脑上玩,无法满足我们多人协同去完成1个论文、书籍的撰写的需求;
如果我们多个人进行同1个项目的开发,如何做到版本控制呢?
于是出现就集中化版本控制(eg:SVN),把所有版本集中式的保存在1台服务器(数据仓库)里,这样大家就可以做协同开发了;
1.4.分布式版本控制工具
集中式的版本控制的缺陷是所有的版本都保存在远程服务器上,我们本地电脑中没有历史版本,如果中心server down掉了,我们的本地电脑无法及时保存所有的历史版本,而分布式的版本控制工具是你可以1次从远程服务器 -----------》 pull到本地所有的历史版本。这样大家都有了历史版本就不怕单点故障了,即使server down了我们也可以把自己本地所以历史版本push-----》server,这样就不影响我们版本迭代了。
-
本地仓库:安装在开发者本机电脑,主要负责版本控制,日志记录
-
二、本地仓库开发
现在我们就从在本地仓库中如何使用git开始;
首先进入要管理的文件夹,进入文件夹后点击 git bash here
1.git区域
git 划分为以下3个区域,从工作区到版本库的过程就是创建1个版本的过程
1.1.工作区
在Git本地仓库中,新增的文件/目录,都需要添加到暂存区由git进行管理;
新文件/目录只需要被add一次,文件/文件夹被add之后,如果内容发生了修改无需再次add.
1.2.暂存区
暂存区是1个缓冲区,通过 git add 把文件由工作区------》暂存区(文件为绿色)
1.3.本地版本库
如果决定生成版本之后, 通过 git commit 把文件由暂存区提交到本地版本库生成1个版本
2.版本生成命令
初始化
$ git init
配置git信息
如果没有给git配置声明个人信息,将无法commit 生成新的版本。
git config --global user.name "zhanggen@le.com" git config --global user.email "张根"
查看文件状态
$ git status
管理
$ git add index.html 管理单个文件
$ git add . 管理当前文件夹下所有文件
生成本地版本
$ git commit -m 'v1' v1为版本名称
查看生成的版本信息
$ git log
查看版本记录
$ git reflog
3.版本库回退
注意再一下撤回这种使用的版本唯一标识符是 你想要回退到版本的唯一标识符,而不是本版本;
一步一步地回退
版本库------>暂存区
$ git reset --soft dc2c764b22b78d544746cd0419091982ca9b3dc8
暂存区------>工作区
$ git reset head index.html
工作区---->最原始未修改状态
如果我们修改了文件,文件会自动被检测到变红,那么我们如何撤销修改呢?
$ git checkout index.html
工作区----->堆栈区(暂时存放)
假设我们正在开发的过程中,原来的代码出现紧急bug需要修改,此时我们既无法提交代码到版本库,也需要保存已修改的代码 去修复源代码的bug怎么办?
那我就可以找个地方暂存一下我们修改的代码;
$ git stash
Saved working directory and index state WIP on master: fc0f6aa ‘yu
$ git stash pop #从堆栈区拿出来
以下是2种方式比较快捷的的回退方式
版本库------>直达工作区(文件已修改的状态)
git reset --mix dc205fe8ddc2f23c97e84a0e40f25c4b8c4bae39
版本----->版本
git log 可以查看每个版本的唯一标识符,通过唯一标识符就可以在版本之间切换;
$ git reflog #查看所有版本记录
$ git reset --hard dc2c764b22b78d544746cd0419091982ca9b3dc8
修改最近1次commit信息
git commit --amend feat:【CI】Artifactory 提供的python 源测试验证 resolve:m-4889012526
wq保存退出
修改多次
在 Git 中,如果你想修改多个 commit 的信息,可以使用 git rebase 命令。这里有一个简单的步骤指南: 1. 启动交互式 Rebase 首先,找到你要修改的起始 commit。假设你想修改最近的 3 个 commit 的信息,可以运行: bash 复制代码 git rebase -i HEAD~3 这将打开一个交互式编辑器,其中会列出最近的 3 个 commit。每一行的开头会有 pick 关键字,类似如下: plaintext 复制代码 pick abc1234 Original commit message 1 pick def5678 Original commit message 2 pick ghi9101 Original commit message 3 2. 将 pick 改为 reword 对于每个需要修改信息的 commit,将 pick 改为 reword(或 r 简写): plaintext 复制代码 reword abc1234 Original commit message 1 reword def5678 Original commit message 2 reword ghi9101 Original commit message 3 保存并退出编辑器。 3. 编辑 Commit 信息 Git 会逐个打开这些 commit 的信息编辑器,让你修改每个 commit 的信息。完成后,保存并退出编辑器以应用修改。
三、多分支并行开发
本地仓库解决了代码版本迭代的问题,如果在团队中需要多个开发人员协作开发,就需要多个分支;
git的分支之间是隔离的;
同时创建多个分支,每个人在不同的分支上开发不同的功能,功能开发完成后,所有子分支--->提交到远程代码仓库, 完成子分支合并到master主分支。
基于master分支反复分裂、合并, 实现了多人在多个分支上并行开发,大大提升了工作效率。
git的每个版本只保存自己修改的部分,原来的基础部分通过指针引指向 上一版本 直到 第1个版本,这种链接式设计节省了存储空间、加快了我们在版本/分支之间切换的速度。
每个分支之间的代码都是相互隔离的,这样也可以帮助我们同时正在不同的分支上同时开发不同的功能,以及之前版本出现bug后及时修复。
git的主分支称为master ,其他分支由人为命名,一般都有master分支(线上代码)、 dev分支(开发新功能)。
创建分支
我们在哪个分支上创建了新分支,新分支的指针就会指向该分支最新的版本(表象是2个分支的代码一模一样)。
git branch dev
查看分支
查看本地分支
1 | git branch |
查看远程分支
1 | git branch -r |
查看所有分支
1 | git branch -a |
切换到远程分支
1 | git checkout -b local_branch origin /reduce_input |
删除分支
git branch -d dev
如果你想让A分支合并到B分支,一定要切换到B分支上,执行git merge A。你想要谁就 merge谁过来。
既然merge就是2个分支合并嘛,但是二者合并的依据是什么呢?根据2个分支中分叉之后的commits。
commit
和当前分支commit
(即 HEAD
所指向的 commit
)分叉的位置起,把目标 分支commit
路径上的所有 commit
的内容一并应用到当前分支commit。
commit
。$ git checkout master Switched to branch 'master' $ git branch bug dev * master $ git merge bug Updating 21fd06b..d559613 Fast-forward index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
当前分支HEAD 领先于目标commit (nothing to do)
如果 merge
时当前分支和目标分支的HEAD
并不存在分叉,而是 当前分支HEAD
领先于目标分支:你就是最新版本,你还想merge旧版本。
那么 merge
就没必要再创建一个新的 commit
来进行合并操作,因为并没有什么需要合并的。在这种情况下, Git 什么也不会做,merge
是一个空操作。
$ git branch * master zhanggen $ git merge zhanggen Already up-to-date.
当前分支HEAD落后于目标分支commit(fast-forward)
如果 merge
时当前分支和目标分支的HEAD
并不存在分叉,切目标分支的HEAD领先于当前分支:既然别人是先进的,我们就fast-forward(快进)。
$ git merge zhanggen Updating 2b26aee..de6f040 Fast-forward src/main.js | 1 + 1 file changed, 1 insertion(+)
合并分支出现冲突
出现原因
我们在master分支 v2阶段创建了dev分支,dev分支引用的就是master v2阶段的代码
然后我又在master分支 v2阶段的代码进行了修改,master开发到了v3阶段。
现在对dev分支和master进行合并,由于dev分支仍对master原来v2阶段的代码进行引用,2个不同的分支,同时修改了同1行代码,就会引起冲突。
冲突出现时机
从远程仓库pull代码
向远程仓库push代码
凡是涉及到2个不同分支合并都有可能出现冲突;
git出现冲突现象
$ git merge dev Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result.
代码出现冲突现象
上面是master修改的代码,下面是dev分支修改的代码。
解决
手工选择1需要的代码部分,然后生成新的版本
git add . git commit -m '修复冲突版本'
避免冲突的方法
pull操作的本质是将远程仓库中的某1个分支merge到本地的某1个分支中;
push操作的本质是将本地某1个分支merge到远程仓库的1个分支中。
所以以上2个操作,都有可能存在冲突,每1次push之前,先pull以下远程仓库的代码;
分支使用场景
分支就是帮助我们多个开发,在不同的分支上同时并行向前开发或者紧急修复bug。
假设目前有1个项目已经在master分支成熟上线,现需要开发1个新的功能,我创建了dev分支,在dev分支开发新功能时,master分支现有的功能又出现了bug。
如何在不耽误开发新功能的前提下修复一下线上的bug呢?
(1)创建bug 分支
(2)去bug分支修复master分支的bug,修复完成后。
(3)切换到master分支,把bug分支合并到master(master分支的bug修复完成)
(4)切换到dev分支继续开发.....开发完了新功能
(5)然后切回master分支,在master分支合并dev开发的新功能。
(6)最新master和dev分支 合并时肯定会出现冲突。
为什么会出现冲突呢?因为合并时 2条分支交叉点往后的版本中,2条分支均修改了同一行代码。
最新的master分支修改了原来的bug,但是dev分支指针指向的还是原来的就master(没有做任何改动)。这就是2条分支存在冲突的地方。
(7)出现冲突不着急,在master分支手动解决冲突
(8)在master分支 生成新的版本git add . 、git commit -m '解决冲突版本' (新功能开发完成)
四、代码保存在远程代码仓库
多分支解决了团队明确分工的问题,在子分支上开发完成之后,如何把自己负责分支分析给团队其他成员呢?
这就需要1个共同的远程代码仓库;
如果需要跟团队其他成员共享文件,可以将代码push(推送)到远程仓库,也可以通过pull(拉取)得到远程仓库中的最新代码
我们在本地开发的代码(版本、分支信息)如何进行网络传播呢?gitlab、github就是做代码托管的远程仓库,它们和git工具进行了无缝衔接,我们可以使用git命令很方便的把代码(版本、分支信息)上传到远程代码仓库,也可使用git 命令下载到本地,使我们的代码可以通过网络传播。
推送本地代码到GitHub
添加远程仓库地址
$ git remote add origin https://github.com/zhanggen3714/dbhot.git
推送本地master分支到github
$ git push -u origin master
本地分支、版本信息都已经提交到github
克隆远程仓库代码
$ git clone https://github.com/zhanggen3714/dbhot.git
所有的分支信息和版本已经拉取到本地
git branch只显示master,但是其他分支也可以通过 git checkout 切换。
$ git branch
dev
* master
从远程仓库分支拉取版本信息
git pull origin dev
等同于
git fetch origin dev #从远程仓库 拿来dev到版本库
git merge origin/dev #然后和本地dev进行合并到工作区
git rebase应用
git 的rebase和merge命令都可以合并2个不同的分支
git rebase命令,会让你的提交记录放在目标分支记录的最前面;
如果你比较关注代码的历史提交记录,rebase可以让代码提交记录看起来更加简洁。
单条分支上的多次commit 记录整合为1次commit记录
有时候我们在本地开发时, git commit了很多次,那么如何把N个版本合并为1个呢?让我们的 commit 提交记录看起来更加简洁呢。
注意不要rebase已经提交到远程仓库的版本。
git rebase -i HEAD~3 #把3条commit 信息合并为1条
s标记要合并的版本
squash | meld into
填写合并后填写 本次合并commit信息
合并2条分支
git rebase给分支中文意思为变基-
在dev分支执行 git rebase master,把master分支所有的版本放到当前dev分支版本的下面(让master分支做dev分支的地基)
$ git rebase master First, rewinding head to replay your work on top of it... Applying: 正在dev分支重新rebase 1
在master分支把dev分支merge过来把所有代码保存在master分支
$ git branch
dev
* master
$ git merge dev Updating 367ca8c..3dacbb6 Fast-forward s.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 s.py
rebase变基完成,使用图形查看git log
提交记录更加简洁了
$ git log --graph --pretty=format:'%h %s' * bbfb548 merge dev to master |\ | * 3df6d26 dev branch * | f2a90ad master branch |/ * 93d4c88 v2 * 58529b9 v1
应用3
使用git fetch + git rebase代替 git pull
假设我们 在公司和家2地之间开发,代码通过gitgub远程仓库的dev分支保存(现仓库中有1个a.py的空文件)。
我现在在公司pull下了代码, 打开a.py文件开发了0-50%只生成了版本,忘记push到github。
那么我到家后接着打开a.py开发了其余50-100%的功能,push到了github。
到了公司之后我该怎么办?才能保存a.py文件在公司开发的前0-50%和在家开发的的50-100%代码, 然后还能使代码提交记录看起来简洁呢?
(1)从github拉取远程仓库里的dev分支
git fetch origin dev
从远程代码库拉取分支,并在本地创建。
git fetch origin dev:dev From githab.com:sre/godos * [new branch] dev -> dev
(2)切换到本地dev分支,让远程仓库的origin/dev分支做本地dev分支的地基。
git checkout dev
git rebase origin/dev
(3)出现冲突
$ git rebase origin/dev First, rewinding head to replay your work on top of it... Applying: 在家 dev分支开发v1 error: Failed to merge in the changes. Using index info to reconstruct a base tree... M a.py Falling back to patching base and 3-way merge... Auto-merging a.py CONFLICT (content): Merge conflict in a.py Patch failed at 0001 在家 dev分支开发v1 The copy of the patch that failed is found in: .git/rebase-apply/patch When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort".
(4)解决冲突
由于在家和在公司各开发的50%,在a.py的同一部分。所以就会出现冲突,出现冲突就手工解决。
(5) 把修复冲突的文件提交到暂存区
注意与git merge是出现冲突不一样的地方是,merge是出现冲突需要 commit而rebase时出现冲突,只需要 add .
$ git add .
(6)继续rebase生成版本
由于之前出现了冲突,rebase就会被中断,现在手工解决完了冲突,就可以继续 rebase了。
git rebase --continue
Applying: 在家 dev分支开发v1
解决冲突的工具
有时候我们进行1次merge/rebase会产生成千上万个冲突,如果逐个文件逐行的去寻找会非常麻烦,所以就需要借助工具。 -Beyond Compare
配置 beyond compare
$ git config --local merge.tool bc4 $ git config --local mergetool.path 'D:\BeyondCompare4' $ git config --local mergetool.keepBackup false
五、常见git开发模式
我们主要使用2种git开发模式: 多分支开发模式、fork开发模式。
1.多分支开发模式
分支开发模式就是你clone线上的代码库到本地PC之后创建自己的分支,在该分支之上进行开发,然后再把新功能所在的分支push到线上。
由代码库Owner在线上对你提交的分支和master分支进行1个合并。
2.fork模式
当我们不是某个代码库A 的项目成员角色(developer)角色时,我们只能查看别人的代码,无法对别人的代码进行修改,但是可以采用fork的开发模式。
其代码库架构如上图
其代码提交流程如下图
1.点击fork/派生等待代码库owner允许你fork他/她的代码。
2.当owner接收你的fork请求之后,就会产生1个和当前代码库一模一样的派生库。
3.我们clone这个派生库到本地进行开发,然后push新功能到派生库 。
4.到代码库A也就是主库发起merge/pull request(PR) ,然后主库的owner就会收到的pull request请求了。如果owner接收了你的pull request那么你的代码就可以提交到线上。
5.如果下次还想提交的话,派生库不会和owner的主库进行实时更新。
6.我需要设置upstream为主库,从upstream pull/clone代码到本地,然后push本地代码到派生库(origin),然后再次发起merge/pull request请求。
git remote add upstream 主库的地址
git fetch upstream master 把主库的代码 git pull upstream master下来和本地master进行更新。
git merge upstream/master
------------------------------------------------
然后就可以在本地进行开发然后把本机代码push到派生库,然后在提交pullrequest/合并请求了。

$ git remote -v origin https://coding.jd.com/yw/nwdp-frount.git (fetch) origin https://coding.jd.com/yw/nwdp-frount.git (push) $ git remote add upstream https://coding.jd.com/yw/nwdp-frount.git $ git remote add origin https://coding.jd.com/zhanggen24/nwdp-frount/ fatal: remote origin already exists. $ git remote rm origin $ git remote add origin https://coding.jd.com/zhanggen24/nwdp-frount/ $ git push origin master Username for 'https://coding.jd.com': zhanggen24 error: unable to read askpass response from 'D:/Git/mingw64/libexec/git-core/git-gui--askpass' Password for 'https://zhanggen24@coding.jd.com': $ git status On branch master 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/router/index.js Untracked files: (use "git add <file>..." to include in what will be committed) src/views/TrapAlarm/ no changes added to commit (use "git add" and/or "git commit -a") $ git add src/router/index.js $ git add src/views/TrapAlarm/ $ git commit -m 'It is first commit of trap alarms for online testing' [master 4d4683d] It is first commit of trap alarms for online testing 5 files changed, 1328 insertions(+), 9 deletions(-) create mode 100644 src/views/TrapAlarm/alarm_black.vue create mode 100644 src/views/TrapAlarm/alarm_config.vue create mode 100644 src/views/TrapAlarm/alarm_list.vue create mode 100644 src/views/TrapAlarm/alarm_sumary.vue $ git remote -v origin https://coding.jd.com/zhanggen24/nwdp-frount/ (fetch) origin https://coding.jd.com/zhanggen24/nwdp-frount/ (push) upstream https://coding.jd.com/yw/nwdp-frount.git (fetch) upstream https://coding.jd.com/yw/nwdp-frount.git (push) $ git push origin master Username for 'https://coding.jd.com': zhanggen24 Counting objects: 11, done. Delta compression using up to 4 threads. Compressing objects: 100% (10/10), done. Writing objects: 100% (11/11), 10.11 KiB | 0 bytes/s, done. Total 11 (delta 6), reused 0 (delta 0) remote: Resolving deltas: 100% (6/6) remote: Coding: Checking the pushed content... remote: Updating references: 100% (1/1) To https://coding.jd.com/zhanggen24/nwdp-frount/ f2a28bf..4d4683d master -> master
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南