GIT版本管理
对代码进行git管理,此处仓库在gitee 存放
一、基本原理
做文档类、代码类工作的人,最需要的就是备份,更具体来讲不仅仅是对文档的备份,而是对整个文档修改历史的备份,这样才可以让我们在意外情况中尽量减少损失,还可以让我们恢复到之前的版本,要实现这样的效果,最直接的办法就是保存每一份文档,并且为其各自起名,如下图所示。
为每个版本单独保存一份拷贝,这样的做法非常简陋粗放,缺点多多,比如文档的名字无法反映出修改的内容,并且对存储空间的利用也非常不合理,还有更加致命的是,当文档、代码需要多人协作修改时,这种混乱的做法根本无法满足生产需要。
后来,人们发明了版本管理器,如CVS、SVN等,它们不保存系列版本原信息,而是专门保存每次的修改信息,这样一来,版本管理库中的信息就没有重复的内容,而是一条由每次版本更迭所形成的时间轴,我们可以沿着这根时间轴来回变换数据的内容,大大提高了版本控制的效率,因此版本控制器也常常被人们称为数据编辑和代码管理的时光穿梭机,如下图所示。
git的基本功能跟老牌版本控制器一样,就是记录这些提交的节点,并且给每一个节点一个编号,使得我们可以非常方便地回到任意一个历史版本中。另外,分支与融合是git的独门绝技,通过分支我们可以轻便地在一定的基础上开展工作,通过融合又可以方便地审核并迭代,通过这种神奇的技巧,多人协作但组织松散的开源软件开发不仅变得可能,而且效率奇高,大部分专业编程开发者在用了git之后,都会由衷地说,是git改变了他们的生活!
二、本地仓库管理
1. 基础操作
1.1. 初始化
在需要进行版本管理的项目路径下进行仓库的初始化
1.2 设置当前用户的基础信息
这个步骤有些时候是必须的,如果没有设置用户的名字和邮箱会导致无法提交变更到仓库中。
git config --global user.name "Jakl"
git config --global user.email "15254949+jaklin@user.noreply.gitee.com"
1.3 暂存(add)和提交(commit)
顾名思义当我们需要暂时先存储一下但又不至于直接生成版本节点时,可以把刚才所做的修改先提交到暂存区。当我们当前版本确定下来后再从暂存区直接提交到分支中,形成一个可以回缩的存档点。
git add . # 把本项目路径下的所有文件暂存入仓库的暂存区
git add xxx.c # 把特定的文件xxx.c提交到暂存区
提交到分支中:
git commit -m "这里填写本次提交的更新说明"
跳过暂存区直接提交到分支中:
主要注意的是,这么操作只能提交那些以往提交过的文件,如果在本次版本更新中有出现新的文件时,他是无法被识并被加入分支的。因此该操作只适用于没有出现新文件的情况。
提交到暂存区:
git commit -a -m "这里填写本次提交的更新说明"
提交时没有使用 -m 来指定本次更新的信息则会进入GNU Nano 文本编辑器 :
该界面上部分提示我们当前提交的操作中有哪些文件需要更新,我们只需要在后面写上本次提交更新的摘要即可。
一些常用快捷键:
保存并退出:
- 按Ctrl + O(Write Out),然后按 Enter 保存文件。
- 按Ctrl + X(Exit)退出编辑器。
取消提交:
- 如果你想取消提交,直接删除所有内容(包括注释行),然后保存并退出。Git 会提示Aborting commit due to empty commit message.,提交会被取消。
其他快捷键:
- Ctrl + G:查看帮助文档。
- Ctrl + K:剪切当前行。
- Ctrl + U:粘贴剪切的内容。
- Ctrl + W:搜索文本。
- Ctrl + \:替换文本。
1.4 查看提交历史
查看当前分支的提交历史:
1.5 查看文件的差异
当我们对项目进行了某些修改时,并没有做任何提交add 或者commit 的时候通过命令 status 可以看到类似一下信息:
1.6 放弃本次更改的内容
回到分支中最后一个存档点。
git checkout mainwindow.cpp # 只从仓库中同步指定的文件mainwindow.cpp
git checkout . # 从仓库中通过当前的所有文件
#使用 checkout 指令来放弃 mainwindow.cpp 文件的修改,也就是同步到最近的一个存档版本
git checkout main.c
Updated 1 path from the index
1.7 版本回退
要了解如何进行回退版本,我们可以先尝试使用git reflog 来查看一下在整个历史历程中都有哪些提交的信息:
从以上的结果可以清楚看到每一个版本中我们提交的版本更新信息(标题),并可以看到对应的版本编号比如第一个版本的编号为0ea1520,如果我们想直接回到第一个版本则可以直接进行回退:
git reset --hard xxxxx编号
这么一来我们前面做的一切都灰飞烟灭了? 并不是,实际上我们在使用git做的所有操作都会被记录,并且支持回溯。比如我对刚才的鲁莽操作有点后悔:
只需要再次执行reset 并且设置版本号为最后一次的更新即可
也可以通过简单的指令回到上一个版本:
git reset --hard HEAD^ # 回到上一个版本
git reset --hard HEAD^^ # 回到上上一个版本
git reset --hard HEAD^^^ # 回到上上上一个版本
没错以上指令中^的数量决定了你返回的是上*N个版本,如果太多不大好数的话可以使用前面的版本号进行回溯或者:
git reset --hard HEAD~N #直接回到第N个版本
2. 版本的分支管理
2.1 概念
git的分布式特性已经让我们欢呼不已,但git的魅力远不止这些,git还有一个大招,那就是神奇的分支。上面提到,每次commit都会将暂存区中的最新修改信息递交到版本库中,从而形成一系列不同时间点的版本节点,形成一个版本历史,这样的一个历史线条,称之为一个分支。git允许并且鼓励一个项目有多个分支,每创建一个分支,相当于将版本演进放到一个单独的世界,不受外界的干扰,独自演化,到恰当的时候可以融合。这非常适合于多人协作的软件开发情景,如下图所示。
2.2 分支的使用场景
继续探讨分支之前,先来总结分支的基本使用场景:
1.多人协作开发时,每个小分队拥有自己的分支,开发完一个阶段之后融合进主版本
2.为稳定的主版本加入新功能时,创建新分支进行Develop,测试成功后融入主版本
3.为已发布的主版本进行Debug时,创建新分支进行修复,成功之后融入主版本
4.将不同软件的版本库作为分支进行融合,这正是开源软件协作的基石
回忆之前两个小节的内容,master是git在初始化的时候默认产生的分支,而HEAD是当前分支的最新版本,实际上master是一个指针,它指向主分支的历史线的最新版本节点,而HEAD是一个指向master的指针,容易想到,如果当前仓库有多个版本分支,比如Develop分支,那么HEAD可以随时切换到Develop。它们的关系如下图所示。
2.3 分支的创建与切换
git branch # 查看当前的分支情况
* master
一目了然,当前项目中只有一个分支,从我们git init 中自动生成的唯一一个分支。
git branch video # 创建一个新的分支 video
git checkout video # 切换到分支video中
Switched to branch 'video'
git branch # 再次查看当前分支情况,会发现在新的分支video前面有个选中标志*
master
* video
实际上也可以直接创建并切换:
git checkout -b test # -b 表示创建该分支test
Switched to a new branch 'test'
git branch
master
* test
video
2.4 分支融合
当我们在某一个分支上调试稳定后,可以把分支中的功能融入到主分支中。
git branch # 查看当前所处分支
master
test
* video
git checkout master # 切换到主分支 master
Switched to branch 'master'
git branch
* master
test
video
git merge video # 把video 分支融入到当前分支
git branch -d video # 把video分支删除
Deleted branch video (was 7f8b667).
2.5 分支合并冲突
来考虑另一种很常见的情况,那就是张三在master分支(这只是举例,一般master是不允许做任何修改的!)上做了修改,而李四再次创建test分支并在上面做了不同的修改,此时张三再想把这两条分支融合,就必然会产生冲突。
发生冲突后,冲突的内容会在项目文件中被标记出来类似:
此时我们处于主分支中,需要手动清理好各个分支之间的差异,然后对主分支进行一次更新:
最后可以通过一个命令来查看刚才究竟经历了什么(目前为止所有分支的历程):
git log --graph --pretty=oneline --abbrev-commit
从上述 git log 命令的输出看到,经过手工修改并commit之后,两个分支成功融合为一个版本了。可见,经过分支和融合就可以实现多路开发,这个功能十分强大,每个人都可以有自己的分支,团队合作的分支看起来差不多是下图的样子。
三、远程仓库管理
1. 分布式版本管理
上一节介绍了版本管理系统的最一般的功能,除此之外,别忘了git有别于传统CVS和SNV的一点,是其分布式的特点。传统版本控制系统都是集中式的,有一个中央服务器,上面存放了唯一的版本历史,当我们用自己的电脑进行开发时,需要从中央服务器下载最新的版本,更新数据之后又要推送到服务器,如上面的图解所示。如果跟同事的修改有冲突,还需要消耗更多的带宽来处理冲突,这要是遇到网络比较糟糕的环境,一次蜗牛般缓慢的版本递交过程就会让人崩溃,这是集中式控制的最大弊端。
集中式版本管理
分布式系统,顾名思义就是每一台电脑都保存了完整的历史版本信息,不存在任何中央服务器,数据被分散到所有的电脑中,如图1-36所示。这样能一方面能大大增加数据的安全性,另一方面能摆脱网络的带宽的束缚。既然每个人都有自己完整的版本库,那多人协作怎么进行呢?比如对于一个项目,我在家修改了模块A,同事小张也修改了模块A,这样的话我们两个人可以互相将自己的修改推送给对方,让对方查看之间的差异,比如我觉得小张的修改比我的要好,那么我就可以将小张的版本融合到我的本地版本库中。
2. 版本管理服务器
实际上我们很少会在两台电脑之间直接推送彼此的修改,一方面是因为不同电脑可能处于不同的网络无法直接访问,另一方面多人协作可能涉及远远超过两个人的情形,因此在实际生产情境下,分布式系统也往往需要一台能24小时开机、可被外网访问的服务器,但这个服务器仅仅用来充当多人协作的版本中转站而已,大家离开了它也能照样工作,这台服务器被用来协调多人开发的版本分支和融合问题。
许多公司都会在公司内部搭建一台git服务器,用来接收和融合各个开发人员递交的版本,人们在离开公司的时候所做的开发工作,可以在任意方便的时候推送到git服务器,不方便的时候可以直接保存在本地电脑中,没有时刻要联网递交修改的要求。当然,git的优势绝不仅限于此,git的分支管理是它的另一门必杀技,后续会讲解。
从以上描述容易想到,应该会有很多公司、组织或者个人无法或者不想搭建一台git服务器,但是又想要享受随时随地可以将本地版本库推送到一个可以被互联网上的其他人很方便访问的公共服务器上,于是gitee就诞生了,从名字看得出来这就是一个提供git仓库托管服务的平台,目前gitee上已经是华语世界最大的开源软件集聚区(对标美国的github,github容易被墙且访问速度缓慢,推荐支持国产gitee),众多优秀的开源软件,基本上在gitee上都能找到,而你只需要在gitee上注册个账号,就可以下载并参与开发,并且拥有自己的git远程仓库。
3. 新建gitee账户并创建一个仓库
4. 提交到远程仓库
一下操作基本根据Gitee的提示即可:
跟着步骤操作,到此处如果显示远程源已经存在可以通过命令查询:
git remote -v
#如果不是你的远程源可以通过此命令更换
git remote set-url origin https://gitee.com/Jaklin/test.git
推送到远程仓库,输入用户名和密码即可:
这样子显示说明已经成功上传,在gitee上查看
后续的提交与更新可以通过新建分支后上传。
四、参与项目开发
1. 复刻gitee上的开源项目
此时,假设有某位同事Jack对我这个项目感兴趣,并想要参与创作,那么他可以随时在gitee上复刻(Fork)该项目,点击下图最右边的按钮Fork,即可将这个项目复刻到Jack自己的远程版本库上。
接着Jack需要将他远程版本库上的这个项目克隆到他自己的电脑上,那样才方便编辑和开发,在Jack的电脑中,可以使用以下命令将gitee上的项目克隆到本地:
git clone https://gitee.com/Jaklin/test.git my_test
2. 对原项目发起PR
Jack重新对项目进行编撰之后,觉得很满意,希望我接纳他的修改,于是他将修改之后的创新push到他自己的远程版本库gitee.com/Jack/justForFun上,并且对我发起了拉取请求。
Jack@ubuntu:~/justForFun$ git add .
Jack@ubuntu:~/justForFun$ git commit -m "做了一些不可思议的修改"
[master 6583dd8] 做了一些不可思议的修改
1 file changed, 3 insertions(+), 1 deletion(-)
Jack@ubuntu:~/justForFun$ git push
发起拉取请求(PullRequest,即PR)的含义,就是Jack希望项目原主看到他所做的修改,并且通过比对接纳他的版本,当然也可以不接纳。Jack给原主发送拉取请求的做法很简单,只需要在gitee相应项目中点击Pull request就可以了,在实际操作前,还可以再次点击旁边的Compare按钮来仔细确认一遍所做的修改
3. 对PR做进一步说明
按下按钮Pull request之后,Jack可以对自己的修改做更多解释:
这些信息将会被gitee一一记录下来,其他的拉取了该项目的成员都可以看得见,并且都可以发表意见,所有的讨论都会一目了然地呈现在相应的页面中,让后来的人们可以马上了解项目的进度和讨论的过程。
然后,Jack就可以等待作者的回应。
4. 接收并评审PR
另一边,我此时应该就收到了Jack的拉取请求了,让我来看看他究竟对我的诗文做了什么修改。通过点击项目justForFun的Pull request标签,就可以看到是谁发起的拉取请求,他总共做过几次提交,对什么文件做了什么修改,都可以很清楚地看到,同时可以参与讨论,如下列截图所示
查看Jack做了哪些提交
查看Jack具体的修改
如果我对Jack的修改很满意,那么就可以将他的版本融合(Merge)到我当前的版本中,点击图1-42左下角的“Merge Pull request”即可融合代码了。
以前,使用集中式的CVS和SNV是一种煎熬,现在,使用git和gitee来进行团队开发变成了一种乐趣!
常用Git指令速查表
| 指令分类 | Git指令 | 核心功能 | 常用场景 |
|---|---|---|---|
| 基础操作 | git init | 初始化本地Git仓库 | 新建项目后首次启用版本管理 |
| 基础操作 | git clone <远程仓库地址> | 克隆远程仓库到本地 | 从GitHub/GitLab拉取项目源码 |
| 基础操作 | git status | 查看工作区、暂存区文件状态 | 提交前检查文件修改情况 |
| 基础操作 | git add <文件名> / git add . | 将文件添加到暂存区 | 修改文件后准备提交 |
| 提交与推送 | git commit -m "提交说明" | 将暂存区文件提交到本地仓库 | 完成功能开发/修复BUG后保存版本 |
| 提交与推送 | git push <远程仓库名> <分支名> | 将本地提交推送到远程仓库 | 同步本地代码到远程(如GitHub) |
| 提交与推送 | git pull <远程仓库名> <分支名> | 拉取远程仓库代码并合并到本地 | 多人协作时同步他人提交的代码 |
| 分支管理 | git branch | 查看本地所有分支 | 确认当前所在分支及已创建分支 |
| 分支管理 | git branch <分支名> | 创建本地新分支 | 开发新功能/修复BUG时隔离主分支 |
| 分支管理 | git checkout <分支名> / git switch <分支名> | 切换到指定分支 | 切换开发环境(如从dev分支切到master分支) |
| 分支管理 | git branch -d <分支名> | 删除本地已合并分支 | 功能开发完成后清理无用分支 |
| 分支管理 | git merge <待合并分支名> | 将指定分支合并到当前分支 | 功能开发完成后合并到主分支(如dev→master) |
| 远程仓库 | git remote -v | 查看远程仓库关联信息 | 确认本地仓库绑定的远程地址 |
| 远程仓库 | git remote add <远程名> <远程仓库地址> | 关联本地仓库到远程仓库 | 本地新建项目后绑定GitHub/GitLab仓库 |
| 版本查看 | git log | 查看提交历史记录(完整信息) | 追溯版本提交记录、查看提交人/时间 |
| 版本查看 | git log --oneline | 简洁显示提交历史(仅ID+说明) | 快速浏览版本记录 |
| 版本回退 | git reset --hard <提交ID> | 强制回退到指定版本 | 提交错误代码后需要撤销版本 |
| 版本回退 | git revert <提交ID> | 创建新提交撤销指定版本的修改 | 已推送远程的版本需要撤销(不破坏历史) |
| 冲突处理 | git diff | 查看文件修改内容(工作区vs暂存区) | 提交前确认修改细节,或排查冲突点 |
| 冲突处理 | git merge --abort | 取消当前合并操作(冲突无法解决时) | 合并分支时冲突过多,放弃本次合并 |
| 标签管理 | git tag <标签名> <提交ID> | 为指定版本创建标签(如v1.0.0) | 发布正式版本时标记稳定版本 |
| 标签管理 | git push <远程名> --tags | 将本地标签推送到远程仓库 | 同步版本标签到远程,方便他人查看 |
| 强制推送 | git push -f | 强制覆盖仓库代码 | 处理云仓库与本地文件不匹配 |
步骤
//GIT全局设置
git config --global user.name "Jakl"
git config --global user.email "15254949+jaklin@user.noreply.gitee.com"
git init
git remote add origin https://gitee.com/Jaklin/xxx.git
用ssh进行上传


浙公网安备 33010602011771号