一.版本控制是什么?
在了解git前必须知道什么是版本控制。
版本控制的概念
版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。
举个例子,这个学期写论文,论文肯定没有办法一稿解决,而每一稿都是基于前面的论文稿进行修改,如果我不对论文的每一稿进行存储的话,当我在写后面论文时如果需要用到之前论文中的一些材料,那么就需要重新去找。这就是不对版本进行管理的代价。
当然上面的例子其实非常的狭义,仅仅基于写论文这么一个场景,而且成员只有我独自一个人参与。试着扩散思维,假如一个超级大公司里面要开发一个体量非常大的项目,不进行版本控制的话会发生什么? 结果不言而喻。
那么版本控制工具的好处是什么呢?
-
实现跨区域多人协同开发
-
追踪和记载一个或者多个文件的历史记录
-
组织和保护你的源代码和文档
-
统计工作量
-
并行开发、提高开发效率
-
跟踪记录整个软件的开发过程
-
减轻开发人员的负担,节省时间,同时降低人为错误
简单说就是利于管理多人协同开发项目。
请记住,多人开发就必须用到版本控制。
二.常见的版本控制工具及分类
这里我只谈一下我在公司实习时接触到的两个也是目前来说最流行的两个版本控制工具。
- Git
- SVN(Subversion)
版本控制主要分为三类
1.本地版本控制
第一类,就是如我之前写论文那样,每次写一稿都放入同一个本地的文件夹中进行管理。适合个人用,市面上的工具主要以RCS为主。
2.集中版本控制 SVN
所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改。
优点:相对于将版本数据放在本地来说显然更加方便而且不用担心内存问题。
缺点:
-
用户本地只有之前所同步的版本
-
必须要联网才能看到历史版本
-
只能在同一个分支工作
-
所有数据都存储在单一服务器上,风险较大。
目前最流行的集中式版本控制工具为svn。
3.分布版本控制 Git
与集中式版本控制的区别是每个用户都可以拥有完整的项目代码。解决了svn的几乎全部缺点。由于每个用户都可以用户所有代码,所以不必担心服务器崩溃所带来的数据丢失的风险。所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。 不会因为服务器损坏或者网络问题,造成不能工作的情况!
Git与SVN的主要区别
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。
Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。Git可以直接看到更新了哪些代码和文件!
三.Git的基本使用
本篇文章暂不谈原理,只讲一些常见的命令。
1.git基本概念以及工作流程
workspace
工作区,我们写代码的地方
Index
暂存区,暂时存放代码的地方
Repository
本地仓库,代码在到达远程仓库之前要存在这里
Remote
远程仓库,也叫代码托管仓库,我们熟悉的有GitHub和码云。
这张图片是网上流行的不错的一张关于git流程的图片,其内容大概如此
- 我们在工作区写完代码之后,将代码放入暂存区 git add .
- 暂存区再将代码提交到本地仓库 git commit -m/-v
- 本地仓库再将代码推送到远程仓库 git push
以上便是工作时比较常用的git一把梭,但是想熟练的使用git这个工具的话我们还需要知道更多。
上面还有一些没有涉及的命令如git push,git clone等。下面会逐一讲解。
2.git 配置命令
在下载好git后,我们还需要进行一些相关的配置。其中最主要的就是邮箱和用户名了。
git config --list 列出当前配置
git config --local --list 列出Repository配置
git config --global --list 列出全局配置
git config --system --list 列出系统配置
通过上述的命令,发现你并没有配置用户信息的话,接下来配置一下👇
前提是你在代码托管平台以及注册了,以下的用户名和邮箱对应的就是你注册时的邮箱和用户名
git config --global user.name "your name" //配置用户名
git config --global user.email "youremail@github.com" //配置邮箱
3.文件状态
文件状态共分为四种,分别是
- Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过
git add状态变为Staged. - Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为
Modified. 如果使用git rm移出版本库, 则成为Untracked文件 - Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过
git add可进入暂存staged状态, 使用git checkout则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改 - Staged: 暂存状态. 执行
git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified
git status
-
Changes not staged for commit- 表示得大概就是工作区有该内容,但是缓存区没有,需要我们
git add
- 表示得大概就是工作区有该内容,但是缓存区没有,需要我们
-
Changes to be committed- 一般而言,这个时候,文件放在缓存区了,我们需要
git commit
- 一般而言,这个时候,文件放在缓存区了,我们需要
-
nothing to commit, working tree clean- 这个时候,我们将本地的代码推送到远端即可
4.状态查询
- 查看状态
- git status
- 查看历史操作记录
- git reflog
- 查看日志
- git log
5.文档查询
- 展示Git命令大纲
- git help (--help)
- 展示Git命令大纲全部列表
- git help -a
- 展示具体命令说明手册
- git help
6.文件暂存
假设此时正在`feat/f1分支开发功能,但是突然接到一个 bug 需要修复,为了保存当前分支的修改,有同学会先进行一次commit作为暂存。之后再切到新的分支去完成 bug 的修复,修复完再切到feat/f1继续功能开发。
这样虽然能达到暂存更改的目的,但是会把这些不重要的commit信息一起带到仓库里去,看起来 git 提交信息不够具体与明确。
所以建议可以去了解一下git stash命令,它能帮助我们将当前修改的记录保存在本地,可随时调取,并且不会影响我们的提交信息。这里我列举了一下我自己常用的:
-
git stash list ---- 查看本地暂存的列表
-
git stash save '暂存提示信息'-u --- 将当前修改暂存到本地
- -u`参数是指把仓库中暂未追踪(untracked)的文件也进行暂存(比如你新建了一个文件,如果不加-u命令,这个新文件就不会被暂存)
-
git stash apply stash@{num} ---- 应用某一次暂存到当前分支
- num是通过
git stash list查看时对应的数字
- num是通过
-
`git stash drop stash@{num} ---- 删除某一次暂存
- num与上一点中一样
-
git stash clear ---- 清空所有暂存,这个使用的时候记得先看一下暂存列表确认一下较好
如果你不小心使用命令 git stash drop 掉你要用到的修改记录,这时候不要慌张,千万不要清除命令行内容,在使用这条命令之后会有类似这样的输出:丢弃了 stash@{1}(53e033a2d02335701cec614d899b005e69a7ec14 你可以使用git stash apply 53e033a2d02335701c 进行恢复
7.操作撤销
-
撤销工作区修改
- git checkout --
-
暂存区文件撤销 (不覆盖工作区)
- git reset HEAD
-
版本回退
-
git reset --(soft | mixed | hard ) < HEAD ~(num) > |
-
| 指令 | 作用范围 | | - | - | | --hard | 回退全部,包括HEAD,index,working tree | | --mixed | 回退部分,包括HEAD,index | | --soft | 只回退HEAD |
-
8.差异比较
-
比较工作区与缓存区
-
git diff
-
比较缓存区与本地库最近一次commit内容
- git diff -- cached
-
比较工作区与本地最近一次commit内容
- git diff HEAD
-
比较两个commit之间差异
- git diff
9.fetch指令
将远程仓库内容更新到本地 fetch推荐写法
git fetch origin <branch-name>:<local-branch-name>
一般而言,这个origin是远程主机名,一般默认就是origin。 branch-name 你要拉取的分支 local-branch-name 通常而言,就是你本地新建一个新分支,将origin下的某个分支代码下载到本地分支。
举个例子👇
git fetch origin feature/template_excellent:feature/template_layout
// 你的工作目录下,就会有feature/template_layout
// 一般情况下,我们需要做的就是在这个分支上开发新需求
// 完成代码后,我们需要做的就是上传我们的分支
fetch其他写法
- 将某个远程主机的更新,全部取回本地。
git fetch <远程主机名>
- 这样子的话,取回的是所有的分支更新,如果想取回特定分支,可以指定分支名👇
git fetch <远程主机名> <分支名>
- 当你想将某个分支的内容取回到本地下某个分支的话,如下👇
git fetch origin :<local-branch-name>
// 等价于👇
git fetch origin master:<local-branch-name>
基本操作
有了上述的基本了解后,那么我们就来看看整体的一个流程吧。
- 创建本地仓库 git init
git init
- 链接本地仓库与远端仓库
git remote add origin
origin默认是远端仓库别名 url 可以是可以使用https或者ssh的方式新建
- 检查配置信息
- git config --list
- Git user name 与email
git config --global user.name "yourname"
git config --global user.email "your_email"
- 生成SSH密钥
ssh-keygen -t rsa -C "这里换上你的邮箱"
cd ~/.ssh 里面有一个文件名为id_rsa.pub,把里面的内容复制到git库的我的SSHKEYs中
- 常看远端仓库信息
- git remote -v
- 远端仓库重新命名
- git remote rename old new
- 提交到缓存区
- git add . 全部上传到缓存区
- git add 指定文件
- 提交到本地仓库
- git commit -m 'some message'
- 提交远程仓库
- git push <远程主机名> <本地分支名>:<远程分支名>
- 查看分支
- git branch
- 创建新分支但是切换分支
- git branch 分支名
- 切换分支
- git checkout
- 创建分支并切换
- git checkout -b
- 删除分支
- git branch -d
- 删除远程分支
- git push -d
- 切换分支
- git checkout
忽略文件 .gitignore
这个文件的作用,会去忽略一些不需要纳入Git管理这种,我们也不希望出现在未跟踪文件列表。
那么我们来看看如何配置该文件信息。
# 此行为注释 会被Git忽略
# 忽略 node_modules/ 目录下所有的文件
node_modules
# 忽略所有.vscode结尾的文件
.vscode
# 忽略所有.md结尾的文件
*.md
# 但README.md 除外
!README.md
# 会忽略 doc/something.txt 但不会忽略doc/images/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为txt文件
doc/**/*.txt
分支命名
master分支
- 主分支,用于部署生产环境的分支,确保稳定性。
- master分支一般由develop以及hotfix分支合并,任何情况下都不能直接修改代码。
develop 分支
- develop为开发分支,通常情况下,保存最新完成以及bug修复后的代码。
- 开发新功能时,feature分支都是基于develop分支下创建的。
feature分支
- 开发新功能,基本上以develop为基础创建feature分支。
- 分支命名:feature/ 开头的为特性分支, 命名规则: feature/user_module、 feature/cart_module。
**这点我深有体会,我在网易,mentor就是这么教我的,**通常建一个feature分支。
release分支
- release 为预上线分支,发布提测阶段,会release分支代码为基准提测。
hotfix分支
- 分支命名:hotfix/ 开头的为修复分支,它的命名规则与 feature 分支类似。
- 线上出现紧急问题时,需要及时修复,以master分支为基线,创建hotfix分支,修复完成后,需要合并到master分支和develop分支