Git 版本控制
-
什么是 Git
Git 是当今世界上最先进/最好用的分布式版本控制系统,没有之一 -
什么是版本控制系统?
版本控制 — 《维基百科》
版本控制是一种软件工程技巧,能在软件开发的过程中,确保由不同人所编辑的同一个代码文件都得到同步.
版本控制能使项目的设计者,将项目恢复到之前任意的状态,这种选择权在设计过程中特别重要.
理论上所有的信息记录都可以加上版本控制:利用版本控制来追踪、维护源码、文件以及配置文件等等的改动 -
版本控制发展史
3.1 文件名方式
早年的软件开发过程,代码管理以手动和邮件等形式,文件命名及保存存在问题
如图 : 文件命名方式
文件命名
如图 : 毕业论文版本
文件名控制版本
3.2 集中式
包括库和工作区两部分:在工作区编码,然后上传至库的方式,完成多人协作。
问题:工作机与库机,需要联网才能控制版本,传输速度较慢。
集中式版本控制
3.2 分布式
每台电脑都有,工作区和库,可以自己控制版本。数据更加安全,有逻辑上的中心。
分布式版本控制
- 常见版本控制系统
如图 : 版本管理器的发展史
版本管理器的发展史
这张图上,分成了四个时期 :
● 史前时期:1982年的RCS。现在你可能还能在Unix的发布包中找到它。
● 古典时期:1990年的CVS自身缺陷已经过时;1985年的PVCS、1992年的clearcase(费用昂贵、功能复杂沿用至今);微软VVS反人类;Perforace(广泛,谷歌内部最大代码管理器)
● 中世纪时期:SVN解决了CVS的问题,集中式领域王者。AccuRev(支持分支合并让很多公司拜托cvs和clearcase)。
● 文艺复兴:BitKeeper(SUN公司大量使用),2002年Linux内核使用BitKeeper,2005年闭源时有人试图破解BitKeeper,于是出现了Git。
Git 问世
Git的第一个版本是Linux之父Linus Torvalds亲手操刀设计和实现的(两周内 用C写完),Linus不仅仅给出一个原始设计,并在向世人介绍Git时强烈批评了CVS和SVN等,Git消除了分支和合并的恐惧。很多大型开源项目由SVN迁移至Git。
2008年GitHub也成为世界最大的SCM系统(软件配置管理),它使用的就是Git版本库的技术.从此Git成为版本控制系统的主流。
GitHub上的著名项目 :
Linux内核、安卓、jQuery、Bootstrap、Ruby …
- Git 的安装 和 基本配置
5.1 安装
Linux 安装
二进制包(在线)
yum -y install git // RedHat系列
apt-get git install // Debian系列
源码包(官网下载)
Windows 安装
Git 在 Windows 使用模拟环境 msysgit
下载地址:
https://git-for-windows.github.io/
注意:如果想让 windows 作为 git 服务器则需要搭建ssh服务。
本教程使用 windows 版本来做演示 :
安装步骤: (如果你不熟悉每个选项的意思,请保持默认的选项)
以管理员方式运行安装包,选择 是 安装
安装00
同意协议条款
安装01
选择安装选项: 安装Git Bash和Git GUI,创建图标(可选)
安装02
选择 Git 的默认编辑器 (默认为vim,可选取自己熟悉的编辑器)
安装03
选择: git form the command line and also form 3rd-party software (GIT命令行和第三方软件)
安装04
选择: 选择 OpenSSL 传输 HTTPS 的信息
安装05
选择 : 换行符默认为 windows 环境为主
安装06
选择 : MinTTY 默认终端
安装07
选择 : 系统文件缓存 和 git 的管理器(需要.net v4.5.1)
安装07
实验选项,暂不选择
安装09
点击 Install 安装,开始安装
安装10
安装完成,选择运行git bash工具
安装11
Git 运行界面 (命令行提示的是 你电脑的用户名)
安装12
5.2 配置
无论 Linux 还是 Windows,安装完成后都要初始化
查看 git 版本
git --version
查看配置
git config -l
设置用户名和邮箱
git config [–global] user.name “Your Name”
git config [–global] user.email “your@email.com”
中括号内的参数:
–local 本地
–system 系统
–global 全局
无参,则为当前库配置身份
如:
git config --global user.name “seeker”
git config --global user.email “3300696254@qq.com”
6. Git常用操作
6.1 生成新的版本库
新建空目录
进入该目录—单击右键—选择 Git Bash Here
弹出 git 的命令行工具
初始化该目录为版本仓库,键入 git init
显示 Initialized empty Git repository in xxxxxx
ls -a 查看该目录下出现.git的隐藏目录,即版本库
初始化完成
6.2 添加文件到版本库
新建文件 1.txt
查看当前版本状态
查看当前版本状态
git status
红字提示有文件未跟踪(未加入版本控制)
在命令行内输入以下,添加文件至版本库:
添加文件至缓存区
git add 1.txt
再次查看版本库状态
git status
提示有要提交的修改,有一个新增的文件
提交文件至版本库
# 直接提交
# 回车后,会打开指定的编辑器编写描述信息
git commit
# 填写完描述信息,保存关闭即可
# 或者带参数 -m 直接写入提交的描述信息
git commit -m "新增1.txt"
新建 2.txt / 3.txt
多文件添加
git add 2.txt 3.txt
将缓存区的多次添加一次提交
git commit -m “新增2.txt+3.txt”
ps:
添加所有改动过的和新增的文件到缓存区 (不包括被删除的文件)
git add .
添加所有文件到缓存区
git add --all
git add -A
执行完后,提示提交完成
查看提交后的版本库状态:
$ git status
On branch master
nothing to commit, working tree clean
至此,最简单的添加文件,到版本库的操作已完成
— PS部分: Git 实现原理 —
工作区 : 就是程序员日常编写代码的文件夹
版本库 : 负责代码版本控制,就是.git隐藏目录
版本库原理图 :
版本库原理
版本库包括:暂存区(index/stage),HEAD(指针),分支(默认为 master 主分支)等。
文件提交至版本库总共分两步:
git add filename # 添加至 stage 缓存区
git commit -m “描述” # 将 stage 的内容提交至版本库的 master 分支
实验:
修改文件 >>> 查看状态
添加到缓存区 >>> 查看状态
再次修改 >>> 提交 >>> 查看状态
实验过程如下,观察理解 Git 实现机制:
修改文件 >>> 查看状态:
修改1.txt文件的内容,添加一行111,查看状态:git status
提示:Changes not staged for commit: (工作区的修改,还没有提交到缓存区)
显示红字,modified: 1.txt
添加到缓存区 >>> 查看状态:
添加到缓存区git add .
查看状态:git status
提示:Changes to be committed (要提交的修改。表示已提交到缓存区,待提交到版本库)
显示绿字:modified: 1.txt
再次修改 >>> 提交 >>> 查看状态
继续修改文件:1.txt文件的内容,添加一行222
提交版本库:git commit -m “第1次修改 1.txt”
再次查看状态:git status
提示:Changes not staged for commit(表示工作区中,还有修改记录,没有被提交到版本库之中)
显示红字:modified: 1.txt
说明:
第 3 步的提交,只是提交了缓存区内,已经缓存过的内容(即,第二步的add .操作)
第 3 步中的第二次修改文件内容的记录,并没有添加到缓存区,所以版本库与工作区文件不一致
此时需要将第二次的修改记录,添加到缓存区,再次提交即可
git add.
git commit -m ‘第2次修改 1.txt’
git status
6.3 查看文件修改状态相关
查看当前版本状态(是否修改)
git status
修改文件,测试区别:
当 工作区/缓存区/版本库 都一致时,使用以下命令不会有任何提示
git diff # 工作区 与 缓存区的区别
git diff --cached # 缓存区 与 版本库的区别
git diff HEAD # 工作区 与 版本库的区别
更改工作区的 1.txt,并将更改添加到缓存区
然后再次更改工作区的 1.txt,并保存文件的更改
再次测试以上三条命令
6.4 Git 日志
查看提交历史
git log
以简短的方式查看提交日志
git log --oneline
行为日志,显示所有提交,回滚等…
git reflog
显示缓存区的所有文件
git ls-files
6.5 版本回退
将当前版本重置为 HEAD(通常用于清空缓存区,或 merge 失败回退)
git reset --hard HEAD
git reset --hard HEAD^ # 回退上一个版本
git reset --hard HEAD^^ # 回退上两个版本
git reset --hard HEAD~n # 回退上n个版本
回退到指定版本,commitid 可根据日志获取,’<>'内的id必填
git reset --hard
6.6 撤销
目的:将尚未提交至版本库的修改撤回
情况一 : 文件修改后,尚未添加至缓存区
修改 1.txt 的内容:添加一行
在工作区撤销文件的修改
git checkout – filename
注意’–‘不可缺少。没有’–’,就变成了“切换到另一个分支”的命令
情况二 : 文件修改后,已添加至缓存区
修改 1.txt 的内容:添加一行,并添加到缓存区
撤回添加至缓存区的修改
git checkout HEAD filename
6.7 Git 删除
删除文件和版本库记录
rm
命令只会删除工作区的文件,不会删除记录
rm 2.txt
git status # 提示2.txt 被删除,是否需要提交到版本库
如果删错文件,则可以撤回删除(因为此时的删除操作,还未写入到缓存区)
git checkout – 2.txt
将 2.txt 的删除记录写入到缓存区,并删除文件
git rm 2.txt
如果还未提交,想要撤回,可使用 git checkout HEAD 2.txt
提交 2.txt 的删除记录到版本库中
git commit -m ‘删除2.txt’
删除缓存区的文件
新建 demo.html 文件,并加入到缓存区
git add demo.html
git status # 提示有新文件等待提交
将 demo.html 文件移出缓存区,但不删除(文件还会保留在工作区)
git rm --cached demo.html
git status # 提示工作区有文件等待 add
重新将 demo.html 加入到缓存区
将缓存区中的 demo.html 文件移出并删除(工作区不保留文件)
git rm -f demo.html
其他删除
新建 aaa/111.txt
新建 aaa/bbb/111.txt
将文件添加到版本库中
git add .
git commit -m ‘添加aaa目录及文件’
递归删除目录(删除的是,已被记录到版本库的目录)
git rm -r 目录名
git commit -m ‘删除aaa目录’
6.8 Git 流程图
Git流程图
- 远程仓库
7.1 得到远程的版本库
可以使用两种方式来得到远程版本库:
在某个指定的文件夹下使用,即可得到远端版本库及代码
git clone <远端版本库url> <本地存放该库的文件夹名>
手动添加版本库,并拉取文件
初始化本地仓库
git init
添加远程版本库 可自行取名,默认origin
git remote add
查看远程版本库信息
git remote -v
查看指定远程版本库信息
git remote show
删除远程remote链接
git remote remove
下载代码及快速合并
git pull
7.2 推送分支代码
得到远端版本库后,可以在本地按正常的步骤编辑 :
新建或改动文件–>添加至缓存区–>提交到版本库
此时,要想将本地版本库发给远端,只有commit提交是不够的.
还需要下面的操作 :
git push
上传代码及快速合并
执行以上代码,会有报错 : 无法直接推送到远端的主分支
此时,可以曲线救国,推送自己的分支到远端即可 :
git push origin master:dev
此时,推送成功!
- Git 分支管理
8.1 查看版本库分支
显示本地分支
git branch
显示所有分支
git branch -a
切换到指定分支或标签
git checkout 分支名/标签名
8.2 创建分支/删除分支
新建分支
git branch 分支名
创建并切换到dev分支
git checkout -b dev
删除本地分支 -D 强制删除
git branch -d 分支名
8.3 合并分支
要将 B分支 合并到 A分支里
请切换到A分支内,合并B分支的操作在A分支内进行
合并分支到当前分支
git merge 分支名
8.4 解决合并冲突
多分支修改同一文件,合并可能出现冲突。冲突部分用<<<===>>>表示
合并冲突
解决方法:
先手动修改冲突部分,再次提交即可。
8.5 分支管理策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
分支管理
8.6 多人协作
多人协作的工作模式通常是这样:
首先,可以试图用git push origin 推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
- 使用代码托管系统
市面上有名的Git托管系统 :
GitHub
码云
CODING
9.1 码云 生成SSH密钥及使用
本地打开git bash ,cd切换到用户的家目录
使用pwd来查看目录是否正确
使用 ssh-keygen.exe -t rsa 来生成SHA256的SSH密钥(按回车确认即可)
cd .ssh/ 切换至ssh目录
ls 查看目录下文件
cat id_rsa.pub 查看生成的密钥,并复制
打开码云,登录自己的账户.点选个人资料
选择SSH公钥
在添加公钥界面,将刚刚复制好的密钥粘贴进来,再自己取一个该密钥的名字,以便于区分管理
本地新建一个目录,用于拉取远端版本库
使用 git init初始化该目录
使用git remote add origin <SSH地址> 来添加远程版本库
使用git remote -v 来查看远程版本库信息
使用git pull origin marster来拉取版本库及代码
9.2 GitHub 生成SSH密钥及使用
运行 git Bash 客户端,输入如下代码:
$ cd ~/.ssh
$ ls
这两个命令就是检查是否已经存在 id_rsa.pub 或 id_dsa.pub 文件,如果文件已经存在,那么你可以跳过步骤2,直接进入步骤3
创建一个 SSH key
$ ssh-keygen -t rsa -C “your_email@example.com”
代码参数含义:
-t 指定密钥类型,默认是 rsa ,可以省略。
-C 设置注释文字,比如邮箱。
-f 指定密钥文件存储文件名。
添加你的 SSH key 到 github上面去
$ cat ~/.ssh/id_rsa.pub
测试一下该SSH key 在git Bash 中输入以下代码
$ ssh -T git@github.com
显示类似如下,表示成功:
Hi username! You’ve successfully authenticated
git clone 远程git仓库地址
10. 文件忽略
想要工作区的某些文件,不受版本的控制,可使用.gitignore文件进行忽略.
!(注意, .gitignore文件 是没有名字的文件.)
规则:
以斜杠 / 开头表示目录
以星号 * 通配多个字符
以问号 ? 通配单个字符
以方括号 [] 包含单个字符的匹配列表
以叹号 ! 表示不忽略(跟踪)匹配到的文件或目录
配置文件是按行 从上到下 进行规则匹配的,
这就意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效.
- 使用 TortoiseGit 操作 Git
TortoiseGit 俗称 [ GIT小乌龟 ]
Git 常用命令速查
master 默认主分支
dev 默认开发分支
创建版本库
初始化本地git版本库(创建新仓库)
git init
配置用户名
git config --global user.name “xxx”
配置邮件
git config --global user.email “xxx@xxx.com”
#查看当前配置列表
git config --list
clone远程仓库
git clone
修改、提交、删除
添加index.php文件到缓存区
git add index.php
添加所有改动过的文件到缓存区
git add .
添加所有文件到缓存区
git add --all
提交缓存区内的文件(回车后需要键入描述:wq保存退出)
git commit
提交缓存区内的文件,并提供描述
git commit -m “描述”
将add和commit合为一步
git commit -am ‘描述’
合并最后一次提交(用于反复修改)
git commit --amend -m ‘xxx’
删除index.php文件
git rm index.php
将index.php文件移出缓存区,但不删除( -r * 递归目录)
git rm --cached index.php
将缓存区中的1.html文件移出并删除
git rm -f 1.html
查看
查看当前版本状态(是否修改)
git status
查看所有添加到缓存区的变更(工作区与版本库的区别)
git diff
查看工作区文件和库文件区别
git diff index.php
查看所有已添加到缓存区,但还未commit的变更(缓存区与版本库的区别)
git diff --cached
查看提交历史
git log
以简短的方式查看提交日志
git log --oneline
行为日志,显示所有提交,回滚等…
git reflog
显示缓存区的所有文件
git ls-files
回退 与 撤销
将当前版本重置为HEAD(通常用于merge失败回退)
git reset --hard HEAD
git reset --hard HEAD^ # 回退上一个版本
git reset --hard HEAD^^ # 回退上两个版本
git reset --hard HEAD~n # 回退上n个版本
回退指定版本,commitid根据log获取
git reset --hard
在工作区撤销文件的修改
git checkout --filename
撤回添加至缓存区的修改,不指定filename则撤回所有
git checkout HEAD [filename]
分支操作
获取远程分支master并merge到当前分支
git pull origin master
显示本地分支
git branch
显示所有分支
git branch -a
切换到指定分支或标签
git checkout 分支名/标签名
新建分支
git branch 分支名
删除本地分支 -D 强制删除
git branch -d 分支名
远程协作
添加远程版本库
git remote add
查看远程版本库信息
git remote -v
查看指定远程版本库信息
git remote show
删除远程remote链接
git remote remove
重命名远程链接名
git remote rename
下载代码及快速合并
git pull
上传代码及快速合并
git push
将本地的远端库合并
git merge origin master
将远端库获取本地但不合并
git fetch origin
更多信息,详见: Pro Git(中文版)