Git学习
Git入门
概述
-
Git是什么?
Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理(档案馆)。区别于SVN:SVN是集中式的版本管理系统。
-
分布式和集中式有什么区别?
集中式就是所有人都只有一个档案馆,而分布式可以每个人都有一个档案馆
-
集中式版本控制(Centralized Version Control Systems,简称 CVCS)
优点:相较于老式的本地 VCS来说。 现在,每个人都可以在一定程度上看到项目中的其他人正在做些什么。 而管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。
缺点:中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据——包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。(只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险)
-
分布式版本控制(Distributed Version Control System,简称 DVCS)
在这类系统中,像 Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。
-
发展历程:
本地版本控制系统(VCS)——> 集中式版本控制系统(CVCS)——> 分布式版本控制系统(DVCS)
安装与配置(基于Linux)
1、下载安装
官方网站:https://git-scm.com/download/
sudo apt-get update
# 安装需要的插件
sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev
# 安装git
sudo apt-get install git
# 查看版本
sudo git --version
2、基础配置
2.1、首次使用添加身份说明
git config --global user.name "名字"
git config --global user.email "邮箱"
# 查看配置
git config --list --global
# 配置也可以在 ~/.gitconfig 或 /etc/gitconfig 看到
这个身份说明其实跟账号密码还是有区别的,它这个配置只是一个说明性的,只是留了一个标记而已,本质上填啥都可以
2.2、创建(克隆)仓库
两种情况:创建自己的仓库和使用其他人项目创建仓库
- 创建自己的仓库:
# 创建文件夹
mkdir gittest
# 创建版本库
git init
# 文件夹中出来一个.git文件夹,后续跟踪管理版本库
- 使用其他人的项目创建仓库:
# 复制其他人项目的路径
git clone url
当我们创建完仓库后,这个仓库中的每个文件都会有一个状态。如果自己新建仓库的话,那么这个仓库里所有的文件都是未被跟踪的,当你生成一个版本之后,这个未被跟踪的文件就不会在这个版本里。现在学习一下如何跟踪一个文件或者一个目录。
3、基本操作
3.1、跟踪文件(目录)
# 理论上跟踪某个文件后,在这个仓库中会一直跟踪该文件
git add <file-name>
# 可以使用以下命令取消跟踪(保存在本地目录中,但是不被跟踪)
git rm --cache <file-name>
# 同样,我们对文件进行修改之后,可以通过git add命令把它的状态设置为缓存(暂存)状态
git reset HEAD <file-name> # 取消文件的缓存状态
git commit -m "说明信息" # 文件暂存后,通过此命令提交此次修改
# 取消文件暂存(退回到已修改状态)
git restore --stage <file-name>
3.2、文件的4个状态
- 未跟踪:建好仓库,仓库里都是未跟踪状态的文件;已跟踪的文件可以通过git rm命令将其取消跟踪
- 未修改:通过git commit提交后,文件变成未修改状态
- 已修改:对跟踪的文件进行修改,文件变为已修改状态
- 暂存:通过git add可以将文件设置为暂存状态
3.3、查看文件状态
git status
# 红色表示修改了,没有暂存
# 绿色表示暂存了,没有提交
# 提交之后,就变成了一个新的版本
git diff # 可以查看更细致的东西
git log # 查看之前的提交历史
git log --pretty=oneline # 美化输出
git log --graph # 图形化输出
3.4、远程仓库的相关操作
git remote add <name> <url> # 链接远程仓库,并命名
git remote rename # 给远程仓库重命名
git push # 推送,此时直接推送,输入用户名和密码是无法通过验证的
# 通过ssh协议去健全
cd ~/.ssh
ssh-keygen -t rsa -C "Email" # 生成ssh密匙(-t是选择密匙的生成算法,此处使用rsa算法;-C添加评论,Github推荐填写邮箱)
# 后续直接回车即可,可以不用填写
# 随后会生成两个文件,一个是私匙(xxx),一个是公匙(xxx.pub)。
以gitee为例:
添加公钥之后,即可在本地通过git clone命令直接克隆了
3.5、分支(branch)
我们每次commit生成新版本的时候,都会生成一个提交对象,每一个提交对象都会有一个独一无二的哈希值,那么分支其实就是包含这个哈希值的一个文件。
我们其实可以简单理解为指向一个提交对象的指针,也就是说我们可以在一个提交对象上新建多个分支(因为分支是包含这个提交对象哈希值的文件)
当我们最开始初始化本地仓库时,我们就已经新建了一个 master 分支,我们每次的提交操作都是在这个 master 分支上进行的,当我们每次进行一个提交的时候,我们的分支也跟着我们的提交对象向前移动
假如说,此时重新在第二次提交对象上新建一个分支,然后我们在 master 分支上做一定的修改并提交一个新的提交对象;在新分支上也做一定的修改并提交一个新的提交对象。此时我们第二次提交对象上就会分出两个叉,其实这两个叉也就是我们的两个分支,这就是分支的概念。
为什么需要分支?
git-flow分支模型可以将分支分为两大类
- 核心分支: main、develop
- 辅助分支: feature/xxx, hotfix/xxx, release/xxx
核心分支:
在git-flow工作流模型中,核心分支main和develop是常驻分支。
- main分支: 长期/稳定分支,HEAD永远指向一个可发布的状态。
- develop分支: 长期存在的开发主分支,HEAD指向最新的、已经开发完成(可能未经完整测试)的状态。 develop分支是开发新特性的基础分支。当要开发一个新特性时,从develop分支checkout一个feature/xxx分支,开发完成后,再合并回develop分支。 develop分支上的代码会包含未被完整测试的代码,因此不可直接用于发布。
辅助分支:
辅助分支都是临时分支,使用完毕后就会被删除。
- feature/xxx: 开发新功能特性的分支,从develop分支checkout而来;开发完成后,或者merge回develop分支(明确该功能会被加入即将发布的版本),或者被丢弃。然后feature/xxx就被删除。
- release/xxx: release分支用于准备一个新的生产版本,release分支从develop分支而来,在release分支上修复测试过程的bug并被完成测试通过后,merge回develop分支或master分支。然后release/xxx分支被删除。 即release在提测和回归阶段使用。 hotfix分支用于对线上Bug进行热修复
- hotfix/xxx: hotfix分支用于对线上需要立即修复的严重Bug进行热修复,hotfix/xxx分支从master分支checkout而来,修复、测试完成后必须merge到develop分支和master分支。
操作流程:
开发新特性:
- 从develop分支checkout出来一个feature/xxx分支,
- 在feature/xxx分支进行特性开发和自测。
- 开发完成后,从feature/xxx分支将功能merge到develop分支。(需要做CodeReview),删除feature/xxx分支
- 从develop分支checkout一个release/xxx分支,用于测试和回归。
- 测试通过后,release/xxx合并回develop分支(如果还不能直接发布)或者master分支(达到可发布的状态);删除release/xxx分支。hotfix
- 从master分支checkout一个hotfix/xxx分支。
- 在hotfix/xxx上做Bug修复,修复完成(测试完成)后,merge到develop分支和master分支。
小结:
在feature分支里开发新特性并自测,自测通过后,可以把几个feature分支一起merge到develop分支。develop会收集各大feature分支。此时再新建release分支进行测试及功能验证,测试通过后,再将release分支合并进master分支。
如何操作分支?
# 查看所在分支
git log
git status
git branch --list # 绿色带 * 的就是当前分支
# 创建分支
git branch <分支名>
ex:
git branch feature
# 切换分支
git checkout <分支名>
git checkout -b <分支名> # 创建分支并切换到相应分支上
# 合并分支
git merge <分支名>
# 拉取远程仓库中的分支
git checkout --track <仓库名/分支名>
example:
git checkout --track <origin/feature1>
合并分支时,这样表面出现了冲突(两个分支修改了某个文件的同一个地方,Git不知道该保存那个丢弃那个),此时就需要自己去解决冲突。我们直接打开冲突文件:
等号上面表示当前路径对这个文件的修改,等号下面代表我们相应合并进来的分支对文件的修改。假如我们只想保存等号下面的修改,则将>>>>、<<<<、====这些符号以及遗弃的内容删掉即可。然后再进行跟踪以及提交
# 将文件推送到远程仓库
git push <仓库名> <分支名>
example:
git push origin master
git push origin feature # 可以推送到不同的分支
3.6、贮藏(stash)
当我们当前分支的文件修改后,需要去另外一个分支解决问题时,是无法直接切换的(当前工作区不干净)。于是我们需要先贮藏当前修改过的内容(贮藏之后当前工作区会变干净),然后切换分支。
git stash # 等价于 git stash push,贮藏
git stash apply # 恢复之前修改的内容
git stash list # 回看我们贮藏的内容
git stash不止可以贮藏一次,我们可以贮藏多次,例如:
{0}代表我们最后一次贮藏的内容,{2}是我们最开始贮藏的内容
# 恢复第一次贮藏的内容
git stash apply stash@{2}
3.7、重置(reset)
git reset head~ --soft
# head表示当前提交,head~表示上一次的提交,~后面可以加数字,代表倒数第几次的提交。soft代表我们只是撤销commit操作,没有撤销add操作
git reset head~ --hard
# 不仅将暂存取消了,修改的内容都会取消(不推荐使用)
3.8、变基(rebase)
比较类似于merge
如果我们在B分支,使用 git rebase A
命令,此时B分支上的修改就会移动到A分支上(相当于一次搬家操作)
// TODO
4、其他
对于Git中引用(Reference)的解释
如上图:
- HEAD -> br1,HEAD 是一个特殊的指针,它始终指向当前所在的分支或提交(commit)。在上述示例中,HEAD 指向 br1,表示现在位于 br1 分支上。
- origin/br1,br1 是一个分支名称,表示一个分支的引用。origin/br1 是一个远程分支的引用。它表示远程仓库 origin 中的 br1 分支。
- origin/master,代表是远程仓库 origin 中的 master 分支的引用。master 是远程仓库 origin 中的默认分支。
- origin/HEAD,origin/HEAD 是一个特殊的引用,通常用于指示远程仓库的默认分支。
如何将文件从暂存状态退回到已修改状态
如果你已经将文件暂存(使用 git add 命令),但希望将它们还原到已修改状态,你可以使用以下命令:
git reset HEAD <文件名>
这个命令将指定的文件从暂存区(即将被提交的区域)中移除,但保留在工作目录中的修改。这样就将文件退回到已修改状态,允许你重新检查和修改它们。
如果要撤销暂存区的所有文件,可以使用:
git reset HEAD .
这会将所有已暂存的文件都退回到已修改状态。请注意,这只是将文件移出暂存区.