admin管理员组

文章数量:1566354

特别感谢向军大叔的B站视频分享《GIT版本控制从入门到实战》和后盾人网站上的GIT课程学习使用手册,在这里我会按照他的视频课程进行笔记记录,供自己或其他小伙伴们学习巩固。学习不得朝三暮四,容易丢了西瓜拣芝麻,导致竹篮打水一场空,所以,希望你可以随着每一节学下去,最终一定会有所收获。那么,让我们开始美妙的Git学习之旅吧!


文章目录

  • 前言
  • 一、集中式与分布式实例分析
    • 1.举个栗子
    • 2.集中式还是分布式?
  • 二、配置作者信息
    • 1.和Linux的操作一样
    • 2.配置账号和邮箱
      • 2.1.配置全局账号
      • 2.2.配置普通账号
  • 三、创建新仓库与维护旧仓库
  • 四、Git流水线操作分析
  • 五、使用命令完成Git流水线操作
    • 1.新文件
    • 2.修改后的文件
    • 3.一次提交全部文件?
  • 六、gitignore详解控制版本库文件管理
    • 1.忽略单个指定文件
    • 2.忽略某一类型的文件
    • 3.不忽略单个指定文件
    • 4.忽略整个文件夹
    • 5.其他组合
  • 七、从版本库中删除资源的技巧
    • 1.同步删除版本库与工作区中的文件
    • 2.只删除版本库中的文件
  • 八、版本库中修改资料名称
  • 九、使用log日志查看历史操作行为
    • 1.查看日志
    • 2.查看最近2次提交日志并显示文件差异
    • 3.显示已修改的文件清单
    • 4.显示新增、修改、删除的文件清单
    • 5.一行显示并只显示SHA-1的前几个字符
    • 6.其他
  • 十、使用amend修改最新一次提交事件
    • 1.修改备注内容
    • 2.将某一最新操作合并到最后一次提交任务中
  • 十一、管理暂存区中的文件
    • 1.移除暂存区文件
      • 1.1 文件之前没有提交过
      • 1.2. 曾经提交过文件
    • 3.恢复初始文件
  • 十二、alias命令别名提高操作效率
    • 1.命令行方式
    • 2.编辑~/.gitconfig文件
  • 十三、详解Git分支Branch存在意义
  • 十四、实例讲解分支branch基本管理操作
    • 1.查看当前仓库所有分支和判定所在分支
    • 2.新建分支和切换分支
    • 3.分支合并
    • 4.分支删除
  • 十五、正确处理分支冲突实例讲解
    • 1.准备工作
    • 2.制造冲突
    • 3.冲突解决
  • 十六、分支管理--merged与--no-merged及分支强制删除操作
    • 1.--merged与--no-merged参数查看已合并与为合并分支列表
    • 2.强制删除分支
  • 十七、标准的分支操作工作流
  • 十八、stash临时储存区实例讲解
    • 1.实例准备
    • 2.stash使用方式
      • 2.1 临时存储
      • 2.2 查看临时存储列表
      • 2.3 恢复临时存储
      • 2.4 删除临时存储
      • 2.5 恢复并删除临时存储
    • 3.反思
  • 十九、使用TAG标签声明项目阶段版本
    • 1.打标签
    • 2.查看标签列表
  • 二十、生成zip代码发布压缩包
  • 二十一、使用系统别名定义git全局指令
  • 二十二、合并分支产生的实际问题演示
  • 二十三、rebase合理的优化分支合并
  • 二十四、在GitHub中创建项目
  • 二十五、使用SSH与GitHub远程服务器进行无密码连接
    • 1.本地创建SSH密钥
    • 2.在GitHub中添加生成的密钥
    • 3. 克隆远程项目至本地
  • 二十六、本地版本库主动使用remote与远程GitHub进行关联
    • 1.本地版本库准备
    • 2.GitHub上建立一个空的版本库
    • 3.远程空版本库与本地版本库关联
    • 4.推送数据到远程仓库
    • 5.解除关联
  • 二十七、本地分支与GitHub远程分支同步
  • 二十八、新入职员工参与项目开发时分支使用
    • 1.克隆开发分支
    • 2.实际开发与贡献提交
  • 二十九、github远程分支的合并
    • 1.利用远程库使本地中的master更新到最新版本
    • 2.将新分支初始提交点后移到master的最新提交点上
    • 3.在master分支上执行分支合并
    • 4.将本地库同步至远程库
  • 三十、远程分支删除操作--delete
    • 1.删除远程分支
    • 2.删除本地分支


前言

使用Win系统的同学,这里推荐使用Win10系统进行开发使用,其他版本可能会因为兼容性等问题导致我们的一些开发软件出现问题。
我们首先需要先安装一个Git for Windows软件,这个软件包含有多个子程序,我们可以使用命令行进行控制,也可以使用图形界面操作的方式使用。


一、集中式与分布式实例分析

1.举个栗子

Git存在的核心价值就是支持我们可以吃“后悔药”,这里以一个简单的程序文件进行介绍

如下图:

->假设我们现在完成了一个名叫a.js的文件,我们将其存储到了我们的版本库M中,并且将该文件的版本命为v0.0.1。
->在后面的日子里,我们修改了a.js文件,然后我们也将修改后的文件存储到版本库M中,版本定为v0.0.2。
->但是 ,在后续的开发中,我们还是觉得最初的v0.0.1版本的文件最合适,那么这个时候版本库就发挥了它应有的作用,支持我们对文件进行“回滚”。

2.集中式还是分布式?

版本库作为一个存储我们程序的仓库,那么就要意味着这个仓库以何种方式进行存储,目前我们常见的是集中式和分布式两种,二者各有利弊,下面是我整理的一个列表,以供使用参考:

【特点】集中式分布式
安全性更安全,易于控制不易控制
存储地点一台远程的服务器中远程服务器中和用户本地电脑中各自存储一份
网络要求必须能够访问远程服务器才可使用,网络要求高用户本地可临时存储修改后的文件,待网络符合要求后统一进行提交
版本库产品实例SVNGit

我们学习使用的Git是属于分布式存储的,相对于集中式功能更加强大,使用也更加方便。


二、配置作者信息

前面我们已经安装了Git for Windows软件,下面我们来讲一下如何标识“你是谁”,即配置作者信息

1.和Linux的操作一样

首先让我们打开该软件,将会呈现出以下界面:

这里需要说的是这个软件其实模拟了linux环境,因此我们可以使用linux的命令进行一系列的操作,非常的好用。比如,我们在当前目录下新建一个名叫“git”的文件夹:

mkdir git

然后输入如下命令进行目录查看:

ls

如图:

可以看到已经在当前目录下创建了这个git文件夹了。这里贴一下常用的Linux命令。

2.配置账号和邮箱

配置文件为 ~/.gitconfig ,执行任何Git配置命令后文件将自动创建。每次 Git 提交时都会引用账号和邮箱信息,说明是谁提交了更新,因此首先我们需要先在配置文件中配置一下我们的信息

账号和邮箱共分为两种,一种是全局的,另一种是只针对某一个仓库的。
同时我们进行信息配置也有两种方式,一种是通过命令行的方式,另一种是直接编辑该文件。

2.1.配置全局账号

方式一:直接输入命令

git config --global user.email "XXX@XXX"
git config --global user.name "myName"

方式二:编辑配置文件 ~/.gitconfig

[user]
	email = XXX@XXX
	name = myName

2.2.配置普通账号

如果我们只想针对某一个仓库创建一个账号可以吗?答案是可以的。首先让我们先来创建一个库。
(1)创建一个新路径~/git/front:

mkdir git/front

(2)切换到新路径下,然后初始化一个空的版本库:

cd git/front
git init

(3)查看是否创建成功:

ls -a

如下图:

可以看到此时我们就可以看到已经创建好了一个库。

接下来,就是对这个仓库进行账号邮箱配置,想必聪明的你已经可以大概知道,我们直接配置这个新路径下的./git/config即可。方式也是两种:
方式一:直接输入命令(此时位于~/git/front/.git/目录下)

git config user.email "XXX@XXX"
git config user.name "myName"

方式二:编辑配置文件 ~/git/front/.git/config

[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
[user]
	email = XXX@XXX
	name = myName

三、创建新仓库与维护旧仓库

创建新仓库已经在上一节的2.2中提到了,可以回去看一下,这里主要说一下怎么维护旧仓库,也就是接手别人已经有的仓库

我们在这里以GitHub上一个已有的购物车项目为例。

首先,让我们打开这个项目,然后复制一下地址:

然后,进行项目克隆。需要注意的是我们要确保我们是位于一个无任何git项目的路径下,也就是说我们当前所处的文件夹里面没有.git文件夹,以防止我们在克隆过程中出现问题。我是在~/git目录下进行的操作:

git clone https://github.com/houdunwang/cart.git

效果如图:

程序会自动在当前路径下新建一个项目文件夹,里面包含该项目的所有文件,这样,我们就成功把这个项目克隆下来啦~


四、Git流水线操作分析

现在我们已经学会了如何在本地创建一个新的库或者接手一个原有的库,我们可以直接在这个基础上进行程序开发了。当我们开发了一段时间,就需要同步更新一下我们的本地版本库了,但是这个更新过程是什么样子的呢?本节就来介绍一下Git的基本流水线操作流程。
*注意,在这里只介绍我们本地版本库同步流程,至于远程版本库的流程会在后面的章节中介绍

话不多说,直接上图:

解读一下,在我们本地中存在有工作区、暂存区和本地版本库。远程服务器中的为远程版本库,我们暂时不需要掌握。

【工作区】即为我们进行程序开发时的实际目录,也是我们刚刚创建的仓库所在路径。在这里我们进行我们日常的程序开发,包括新建文件、修改文件、删除文件、重命名文件等;
【暂存区】为我们希望将工作区的指定文件同步至本地版本库的缓存区域。我们可以将这个区域想象成一个运输车,用来实现从本地工作区到本地版本库的打包运输工作,因此我们可以将我们本地工作区文件传到这里面的动作叫做“装车”,即图中标注的红圈1:add
【版本库】就是我们真正意义上的代码仓库了,用来存储我们开发过程中每次同步提交的各个历史版本的代码,版本库共分为两种,一种是本地版本库,一种是远程版本库,毕竟我们用的Git是分布式的,所以会有这种结构。针对本地版本库,里面的每一版本的代码都是通过我们的“运输车”运输过来的,运输车的每一次传递动作可以叫做“入库”,即图中标注的红圈2:commit;针对远程版本库,则是我们存储在远程服务器中的版本库,用来辅助我们进行协同开发,这部分的工作流程会在后续章节介绍。

以上就是Git流水线的基本流程,那么还有一个同步的问题,也就是我们工作区、暂存区、版本库之间的文件在大部分的时间中是不同的,比如我们需要知道我们工作区中还有哪些文件没有“装车”,我们还有哪些文件已经“装车”但是还没有入库,以及我们工作区中和版本库里的文件是否一致。针对这个问题,git为我们提供了一个git status命令,帮助我们需要来监控我们的文件状态。


五、使用命令完成Git流水线操作

上一节我们已经学习了基本的流水线操作过程,那么在本节就让我们学习一下如何使用命令完成上述的过程

1.新文件

这里我使用上面我新创建的front库,首先切换到路径~/git/front下:

cd ~/git/front

这里我们新建两个文件,分别为a.js 和 b.js:

touch a.js
touch b.js

现在,两个文件就已经在工作区中被创建好了。我们使用下面的命令来查看一下文件状态:

git status

显示如下:

可以看到提示我们这两个文件未被追踪。下面我们使用这个命令先将a.js文件进行“装车”:

git add a.js

这时再查看一下文件状态:

git status

显示如下:

可见a.js文件已经被“装车”,变为了绿色,且显示是属于一个全新的文件(new file),而b.js文件我们没有执行“装车”动作,因此还是未被追踪到的状态。现在,我们也将b.js文件执行下面的“装车”命令:

git add b.js

再次查看文件状态(git status):

这时b.js文件也已经装车完毕了。接下来我们执行下面的命令进行“入库操作”:

git commit -m '测试学习'

该命令要求我们每次入库时添加一个备注信息,在这里我备注的是“测试学习”,下面是命令执行完成后的反馈:

可以看到两个新文件已经成功同步到我们的本地版本库中了~

2.修改后的文件

假设我们现在又修改了a.js文件里的内容,那么执行文件状态查看命令后显示的是什么呢?让我们尝试一下:

在a.js文件中添加如下内容:

这里是修改的内容
哈哈哈

保存后,我们执行文件状态查看命令(git status),可以看到如下的反馈:

看得出来系统已经检测到我们的a.js文件被修改了,而且还提示我们可以使用git add <file>...命令进行commit

那么我们就再次执行“装车”命令(git add a.js),然后查看文件状态(git status)可看到如下反馈:

此时a.js文件变绿了,而且提示我们该文件等待被入库(commit),下面我们就执行入库操作(git commit -m 'a文件修改后入库'),然后查看文件状态(git status),可看到如下反馈:

由此可知修改后的a.js文件已经被同步到本地版本库中了~

3.一次提交全部文件?

现在我们已经学会了如何以命令行的方式将工作区的文件一个一个添加到暂存区中,然后统一打包同步到本地版本库中 。那么现在延伸出来一个问题:如果工作区中存在100个文件,需要针对每一个文件都执行一遍git add [fileName.type]命令吗?当然你可以这样做,只要不嫌辛苦的话。Git为我们提供了一个命令,可以允许我们一次性将工作区中的全部文件一次性“装车”至暂存区中,命令如下:

git add .

对,就是直接用一个.代表全部文件,非常的好用,快去试试吧!


六、gitignore详解控制版本库文件管理

前面我们已经学会了如何一次性将工作区中的全部文件“装车”,但这里面还存在一个问题,就是如果我们只是想让大部分文件“装车”,一小部分的指定文件不装车,怎么办?办法还是有的,那就是配置一下.gitignore文件,用来告诉我们的系统哪些文件这装车的时候需要被忽略掉

假定我们还位于~/git/front路径下,使用命令(ls)查看一下,可看到经过上面的操作,我们的目录中已经含有了下面的文件:

让我们再新建以下文件:c.js、d.txt、e.txt,目前~/git/front路径下一共有以下文件:

查看一下文件状态(git status)效果如下:

此时c.js、d.txt、e.txt都被系统检测到了,如果现在执行git add .命令,那么将会将三个新文件全部“装车”

1.忽略单个指定文件

现在我们不想让d.txt文件被检测到,怎么办?办法是建立一个.gitignore文件,然后在里面定义我们的忽略规则。
首先执行命令新建.gitignore文件:

touch .gitignore

在文件中写入如下内容:

d.txt

保存文件,然后再次查看文件状态(git status):

现在b.txt已经被系统忽略了。

2.忽略某一类型的文件

那么如果我们想忽略全部的txt文件呢?直接在.gitignore中定义如下:

*.txt

再次执行状态查看,可看到所有的txt文件都被忽略了:

3.不忽略单个指定文件

如果我们想忽略全部的txt文件,但是唯独不想让e.txt被忽略怎么办?我们可以使用上面两个规则的组合:

*.txt
!e.txt

再次查看文件状态:

注意:该文件中下面行的规则权重会比上面行的大,因此顺序很重要,如果我们将上述两个规则换一下位置,那么e.txt同样将不会被检测到。这个注意点同样适用其他的规则。

4.忽略整个文件夹

有时候我们不希望某个文件夹被同步至版本库中,这里我们新建一个叫“dir”的文件夹,里面新建一个index.html文件:

然后我们再切换回~/git/front路径下,执行查看文件状态命令:

此时dir路径是被检测到的。如果我们不希望被检测到,可以在.gitignore文件中我们可以进行如下定义:

/dir

再次查看状态,会发现dir路径被忽略了:

5.其他组合

现在我们已经学会了基本的如何进行忽略规则的定义,下面我贴出配置的语法,大家在日后可以自行组合使用,定义时要注意规则的顺序哦~

符号含义示例示例解释
#单行注释符号# !a.txt注释掉“不忽略a.txt文件”这条规则
/目录/dir忽略整个dir文件夹
*通配多个字符*.txt忽略所有的txt类型文件
?通配单个字符/dir/a?.txt忽略dir文件夹下所有以a开头且名称为两位字符的txt类型文件,如:a3.txt、a5.txt
[ ]单个字符的匹配列表[abcd].txt忽略a.txt、b.txt、c.txt和d.txt文件
!不忽略匹配到的文件或目录!a.txt不忽略a.txt文件
**匹配多级目录/dir/**/a.txt忽略dir路径下的所有子路径里面的a.txt文件

七、从版本库中删除资源的技巧

现在我们已经学会了如何利用.gitignore文件过滤式批量添加文件,但是当我们需要删除的时候应当如何操作呢?一共有两种方式,第一种是将把版本库中的和工作区中的同步删除,第二种是只删除版本库中的文件

1.同步删除版本库与工作区中的文件

还是继续使用上节的front仓库,让我们先查看一下文件状态(git status):

可以看到上面的文件都已经被追踪到了,我们批量装车一下(git add.),然后入库(git commit -m '批量添加文件'):

可以看到我们已经把这些文件批量添加了。但是我们发现.gitignore文件也别添加进去了,如果此时我们不希望.gitignore文件存在版本库中,我们可以执行下面命令进行删除:

git rm .gitignore

结果如下:

此时我们查看下工作区目录(ls -a):

发现在工作区目录下的.gitignore也被同步删除了

2.只删除版本库中的文件

使用git rm .gitignore命令会将版本库和工作区的.gitignore文件都删除,但如果我们只想删除版本库中怎么办?可以加一个参数--cached

现在让我们新建一个.gitignore文件(touch .gitignore),然后装车(git add .gitignore)、入库(git commit -m '添加ignore文件'):

使用下面命令删除版本库中的.gitignore文件:

git rm --catched .gitignore

结果如下:

再次查看一下工作区目录(ls -a):

发现这一次工作区中的.gitignore文件没有被删除。查看一下文件状态(git status):

会发现提示我们将要将.gitignore文件删除,此时我们执行入库操作(git commit -m '删除'),即可将这一更改执行:

总结一下:
删除版本库与工作区中的文件:git rm [fileName]
只删除版本库中文件但保存工作区中的文件:git rm -cached [fileName]


八、版本库中修改资料名称

在实际开发过程中我们会遇到更改文件名称的需求,在Git中的操作方法是使用git mv [oldFileName] [newFileName]命令

首先新建一个index.html文件(touch index.html),然后装车(git add .)、入库(git commit -m '添加index.html文件'):

现在我们希望将index.html文件重命名为Index.html,使用下面的命令:

git mv index.html Index.html

然后查看一下文件状态(git status),结果如下:

使用命令git commit -m '重命名index.html'提交修改,然后再次查看工作区目录(ls):

此时版本库和工作区的index.html文件都已经被重命名为了Index.html


九、使用log日志查看历史操作行为

我们已经学会了如何进行文件添加、删除、重命名,Git会将我们每一次的提交git commit行为记录到log中,并且Git提供git log命令帮助我们进行日志查看。本节中我新建了一个名叫logLearn的仓库,并且先新建了一个a.js文件,而后新建了一个b.js文件,最后将a.js文件进行了修改。以下是不同log命令的结果

提示:退出日志的方法为输入字母q

1.查看日志

git log

结果:

黄色字体为某次提交历史的哈希值,而后列出了提交人和提交时间

2.查看最近2次提交日志并显示文件差异

git log -p -2

结果:

3.显示已修改的文件清单

git log --name-only

结果:

4.显示新增、修改、删除的文件清单

git log --name-status

结果:

5.一行显示并只显示SHA-1的前几个字符

git log --oneline

结果:

6.其他

除了上述几种用法外,还有其他的参数,这里贴出git log详解
以供参考


十、使用amend修改最新一次提交事件

在之前的使用中我们一直使用的是git commit -m '提交的备注'进行我们git任务的提交,如果我们需要对最后一次提交进行修改,可以使用git commit --amend打开进行相应修改

1.修改备注内容

新建一个叫做amend的仓库,而后添加a.js文件,此时查看log日志,会看到如下内容:

如果我们希望将备注内容“a.js文件”改为“添加a.js文件”,可以执行下面的命令:

git commit --amend

而后在打开的文件中将第一行修改为如下内容:

再次查看日志,会发现任务备注信息已经更改了:

2.将某一最新操作合并到最后一次提交任务中

--amend参数不仅支持我们修改最后一次提交任务的备注信息,还支持将最新操作合并到最后一次提交任务中。

新建一个b.js文件,而后执行装车操作,此时查看文件状态,会有如下结果:

会发现b.js文件已经加载到暂存区了,如果此时我们执行git commit -m '添加b.js文件',则会新增一个提交任务,且log中会增加一条对应的记录。现在我们希望将添加b.js文件的操作合并到刚刚添加a.js的提交任务中,同样只需执行如下命令:

git commit --amend

在打开的文件中将第一行修改为如下内容:

保存。然后再次查看Git日志,会发现没有新增记录,添加b.js文件的操作合并到了最后的提交操作中


十一、管理暂存区中的文件

Git支持我们管理暂存区的文件,如何添加git add .我们已经掌握了,现在,让我们学习一下其他的文件管理方式。现在新版本Git已经支持新的命令(restore)来实现移除或恢复操作了,本文中使用的新命令。总而言之我们可以根据命令的提示来实现我们想要的效果

1.移除暂存区文件

1.1 文件之前没有提交过

首先创建一个名叫manage的仓库,而后新建文件a.txt,将其添加进暂存区,查看文件状态:

此时的a.txt文件属于新文件,未被提交(commit)过,并且该文件在暂存区中已经存在了一份,如果此时我们希望从暂存区中移除,可以使用下面的命令:

git rm --cached a.txt

执行后,再次查看文件状态:

发现已经从暂存区移除了,恢复到了装车(git add .)前的状态。

1.2. 曾经提交过文件

继续使用manage库,我们分别执行装车和提交命令,将a.txt文件提交到版本库中。而后我们修改一下a.txt的文件内容,再次执行装车命令,查看文件状态,结果如下:

如果此时同样想从暂存区中撤销这一操作动作,可以使用如下命令:

git restore --staged a.txt

再次查看文件状态:

发现此时a.txt已经从暂存区中移除了

注意:视频中介绍的是使用命令git reset HEAD <file>来实现从暂存区中去除修改后文件的方法,这个是旧的方法,也可以使用。本笔记中的方法是Git 2.23后新加的,也可以使用。

3.恢复初始文件

刚刚我们修改了a.txt文件的内容,具体文件内容如下:

如果我们此时想恢复一下最后一次提交到版本库的文件,可以使用如下命令:

git restore a.txt

执行完毕后让我们再次查看a.txt的文件内容:

此时工作区中的a.txt已经恢复为了版本库中的最后一次提交的那个版本

注意:视频中介绍的是使用命令git checkout -- <file>来实现从版本库覆盖恢复工作区文件的方法,这个是旧的方法,也可以使用。本笔记中的方法是Git 2.23后新加的,也可以使用。


十二、alias命令别名提高操作效率

截止目前我们已经掌握了一些常用的Git命令,但是一些命令单词很长,每一次需要我们敲很多键盘,非常的费时。好在Git为我们提供了alias方法,允许我们为一些命令创建别名,从而方便我们的使用

alias命令别名的方式同配置作者信息类似,一共有两种方式,一种是命令行方式,另一种是直接编辑~/.gitconfig文件

1.命令行方式

使用如下命令,将查看文件状态命令(status)设置别名为(s):

git config --global alias.s status

这次我们再次查看文件状态,就可以使用git s了,而无需使用git status命令,效果是一样一样的:

2.编辑~/.gitconfig文件

同配置作者信息类似,我们也可以直接编辑~/.gitconfig文件对一些命令设置别称,我将一些常用命令定义如下:

现在,我们就可以直接使用别称进行Git操作啦


十三、详解Git分支Branch存在意义

前面几节我们一直在独自操作,我们可以在需要的时间对代码进行撤销恢复等操作,不过Git可不仅仅只支持我们吃“后悔药”这一特点,其另外一个很大的价值就是支持我们进行程序的协作开发,采用的方式就是分支Branch。有了分支,我们可以将一个程序的不同功能或模块分别交予不同的开发者同时进行开发,在保证代码安全性的基础上极大提高了我们的程序开发效率


上面是一个Git分支的示例图,我们前几节一直进行的操作均是在master分支上进行的。在Git中,master分支代表了程序版本的主分支,其他所有的分支都是从master上分出去的,最后也都是在审核通过后合并到主分支上的。

上图中我们在1月1日、1月2日和1月3日均在master分支上进行了commit提交,假设1月3日master分支上的当前程序版本已经是一个相对稳定的版本了。这个时候我们的程序可能还需要其他两个重要的功能,如果直接在master上操作不是不可以,但可能会导致在新功能开发过程中使得现有的稳定版本出现问题,此时我们将无法恢复;另外因为是两个功能添加,直接在master上进行就意味着为了程序的稳定我们需要一个一个功能进行,不利于效率的提升。

此时我们就可以利用Git的分支功能了,在1月3日master稳定版程序的基础上,我们分别创建了两个分支:branch1branch2。而后这两组开发人员开始着手在自己的分支上开发相应的新功能。branch1组的人员在两次commit提交后发现该功能已经完善并稳定了,可以将其合并到master上,于是在1月7日进行了合并,并删除了branch1分支;branch2组的人员在三次commit提交后发现他们的功能也已经完成,于是在1月8日完成了和主分支master的合并工作,并删除了branch2分支。至此,程序的两个新功能完成了开发,并且程序有了一个更新的稳定版本。


十四、实例讲解分支branch基本管理操作

十三节我们讲解了分支branch的意义与基本流程,本节就让我们通过实例来进行一遍代码实操

1.查看当前仓库所有分支和判定所在分支

首先我们先新建一个仓库easyBuy,里面新建一个文档readme.txt,而后进行文档的“装车”和操作提交:

这个时候master分支就已经存在了。Git提供下面的命令供我们查看当前仓库里所有已存在的分支:

git branch

结果如下:

我们发现里面共有一个分支,即master主分支,前面的*号表示我们当前命令环境所处的分支,可以看到我们正处于master主分支里,即我们当下所有的操作都是在修改master主分支里的文件。

2.新建分支和切换分支

让我们新建一个名叫branch1的分支,使用下面的命令(git branch <new branch name>):

git branch branch1

此时我们再次查看所有分支(git branch):

可以看到branch1分支已经创建出来了。但是注意*号,表明我们当前还处于master分支中,可以使用下面的命令切换至branch1分支(git checkout <exist branch name>):

git checkout branch1

结果如下:

现在已经成功切换到branch1分支中啦~(这个时候我们进行后续操作则只会修改branch1分支中的文件,master分支中的不受影响)

Tips:我们可以使用如下命令一次性实现分支的创建和切换(git checkout -b <new branch name>):

git checkout -b branch2

效果如下:

可以看到我们已经成功新建了branch2分支并且切换到了该分支上~

3.分支合并

继续使用本节创建的仓库,切换到branch1分支上,而后我们新建一个文档index.html,然后“装车”、提交:

通过ls我们可以发现在当前branch1分支的工作区目录下我们已经新增了index.html文件。此时我们再次切换至master主分支中,查看工作区目录:

我们发现master工作区目录下是没有index.html文件的,这是因为我们刚刚的操作时在branch1分支上进行的,那么master分支必然不会受到影响。

现在,假设我们的branch1分支上的工作已经完成了,那么就可以执行下面的命令进行分支的合并(git merge <exist branch name>):

git merge branch1

执行结果如下:

可以看到我们已经成功将branch1分支合并到了master分支上了,通过ls命令也可以发现此时master工作区目录下已经有了index.html文件。

注意:必须在master分支上执行git merge <exist branch name>命令,才可将其他分支合并到master分支上。(merge会将目标分支合并到当前所处分支上)

4.分支删除

当我们将branch1分支合并到master分支上后,branch1分支就完成了历史使命,此时我们可以选择将其删除,只需执行下面的命令(git branch -d <exist branch name>):

git branch -d branch1

此时我们再次查看所有分支,会发现branch1已经被删除了:

注意:删除时,当前分支不得为要删除的分支,否则会删除失败。比如当我们在branch1分支上执行删除branch1分支命令时,会提示我们删除失败:


十五、正确处理分支冲突实例讲解

从上面我们已经了解到,在实际开发过程中可能会同时存在多个分支同时进行开发的情况。此时就不得不面临另一个问题:如果多个分支的开发者都分别修改了某一个文件,并且每个小组修改的内容还不同,那么当向master主分支合并时,就会发生分支冲突,此时Git会自动提示我们该文件冲突,需要我们人工处理这一冲突的文件。

1.准备工作

让我们新建一个仓库conflict,里面新建一个文档readme.txt,写入如下内容:

这里是master中书写的内容

然后进行文档的“装车”和操作提交:

接着我们在当前master分支的基础上创建一个分支branch1,并且将其中readme.txt文件的内容修改为如下内容:

这里是master中书写的内容
这里是branch1中增添的内容

然后“装车”、提交:

然后我们在当前master分支的基础上再创建一个分支branch2,并且将其中readme.txt文件的内容修改为如下内容:

这里是master中书写的内容
这里是branch2中增添的内容

然后“装车”、提交:

2.制造冲突

经过上面的工作准备,我们目前已经有了是三个分支:master、branch1、branch2。并且在branch1分支和branch2分支中分别对readme.txt文件进行了不同的修改。

假设branch1的工作率先完成,执行向master分支的合并工作:

可以看到成功将branch1合并到了master分支中,无任何异常提醒。master中readme.txt文件内容也与branch1中的保持了一致。

现在,让我们执行将branch2合并到master分支中的操作:

会发现Git会提示我们readme.txt文件出现了分支冲突,自动合并失败,需要我们手动修改。

3.冲突解决

出现上述分支冲突后,解决办法就是手动修改出现冲突的文件。让我们打开出现冲突的readme.txt文件,会看到如下内容:

可以看到Git将文件内容划分为了三个部分:
第一个是各分支修改前的文件内容;
第二个是branch1分支中修改的文件内容,并且提示我们此时HEAD指针指向的是这部分内容(因为我们先执行的branch1合并操作,因此会自动将HEAD指针指向branch1分支以完成合并操作)
第三个是branch2分支中修改的文件内容,并且提示我们这部分内容是属于branch2分支的。

这时候就需要我们自己修改文件的内容了,看哪部分保留,哪部分删除,哪部分修改。在本例中假设branch1和branch2分支中修改的内容我们都需要,所以可以将文件内容修改如下:

保存,关闭文件。然后“装车”、提交:

至此,分支冲突就解决了,branch2分支也成功合并到了master分支上~


十六、分支管理–merged与–no-merged及分支强制删除操作

随着开发的进行我们创建的分支会越来越多,Git为我们提供了--merged参数和--no-merged参数辅助我们集中查看已经合并的分支和未合并的分支。当某一分支尚未合并到master分支上时,Git默认是不允许我们使用普通分支删除命令git branch -d <exist branch name>将其删除的,此时我们可以使用强制分支删除命令git branch -D <exist branch name>进行删除

1.–merged与–no-merged参数查看已合并与为合并分支列表

我们继续使用十五节的conflict仓库,首先查看一下当前分支(git branch):

可以看到当前所在分支为master分支。值得一提的是,git branch不仅支持我们查看当前所在分支,我们还可以从结果中了解到目前我们项目存在的所有分支,以当前仓库为例,我们可以看到我们目前共有三个分支:branch1、branch2和master分支。

在这个命令的基础上添加--merged参数,我们即可看到此刻已经合并了的分支:

可以看到当前我们所有的分支都进行了合并。现在我们新建一个分支branch3再看看效果:

很奇怪,新建的branch3分支很明显并没有执行合并操作,为啥Git也会将其归入已合并类别下呢?这是因为当我们创建一个新分支时,该新分支与master分支共用一个提交点,其内容和master分支是一模一样的,因此可以认为该分支无需合并到master分支上,进而将其归入了已合并类别下。

现在,我们切换至branch3分支上,新建一个a.js文件,而后“装车”、提交:

切换回master分支,然后再次查看已合并的分支列表:

现在,branch3分支就不属于已合并的分支类别下了。如果使用--no-merged参数,则可以查看此刻尚未合并的branch3分支:

2.强制删除分支

Git默认不支持我们删除尚未合并的分支:

当我们要删除branch3分支时,Git提示我们该分支还没有合并,如果我们确认要删除,需要使用如下强制删除命令:

git branch -D <exist branch name>

执行后结果如下:

可以看到我们成功强制删除了branch3分支~


十七、标准的分支操作工作流

在实际协同工作中,分支操作工作需要遵循一定的规则,本节就来介绍一下标准的分支操作工作流

直接上图:

我们在实际开发工作中,远程版本库中一般会存有两个分支,分别为master分支和develop分支。其中master分支是稳定版本的程序,可以理解为供用户实际使用的正式稳定版应用;develop分支则为我们为了进行程序升级或修改而创建的开发版本程序,可以理解为供用户选择使用的Beta版本应用。

一般当我们需要对当前稳定版本的程序进行新需求开发时,会从master分支中分出develop分支,然后不同的开发者会在新分出的develop分支上clone到本地版本库,而后再自行根据子功能的需要在本地版本库进行分支,逐步开发自己负责的功能模块。

当某个功能模块开发完毕并合格后,负责此功能模块的开发者会将此分支合并到develop分支上。当所有的功能模块都开发完毕且已合并到develop分支上时,新版本的程序开发宣告完毕,在经过各种测试合格后,即可将develop分支合并到master分支上,然后一个新稳定版本的应用就可以发布啦~


十八、stash临时储存区实例讲解

我们在某个分支中进行程序开发时,暂存区中可能会存有一部分我们需要提交的文件。这个时候如果我们临时需要切换到其他分支进行工作时,Git将不允许我们切换(可以理解为本地所有分支共用一个暂存区,当切换到别的分支时,当前分支存到暂存区的文件将会丢失)。这时候我们有两种选择:1、commit到版本库(相当于清空了暂存区);2、使用stash将暂存区的文件临时存储起来,需要时再进行恢复。可是一般情况下文件需要完整修改好才会提交到版本库,因此stash是相对更好的选择

1.实例准备

新建一个仓库stash,master分支中创建master.txt文件并提交到版本库;新建分支branch1和分支branch2:

切换至branch1分支,并新建文件brnach1.txt,“装车”、提交:

向branch1.txt文件增添内容如下:

再次执行“装车”操作,然后切换至brnach2分支:

这里可以发现Git拒绝了我们的切换指令,此时就需要我们使用stash将这个暂存区临时存储起来。

2.stash使用方式

2.1 临时存储

使用如下命令进行临时存储:

git stash

效果如下:

可见已经成功切换到了branch2分支中了

2.2 查看临时存储列表

使用如下命令查看当前临时存储列表:

git stash list

效果如下:

其中最前面为该临时存储的索引,后面为相应描述信息

2.3 恢复临时存储

使用如下命令可恢复临时存储:

git stash apply [stash index]

默认恢复的是第一个索引的临时存储,支持恢复指定索引的存储,效果如下:

2.4 删除临时存储

apply恢复临时存储后,该临时存储并不会被删除,可以使用如下命令进行删除:

git stash drop <stash index>

临时存储的索引为必选参数,执行结果如下:

2.5 恢复并删除临时存储

有时候我们希望在恢复临时存储时顺便删除该临时存储,可以使用如下命令:

git stash pop [stash index]

默认恢复并删除第一个索引的临时存储,也可以指定要恢复删除的索引,执行结果如下:

3.反思

某个没有commit过的新分支与原分支会共用一个提交点,因此当在此分支上修改某个原有文件但尚未commit时,与之共用一个提交点的分支上该文件都会同步修改,因为Git会认为这个文件是同一个版本文件。当在新分支上commit过一遍后,因为该文件不再与其他分支共用一个提交点了,所以此时其他分支上的不再同步更改,仍然为原始内容。

并且,未commit过的分支修改文件,即使“装车”后,也可以正常进行分支切换,因为Git认为它们是同一个分支。

总之:共用同一个提交点的分支,会被Git认为是同一分支,所有操作都会被同步更改。


十九、使用TAG标签声明项目阶段版本

在代码开发一段时间后,会产生一个稳定版本的程序,此时我们可以为其打一个标签,用于作为某一个阶段的总结声明

注意:打标签的程序一定是相对稳定的版本

1.打标签

打标签很容易,命令如下:

git tag <version>

版本号为必选参数,执行效果如下:

2.查看标签列表

使用如下命令查看标签列表:

git tag

执行效果如下:


二十、生成zip代码发布压缩包

在项目开发好后,就可以进行代码发布了,这里介绍如何生成项目代码的zip压缩包

使用下面的命令进行代码压缩打包:

git archive <exist branch name> --prefix='<dir path>' --format=zip > <zip file name>

解释一下,首先需要选择要打包的分支是哪个,一般我们实际开发中打包的都是master分支;其次要定义我们打包的根目录名称;最后还要给最后的压缩包定义名称。示例如下:

示例中,我将master分支进行了打包,打包的根目录为stash,压缩包名称为test.zip。让我们进入项目目录查看一下:

可以看到压缩包已经打包完成了,打开压缩包:

根目录即为我们事先定义的stash


二十一、使用系统别名定义git全局指令

之前我们学会了如何使用alies定义操作别名,比如:使用命令git l代替原有的git log命令。但是alies只能替换掉操作的名称,前面的git无法进行替换。我们可以修改根目录下的.bash_profile文件定义git全局指令,使得我们需要输入的字符更少

打开位于根目录下的.bash_profile文件(没有的话可以新建一个),然后填入如下内容:

alias gs="git status"
alias gc="git commit -m "
alias gl="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit  "
alias gb="git branch"
alias ga="git add ."
alias go="git checkout"

保存。然后重新打开git bash软件,此时我们就可以使用定义的git全局指令啦:

二十二、合并分支产生的实际问题演示

分支合并往往会出现很多问题,前面我们已经知道了如何解决多个分支合并冲突的解决方法,现在再来学习一下合并时的其他问题

如下图:

之前我们进行分支合并的情况均为图一的情况,即当从master分支分出一个分支后,我们的所有commit都在新分支上,master分支不再commit。

然而有时会出现图二所示的情况,即在分出一个分支后,master分支上仍然在进行commit,因此当新分支合并到master上时将会出现问题。下面,我们用命令行实现一下图二所示的情况:

新建一个名叫rebase的仓库,然后在master分支中新增master.txt文件,执行“装车”、提交:

创建新分支branch,然后在新分支中创建文件branch.txt,执行“装车”、提交操作:

再次返回master分支,修改master.txt文件,填入如下内容:

这里是在master中修改的内容

保存,“装车”、提交:

现在,我们已经在创建新分支branch后,在master上又执行了一次commit,符合上述图二的示例情况。下面执行合并操作(git merge branch),将会暴露出以下问题:

首先需要master分支负责人填写该分支合并的必要性

其次合并后,查看日志变成了如下的样子,不利于我们的日志查看:

在下一节中,我们将使用rebase解决上述问题~


二十三、rebase合理的优化分支合并

前一节我们已经演示了在创建新分支后,master分支继续进行提交,当新分支合并回来后需要master分支负责人解决冲突的问题,本节我们将使用rebase来解决这个问题

rebase的解决思路就是将branch分支的初始提交点后移到master的最新提交点,这样就将图二的情况转换为了与图一类似的情况(图三),再次执行合并,就不会产生上述问题了,图示如下:

执行rebase操作很简单,只需要在要合并的子分支上执行下面的命令:

git rebase <base branch name>

base branch name指的是我们要进行初始提交点移动的基本分支,这里我们一般是master分支。

我们继续使用上节的例子演示一下。首先创建一个新分支branch1,在新分支中创建新文件branch1.txt,“装车”、提交:

然后返回master分支,修改master分支里的master.txt内容如下:

这里是在master中修改的内容
这里是第二次在master中修改的内容

保存,执行“装车”、提交命令:

此时,我们模拟的新分支branch1和master的关系符合图二的那种情况,如果我们直接进行合并就会出现上节最后提到的那种错误。现在我们使用rebase来解决一下:

切换至branch1分支中,执行命令git rebase master

这个时候返回master分支中再次执行分支合并操作,不再出现上节最后提到的问题了:

Tips:在本节中部分操作命令使用了第二十一节中定义的git全局指令,不清楚的同学可以返回温习一下~


二十四、在GitHub中创建项目

一开始我们说到,Git是一个分布式的版本控制系统。我们前面的操作都是针对本地版本库进行的。本节开始我们开始学习如何使用远程版本库

目前国内外有很多优秀的代码托管平台,常见的有GitHub、GitLab、gitee、coding。我们在这里主要学习GitHub的使用。

这里是百度百科上面对GitHub的介绍:GitHub是一个面向开源及私有软件项目的托管平台,因为只支持Git作为唯一的版本库格式进行托管,故名GitHub。GitHub于2008年4月10日正式上线,除了Git代码仓库托管及基本的Web管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。目前,其注册用户已经超过350万,托管版本数量也是非常之多,其中不乏知名开源项目Ruby on Rails、jQuery、python等。

下面说明如何在GitHub中创建项目:

首先打开GitHub官网,然后选择下图中所示的“+”号,点击“New Repository”:

然后在打开的创建新版本库的页面中填写我们要新建项目的相关信息,包括项目名称、描述项、公开还是私有、README文件、.gitignore文件、开源协议等,可以根据自己的需要进行选择。选择完毕后点击页面下方绿色按钮“Create repository”,即可创建该项目了~

项目创建完成后如下图所示:


二十五、使用SSH与GitHub远程服务器进行无密码连接

GitHub支持我们使用Https或SSH的方式与我们的本地版本库进行连接。使用SSH连接Github发送指令更加安全可靠,也可以免掉每次输入密码的困扰,因此这里我们学习使用SSH的方式进行无密码连接

1.本地创建SSH密钥

在Git Bash中输入命令ssh-keygen -t rsa,然后一直按回车直到结束:

结束后系统会自动系在~/.ssh 目录中生成 id_rsa和id_rsa.pub,即密钥id_rsa和公钥id_rsa.pub:

2.在GitHub中添加生成的密钥

首先进入到GitHub的个人设置里的SSH配置页面中,然后点击绿色按钮“New SSH key”:

然后按照下面的提示填入相应的内容:

3. 克隆远程项目至本地

进入到我们希望连接的项目,然后复制红框里的链接:

在Git Bash中进入到希望存储本地项目的位置(本例中我选择桌面作为存储位置),输入如下命令进行克隆:

git clone <ssh link>

执行效果如下:

当克隆完毕后,本地版本库就与远程版本库关联起来啦~

【验证一下】:
此时我们新建一个a.js文件,然后“装车”、提交:

现在本地版本库中已经拥有了a.js文件。我们使用下面的命令实现本地版本库与GitHub远程版本库的同步:

git push

反馈如下:

我们再到GitHub上查看一下:

可以发现已经有了a.js文件,我们的本地版本库和GitHub远程版本库已经实现了关联~

Tips:我们在执行clone命令时提示我们下载失败,有可能是我们的host文件的缓存的问题,我们可以打开~/.ssh/known_hosts文件,将里面的内容全部删除。再次执行clone,应该就可以了~


二十六、本地版本库主动使用remote与远程GitHub进行关联

上一节我们讲了如何将GitHub上已有的项目clone下来,并在本地建立相应的本地版本库以及与远程项目关联;本节我们将这个过程反过来,学习一下如何将本地已有的项目放到GitHub上,并在远程中建立对应的版本库以及与本地项目关联

1.本地版本库准备

让我们现在本地建立一个叫test的仓库,里面新建README.md文件,输入如下内容:

本地库主动使用remote与远程GitHub进行关联

保存,“装车”、提交:

现在,我们就拥有了一个本地版本库。

2.GitHub上建立一个空的版本库

步骤大致同前面介绍的版本库建立,首先打开GitHub官网,然后选择下图中所示的“+”号,点击“New Repository”:

然后在打开的创建新版本库的页面中只填写我们要新建项目的名称,其他不填。然后直接点击页面下方绿色按钮“Create repository”,即可创建一个空的项目了~

3.远程空版本库与本地版本库关联

复制下方红框里的命令(根据自己页面找这个位置进行复制)

回到命令行,将复制的命令粘贴进去,然后提交:

此时我们就将远程库与本地库关联起来了,也可以使用命令git remote -v来查看我们的远程库:

4.推送数据到远程仓库

关联完成后,就可以推送本地数据到远程仓库了。使用命令git push -u origin master实现数据推送:

这个时候我们刷新一下GitHub的页面:

可以看到数据已经推送上去啦~

5.解除关联

当我们不需要与远程仓库进行关联时,可以使用如下命令进行关联解除:

git remote rm origin

结果如下:


二十七、本地分支与GitHub远程分支同步

git允许我们对分支进行操作,本节我们来学习下如何将本地分支与GitHub远程分支进行同步

继续使用二十六节中使用的test库,在此基础上新建一个分支branch1,然后在新分支上创建新文件a.js,执行“装车”、提交操作:

现在如果我们贸然使用git push命令进行数据文件提交,将会报以下错误:

意思是在远程版本库中不含有当前分支,我们可以使用命令git push --set-upstream origin branch1进行分支同步:

这时候刷新一下GitHub页面,即可发现branch1分支已经同步上去啦:


二十八、新入职员工参与项目开发时分支使用

当我们新入职时,可能当前项目已经开发了一些,本节就来学习一下如何参与项目开发

1.克隆开发分支

以下面的项目为例,假设项目的稳定分支为master,开发团队正在进行开发的分支为branch1分支:

我们在本地对该项目进行ssh克隆:

会发现只能将master分支克隆下来,但是我们需要对branch1分支进行操作,可以使用命令git pull origin branch1:branch1将该分支克隆下来:

2.实际开发与贡献提交

将开发分支克隆下来后,就可以在该分支上进行正常的开发工作了:

此时在远程的branch1分支上就有了我们工作成果:


二十九、github远程分支的合并

当branch1分支开发完成后,需要将其合并到master中。之前我们学会了怎样在本地版本库中进行分支合并操作,本节我们将学习怎样合并远程库中的分支

当进行分支合并时,我们之前提到了需要尽量减少master分支负责者对于分支合并冲突的处理,也就是说在合并前要使用rebase将新分支的初始提交点后移到master的最新提交点上。由于我们本次还涉及到了远程库,因此我们在rebase之前还需保证我们本地的master分支是远程库中最新的版本,可以使用命令git pull来实现。下面来讲一下具体的步骤:

1.利用远程库使本地中的master更新到最新版本

在master分支中使用命令git pull

2.将新分支初始提交点后移到master的最新提交点上

在我们实际开发的分支上执行命令git rebase master

3.在master分支上执行分支合并

在master分支上使用命令git merge branch1将branch1分支合并到master分支上:

4.将本地库同步至远程库

使用命令git push实现本地与远程的同步:

此时整个流程就执行完毕了,我们打开GitHub页面查看一下:

可以看到远程的brnach1分支已经合并到了master分支上~


三十、远程分支删除操作–delete

当开发分支已经合并到master分支上以后,理论上就可以将其删掉了。本节我们来学习下如何删除远程版本库中的开发分支

1.删除远程分支

继续使用上一节的仓库,执行命令git push origin --delete branch1即可删除远程分支:

我们到GitHub页面上查看一下:

现在就只剩下master分支啦~

2.删除本地分支

当远程分支删除后,本地分支理论上也不需要了,我们也可以进行删除,执行命令git branch -d branch1

此时可以看到本地的branch1分支也已经被删除啦~


本文标签: 学习笔记版本Git