实验目的:
- 了解分布式系统版本管理的核心机理
- 熟练掌握git的基本指令和分支管理指令
实验内容
1.安装git
2.初始化配置git,git init ,git status
3.掌握git log,git diff,git add
4.掌握git tag ,git branch,git commit
5.掌握git revert指令
实验记录
1.安装git
Github 下载 Windows 版git,安装时选择默认配置即可
2.初始化配置 git
为了你能够使用git,以及连接远程仓库,需要配置本地的git信息
- 设置你的用户名
- git config --global user.name "
"
- git config --global user.name "
- 设置你的 Git 邮箱
- git config --global user.email "
"
- git config --global user.email "
- 确保 Git 输出内容带有颜色标记
- git config --global color.ui auto
- 对比显示原始状态
- git config --global merge.conflictstyle diff3
- git config --list
3.从头开始创建仓库
3.1 创建项目目录
在本地的E/learnGit 下创建一个名为:new-git-project的目录,然后进入此目录下,代码如下图:
3.2 初始化仓库
对仓库进行管理和操作必须要有一个实际的仓库,使用一下命令可以创建一个空的仓库,代码如下图:
3.3 克隆现有的仓库
首先确定此时的目录位置,其次这个目录下没有存在的仓库((可在目录下运行 git status ,查看目录里的文件是否在git仓库,此外如果你位于 Git 仓库目录下,提示符将包含一个用小括号括起来的名称,注意上图新建仓库的 master),因为git不能嵌套仓库,然后可以使用如下命令克隆仓库,代码如下图:
注意:如果此时遇到错误,如下图:
解决方法参考:清空dns,重新试了几次竟然可以了,好像因为缓存不够
3.4 克隆仓库的状态
进入仓库,命令如下图:
git status 命令将显示很多信息,具体取决于你的文件状态、工作目录和仓库。但是你不需要过于关心这些内容…只需运行 git status,它将显示你需要知道的信息。
- 输出结果告诉了我们几条信息:
- On branch master – 这部分告诉我们 Git 位于 master 分支上,(也就是默认分支)。
- Your branch is up-to-date with 'origin/master'. – 因为我们使用 git clone 从另一台计算机上复制了此仓库,因此这部分告诉我们项目是否与所复制的仓库保持同步状态。
- nothing to commit, working directory clean – 表示没有任何待定的更改。
4.显示已经提交的信息
此命令可以查看许多信息,包含每次提交的具体信息,命令如下图(默认):
其他的附加选项如下简介
- git log 默认情况下,该命令会显示仓库中每个 commit 的:
- SHA 每个 SHA 都是唯一的,因此,我不需要查看整个 SHA。只需知道前 6-8 个字符即可
- 作者 出结果显示了每个 commit 的作者
- 日期
- 消息 这是 commit 消息最重要的部分…我们通常都希望看到此信息
- git log --oneline 命令
- 每行显示一个 commit
- 显示 commit 的 SHA 的前 7 个字符
- 显示 commit 的消息
- git log --stat 命令
- 显示被修改的文件
- 显示添加/删除的行数
- 显示一个摘要,其中包含修改/删除的总文件数和总行数
- git log -p 命令
- 显示被修改的文件
- 显示添加/删除的行所在的位置
- 显示做出的实际更改
- git log -p +
/ git show + 命令 - 仅显示一个commit的信息
- git show 可以与大部分选项使用 如--stat:显示更改哦了多少文件
- 这两条命令功能几乎一样
5 添加,提交文件,检查状态
可以使用git或者进入文件管理器 建立以下目录,如下图:
然后回到git查看此时仓库的状态,命令如下图:
可见git自动记录了这个文件夹一下的变更,但是此时仓库的状态还是空的,也就是说这些修改只存在在工作目录中git还未对其进行跟踪,因为还没有添加,提交
5.1 将文件从工作目录移到暂存区
终端输入:git add index.html,此时index.html已经移到暂存区中
然后可以把其他的文件也转移到暂存区
5.2 将暂存区修改提交仓库
终端输入:git commit,此时暂存区所有内容都会被提交到仓库
随后你就可以进行更复杂的修改操作,然后像以上过程一样提交给仓库
5.3 git commit小结
仅仅使用git commit会打开默认的编辑器,然后输入你的说明,你可以使用git commit -m +
-对于良好的提交说明建议
- 消息篇幅简短
- 解释提交的作用
- 请勿解释为何做出了这些更改
- 请勿解释如何进行了更改
- 请勿使用单词and
- 如果你必须使用 "and",则你的提交说明可能进行了太多的更改,将这些更改拆分为独立的 commit
你想要解释原因的话:在编写提交说明时,第一行是消息本身。消息之后空一行,然后输入正文或说明,包括关于为何需要该 commit 的原因详情(例如 URL 链接)。提交说明的详情描述部分包含在 git log 中
5.4 git diff查看修改内容
此工具可以在进行提交之前告诉我们已对文件进行了什么样的更改,这些更改是已被加入但是尚未提交的更改。你可以修改index.html的内容,保存之后使用次命令查看结果,可见修改之前的内容是红色的,修改之后的内容为绿色,还包括git的统计信息。如下图所示:(和运行 git log -p 的结果一样)
5.5 gitignore提交时可以忽略的文件
如果你想将某个文件保留在项目的目录结构中,但是确保它不会意外地提交到项目中,可以使用名称特殊的文件 .gitignore(注意文件名开头的点,很重要!)。将此文件添加到 new-git-project项目根目录。你只需列出希望 git ignore(忽略,不跟踪)的文件名,git 将忽略这些文件。如此时仓库中有新建的一个world.docx文档,然后新建了.gitignore文件,文件内容以及查看仓库状态结果如下图:
git 知道查看名称为 .gitignore 的文件的内容。因为它在其中看到"world.docx",所以忽略了该文件,并且没有在 git status 的输出结果中显示该文件。
5.5 忽略文件文件名的通配符
通配符允许你使用特殊的字符来表示某些格式/字符。在 .gitignore 文件中,你可以使用:
- 空白行作为空格
- 井号 将行标记为注释
-
- 与 0 个或多个字符匹配
- ? 与 1 个字符匹配
- [abc] 与 a、b 或 c 匹配
- ** 与嵌套目录匹配 - a/**/z 与以下项匹配
- a/z
- a/b/z
- a/b/c/z
6 标签分支
6.1 创建标签
以下命令用来创造一个标签标记一个版本信息, 而且是向最近的 commit(如果提供了 SHA,则向具体的 commit 添加标签) ,比如创造一个v1.0的标签,具体用法: git tag -a v1.0
注意:在上述命令 (git tag -a v1.0) 中,使用了 -a 选项。该选项告诉 git 创建一个带注释的标签。如果你没有提供该选项(即 git tag v1.0),那么它将创建一个轻量级标签。
-建议使用带注释的标签包括:
- 标签创建者
- 创建日期
- 标签消息
6.2 验证标签
git tag显示所有的标签,还可以使用git log来查看标签处在那个位置,如下图:
6.3 删除标签
可以通过输入 -d 选项 (表示 delete 删除!)加上标签名称来删除 git 标签,如:git tag -d v1.0
6.4 git branch管理分支
6.4.1 创建分支
使用此命令可以创建一个分支,比如创建一个siber的分支命令:git branch siber
虽然你已经创建了分支,但是你目前仍然在默认分支上!
6.4.2 切换分支
此命令可以切换到另外一个分支,比如切换到上边建立的siber分支:git checkout siber
然后你就可以在这个分支上做你想做的修改,分支是一个很强大功能!下图是日志显示的信息,可以看到当前分支:
注意:在进行 commit 时,该 commit 将添加到当前分支上;而且最重要的是:此命令将删除 master 分支中的 commit 引用的所有文件。它会将这些文件替换为 sidebar 分支中的 commit 引用的文件,请务必理解这种工作方式。
6.4.3 删除分支
分支用来进行开发或对项目进行修正,不会影响到项目(因为更改是在分支上进行的)。在分支上做出更改后,你可以将该分支组合到 master 分支上,合并了分支的更改后,你可能不再需要该分支了。如果你想删除分支,可以使用 -d 选项,命令如:git branch -d siber(要删除 side 分支,你需要切换到 master 分支,或者创建并切换到新的分支)
- 删除可能会有一下情况
- 如果某个分支上有任何其他分支上都没有包含的 commit(也就是这个 commit 是要被删除的分支独有的),git 不会删除该分支。
- 无法删除当前所在的分支
- 如果你切换到 master 分支并尝试删除 sidebar 分支,git 也不会让你删除,因为 sidebar 分支上的新 commit 会丢失!要强制删除,你需要使用大写的 D 选项 。
6.4.5 分支实战/查看所有分支
通过建立另外一个分支并在其上添加对应的commit,然后回到master分支,再添加其他的commit,观察结果,如下图(这个分支是为了下边合并做铺垫):
通过图的形式显示了目前已经存在的所有分支以及其上的修改附加信息,下边开始合并分支。
7.合并
分支的存在是为了不影响默认分支的情况下做出一定的更改。当你在主题分支上做出更改后,如果觉得不想要该分支上的更改,则可以删掉该分支,或者你决定要保留更改,则可以将该分支上的更改与其他分支上的更改合并。将分支组合到一起称为合并。git 可以自动将不同分支上的更改合并到一起。这种分支和合并功能正是 git 的强大之处!你可以在分支上做出小的或大的更改,然后使用 git 合并这些更改。发生合并时,git会做以下操作:
- 查看合并的分支
- 查看分支的历史记录并寻找两个分支的 commit 历史记录中都有的单个 commit
- 将单个分支上更改的代码行合并到一起
- 提交一个 commit 来记录合并操作
7.1 合并指令git merge
因为合并的是两个完全不一样的分支,因此将提交 commit。在进行 commit 时,需要提供 commit 消息。因为这是合并 commit,因此已经提供了默认消息。你也可以更改消息,但通常都会直接使用默认的合并 commit 消息。命令如下图:
- 快速合并
- 要合并的分支必须位于检出分支前面。检出分支的指针将向前移动,指向另一分支所指向的同一 commit。
- 普通类型的合并
- 两个完全不同的分支被合并
- 创建一个合并 commit
7.2 合并冲突
大部分情况下,git 将能够成功地合并分支。但是,有时候 git 无法完全自动地进行合并。合并失败时,就称为合并冲突。如果出现合并冲突,git 将尝试尽可能合并多的内容,然后将留下特殊选项,告诉你需要从何处手动修复。
7.2.1 创造合并冲突
正如你所知道的,git 会跟踪文件中的代码行。如果完全相同的行在不同的文件中更改了,这时 git 不确定你要使用即将合并的分支中的哪些行,就会出现合并冲突。因此我们需要在两个不同的分支上修改同一行,然后重设合并它们。现在我们首先需要创建一个合并冲突。
现在我们新建一个分支为heading-update,并在master上修改和其一样的标签元素h1,而且设置为不同的代码(这里master中h1内容为Quest,heading-update分支 h1内容为Crusade)然后分别提交给仓库,修改位置如下图:
具体修改之后用log命令查看分支图,如下:
我们即将导致合并冲突,确认做出以下的更改:
- 已经在 master 分支上做出了更改标题的 commit
- 已经在 heading-update 分支上做出了同样更改标题的 commit
- 已经位于 master 分支上
7.2.2 解决冲突
然后就可以使用合并分支的命令了,可以尝试一下,看会发生什么!如下图:
好的,提示已经出现了合并冲突!然后git status命令可以查看仓库状态,随后打开源文件index.html即可看到git所提示的需要修改的地方,如下图:
合并指示符: <<<<<<< HEAD 此行下方的所有内容(直到下个指示符)显示了当前分支上的行
||||||| merged common ancestors 此行下方的所有内容(直到下个指示符)显示了原始行的内容
======= 表示原始行内容的结束位置,之后的所有行(直到下个指示符)是被合并的当前分支上的行的内容
>>>>>>> heading-update 是要被合并的分支(此例中是 heading-update 分支)上的行结束指示符
然后开始解决冲突,切换到index.html修改文件如下图:
保存所作的修改然后commit ,就可以完成合并冲突!
注意:git 将 commit 包含合并冲突指示符的行!它们只是普通的字符,因此 git 不会因为它们而停止 commit。你需要自己决定是否删掉它们。别忘了使用 git diff 检查哪些内容将暂存并 commit!
7.2.3 解决冲突的一般过程
- 找到并删掉存在合并冲突指示符的所有行
- 决定保留哪些行
- 保存文件
- 暂存文件
- 提交 commit!
8.撤销更改
8.1 git commit --amend
- 更改最后一个commit
- 你已经使用 git commit 命令提交了大量的 commit。现在,借助 --amend 选项,你可以更改最近的 commit。即命令:git commit --amend
- 向 commit 中添加忘记的文件
使你能够包含忘记包含的文件(或文件更改)
8.2 还原commit
当你告诉 git 还原(revert) 具体的 commit 时,git 会执行和 commit 中的更改完全相反的更改。现在假设仓库中有个 commit 将h1标题改为 Quests & Crusades,下面是该修改之后的log graph图:
在此基础上使用还原命令还原到具体的SHA,命令如下图:
再次查看此时的log graph图可见,命令创建了新的commit
- 将撤消目标 commit 所做出的更改
- 创建一个新的 commit 来记录这一更改
8.3 重置
重置(reset) 似乎和 还原(revert) 相似,但它们实际上差别很大。还原会创建一个新的 commit,并还原或撤消之前的 commit。但是重置会清除 commit!
注意:可以从仓库中清除 commit 的命令。如果某个 commit 不再存在于仓库中,它所包含的内容也会消失;git 会在完全清除任何内容之前,持续跟踪大约 30 天。要调用这些内容,你需要使用 git reflog 命令。请参阅链接以了解详情
8.4 commit引用
你已经知道可以使用 SHA、标签、分支和特殊的 HEAD 指针引用 commit。有时候这些并不足够,你可能需要引用相对于另一个 commit 的 commit。例如,有时候你需要告诉 git 调用当前 commit 的前一个 commit,或者是前两个 commit。我们可以使用特殊的“祖先引用”字符来告诉 git 这些相对引用。这些字符为:
- 父 commit : 以下内容表示当前 commit 的父 commit
- HEAD^
- HEAD~
- HEAD~1
- 祖父 commit – 以下内容表示当前 commit 的祖父 commit
- HEAD^^
- HEAD~2
- 依次类推
git reset根据所使用选项来判断是清除、暂存之前 commit 的更改,还是取消暂存之前 commit 的更改。这些选项包括:
- 使用 --hard 选项清除 commit
- 使用 --soft 选项将 commit 的更改移至暂存区
- 使用 --mixed 选项取消暂存已被 commit 的更改(默认)
8.5 备份commit
在使用git reset的--hard选项时,你以后可能还会需要这个commit,这时候就需要备份。这需要在当前 commit 上创建一个分支。在进行任何重置操作之前,我通常会在最近的 commit 上创建一个 backup 分支,因此如果出现错误,我可以返回这些 commit:git branch backup ;如果真的操作出错或者其他原因想回到重置之前的commit,你需要:
- 从工作目录中删除未 commit 的更改
- 将 backup 合并到 master(这将导致快进合并并使 master 向上移到和 backup 一样的点)
命令如下: - $ git checkout -- index.html (撤销工作区的修改)
- $ git merge backup
实验总结和体会
本次实验主要学习如何使用git来控制版本的更替。首先熟练了基本命令,其次明确了每条命令的含义和作用,最后用git操作了一个简单的demo。非常简单实用的工具,很方便实现版本的控制。而且这种软件中很多设计思想很好,值得我们学习。
思考题
阅读维基百科和百度百科 的Git词条,总结分布式版本控制系统的核心机理?
答:分布式版本控制系统的客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。