阅读 316

从文件生命周期看GIT的提交流程

紧接上篇,今天从实在操作方面说一下GIT使用中,使用最多的流程-提交到仓库。开始说明提交流程之前,可以先去看一下上篇提到的GIT整体架构图。本章说的内容是上面这张图的前面部分,如下:

只有提交本地仓库的流程,并没有涉及到远程仓库。关于提交流程,常用的命令:add和commit,add负责提交到暂存区,commit提交到仓库。但并不是只有这两个命令就足够了。

在开始之前,我们先需要做一些初始化工作。

操作系统:centos7 GIT版本: 1.8.3.1。

配置环境

提交git仓库,需要做两个基本的配置操作:

$ git config --global user.name poloxue
$ git config --global user.email poloxue123@163.com
复制代码

配置姓名与邮箱地址。关于git配置还有很多内容,本章内容重点不在于此,就不作过多详解。

准备仓库

首先我们需要一个git仓库,两个命令可以实现: init 和 clone。 git init,是通过初始化本地目录的方式创建仓库。 首先,创建一个测试的文件夹。执行初始化操作,查看文件夹变化,如下:

$ mkdir experiment
$ cd experiment/
$ git init
复制代码

初始化空的 Git 版本库于 /home/vagrant/work/git/experiment/.git/

$ ls -a
. .. .git
复制代码

文件夹下多出了一个.git的文件,上面一节对.git有过简单说明。我们的暂存区和本地仓库就是存在于这个文件下面。

git clone,通过远程克隆方式获取版本库。本人刚开始使用git的时候,以为git像svn一样需要依赖远程,获取仓库首先想到的是去github上面clone。

clone的使用很简单,我们通过克隆goquery的源码来演示,如下:

$ git clone https://github.com/PuerkitoBio/goquery.git
Cloning into 'goquery'...
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 1212 (delta 2), reused 8 (delta 2), pack-reused 1204
Receiving objects: 100% (1212/1212), 434.03 KiB | 49.00 KiB/s, done.
Resolving deltas: 100% (697/697), done.
Checking connectivity... done.
$ ls -a
.                       bench_array_test.go     expand.go               property.go
..                      bench_example_test.go   expand_test.go          property_test.go
.git                    bench_expand_test.go    filter.go               query.go
.gitattributes          bench_filter_test.go    filter_test.go          query_test.go
.gitignore              bench_iteration_test.go go.mod                  testdata
.travis.yml             bench_property_test.go  go.sum                  traversal.go
LICENSE                 bench_query_test.go     iteration.go            traversal_test.go
README.md               bench_traversal_test.go iteration_test.go       type.go
array.go                doc                     manipulation.go         type_test.go
array_test.go           doc.go                  manipulation_test.go    utilities.go
bench                   example_test.go         misc                    utilities_test.go
复制代码

提交流程

从文件生命周期看提交流程,首先一个文件在整个生命周期可能存在哪些状态,如下:

  • 未追踪 untracked file
  • 已暂存 staged file
  • 未更新 no updated file
  • 已更新 updated file

还是先动手画个图,如下:

上面的图以文件状态的角度出发,指出了一个文件从创建到提交文件仓库再到脱离仓库追踪的整个过程可能经历的各种状态。

在开始正文之前先介绍一下GIT查看仓库中文件状态的命令:git status。如果仓库文件有所变化,执行此命令可以查看各个变化文件状态。

未追踪

在工作目录下新创建的一个文件初始状态处于未追踪。此时文件不受版本系统的控制。 下面在我们之前初始化为git仓库的experiment的工作目录,新建一个README.md。然后随意输入一些内容。使用git status查看一下当前仓库状态,如下:

$ touch "experiment" >> README.md
$ git status
# On branch master
#
# Initial commit
#
# Untracked files
#   (use "git add <file>..." to include in what will be committed)
#
#       README.md
nothing added to commit but untracked files present (use "git add" to track)
复制代码

此时README.md为untracked file,下面提示 Use "git add ..." to include in what will be committed,即为使用git add命令去添加将被提交的文件。似乎没有说明怎么追踪文件,继续看,如需要被追踪 use "git add" to track, 意为使用git add追踪文件。

已更新

为了下面的内容更方便讲解,先来说说文件的已更新状态。啥叫已更新呢?个人总结,上图中把文件的三种情况都归于已更新:编辑更新,冲突更新,删除更新。下面从这三种更新的角度来谈谈,看看这些更新状态如何产生。

编辑更新

编辑更新就是因我们修改文件而导致的更新。下面看下如何产生一个编辑更新状态的文件。

首先,快速通过以下三步添加一个新文件modify.go到版本库中。

$ touch modify.go
$ git add modify.go
$ git commit -m "new file modify.go"
复制代码

下面我们修改文件modify.go,添加任意内容修改,git status查看状态:

#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes will working directory)
#
#        modified:   modify.go
#
# no changes added to commit (use "git add" and/or "git commit -a")
复制代码

此时可以看到modify.go文件为modified状态。使用git时,大多数更新都是属于这种类型。

冲突更新

冲突更新是怎么产生的呢?我们知道GIT支持强大的分支功能,前面说明GIT的优点也提到了这个问题。但是分支就会有一个问题,两个分支同时修改同一文件的同一部分内容,冲突就产生了。下面演示这种类型的更新如何产生?

首先,快速通过以下三步添加一个新文件conflict.go到版本库中。

$ touch conflict.go
$ git add conflict.go
$ git commit -m "new file conflict.go"
复制代码

创建两个分支:feature

$ git branch feature
复制代码

在master上conflict.go添加内容: master,在feature上conflict.go添加内容: feature。并都提交到仓库。

在master执行合并操作:

$ git merge feature
Auto-merging conflict.go
CONFLICT (content): Merge conflict in conflict.go
Automatic merge failed; fix conflicts and then commit the result.
复制代码

可以看到冲突很容易就产生。团队合作开发时,冲突更新也是我们平时最不喜欢遇到的,如果冲突的内容都是自己的,那还好处理。如果涉及了很多人,就会涉及大量的沟通成本。

删除更新

删除也算更新,这个逻辑理解起来有点怪。但删除毕竟改变了文件内容,让文件不存在了,所以也算更新。这种更新如何产生呢?

首先,快速通过以下三步添加一个新文件delete.go到版本库中。

$ touch delete.go
$ git add delete.go
$ git commit -m "new file delete.go"
复制代码

提交之后,手动删除delete.go文件

$ rm delete.go
复制代码

此时使用git status查看delete.go文件状态便是删除更新的状态。

已暂存

在上面的1、2两段,关于未追踪和已更新,总结的是工作区文件存在的各种状态。但是在把文件提交到版本之前,还需要中间的一个过渡阶段:暂存区。

文件提交到暂存区便是已暂存状态。看上面文件各个状态之间的转化图,我们知道文件可以由未跟踪和已更新两种状态转化而来。

由之前的操作,现在已经有了各种状态的文件:

  • 未追踪文件:README.md
  • 编辑更新文件:modify.go
  • 冲突更新文件:conflict.go
  • 删除更新文件:delete.go

下面如何使用git add将这些文件添加到暂存区:

  • git add -A 最省事,所有文件添加到暂存区;
  • git add -u 已更新文件添加暂存区,即modify.go conflict.go delete.go;
  • git add . 将除删除更新的其他文件加到暂存区,即README.md modify.go conflict.go;
  • git add * 会忽略.gitignore规则,把本来应忽略文件添加暂存区,慎用;

当不确定时,可直接添加某文件git add filepath;

注:评论区有朋友回复说,他的测试 git add . 会把删除更新加入暂存区,我分别在 git 1.8.3.1 和 2.9.3 两个版本测试了下,新版的确和旧版行为不同,会把删除更新加入到暂存区。

$ git add modify.go;
复制代码

删除更新也可以使用git rm命令,直接将删除文件提交到暂存区同时删除文件,如需删除提交暂存区但工作区文件保留可使用选项--cached:

$ git rm delete.go
$ git rm delete.go --cached
复制代码

好!下面把所有文件提交到暂存区:

$ git add -A
复制代码

此时,git status查看文件状态:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage
#
#      renamed:    delete.go -> README.md
#      modified:   conflict.go
#      modified:   modify.go
#      new file:   new.go
复制代码

因为同时存在删除和新建,delete.go被认为rename为README.md,正常情况工作区文件状态与暂存区的对应关系如下:

工作区           暂存区
untracked       new file
modified        modified
both modified   modified
deleted         deleted
复制代码

未更新

怎么让文件转化为未更新状态呢?提交仓库!我们已经把所有内容提交暂存,下面可以借助于commit命令进行仓库提交:

常用方式

提交仓库的常用,执行如下命令:

$ git commit -m "feat: new function"
复制代码

再查看文件状态,发现已经没有内容可以提交,此时仓库处于未更新的状态。

更新直接提交

git commit -am "message" 
复制代码

可以将编辑更新直接从工作区提交仓库,即跨过暂存区。不支持删除与冲突更新和新文件的提交。

提交修订

如提交有误,支持对当前提交进行修订。

$ git commit --amend
复制代码

有什么作用?可用来修改提交日志;在提交漏提交文件时,仍保持为一个提交。

总结

本文主要从GIT文件的生命周期来看整个提交流程。为了便于理解,自己总结了编辑更新、删除更新、冲突更新几个新词,希望不会造成误解。

关注下面的标签,发现更多相似文章
评论