1. 原始的版本控制
1.1 版本控制的起源:diff与patch
diff:diff是用来比较两个文件或目录之间的差异
patch:patch是diff的反向操作
$ patch left.c diff.txt
//将left.c中的内容修改成right.c的内容
1.2 RCS版本控制攻击
RCS只适合本地操作;
CVS集中式版本控制
CVS存在的问题:不支持原子化操作,会导致客户端向服务端提交不完整的数据,网络传输效率也比较低下。
SVN
优化了服务端内容上的存储,支持原子提交。只能使用局域网,会造成很大的时延性。
集中式版本控制存在的问题:
狭窄的提交通道:
- 提交排队,不能同时修改,提交缺乏质量控制。
- 缺乏代码门禁,在本地代码提交到服务器之间缺乏检查防护(解决方法是:rietveld 提供旁路检查)
数据安全性差
- 单点故障
- 黑客攻击
1.3 Git起源
bitkeeper是作为Linux内核的代码管理工具。
1)集中式与分布式区别在于记录差异还是记录快照;
- 集中式记录的是差异
- 分布式记录的是快照
2)脆弱的中央库和强壮的分布库
脆弱的中央库:
- 备份数据的重要性(存在单点故障,备份极其重要)
- 服务器压力(基本上所有的操作都需要与服务器交互,操作受限于带宽,不能移动办公)
- 安全性(集中式CVS假定服务器是安全的,存在黑客攻击)
- 不适合开源项目(强调集中式管理,适合人数不多的项目)
强壮的分布式
- 全是服务器(数据最安全,无带宽和性能瓶颈)
- 提交为本地操作(快,全离线操作,编码不会被冲突打断;能够移动办公)
- 数据的完整性(Git数据,提交全部使用SHA1哈希,确保完整,甚至提交可以使用PGP签名)
- 工作模式(适合分布式开发,强调个体)
SVN与Git适用的领域:
SVN不适合场景:
- 跨地域的协同开发;
- 对代码高质量追求和代码门禁
Git不适合场景:
- 不适合Word等二进制文档的版本控制(因为Git无锁定/解锁模式,故不能排他式修改)
- 不能将读授权精细到目录级别(解决方案,版本库按照目录拆分)
Git 结语
2 Git安装和配置
Linux系统下安装Git
// Ubuntu
$ sudo aptitude install git
$ sudo aptitude install git-doc git-svn git-email gitk
//RHEL、Fedora、CentOS
$ yum install git
$ yum install git-svn git-email gitk
从源码开始安装
$ tar -jxvf git-2.19.0.tar.bz2
若将git安装再/user/local/bin中可以使用如下指令
$ make prefix=/usr/local/ all
$ sudo make prefix=/usr/local install
安装git文档
$ make prefix=/usr/local doc info
$ sudo make prefix=/usr/local install-doc install-html install-info
命令补全
Linux的shell环境通过bash-completion软件包提供命令补齐功能,能够实现在录入命令参数时按一下或者两下TAB键,实现参数的自动补全或提示。例如输入 git com后按下TAB键,会自动补齐git commit。将Git源码包中的命令补全脚本复制到bash-completion对应的目录中:
$ cp contrib/completion/git-completion.bash /etc/bash_completion.d/
重新加载自动补全脚本,使之在当前shell中生效
$ ./etc/bash_completion
为了能够在终端开启时自动加载bash_completion脚本,需要在本地配置文件 ~/.bash_profile 或全局文件 /etc/bashrc 文件中添加下面的内容:
if [ -f /etc/bash_completion ]; then
./etc/bash_completion
fi
Windows下安装Git
Git 基本配置
git有三种配置,分别以文件形式存放在三个不同的地方。可以在命令行中使用git config查看这些变量。
- 系统配置(对所有用户都适用) 存放在git的安装目录下:%Git%/etc/gitconfig 若使用git config时用–system 选项,读写的就是这个文件:git config --system core.autocrlf
- 用户配置(只适用于该用户) 存放在用户目录下。例如linux存放在:~/.gitconfig;若使用git config时用–global选项,读写的就是这个文件:git config --global user.name
- 仓库配置(只对当前项目有效)当前仓库的配置文件(也就是工作目录中.git/config文件);若使用git config时用–local选项,读写的就是这个文件:
git-config --local remote.origin.url
配置个人身份
首次的Git设定
git config --global user.name “zhang san”
git config --global user.eamil zhangsan123@huawei.com
这个配置信息会在Git仓库中提交的修改信息中体现,但和git服务器认证使用的密码或者公钥密码无关
文本换行符
$git config --global core.autocrlf true
git提交时会将CRLF转换成LF
与服务器的认证配置
常见的两种协议认证方式
- http/https协议认证
设置口令缓存
git config --global credential.helper store
添加HTTPS证书信任
git config http.sslverify false
- ssh协议认证
SSHx协议是一种非常常用的Git仓库访问协议,使用公钥认证,无需输入密码,加密传输,操作便利又保证安全性
SSH认证的配置过程
生成公钥:
Git工具安装成功后运行Git Bash,在弹出的客户端命令行界面中输入下面的提出的命令。
生成公钥举例:
添加公钥到代码平台:
1、登录代码平台
2、进入”Profile Settings“
3、点击左侧栏的”SSH Keys“
4、点击”Add SSH Key“,将刚生成的公钥文件内容,复制到”Public Key“栏,保存即可
本章小结
Git命令
Git版本控制下的工程区域只有三种
1、版本库(Repository)
在工作区有一个隐藏目录git,这个文件夹就是Git的版本库,里面存放Git用来管理该工程的所有版本数据,也叫本地仓库
2、工作区(Working Directory)
日常工作的代码文件或者文档所在文件夹
3、暂存区(stage)
一般放在工程根目录.git/index文件中,所有我们也可以把暂存区叫作索引(index)
Git版本控制下的文件状态只有三种:
1、已提交
该文件已经被安全地保存在本地数据库中了
2、已修改
修改了某个文件还没有提交保存
3、已暂存
把已修改的文件放在下次提交时要保存的清单中
Git常用命令
工程准备
Git clone用于克隆远端工程到本地磁盘
如果想从远端服务器获取某个工程,那么:
1、确定自己的Git账号,下载该工程的权限
2、获取该工程的Git仓库URL
3、本地命令行执行git clone [URL] 或 git lfs clone [URL]
如果所在的项目git服务器已经支持git-lfs,对二进制文件进行了区别管理,那么克隆工程的时候务必使用git lfs clone 否则克隆操作无法下载到工程中的二进制文件,工程内容不完整。
在提交你修改的文件之前,需要git add把文件添加到暂存区
如果该文件是新创建的,尚未被git跟踪,需要先执行git add将文件添加到暂存区,需要执行提交。如果文件已经被git追踪,即曾经提交过了,在早期版本git中,需要git add再提交,在新版本git中,不需要git add即可提交。
git rm 将指定文件彻底从当前分支的缓存区删除,因此它从当前分支的下一个提交快照中被删除。如果一个文件被git rm后进行了提交,那么它将脱离git追踪,这个文件在之后的节点不再接收git工程的管理
执行git rm后,该文件会在缓冲区小时,删除后执行git commit,效果一样
git mv移动文件,也可以用于重命名文件
git mv codehunter_nginx.conf config
重命名
git mv config/codehunter_nginx.conf config/new_nginx.config
查看工作区
git diff用于比较项目中任意两个版本的差异,也可以用来比较当前的索引和上次提交间的差异
当然它还有其他用途,在后文会进一步描述。
git status命令用于显示工作目录和暂存区的状态
git commit主要用来将暂存区里面的文件改动提交到本地的版本库中,这个提交动作是本地版中记录改动,不影响远端服务器。git commit一般需要附带提交的描述信息,常见的方法是:
git commit file_name -m "commit message"
如果要一次性提交所有在暂存区改动的文件到版本库,可以执行:
git commit -am "commit message"
git log 用于查看提交历史
git push将本地版本库的分支推送到服务器上对应的分支
常见格式:
git push origin branch_name
你的本地分支名可以与推送到远端的分支名不同
git push origin branch_name:new_branch_name
git branch 命令查看本地工程的所有git分支名称
"*"表示当前工作区所在的分支是master
如果想查看远端服务器上拥有哪些分支,执行git branch -r即可,返回的分支名带origin前缀,表示在远端
如果想查看远端服务器和本地工程的所有分支,那么执行git branch -a即可
git branch 和 git checkout -b的异同
- 相同点:都可以用于新建分支(默认基于当前分支节点创建)
- 不同点:git-branch新建分支后并不会切换到新分支,而git checkout -b会自动切换到新分支
分支切换:使用 git checkout 分支名
删除分支的命令:git -branch -d branch_name
删除服务器上的远程分支可以使用git -d -r branch_name
删除后还需要推送到服务器才行,git push origin : branch name
git pull的作用 从远程服务器中获取某个分支的更新,再与本地指定的分支进行自动合并。
常见的切换分支命令格式:git pull origin remote_branch:local_branch
如果远程指定的分支与本地指定的分支相同,则可以直接执行git pull origin remote_branch
git fetch的作用,从远端服务器中获取某个分支的更新到本地仓库,与git pull不同,并不会进行合并操作。这样能留给用户一个操作空间,git fetch origin remote_branch:local_branch 如果远程指定的分支与本地指定的分支相同,则可以直接执行 git fetch origin remote_branch
git merge:是用于将指定的分支合并到当前分支的操作,git会将指定的分支与当前分支进行比较,找唱两者最近的一个共同节点base,之后将指定分支在base之后分离的节点合并到当前分支上。分支合并,实际上是分支间差异提交节点的合并。常用的切换分支命令格式:
git merge branch_name
git rebase:用于合并目标分支内容到当前分支,与前者git merge差异在于合并后对节点的影响有很大的差异。
git reset:通常用于撤销当前工作区中某些git add/commit 操作,可以将工作区内容回退到历史提交节点。常用的命令
git reset commit_id
git checkout . //用于回退本地所有修改而未提交的文件内容
git checkout . 这条是有风险的命令,这是因为他会取消本地工作区的修改,用暂存区的所有文件直接覆盖本地文件,达到回退内容的目的,但是它不给用户任何确认机会,所以谨慎使用。
- 如果仅仅想回退某个文件的未提交改动,可以使用git checkout -filename来达到目的;
- 如果想将工具区回退到某个提交版本,可以使用git checkout commit_id
shell命令
//将“readread”写入到READ.md文件中
echo "readread" >> READ.md
ls //查看文件
cat READ.md
使用git status查看状态 发现没有被git跟踪,需要将该文件添加到git中
git commit退出编辑步骤如下:
多了A 表示增加操作
如何推送到服务器
git push origin main
origin表示什么?
git remote用来查看服务器的名称
git push origin main表示:
把main分支推送到服务器名称为origin上
创建几个文件:
这个时候想要提交所有文件可以使用 git add .
即
git add .
提交所有文件到本地仓库可以使用:
git commit -am "new added files"
修改commit描述可以使用
git commit --amend
可以修改最近一次提交的内容
输入键盘中的”I“键,即input
接着摁下ESC 退出编辑模式,
:wq //保存退出
接着远端推送:
git push origin main
拉分支操作
git checkout -b zw/test1
查看详细的日志
git log --status-name
查看最近一次日志
git log -1
推送到远端服务器
查看本地分支:
git branch
查看远端分支
git branch -r
同时查看分支
git branch -a
如何将分支合并呢?
使用 merge commit
git main merge commit
也可以使用git rebase 但是不要在主干分支上使用git rebase,时间节点也会存在错误。
推送远端
使用 git diff查看区别
其中
git fetch + git merge = git pull
其中git fetch比较温和的从远端服务器拉文件到本地仓库,并不会合并数据
可以先使用git branch -a 查看所有的分支,即本地和远端的分支
接着使用 git fetch origin 分支名
使用git log查看相关的日志更新
使用git checkout 分支名 进行分支切换
git cherry-pick 语句作用
指定一个commit节点,并会生成新的commit id
分支合并过程中的冲突问题?
举个例子说明
假设在zhangwei/test1上对c.txt文件进行编辑并修改提交,同时对main上的c.txt文件也进行相同操作。
这个时候进行git merge操作,即:
git merge zhangwei/test1 main
会出现错误
解决方法,先看状态 git status
并进行修改c.txt文件,即:vim c.txt
双击del可以整行删
解决冲突
这个时候查看日志发现问题已经解决:
这个时候可以使用diff查看相应的分支差异,即:
撤销操作
git reset
也可以使用git checkout 文件来恢复为add到本地库的文件
比如read.md里面的内容发生了意外,被修改了,这个时候可以使用
git checkout read.md
git checkout . //恢复所有未提交的
使用git reflog查看近期操作指令
SSH配置项目密钥
首先使用
$ ssh-keygen -o -t rsa -b 4096 -C "1021010419@njupt.edu.cn"
使用cat命令读取加密密钥:
将其添加在gitlab的SSH认证密钥空白处即可。
接着就可以免认证克隆远端服务器的项目了:
如何管理仓库?
new group 创建组别
组别里面有相应的成员:Guest Reporter Developer Maintainer Owner
new project 创建项目
Fork仓库并创建Merge Request
Fork是派生的意思
点击代码合并请求
分支比较
变更内容
在合并请求下面查看内容
变更信息如下:
如何解决Merge Request冲突?
如何进行Merge Request代码检视?