版本控制系统演进历史
1. 本地版本控制系统(解决个人的版本管理)
最早时期,版本控制的解决方案一般都是将文件备份,并根据时间或者其他标志做备份。这种方式虽然简单方便,但是当文件数量增多,项目结构复杂的时候,就很容易出错。为了解决这个问题,就出现了VCSS,他可以保留所有文件的版本到简单数据库中。
比如,小说的多个修订版本。
2. 集中式版本控制(SVN)
一个系统不可能一个人员单独开发,个人的版本管理虽然得到了解决,但是当需要多名开发者之间合作市,个人版本控制管理工具就显得力不从心。为了解决这个问题,出现了集中式版本控制系统(CVCs),比如CVS、Subversion和Perfore。集中式版本控制系统中,分为服务端与客户端,所有文件的版本历史以及版本号(一个数字)存储到服务端中,也就是代码仓库。众多客户端从这个server上检出文件(只有文件版本,没有仓库的概念)。
集中式版本控制的主要缺点是中央服务器单点故障,Server的故障,有可能造成长时间代码无法提交、甚至是代码丢失、代码版本历史丢失的情况。
3. 分布式版本控制(Git)
针对集中式版本控制的缺点,演变了分布式版本控制(DVCSs),分布式版本控制不只是检查出文件的最新快照,还会将文件的历史版本完全克隆到本地中。如果远程服务器出现问题,任何客户机的仓库都可以克隆被分到远程仓库中。并且,当Server宕机时,完全不影响代码的commit、reset。
Git 与 SVN 的主要区别
- Git是分布式版本控制系统、SVN是集中式版本控制系统
- 由于Git是分布式版本控制系统,拥有本地仓库,所以Git的大部分操作都可以在离线环境下完成,而SVN严重依赖中心仓库。
- Git在存储文件历史时,存储的是完整的文件,而SVN存储的是文件中的差异。所以,Git可以reset文件到指定的版本,而SVN只能获取差异并重新提交。
- Git 的分支功能使用更优雅
- Git速度更快、效率更高
Git的本地结构
Git作为分布式版本控制系统,主要分为三个部分:
- 工作区:写的代码文件都存储在工作区中
- 暂存区:已经添加到版本控制中,但是暂未提交
- 本地库:每个客户端都是一个代码仓库,代码的修订历史
工作区代码通过 git add
命令讲代码提交到暂存区,暂存区通过命令git commit
提交代码到本地库。
本地库和远程库交互
远程库就是代码托管中心,常见的公共远程库有:Github、Gitee公共代码远程库,可以通过因特网访问的代码仓库。 大部分公司采用私有远程库:在内网环境下搭建Gitlab。
远程库可以让团队内部协同开发:
也可以通过fork和pull request完成跨团队合作:
安装Git
ubuntu:sudo apt-get install git-core
查看git版本
git --version
配置Git
根据邮箱、用户名区分提交人:
- 配置用户名:
git config --global user.name "Feathers"
- 配置邮箱:
git config --global usr.email "616510229@qq.com"
- 检查配置:去除上述命令双引号部分即可
本地库常用操作
git init 创建本地库
进入项目根目录 输入命令 git init
,即可创建代码仓库,用于存储代码的修订版本。仓库创建完成后,会在项目根目录下生成一个隐藏的.git
文件夹,这个文件夹用来记录本地所有的git操作。
git add 在工作区编写代码,并将代码提交到暂存区
使用add
命令将想要提交的代码添加到暂存区,比如git add src
,将现在所在的文件夹的src目录以及他的所有文件提交到git上。
git commit 将暂存区代码提交到本地库
git commit -m "First commit."
这样就将代码提交到了本地库中。
commit 命令的 -m 参数用来加上提交的描述信息,没有描述信息的提交是不合法的。
git status 查看本地库状态
刚刚创建好的本地仓库:
当前位于主分支
On branch master
# 初始化提交
Initial commit
# 没有东西需要提交(暂存区中无内容)
nothing to commit (create/copy files and use "git add" to track)
创建一个A.txt:
On branch master
Initial commit
# 未被追踪的文件,A.txt未被添加到暂存区
Untracked files:
(use "git add <file>..." to include in what will be committed)
A.txt
执行 git add ./A.txt,将其加入到暂存区,并且新建一个B.txt:
On branch master
Initial commit
# 改变将会被提交,暂存区内容:
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
新增一个A.txt
new file: A.txt
未被加入到暂存区的文件
Untracked files:
(use "git add <file>..." to include in what will be committed)
B.txt
执行git commit -m "xx" 将代码提交到本地库:
On branch master
这里没有了 Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
B.txt
git log 查看版本历史
查看当前仓库的提交历史git log
:
commit b4ab945918e01583f2f0e130b72dcee2269df75a 提交id
Author: Feathers <616510229@qq.com> 作者
Date: Sun Jul 12 14:55:05 2020 +0800 提交时间
test 注释参数
commit 70138ca4487d1f35f518fa08bd2e4e80e17fbbe5
Author: Feathers <616510229@qq.com>
Date: Sun Jul 12 14:43:27 2020 +0800
<E6><8F><90><E4><BA><A4><E5><88><B0><E6><9C><AC><E5><9C><B0><E5><BA><93> 注释参数:这里是中文乱码,需要设置控制台编码
过多条数使用空格到下一页,按B返回上一页,按q退出
查看单个文件提交记录:
git log ./A.txt
pretty展示:
git log --pretty=oneline
b4ab945918e01583f2f0e130b72dcee2269df75a test
70138ca4487d1f35f518fa08bd2e4e80e17fbbe5 <E6><8F><90><E4><BA><A4><E5><88><B0><E6><9C><AC><E5><9C><B0><E5><BA><93>
online展示:
对提交索引七位截取
git log --oneline
b4ab945 test
70138ca <E6><8F><90><E4><BA><A4><E5><88><B0><E6><9C><AC><E5><9C><B0><E5><BA><93>
git reflog,展示指针当前历史版本,需要走的步数:
git reflog
b4ab945 HEAD@{0}: commit: test
70138ca HEAD@{1}: commit (initial): <E6><8F><90><E4><BA><A4><E5><88><B0><E6><9C><AC><E5><9C><B0><E5><BA><93>
回退到 70138ca 指针需要走1步
git reset 恢复代码到某一版本
查看代码版本:
git reflog
b4ab945 HEAD@{0}: commit: test
70138ca HEAD@{1}: commit (initial): <E6><8F><90><E4><BA><A4><E5><88><B0><E6><9C><AC><E5><9C><B0><E5><BA><93>
想将本地代码撤回到仓库最新版本(移动指针0次): `git reset --hard b4ab945`
湘江本地代码撤回到仓库的上一个版本(移动指针1次,到达指定指针): `git reset --hard 70138ca`
以此类推
–hard参数:git reset --hard [索引]
,本地库指针移动时,重置暂存区重置工作区(将对应版本的代码修改到工作区和暂存区中) 最常用,执行结束后,会发现工作区代码就是指定版本的代码。
–mixed参数:git reset --mixed
,本地库指针移动时,重置暂存区,但是工作区不动
–soft参数:git reset --soft
,本地库指针移动,不重置暂存区和工作区
撤回到上次提交:git reset --hard HEAD
git diff 比较
比对工作区与暂存区的所有不同:
git diff
比对工作区与暂存区某一文件的区别:
git diff Test3.txt
比较暂存区与本地库之前的区别:
# git reflog 查看要比较的版本,本地库最新版本指针为HEAD
git diff HEAD
比较暂存区与指定版本本地库之间的区别:
git diff 39a0d42
比较暂存区与指定版本本本地库的指定文件的区别:
git diff 39a0d42 Test3.txt
git branch 分支
分支有效的降低了版本之间的耦合。
建立一个分支
git branch v1.0
查看分支列表与当前分支
git branch -v
星号代表当前分支。
切换分支
git checkout v1.0
合并分支
# 首先进入分支 master
git checkout master
# 然后使用merge命令讲其他分支合并到主分支
git merge v1.0
解决合并冲突
合并分支时,有可能出现代码冲突:
查看Test.txt:
使用文本工具修改Test4.txt,然后重新讲修改后的内容,添加到暂存区:
使用commit操作,推出merging状态:
删除分支
git branch -D v1.0
tag 标签
打标签。和其他VCS类似,Git也可以对某一时间点上的版本打上标签。们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做。
显示已有的tag
显示此仓库所有的tag:
$ git tag
v0.1
v1.3
筛选tag:
$ git tag -l 'v1.4.2.*'
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
切换到某个tag
$ git checkout v0.1
注意:如果你的当前仓库含有未提交的内容,需要提交后才可以切换tag,否则会出现以下的错误提示:
λ git checkout dubbo-2.7.0
error: Your local changes to the following files would be overwritten by checkout:
dubbo-admin/src/main/webapp/WEB-INF/dubbo.properties
dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java
Please commit your changes or stash them before you switch branches.
打一个tag
git tag -a 0.1.3 -m “Release version 0.1.3″
# -a 标签名称
# -m 标签注释
提交tag到远程
git push origin --tags
删除tag
git tag -d 0.1.3
删除远端服务器tag
git push origin :refs/tags/0.1.3
与远程版本库协作
首先创建本地库与远程库,仓库名称最好保持一致。 如何选择开源协议?
将本地库推送到远程库
# 进入本地库, 指定远程仓库地址与要push的分支
git push http://github.com/example/test.git master
给远程仓库设置别名
在推送代码时,远程仓库地址较长,可以为其设置别名,方便提交:
# 查看别名
git remote -v
# 增加一个别名
git remote add origin http://github.com/example/test.git
现在,你可以通过orign 替代远程库的地址了,比如上面的push操作可以替换为git push origin master
。
克隆远程库代码到本地
如果电脑中没有本地库,需要将远程库代码完整的克隆到本地:
# 克隆下来的本地库,有一个origin的别名,对应远程库的地址
git clone http://github.com/example/test.git
拉取远程库代码的修改
远程库代码可能被团队其他人员修改,需要抓取远程库某一分支的代码:
# 下载远程库代码到本地,但不会更新到工作区(所以抓取之后看不到更改)
git fetch origin master
查看远程分支的修改,确保远程分支修改正确:
# 切换到远程仓库origin的主分支代码
git checkout origin master
合并远程主分支到本地分支:
# 切换到本地主分支
git checkout master
# 合并分支
git merge origin/master
使用pull代替fetch+merge拉去远程代码的修改:
git pull origin master
--set-upstream-to
使用–set-upstream-to将本地分支与远程分支关联,这样在执行git pull 以及 git push 时就无需指定远程分支了:
git branch --set-upstream-to master origin/master
git pull
git push
跨团队合作
假设与A公司与B公司合作,B公司要需要在A公司代码上进行开发。
在Github/Gitlab上Fork A公司的远程库,将会将代码仓库同步到B公司上。B公司员工将会把代码clone到本地,然后在本地库上开发。B公司员工开发完毕,将代码提交,并将代码oush到B远程库。
开发完毕后,在远程库中进行pull request操作:
A公司的仓库将会接收到pull request (求拉代码)的请求:
对B公司的修改进行具体的审核:
审核通过,代码就完成了合并:
远程库其他操作
让团队人员加入项目
Github:
免密登录 ssh key
生成公私钥:
ssh-gen -t rsa -C 616510229@qq.com
# 然后进行三次回车
将会在home目录下生成 .ssh/id_rsa
(私钥),.ssh/id_rsa_pub
(公钥),打开公钥文件,并且复制,将其设置到远程仓库中: