版本控制 GitChat 课

本贴最后更新于 502 天前,其中的信息可能已经时异事殊

Git

目录

版本控制 GitChat 课

王庆港 5 月 ago 6 min read

本文章内容转自个人 GitChat 付费 chat 课,该文章 2020 年疫情期间写作首发 GitChat,目前 GitChat 版权已到期,可以附带本篇文章地址进行转载。

原文章地址:动画讲解 Git 版本控制(全栈开发系列)

Git 是开源与企业协作开发的必备工具。大多数人都知道 Git,但大多数人对许多功能一知半解,很多 Git 功能没有发挥出来,初级开发者甚至不知道 Git 的一些高效用法,另有一部分初学者对 Git 术语理解模糊,难以入门。

本门课程以实际案例,配合动画图片讲解 Git 基本知识及使用。你将学会创建开源仓库并维护,掌握企业中常用 Git 技能,参与团队开发。​


学完本场 Chat 中,你会掌握如下内容:

  • 版本控制术语
  • 新建 Git 代码仓库
  • 提交代码变更
  • 审查 Git 仓库历史
  • 给软件代码创建版本标签
  • 多分支开发与合并
  • 撤销软件代码变更
  • 远程仓库使用与同步(GitHub、码云)
  • 参与开源项目


课程特色

亮点一: 精简动画,快速理解

精心制作动画 GIF,精简形象,便于理解。

亮点二: 实战场景,快速应用

结合实际场景,给出相应解决方案,轻松引入,快速应用。

亮点三: 精简笔记,双管齐下

配备精简总结,教程轻松入门,笔记快速复习。

适用人群:Git 初学者,开发者,其他想学习版本控制的人群。

01 什么是版本控制?

欢迎大家学习《Git 版本控制》课程,今天我们将开始学习版本控制工具 Git,它能帮助我们管理软件项目的不同版本。在我们详细讲解版本控制之前我们先讲一个小故事。


昨天我和小明在家里下象棋,好长时间没下完,我俩希望下次接着下,就用手机拍个布局图就休息了。休息期间我可以跟其他人重新摆放棋盘下棋,只要有先前棋局照片,我们就可以在任何时间从原先暂停的地方重新开始。

版本控制存在类似照片的暂存点,能够保存某一时间点的工作,你可以像玩游戏一样从任意一个暂存点开始。

我们将使用版本控制系统管理不同版本软件的源代码。

Git 仓库每次提交代码相当于一次快照


版本控制无处不在,我们即使不了解版本控制,但大多数人都使用过它。

我们都用过 word 文档,当我们编辑信息时,我们可以点击保存。

当我们误删除或重新编辑时我们可以点击撤销回退到上一步,这其实就是一个版本控制功能。

而版本控制软件是这种功能的强化:

  • 标记更改了哪里
  • 标记是谁在什么时间更改
  • 做出为何更改的详细描述
  • 在同一文档的不同版本之间切换

如今的版本控制系统模型包括两大主要类型:

  • 集中式模型 – 所有用户都连接到一个中央的主仓库
  • 分布式模型 – 每个用户都在自己的计算机上拥有完整的仓库

本地版本控制是其他模型的基础,在一台电脑上就拥有版本控制的全部功能。在本地仓库中可以进行检出与提交操作(检出指将某一版本提取到工作空间,提交是将工作区代码保存到版本库,详细概念稍后讲解)。

集中式版本控制将版本库与工作空间分离,用户计算机上只保存当前要处理的项目,而版本库只存在于中央仓库里。

集中式每次提交到一个相同的中央主仓库

分布式版本控制中,无论是用户主机还是远程仓库主机,都是一个完整的版本控制系统。

那么分布式比集中式有什么好处?

  • 分布式中每个人电脑都有一份完整仓库,代码误删除可从其他人哪里恢复。
  • 分布式中每次的更改先提交到本地版本库,达到一组完整变更再提交到主版本库,减少了远程提交次数。

我们要学习的是分布式版本控制系统 Git,我们先学习本地仓库的使用,然后再学习远程仓库协作,让我们一起开始进入 Git 版本控制系统的学习!

02 版本控制中的术语

在深入学习版本控制之前,我们必须了解一些版本控制术语。当我第一次学习 Git,这些术语是我入门前的最大障碍,当我逐渐了解 Git 使用后我才逐渐明白这些术语含义,所以说边学边理解,先认识他们,以后就熟悉了。

了解这些术语后,我们将探寻使用版本控制的一般流程,从更高的层面了解如何使用 Git。


让我们一起看一下 Git 中提交到仓库的一般流程

新建了一个 Git 仓库,Git 仓库里可逻辑上划分三个区域,工作目录,暂存区,版本库,这三个区域是抽象的,Git 仓库中以文件来记录各个区域的内容。

Git 会追踪工作目录里文件及内容的变更。

当我们在 Git 仓库的工作目录下新建三个文件,Git 会将新建的文件视作变更(图中五角星表示被 Git 检测到)。

我们想将 html 文件提交到仓库中,首先将变更(新建的 html )从工作目录添加到暂存区。然后将这个文件从暂存区提交到版本库。这时才算拍摄了一组快照,提交的更改不会丢失。

注:提交到版本库中的内容才保存到了 Git 仓库中,成为一个版本快照。

Git 中的提交流程

新建了三个文件,先将 html 文件添加到暂存区,然后添加到仓库,再将 css 文件添加到暂存区,提交到仓库。

注:Git 仓库中为每次提交都创建了 Id,也就是 SHA 。他们看起来类似这样 e2adf8ae3e

当我们在工作目录下修改了一个文件, Git 仓库会识别文件修改部分(标记 2 颗星),然后我们将文件修改添加到暂存区,最后将文件修改提交到版本库。

一次文件修改并提交

修改 css 文件,将修改添加到暂存区,再提交到仓库

问题:
如果我们在工作目录下第一次修改一个文件,并将它添加到暂存区,然后我们第二次修改文件,第二次修改没有添加到暂存区,最后我们将文件 commit 到版本库,请问仓库的文件内容是第几次修改的?请思考。


如果第一次修改 css 文件,添加到暂存区,再第二次修改 css 文件,现在执行 commit,提交到版本库只有第一次修改的内容。

修改文件后提交 然后再修改文件

当执行 commit 时,只有暂存区中的内容会被提交到版本库。

如果我们想要将第二次修改也 commit 到版本库,

我们必须先将第二次修改先添加到暂存区,第一次修改的暂存与第二次修改的暂存合并,然后执行 commit,仓库中就会有第一次和第二次修改的内容。

多次暂存会覆盖暂存区内容

添加到暂存区的内容会合并,一起提交到仓库。

第一次修改 css 文件,添加到暂存区,但没有提交仓库;第二次修改 css 文件,添加到暂存区,会与第一次的修改合并,这时提交到版本库的内容是两次修改的合并。

我们已经知道了提交到仓库的流程。接下来让我们一起详细学习 Git 的使用


03 安装配置 Git 工具

不知你能否理解 Git 与 GitHub 等代码托管平台的区别。

Git 是版本管理工具,版本管理时需要用到这个工具;而 GitHub 等代码托管平台是远程仓库,版本控制还是由 Git 工具来管理。

安装 Git

接下来我们安装 Git

  1. 转到 https://git-scm.com/downloads
  2. 下载 Windows 版软件(请根据自己的系统选择合适的安装包)
  3. 安装 Git

安装完毕后,你应该能够在命令行工具中运行 git


初次 Git 配置

在开始使用 Git 之前,你需要配置 Git。在命令行工具中运行以下命令,确保所有选项都已被配置好。

windows 系统下 win+R 快捷键,输入 cmd 即可打开命令工具,或使用刚安装的 git bash 软件(推荐)

Git Bash

# 设置你的 Git 用户名
git config --global user.name "<Your-Full-Name>"
​
# 设置你的 Git 邮箱
​
git config --global user.email "<your-email-address>"
​
# 确保 Git 输出带有颜色
git config --global color.ui auto
​

请填写你自己的用户名和邮箱,这很重要,因为 Git 需要标识是谁修改了内容


04 创建 Git 仓库

我们的学习路线是先学会操作本地仓库,再学会远程仓库操作,及远程仓库与本地仓库的交互。

注:本地仓库就是一个完整的版本控制仓库,其他人电脑上的仓库,以及远程服务器的仓库都是远程仓库。-

我们将一起创建一个仓库,我提供了一个 html 单页简历模板,我们将逐步修改这个简历模板,并一步步学会 git 的常用命令操作。简历样式如图。

单页简历

本地创建仓库

在对 Git 仓库进行 commit 或执行任何其他操作之前,需要一个实际存在的仓库。

要使用 Git 新建一个仓库,使用 git init 命令。init 子命令是”initialize”(初始化)的简称。

我们会用到以下终端命令:

- `ls` - 用来列出文件和目录
- `mkdir` - 用来新建目录
- `cd` - 用来选择目录
- `rm` - 用来删除文件和目录


本地创建 Git 仓库

在电脑本地文件夹选择合适的项目存储位置,比如我会在 D 盘下新建一个 Git-Repository 目录,然后在该目录下新建不同的仓库。

  • 进入 Git-Repository 文件目录下,新建文件夹 resume
  • cd 命令进入新建文件夹 resume
  • 执行 git init 命令初始化本地仓库

你可以尝试自己根据指示创建本地仓库,下面是要用到的具体命令。


在终端下执行命令

#进入D盘。你可以选择合适的盘
$ cd D:
​
# 在合适的位置新建git仓库的管理目录,里面专门放置git项目
$ mkdir Git-Repository
​
# 进入git仓库管理文件夹
$ cd Git-Repository
​
#---------------------------------------------
​
# 新建本次要使用的代码仓库文件夹
$ mkdir resume
​
# 进入本次使用的代码仓库文件夹
$ cd resume
​
# 初始化本地仓库
$ git init
​

使用 git init 命令可以在当前目录下创建新的空仓库。

也可以在已有项目代码的目录下执行该命令

运行此命令可以创建隐藏 .git 目录。此 .git 目录是仓库的存储中心。它存储了所有的配置文件和目录,以及版本库 commit。

请勿直接修改 目录下的任何文件。这会导致版本控制失效

查看仓库状态

在我们每次对 Git 仓库进行操作前,我们需要了解当前仓库的状态。

$ git status

git status​ 是了解 Git 仓库状态。

在执行操作前常常需要先查看仓库状态,了解仓库情况后再采取操作。执行结果

$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

git status 命令将告诉我们:

  • 当前版本分支
  • 已在工作目录中被创建或修改但未添加暂存区的内容
  • Git 正在跟踪的已修改文件

克隆远程仓库

除了本地执行 git init 初始化仓库,也可以从远程克隆仓库到本地。

工作中我们常克隆已存在的远程仓库项目到本地进行编码。

在 Git 上进行克隆运行命令 git clone,传入要克隆的 Git 仓库的路径(通常是 URL,如下所示)。

GitHub 上克隆仓库

输入命令 git clone,然后输入你要克隆的 Git 仓库的路径。我们使用的项目地址为:https://github.com/wangqinggang/resume.git。因此,使用该 URL 克隆远程仓库的完整命令是:

$ git clone https://github.com/wangqinggang/resume.git

温馨提醒: 复制上述代码时,记得去掉 $ 。若出现冲突请阅读实践以下内容。


git clone 命令有如下作用

  • 默认地将创建与被克隆的仓库名称相同的目录
  • 可以提供第二个参数,作为该目录的名称 $ git clone https://xxx.git myresume
  • 将在现有工作目录下创建一个新的仓库

git clone 也可以克隆本地仓库, 在 Git-Repository 目录下执行如下命令。

$ git clone resume resume2

将会克隆 resume 仓库到 resume2


05 提交代码到仓库

Git 仓库由 commit 组成,如果没有 commit(提交),Git 仓库内容就为空。

我们已经掌握了仓库的创建,并掌握了 git initgit clonegit status 这几个命令的使用,接下来我们会讲解添加 commit 需要用到的几个命令。

  • git add 添加工作目录中的文件到暂存区
  • git commit暂存区内的文件保存到仓库
  • git diff 查看一个文件版本区别

新建代码文件

确保你进入新创建的代码仓库,先执行 git status 查看仓库状态

$ git status
​
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

执行结构告诉我们在分支 master 上(分支稍后讲解),仓库中还没有 commit,并且暂存区没有要 commit 的内容。建议我们新建或复制文件,然后使用 git add 命令来使 git 追踪他们。

我们需要在仓库下新建任意代码文件,你可以跟从本案例,或开始一个自己的代码项目。

本案例使用简历模板进行讲解,请下载 Html 简历模板,我们稍后会用到。

下载地址:https://github.com/wangqinggang/resume/archive/master.zip

下载后解压 resume-master.zip ,将 resume-master 文件夹下的内容复制到 resume 仓库。

此步骤相当于在工作目录下新建拷贝的文件,并添加文件内容。

此时我们执行 git status 查看仓库状态。

$ git status
On branch master
​
No commits yet
​
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        README.md
        assets/
        index.html
​
nothing added to commit but untracked files present (use "git add" to track)
​

控制台告诉我们新建的文件未被追踪,需要执行 git add 添加到暂存区进行跟踪。

文件添加暂存区

要将文件提交到仓库中,首先需要将这些文件从工作目录移到暂存区。

我们将使用 git add 命令将这文件移到暂存区。

暂存文件

在终端上运行以下命令,使用 git addindex.html 添加到暂存区:

$ git add index.html

注意:我们仅添加了 index.html 文件。稍后我们将添加其他文件。

$ git status
On branch master
​
No commits yet
​
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.html
​
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        README.md
        assets/
​

(use "``git rm --cached ...``" to unstage)​*,也就是当你不小心运行了* git add * 并提供了错误文件,它会提示你运行该命令撤销暂存某文件。

暂存剩余的文件

index.html 文件已暂存。我们再暂存另外的文件。现在我们可以运行以下命令:

$ git add assets/all.js assets/style.css

一个一个得添加文件太慢了,我们可以使用一个特殊的命令行字符:

**句点 ******

句点指代当前目录,可以用来表示所有文件和目录。

$ git add .

这时所有的文件都添加到了暂存区,可是在实际开发中,IDE 自动生成的许多文件并不需要上传到仓库,而我们又不能一个个的添加文件,Git 通过 .gitignore 文件完美的解决了这个问题。

忽略跟踪某些文件

git add . 会将工作目录中所有的文件添加到暂存区,我们可以在仓库根目录下创建 .gitignore 文件,里面添加需要 Git 排除追踪的文件。

我们在仓库目录下创建几个需要排除的文件:

$ touch read.txt read.png

然后在仓库目录下新建 文件

$ touch .gitignore

.gitignore 文件中可以直接加如要排除的文件名,如直接加入

read.txt 
read.png

也可以使用通配符,如加入

read.*

.gitignore 通配符的语法如下

# - 注释
? - 匹配一个字符
* - 匹配0到多个字符
[abc] - 匹配 a、b 或 c
** - 匹配嵌套目录- a/**/d 
  a/d
  a/b/d
  a/b/c/d

注意:已经被追踪的文件不会被排除

这时执行 git add . Git 不会追踪这两个文件(将文件添加到暂存区)。

添加 commit 提交

现在我们已经将新建的代码文件添加到了暂存区,我们可以将暂存内容提交到版本库,实现一个版本快照。

git commit 命令会将暂存区内容提交到版本库,常用方法是添加参数 -m ,它可添加当前版本信息。

$ git commit -m "create resume"

对于个人开发者,一行的简单信息已经足够,若需规范化,则直接执行

$ git commit

会跳出一个文本文件,采用默认的文本编辑器打开。

Sublime Text 编辑提交信息

在打开的文件中,可以添加描述。

注:# 号为注释

另起一行写主题(简短描述),其后留空行,其他所有内容都是扩展描述(正文)。

Git 提交消息规范

  • 用空行将简述与具体描述分开(git log --oneline 只显示简述)
  • 简述消息篇幅简短,限制在 20 个字以内
  • 具体描述解释是什么、为什么、如何做的,70 字以内。

建议每次 commit 只修改一个模块或功能,大的更改会用 Tag 标识版本(稍后讲解)

在编辑器文件末尾添加:

创建了单页简历
​
为练习 Git 创建该单页 Html 简历,后续将通过修改 index.html 内容来完善简历。

编辑完成保存文件关闭编辑器即可。

也可以采用两个 -m 参数的方式添加简短描述与正文,

git commit -m "创建了单页简历" -m "后续将通过修改 index.html 内容来完善简历。"

添加代码变更

我们已经完成了第一次提交,请修改 index.html 文件,添加自己的内容。

以下是我为你提供的每次提交简述信息,请根据自己耐性完成 3 次以上提交。

注:根据情景选择英文或中文

add objective  添加求职目标
​
add profile    添加简介
​
add working experience  添加工作经验
​
add projects  添加项目      
​
add education and awards   添加教育经历和奖项
​
add certification 添加资质证书
​
add skills 添加工作技能
​
add language and interest 添加语言和兴趣

06 查看仓库历史

在多次添加 commit 后,我们想要查看本地仓库的提交历史,我们会用到 git loggit show 命令。

查看提交历史

查看已经提交的历史:

$ git log

提交历史

若记录较多可以用上下箭头来翻阅,采用 q 键退出查看

不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面

我们可以使用 git log --oneline 参数查看简短的历史描述

$ git log --oneline

单行提交信息

提交历史中的文件修改

如果想更详细的查看更改了那些文件,可以使用 git log --stat 来查看

$ git log --stat 

查看文件更改内容概况

① 表示修改了 1 个文件(index.html),该文件有 14 处修改,7 处增加,7 处删除。

② 表示修改了 1 个文件(index.html),该文件有 20 处修改,10 处增加,10 处删除。

注:Git 中的修改按行来计算,即使是增加空行也会被计算在内

查看某次提交详情

我们想查看某次提交具体修改了什么内容,可以使用 git show 命令,

后面加 commit 的 SHA 简写(大于 4 个字符)

git show 会显示:

  • commit SHA
  • 作者
  • 日期
  • commit 消息
$ git show 7a2b

查看修改详情

① a/index.html 与 b/index.html 是该文件修改前和修改后的版本;index 后的字符代表 文件前后版本的 SHA。

② 表示从 index 文件从旧版本 348 行后的 19 行,修改成了新版本 348 行后的 19 行,- 号代表之前版本,+ 号代表修改后版本

③- 号代表位于原始版本中,但被删除的行,+ 号代表新版本中增加的行。

查看尚未提交的更改

在实际工作中,我们前一天开始开发项目的一个功能,但一天没完成,当我们第二天开始工作的时候,有一些没有提交的更改。(没有完成功能模块,所以没有提交)

我们可以使用 git diff 命令来查看已经执行但尚未 commit 的更改。

$ git diff

此命令会显示:

  • 已经修改的文件
  • 添加 / 删除的行所在的位置
  • 执行的实际更改

要查看 git diff 的效果,我们需要未经提交的更改。

我们修改简历的名称,添加英文名 ideaworks。保存文件然后在终端上执行

修改简历名称,加入英文名

$ git diff

git diff 结果:红色为删除,绿色为新增

根据命令的执行结果,我们知道昨天我们工作进程到哪里,可以继续进行上次未完成的工作。

07 标签

  • git tag :给某个 commit 添加标签
  • git branch :多分支软件开发
  • git checkout :切换不同分支和 Tag
  • git merge :合并不同分支

7.1 添加 Tag 标签

当我们软件开发到一定程度,具备一定功能时,已经成为一个可发布的版本,我们会为它添加系统版本号。

为某次提交添加 Tag

git tag 命令用来标记特定的 commit 。

$ git tag -a v1.1.0

此命令将:

  • 向最近的 commit 添加标签
  • 如果提供了 SHA,则向具体的 commit 添加标签

(注意:在上述命令中,使用了 -a 选项。该选项告诉 git 创建一个带注释的标签​*。如果你没有提供该选项(即* git tag v1.1.0​*),那么它将创建一个轻量级标签。*

此处可以了解下软件版本号定义:

<主版本号>.<次版本号>.<修订版本号>.<日期版本号加希腊字母版本号>

希腊字母版本号共有 5 种:base、alpha、beta、RC、release。例如:

1.1.1.200512_beta

软件版本阶段说明:

  • Alpha 版:以实现软件功能为主,Bug 较多,内部交流使用,需要继续修改。
  • Beta 版:消除了严重错误,但存在缺陷,需要继续测试。
  • RC 版:该版本已经相当成熟,基本上不存在 Bug,与即将发行的正式版相差无几。
  • Release 版:交付用户使用的版本,该版本有时也称为标准版。

版本号修改规则(1.1.1.200512_beta):

  • 主版本号(1):当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。
  • 子版本号(1):当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。
  • 阶段版本号(1):一般是 Bug 修复或是一些小的变动,常修复 Bug 发布修订版。
  • 日期版本号(200512):记录修改项目的当前日期,每天对项目的修改都需要更改日期版本号。
  • 希腊字母版本号(beta):用于标注当前版本的软件处于哪个开发阶段,进入到另一个阶段时需要修改此版本号。

我们需要用到的命令:

# git tag -a [版本号]  为当前 commit 创建版本

# git show [版本号] 查看版本

# git tag -d [版本号] 删除版本


使用了 -a 选项。该选项告诉 Git 创建一个带注释的标签。如果你没有提供该选项,它将创建一个轻量级标签。

git bash 中将默认编辑器修改为 VS Code(不然在要添加注释的时候没有默认编辑打开) git config --global core.editor "code -w"

建议使用带注释的标签,实际开发中需要标识大量的额外信息,例如:

  • 标签创建者
  • 标签创建日期
  • 标签消息:版本功能信息

添加详细标签信息

使用 -a 选项会跳出标签信息文本编辑,记住填写格式同 commit 信息

要查看某个标签的详细内容可以运行以下命令,将会显示该标签描述信息。

$ git show v1.1.1.200512_beta

查看标签详情

我们可以使用以下命令删除标签:

$ git tag -d v1.1.1.200512_beta

补充:给过去的 commit 添加版本号,后面直接跟过去的 commit SHA(commit id 或者叫修订号)。

$ git tag -a v1.1.0 a1d2fa

08 分支 branch

在团队开发中,团队各成员都有自己的任务,当软件出现 Bug 或开发新功能时,为了不影响当前的开发流程,会创建一个新的分支用于 Bug 修复或新功能开发,当任务完成后再合并到主开发流程(master 分支)。

要创建分支,使用 git branch 命令并提供要创建的分支对应的名称。如果你想创建一个叫做 dev 的分支,只需运行以下命令:

$ git branch dev

分支创建:图中红色的指针

如果你想给之前的 commit 创建分支,只需在 git branch 命令后添加 SHA。

$ git branch bugfix 4e5f

补充:当我们创建错误分支是可以采用 git branch -d 分支名 来删除分支。

问题:执行  命令后,进行修改提交,将会提交到哪个分支上?

如果我们现在进行 commit 的话,该 commit 将添加到 master 分支,而不是 dev 分支。要在分支之间进行切换,我们需要使用 git 的 checkout 命令。

$ git checkout dev

新建 dev 分支之后使用 checkout 切换到 dev 分支

在 Git 中分支相当于指向 commit 的指针,Git 采用了 HEAD 指针来标记当前活跃分支,如果我们想将更改提交到 dev 分支上,需要使用 git checkout dev 来激活 dev 分支,也就是将 HEAD 指针指向 dev 分支。

运行该命令会将工作目录中文件和目录替换为分支指向的 commit 所对应的文件和目录。

为了制造分支合并的条件,请分别在 master 分支和 dev 分支进行提交:

  • 请在 dev 分支修改 ① 简历名称 ② 个人邮箱
  • 请在 master 分支修改 ① 简历名称 ② 求职岗位

在 dev 分支上修改提交后后切换到 master 分支上进行修改提交

修改的简历具体位置如图:

在 dev 分支上修改简历名、邮箱;在 master 分支修改简历名和求职目标

接下来我们将学习如何合并这两个分支并处理合并的冲突。在此之前,求确保你的分支修改如下:

dev 和 master 分支合并

分支合并

在正式开发过程中,我们在 dev 分支开发功能完成后,需要将 dev 分支上的内容合并到 master 分支上。将分支组合到一起称为合并。合并时 Git 可以自动将不同分支上的更改合并到一起。

我们要做的是将 dev 分支上的内容合并到 master 分支上,由于 dev 分支与 master 分支修改了相同的内容,我们需要处理合并的冲突。

将 dev 分支内容合并到 master

当你要合并分支时,务必知道当前位于哪个分支上。合并分支会提交 commit。

合并指令

git merge 指令用来合并 Git 分支,合并 dev 分支前,你必须位于 master 分支。

# 查看当前所在分支,确保自己位于 master 分支
$ git branch
# 切换到 master 分支
$ git checkout master
# 执行合并
$ git merge dev

发生合并时,Git 将更改的代码行合并到一起,提交一个 commit 来记录合并操作。

因为我们合并的内容有冲突,Git 会在编辑器显示冲突的代码,由我们决定保留哪些代码。

合并冲突提示:注意 <<<||| ==>>> 符号

编辑器中的字符:

  • <<< 到 ||| 显示的是当前 master 分支上修改后的内容
  • ||| 到 ---- 向您显示 master 分支与 dev 分支修改前共同的内容是什么
  • --- 到 >>> 显示的是 dev 分支上修改后的内容,也就是要合并分支的内容

我们根据需要删除无用的代码,然后将修改添加到暂存区,并进行提交更改。

解决冲突,保留最终代码

提交完成后,你可以采用如下命令查看当前分支情况(去掉 --all 不显示 Tag):

$ git log --oneline --decorate --graph --all

合并冲突解决后的提交历史记录

注意图中每一行注释的注释对象是 * 位置的 commit

快进合并

当我们合并时,我们是将其他分支合并到当前活跃(checkeout)分支上。而不是将两个分支合并到一个新的分支上。

有一种简单的合并我们称为快进合并,如图:

快进合并

master 分支没有提交修改, dev 提交了修改,此时将 dev 合并到 master 中将导致快进合并。快进合并将使当前检出(checkout)的分支向前移动,直到它指向与另一个分支(这里是 dev)指向的 commit。

撤销更改

改最后一个 commit

我们已经使用 git commit 命令提交了大量的 commit。借助 --amend 选项,我们可以更改最近的 commit。

$ git commit --amend

我们修改简历的电话和网站,提交新的 commit,并添加消息 “modify resume phone”。

当我们提交完成后,发现我们的 commit 消息忘记添加网站的修改信息,如果当前工作目录没有新改动(没有未 commit 的更改),我们可以运行 git commit --amend

$ git commit --amend

amend 修改最近一次提交的信息描述

这将使我们能够重新提供 commit 消息。代码编辑器将打开,并显示原始 commit 消息。修改信息然后保存文件并关闭编辑器即可。

向 commit 中添加忘记更改的文件

git commit --amend  也使能够重新添加忘记在一次 commit 中的更改。

我们刚刚修改了简历的电话和网站,我们发现在这次 commit 中忘记修改邮箱信息,我们不用再次提交 commit,可以在上次 commit 中添加新的内容。

想要在上次 commit 中添加新的内容,可以按照以下步骤:

  • 编辑文件
  • 保存文件
  • 暂存文件
  • 运行 git commit --amend

我们在编辑文件时加入对邮箱的修改,暂存并执行 git commit --amend

还原上次提交

Git 还原(revert) 具体的 commit 时,Git 会执行恢复上次 commit 的更改,并提交一个 commit 保存还原的内容。

我们详细讲解下。假设 commit A 修改了简历的标题,如果 Git 还原 commit A,那么 Git 将创建一个新的 commit,并还原修改的简历标题。

git revert 命令,后面加要还原的 commit SHA。

$ git revert SHA

运行该命令会弹出代码编辑器,以便编辑 commit 消息。

重置提交

git reset 命令用于重置(删除)提交:

$ git reset SHA

它有三个选项:

-- mixed
-- soft
-- hard

git reset --mixed SHA 会将对应的 commit 更改回退到工作目录:

Git reset 重置版本库中 Head 索引

假设之前的文件状态为

修改之前的提交状态

执行 git reset --mixed B  后的状态

暂存区中的内容都被消除

可以看到 mied 回退到 B 提交会将版本库中 B 之后的 C 提交清除,暂存区中的所有修改被删除,C 提交的内容和之前暂存的 D 只存在于工作目录中。

soft 选项会将内容回退到工作目录(动画中未体现)和暂存区

假设之前的文件状态为

修改之前的提交状态

执行 git reset --soft B 后的状态如下 (此处注意 soft 选项后跟要回退到的 commit 版本)

soft 选项会将 C 提交内容回退工作目录和暂存区

git reset --hard SHA 会将对应的 commit 直接删除,无法恢复。

hard 选项会将之后的提交全部删除(工作目录和暂存区的修改不存在)

假设之前的文件状态为

修改之前的提交状态

执行 git reset --hard B  后的状态:

hard 选项 B 提交后的工作目录原有修改内容和暂存区都被清除

一定要注意 git reset 命令的使用!!不要造成事故。

09 远程仓库管理

在工作中,我们很少单枪匹马作战,通常需要进行团队协作。团队开发时会搭建一个专门的 Git 仓库,里面放置项目的最新代码。因此学会与远程仓库的协作是团队开发的第一步。

开始之前我们先明确 Git、GitHub 和 Gitee (码云) 的区别。

Git 是版本控制工具,帮助我们管理仓库;而 GitHub、码云等平台是远程仓库。本地电脑上的仓库是本地仓库,其他电脑和 GitHub 等平台的仓库是远程仓库。

本小节我们将学习三个命令:

 · # 添加远程仓库地址
   git remote
  ·# 将远程仓库拉取到本地仓库
   git pull
   # 将本地仓库推送到远程仓库
   git push

首先我们需要新建远程仓库。请提前注册 GitHub 或码云的帐号。

新建远程仓库

填写仓库信息,只填写仓库名称和仓库描述,其他保持默认,保持仓库内容为空便于上传本地仓库(不要勾选 创建Readme 文件)。

填写仓库基本信息

空仓库创建完成后 Github 或码云会给出上传本地仓库的提示:

提示信息

git remote add 命令中的 origin 为远程仓库的别名,可以更改,最后加仓库地址。

git remote add origin https://github.com/wangqinggang/idearesume.git

git remote add 命令可以把一个已有的本地仓库与远程仓库关联,但请注意,请关联自己的远程仓库,因为你的 SSH Key 公钥不在我的账户列表中,你无法提交推送到我的远程仓库。

现在我们已经关联了远程仓库,我们可以使用 git remote -v 查看关联的仓库。

$ git remote -v

SSH Key 配置

Secure Shell(SSH)网络协议允许两台电脑之间安全的进行数据交换。而 SSH Key 密钥对能让你无需输入密码就能登录到 SSH 服务器。

使用 SSH key 的步骤:

在客户端生成 SSH key(密钥对:公钥和私钥) 在服务端(GitHub 或码云)加入你的公钥

码云官方的密钥配置教程:

https://gitee.com/help/articles/4181#article-header0

GitHub 的密钥说明:

https://help.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh

关键部分如下。

  1. 打开 Git Bash。

  2. 粘贴以下文本,替换为您的 GitHub 电子邮件地址。
    $ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    使用提供的电子邮件作为标签创建一个新的 SSH 密钥三次回车保持默认生成密钥。

  3. 将生成的 SSH 密钥复制到剪切板,点击 GitHub 右上方头像三角 > Settings > SSH and GPG keys > New SSH Key,将密钥复制到 Key 文本框,填写合适的标题并保存。

    SSH Key 秘钥

  4. 测试 SSH Key 连接。

打开 Git Bash,输入下列命令:

$ ssh -T git@github.com

输出提示选择 yes,会看到成功消息

> Hi username! You've successfully authenticated, but GitHub does not
> provide shell access.

本地仓库上传到远程仓库

要将本地内容提交到远程仓库,需要使用 git push 命令。 提供远程仓库简称,然后提供要推送提交的分支名称:

$ git push <远程仓库简称>  <要推送的分支>

我们本地已经创建了仓库,并且提交了更改,现在我们需要将本地仓库上传到远程仓库。

git push 流程动画

注意:如果远程仓库为空,该命令会将整个分支的 commit 全部提交到远程仓库。

在 git remote 命令中,我们已经添加了 Git 的远程仓库别名为 origin。我们想推送 master 分支,命令为:

$ git push origin master

现在,我们以将本地的简历仓库上传到了远程仓库中。

注:我们也加入 -u 选项,git push -u origin master 会使得下次推送提交时只运行 git push 命令即可。

此时我们的本地项目已经上传到 GitHub,现在我们在 Github 上编辑 index.html 修改简历名称创建一次提交,模拟远程仓库版本提交本地一个提交。

在远程仓库上修改文件模拟其他项目成员的更改

远程仓库进行编辑提交与本地仓库大致相同。

远程仓库提交信息填写

远程仓库拉取到本地

在团队开发时,当我们第一次加入项目或远程仓库项目领先本地 commit 时需要将远程仓库的项目拉取到本地仓库。

我们已经人为制造了远程仓库版本大于本地仓库,现在我们可以使用 git pull 命令将远程项目拉取到本地。

同步远程仓库内容

我们想将远程仓库 origin 上的 master 分支拉取到本地,运行以下命令:

$ git pull origin master

但是实际开发中,远程仓库有版本变更,本地仓库也有版本变更,此时远程与本地都有新的 commit 提交,此时我们可以使用 git fetch 命令。

$ git fetch origin master

都进行一次提交,然后本地拉取远程仓库修改内容

fetch 和 pull 有什么不同?

Git 在本地会保存两个版本的仓库,分为本地仓库和远程仓库。

  • 本地仓库就是我们平时执行暂存、commit 的那个仓库。
  • 远程仓库可以用 git remote -v 查看。

例如本地仓库的 master 分支与远程仓库的 origin/master 分支。

  • fetch 只能更新本地远程仓库(远程仓库副本在本地的缓存,可以代表远程仓库)的代码为最新版本,本地仓库的代码还未被更新。
  • pull 操作是将本地仓库和远程仓库(本地的)一起更新到远程的最新版本。

git fetch 命令会将远程仓库的更改拉取到本地,作为 master 的一个分支,分支的地点是本地与远程同步的 commit。将 origin/master 分支合并到 master 分支,先完成然后再将本地仓库内容上传到远程仓库。

$ git merge origin/master

本地合并远程分支

此时我们可以将本地仓库 master 分支 push 到远程仓库,远程仓库会包含本地的合并:

$ git push origin master

推送本地分支到远程仓库

10 开源项目协作

作为开发者,我们大多数时间都在使用开源软件,许多著名的项目框架都是开源的。开源使开发者们互相协作,创作更好的软件。本小节将讲述如何参与开源项目,与其他开发者协作,为开源项目做出贡献

参与开源项目

开源项目中常有以下类型的人员:

  • 作者:创建项目的个人或组织
  • 所有者:对组织或存储库具有管理所有权的人
  • 维护者:负责推动愿景和管理项目组织方面的贡献者
  • 贡献者:每个为项目做出贡献的人
  • 社区成员:使用该项目并提出建议的人

如何成为项目的贡献者?

Fork 项目

Fork 的名词含义为叉子,动词为分叉,如果你 fork 仓库,相当于复制仓库到你账号下。

在码云或 GitHub 等平台上,你可以 fork 其他人的仓库,该操作在你的账户下复制了一份相同的仓库。

fork 其他人的项目

注意:克隆仓库是复制到本地,而 fork 仓库是将仓库复制到自己账户下。

此时我们可以将该仓库克隆到本地进行更改提交,按照之前讲解的步骤进行远程仓库上传,此时上传的仓库为你账户下 fork 的仓库。

审查现有工作

在办公室中的团队协作与在互联网上的开源协作都会遇到项目进度协调的问题。

因为多个开发人员创建了多个分支进行工作。我们如何查看某人做的所有提交?如何查看某人解决的问题(issue)?

注:开源项目中常以问题( issue)来交流开发问题。

要查看所有合作者的 commit,我们可以使用 git shortlog

$ git shortlog

它将分组显示每个合作者提交了多少 commit,并给出提交 commit 的简短描述。

也可以按照合作者名称进行筛选,查看某个参与者的 commit:

$ git log --author=参与者名

如果人名有空格必须加双引号:

$ git log --author="William Wang"

此时我们可以使用 git show 查看贡献者某次提交的详细内容。

$ git show SHA

从 GitHub 或码云的 issue 中查看有哪些问题是你可以解决的,据此 fork 项目,并将自己账户下的 fork 项目克隆到本地,根据要解决的 issue 新建分支,在新分支上进行开发。

一定不要在主分支 master 上开发,主分支作用是所有功能的集成。

在开始开发工作之前,应先查找参与贡献的说明文件。请先阅读在项目中的 CONTRIBUTING.md 等说明文件,这是项目所有者发布的如何参与贡献的说明,该文件列出了为该项目做贡献应遵循的信息。

GitHub 和码云中都采用 issue 的方式与原作者交流,你在开发之前需要提前搜索有没有人提出过该 issue,没有的话就添加 issue 与作者交流。不要等到花费长时间完成后才发现早有人完成了该功能。

创建拉请求

pull request (拉请求)是对原始仓库的维护者的请求,创建 pull request 是为了让仓库维护者 pull (拉取)你的更改到它的原始仓库。

在 GitHub 或码云等平台 fork 仓库,并将仓库克隆到本地进行开发,开发完成后将本地仓库上传到 fork 仓库。

# 本地新建 bugfix 分支进行开发
$ git branch -b bugfix

# 将 bugfix 分支 push 到 fork 仓库
$ git push fork bugfix

注意进行 push 操作前需要在本地配置远程仓库地址。可以使用 git remote -v 查看本地配置的仓库信息,不存在远程仓库信息需要使用 git remote add upstream https://xxx.git 命令来添加。

其中 add 后面跟的是 git 仓库地址的别名,注意理解动画中的仓库地址别名(/ 前为别名)。

  • 本地仓库为你电脑上的仓库
  • Fork 仓库为你账户下复制的仓库
  • 原始仓库为你要参与的其他人账户下的仓库

将本地 bugfix 分支提交到 fork 仓库

然后在 GitHub 或码云等平台 fork 仓库页面创建 pull request,让原作者将 fork 仓库内容提取到原始仓库,将你的开发内容合并到原始仓库的 master 分支上。

原始仓库作者账户下合并你的 Fork 仓库提交

在 GitHub 或码云中,在自己账号的以下位置创建拉请求:

github 创建拉请求

与原仓库保持同步

在 GitHub 和码云中,我们可以 star 项目来收藏项目,watch 项目来监视项目动态。

如果我们 fork 仓库进行本地更改时原始仓库有了新的提交,我们如何保持本地仓库的 master 分支与原始仓库 master 分支保持同步?

请先看懂这张图,明确哪些分支未同步

还记得添加远程仓库的命令么,我们初始学习 Git 常常使用 origin 作为克隆的远程仓库名称。现在我们要与第二个远程仓库保持同步,一个是自己账户下 fork 的仓库,另一个是原始仓库。在这里使用 fork 代表账户下 fork 的仓库,使用 start 代表原始仓库。

git remote add <仓库简称>  <仓库地址>

注:使用上述命令将原始仓库加入到 Git。

#  重命名远程仓库 origin 为 fork
$  git remote rename origin fork

本地仓库现在与 fork 仓库保持同步(注意图中颜色),但本地与 fork 仓库的 master 分支都落后原始仓库一个提交,我们需要用 fetch 命令将 start 远程仓库的内容拉取到本地。

$ git fetch start master

将 start/master 分支拉取到 local 仓库

我们现在需要将 start/master 分支合并到本地的 master 分支,使本地的 master 分支同步原始仓库。

切换到 master 分支,将 start/master 分支合并。

$ git checkout master
$ git merge start/master

在 local/master 分支上合并 start/master 分支

最后将本地仓库的 master 分支 push 到 fork 仓库。

$ git push fork master

11 精简笔记

11.1 创建新仓库

创建新文件夹,打开,然后执行 git init 创建新的 Git 仓库。

11.2 克隆仓库

  • 执行 git clone <仓库名> 以创建一个本地仓库的克隆版本
  • 执行 git clone <远程仓库地址> 克隆远程仓库

11.3 添加与提交

  • 执行 git add <文件名> 把文件添加到缓存区
  • 执行 git add * 把所有文件添加暂存区
  • 执行 git commit -m "提交信息" 提交改动
  • 执行 git checkout SHA 将某个历史版本替换到工作区
  • 执行 git rebase -i HEAD~2 合并最近两次 commit

11.4 推送改动

  • 执行 git push origin master 将 master 分支改动提交到远程仓库 origin

11.5 分支

  • 执行 git checkout -b feature_x 创建 “feature_x” 分支并切换过去
  • 执行 git checkout master 切换回主分支
  • 执行 git merge feature_x 合并 feature_x 分支到 master
  • 出现冲突在编辑器合并冲突,保存关闭后执行 git add <filename> 暂存修改,并执行 git commit -m "提交消息" 来提交合并冲突
  • 执行 git branch -d feature_x 删除新建分支

11.6 更新本地仓库

执行 git pull 更新你的本地仓库至最新改动。

若本地与远程都有更改,pull 失败,就在你的工作目录中获取(fetch)并合并(merge) 远端的改动。

$ git fetch origin master
$ git checkout master
$ git merge origin/master

11.7 创建标签

  • 执行 git tag v1.0.0 d63af 给 d63af 创建 v1.0.0 的标签
  • 执行 git tag 查看所有标签
  • 执行 git tag -d v1.0.0 删除标签

11.8 查看历史纪录

  • 执行 git log --oneline 查看历史提交
  • 执行 git show SHA 查看某次提交的详细信息
  • 执行 git shortlog 查看每个人的 commit 记录
  • 执行 git log --author="name" 查看某个人的提交记录

11.9 撤销代码变更

  • 执行 git branch backup 创建备份分支
  • 执行 git reset --hard HEAD^ 来回退到上一次 commit 的状态
  • 执行 git reset --hard SHA 回退到任意版本

11.10 开源协作

远程仓库平台执行 fork。将 fork 仓库 clone 到本地:

$ git clone http://xxx.git

本地新建分支进行 issue 解决:

$ git branch -b bugfix

开发完成后将 bugfix 分支 push 到远程 fork 仓库,并在页面上创建 pull request:

$ git push fork bugfix
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    209 引用 • 358 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...