【Git】 之二 架构、工作流程、常用命令
写在前面
Git 的官网上有很详细的使用教程(当然有翻译版本),具体地址是 https://git-scm.com/book/zh/v2。唯一不足就是,很多讲解并没有实机演示。但是,毫无疑问,官网资料是最全面的!如果有任何疑问,可以去官网看看!
架构
原理
Git 和其它版本控制系统(包括 Subversion 和近似工具)的主要差别在于 Git 对待数据的方法。 概念上来区分,其它大部分系统以文件变更列表的方式存储信息。 这类系统(CVS、Subversion、Perforce、Bazaar 等等)将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。
Git 不按照以上方式对待或保存数据。 反之,Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个快照流。
Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来。
Git 管理的文件有三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。由此引入 Git 项目的三个工作区域的概念:Git 仓库、工作目录以及暂存区域。
- 工作目录:就是 Git 管理的文件夹。
- 暂存区域:暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作“索引”。
- Git 仓库:Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。主要就是我们工作目录中的 .git 文件夹
工作流程
根据是否使用远程仓库,工作流程可以分本地工作流程和远程工作流程。
本地工作流程
主要是指的对于本地仓库的各种操作!如下图所示:
下面是实际的 Git 命令示例:
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3
$ git init
Initialized empty Git repository in E:/N_W_Z/N_W_Z_3/.git/
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ vim a.txt
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
a.txt
nothing added to commit but untracked files present (use "git add" to track)
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ git add a.txt
warning: LF will be replaced by CRLF in a.txt.
The file will have its original line endings in your working directory
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: a.txt
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ git commit -m "新增"
[master (root-commit) ba06d60] 新增
1 file changed, 1 insertion(+)
create mode 100644 a.txt
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$ git status
On branch master
nothing to commit, working tree clean
ZCShou@ZCShou-PC MINGW64 /e/N_W_Z/N_W_Z_3 (master)
$
远程工作流程
主要是指的本地仓库与远程仓库的关联同步的问题。在关联了远程仓库后,我们本地仓库有变动之后,通常还需要将变动推送到关联的远程仓库。如下图所示:
下图是一个使用 Git 开源项目的典型工作流程
常用命令
虽然 Git 同时提供了 GUI 界面 和 Bash,但是,GUI 界面的功能相对来说还是有点简陋的。要想熟练掌握 Git 的使用,还是需要了解 Git 一系列的命令!
Git 命令还是比较多的,后面我们以实际用到的功能来介绍。有个需要注意的地方就是命令的参数:参数分为简写和全称两种方式,但是功能完全相同! 例如:git clone -b xxxxx
与 git clone --branch xxxxx
其实是一模一样的,参数 --branch
简写为 -b
!但是,不是每一个参数都有简写,且在不同命令下,可能存在相同的简写,但是功能含义可能不同。下图是 Git 官网对于 Git 命令的分类列表
其中,红色框中的是我们平时常用的一些命令。
初始化仓库
初始化仓库有两种方式:本地新建和克隆远程仓库,分别对应 git init
和 git clone
这两个命令!创建仓库后,会在指定的目录下生成一个 .git 的文件夹,其中存储 Git 管理我们代码需要的各种配置。
本地新建
创建本地仓库相对比较简单,在我们想要建立仓库的文件夹中打开 Bash 命令框,执行 git init
命令即可。如下图:
完整的 git init
命令如下:
git init [-q | --quiet] [--bare] [--template=<template_directory>]
[--separate-git-dir <git dir>]
[--shared[=<permissions>]] [directory]
常用参数如下:
-q、--quiet
:仅打印错误和警告消息; 所有其他输出都将被抑制。--bare
:创建一个裸存储库。 如果未设置 GIT_DIR 环境,则将其设置为当前工作目录。--template=<template_directory>
:指定将使用的模板的目录[directory]
:用于给出 Git 配置文件的路径(含名称)。如果不指定则表示当前目录。默认生成名字为 .git 的目录
执行命令成功之后,在当前目录下生成一个名为 .git 的隐藏文件夹,Git 的所有配置文件就存在该文件夹中。接下来就可以在此文件夹(仓库)中,增删改自己的文件了。
使用 git init
初始化本地仓库之后,本地仓库是空的,连一个分支都是没有的!如果此时进行创建分支则会报错。如下图所示:
[我们也可以打开 .git 目录进行查看,会发现暂时没有 master 分支。如下图所示:
当我们提交一次修改之后,Git 会默认生成一个名为 master 的分支。
分支的默认名字 master,在 Git 中并没有任何特别的含义一样。 同时 “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用。
以上方式创建的本地仓库只能本地使用,其没有与任何远程仓库关联!如果要关联远程仓库,则必须使用 git remote
命令进行关联。
关联远程仓库
Git 通常也会有个远程仓库。使用 git init
方式创建的本地仓库只能本地使用,其没有与任何远程仓库关联!远程仓库的增、删、改、查都是通过 git remote
命令来实现。
在 Git 中,会为关联的远程仓库创建一个本地名称,默认不显示指定时为 origin,这样我们在与远程仓库通信时,直接使用本地名称就可以了!例如,我们要将代码推送到以上关联的远程仓库,直接使用 git push origin
就可以了。以下是一些常用的命令参数
git remote -v
:参数-v
==--verbose
。用于列出关联的远程仓库,格式为:本地名称 + 远程仓库地址。如下图:
git remote add
:命令格式:git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
。关联一个远程仓库 <url>,本地名称为 <name>。
git remote rename
:命令格式:git remote rename <old> <new>
。将名为 的远程仓库名重命名为。git remote rm
:命令格式:git remote remove <name>
。其中,参数--rm
是--remove
的简写。删除关联的名为 <name> 的远程仓库的关联信息。
与远程仓库相关的配置,均位于 工作目录下/.git/config
文件中,这是个文本文件,我们也可以直接打开改文件进行修改。
还有一点就是,一个本地仓库可以关联多个远程仓库! 如下图所示是增加了一个远程仓库之后的情况。
如上所示,建议在关联远程仓库的时候,指定一个本地名称,这样我们就可以很容易的知道关联情况。这个在我们往远程仓库提交代码是很有用处!
更新详细的说明,见独立的博文《Git 之四 通信协议(HTTPS、SSH、Git)、使用远程仓库(GitHub、GitLab、Gitee等)》!
远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。 同时 “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” 是当你运行 git clone 时默认的远程仓库名字。 如果你运行 git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master。
克隆远程仓库
同样也非常简单,在我们想要保存远程仓库的文件夹中打开 Bash 命令框,执行 git clone https://github.com/ZCShou/N_W_Z_1.git
命令即可(注意将以上仓库地址换为自己的)。如下图:
该命令将远程存储库克隆到新创建的目录中,并为本地存储库中的每个分支创建远程跟踪分支,并创建和检出从远程存储库当前活动的分支派生出来的初始分支。该命令的完整格式如下:
git clone [--template=<template_directory>]
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--dissociate] [--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
[--[no-]remote-submodules] [--jobs <n>] [--] <repository>
[<directory>]
该命令常用参数如下:
-o <name>、--origin <name>
:指定远程仓库的本地名称为 <name>,而不使用默认的 origin。-b <name>、--branch <name>
:用于克隆名为 <name> 的远程分支,而不是以 HEAD 创建分支。在非空的仓库中执行该命令,表示将指定的分支同步到当前仓库!<repository>
:要克隆的(可能是远程的)存储库。<directory>
:指定保存克隆的仓库的本地目录名称。 如果没有明确给出目录,则使用远程库名字在当前目录。只有当目录为空时,才允许克隆到现有目录。
克隆之后,默认会使用没有参数的 git fetch
将更新所有远程跟踪分支,并且没有参数的 git pull
将另外将远程主分支合并到当前主分支中(如果有的话)。其中也会有个 .git 的文件夹!
使用以上命令之后,本地仓库就会和以上指定的远程仓库管理关联,且会管理所有远程分支。在 Git 中,会为关联的远程仓库创建一个本地名称,不显示指定时默认为 origin。我们可以在以上命令中使用参数 --origin 本地名称
来指定本地名称(git clone --origin NWZ_xxx https://github.com/ZCShou/N_W_Z_1.git
)。
分支
使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。 Git 的一大特点就是对于分支的支持!Git 的分支可谓是难以置信的轻量级,它的新建操作几乎可以在瞬间完成,并且在不同分支间切换起来也差不多一样快。
Git 引入了一个概念:upstream。一个分支的 upstream,其实就是与远程分支做关联,告诉 Git,默认此分支为推送及拉取的远程分支的信息。如下图所示:
更新详细的说明,见独立的博文《Git 之三 分支管理》!
.git 目录解析
前面已经说过,在 Git 仓库初始化之后,会在指定的目录下生一个名为 .git 的文件夹。这个文件夹是个隐藏目录,Windows 系统需要开启显示隐藏才能看到!对于.git 所在的仓库的所有操作,都会记录在该文件中的各文件中。下面我们就来分析一下这个目录。
- config 文件: 该文件主要记录针对该项目的一些配置信息,例如是否以 bare 方式初始化、remote 的信息等,通过 git remote add 命令增加的远程分支的信息就保存在这里;
- objects 文件夹: 该文件夹主要包含 git 对象。Git 中的文件和一些操作都会以 git 对象来保存,git 对象分为 BLOB、tree 和 commit 三种类型,例如 git commit 便是 git 中的 commit 对象,而各个版本之间是通过版本树来组织的,比如当前的 HEAD 会指向某个 commit 对象,而该 commit 对象又会指向几个BLOB 对象或者 tree 对象。
- 13、21 等文件夹: Git 对象保存在以其 sha-1 值的前两位为文件夹名,后 38 位为文件名的文件中;Git 为了节省存储对象所占用的磁盘空间,会定期对 Git 对象进行压缩和打包!
- pack 文件夹: 用于存储打包压缩的对象。
- info 文件夹: 用于从打包的文件中查找 git 对象。
- HEAD 文件: 该文件指向当前分支。比如当前分支是 master,则该文件就会指向 master。但是,并不是存储一个 master 字符串,而是分支在 refs 中的表示,例如 ref: refs/heads/master。如下图所示:
- index文件: 该文件保存了暂存区域的信息。该文件某种程度就是缓冲区(staging area),内容包括它指向的文件的时间戳、文件名、sha1值等;
- refs 文件夹: 该文件夹存储指向数据(分支)的提交对象的指针。
- heads 文件夹: 存储本地每一个分支最近一次 commit 的 sha-1 值(也就是commit对象的sha-1值),每个分支一个文件;如下图所示:
上图示例中, 分支 Dev 和 Feature 都是从 master 分支创建的,并且都还没有任何提交,因此它们目前都执行同一次提交记录。当在不同的分支进行提交之后,它们将指向不同的提交记录。 - remotes文件夹: 记录你最后一次和每一个远程仓库的通信,Git 会把最后一次推送到这个 remote 的每个分支的值都记录在这个文件夹中;
- tag 文件夹: 这个是 Git 中一个概念,其实就是分支的别名
- heads 文件夹: 存储本地每一个分支最近一次 commit 的 sha-1 值(也就是commit对象的sha-1值),每个分支一个文件;如下图所示:
- hooks文件夹: 主要定义了客户端或服务端钩子脚本,这些脚本主要用于在特定的命令和操作之前或者之后进行特定的处理,比如:当你把本地仓库push到服务器的远程仓库时,可以在服务器仓库的hooks文件夹下定义post_update脚本,在该脚本中可以通过脚本代码将最新的代码部署到服务器的web服务器上,从而将版本控制和代码发布无缝连接起来;
- description文件: 仅供 GitWeb 程序使用
- logs 文件夹: 记录了本地仓库和远程仓库的每一个分支的提交记录,即所有的commit对象(包括时间、作者等信息)都会被记录在这个文件夹中,因此这个文件夹中的内容是我们查看最频繁的,不管是Git log命令还是tortoiseGit的show log,都需要从该文件夹中获取提交日志;
- info文件夹: 保存了一份不希望在 .gitignore 文件中管理的忽略模式的全局可执行文件
- COMMIT_EDITMSG 文件: 记录了最后一次提交时的注释信息。
检查状态
当我们修改了仓库中的文件时,使用 git status
可以列出当前目录所有还没有被 Git 管理的文件和被 Git 管理且被修改但还未提交(git commit)的文件。
格式:$ git status <参数>
# git status命令一般不用加参数,可能用到的参数如下:
$ git status -s # 将结果以简短的形式输出
如下图所示:
DIFF
使用 git status
我们仅可以看到文件级别的更改,如果我们想要查看文件内部具体有哪些变动,则需要 git diff
命令。
git diff [<options>] [<commit>] [--] [<path>…]
git diff [<options>] --cached [<commit>] [--] [<path>…]
git diff [<options>] <commit> <commit> [--] [<path>…]
git diff [<options>] <blob> <blob>
git diff [<options>] --no-index [--] <path> <path>
如下图所示:
添加追踪
在我们修改了仓库中的文件后,必须要将修改添加到 Git 中。使用 git add
命令要用于把我们要提交的文件的信息添加到索引库中。
格式:$ git add <参数> <path> # 文件名或者路径,支持通配符,多个文件可以用空格来隔开,省略<path>表示用 . (点表示当前目录)
注意几个参数的区别:
$ git add . # 监控文件内容修改(modified)以及新文件(new),但不包括被删除的文件
$ git add -u # 仅监控已经被add的文件(即tracked file),他会将被修改的文件提交到暂存区。add -u 不会提交新文件(untracked file)
$ git add -A # 是上面两个功能的合集,提交所有变化 等价于 git add *
$ git add -i # 交互式的方式进行添加
$ git add -h # 查看git add的帮助信息
如下图所示:
提交修改
使用 git commit
命令提交的是暂存区里面的内容。
格式:$ git commit <参数> <-F file/ -m "msg" ...>
注意几个参数的区别:
$ git commit -m # 提交说明。不用-m参数的话,git将调到一个文本编译器(通常是vim)来让你输入提交的描述信息
$ git commit -a # -a 选项可只将所有被修改或者已删除的且已经被git管理的文档提交倒仓库中。如果只是修改或者删除了已被Git 管理的文档,是没必要使用git add 命令的。
$ git commit --amend #用来修复最近一次commit. 可以让你合并你缓存区的修改和上一次commit, 而不是多出提交一个新的快照. 还可以用来编辑上一次的commit描述。注意:生成的commit是一个全新的commit, 之前的老的commit会从项目历史中被删除
例如:忘记了add一个文件:先 git add 忘记的文件,然后使用 git commit --amend --no-edit # 描述会是上一次commit的描述, --no-edit能让我们修复commit,而且不要修改commit描述.
再例如:又或者我们发现在提交时忘记使用 -a 选项,导致 Changes bu not updated 中的内容没有被提交:直接使用 git commit --amend -a 即可
如下图所示:
查看记录
使用 git log
命令列出历史提交记录如下:
git log -p -2 # -p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新
如下图所示:
也可以使用 git log --oneline
命令列出历史提交记录的精简版,如下:
使用 git log --graph
命令查看历史中什么时候出现了分支、合并
git log --oneline --graph
如果只想查找指定用户的提交日志可以使用命令:git log --author=xxx
git log --author=Linus --oneline -5
如果你要指定日期,可以执行几个选项:–since 和 --before,但是你也可以用 --until 和 --after,如下:
git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
回退
git reset
命令将当前的分支重设(reset)到指定的或者HEAD(默认,如果不显示指定 commit,默认是 HEAD,即最新的一次提交)
格式:$ git reset [--hard|soft|mixed|merge|keep] [<commit>或HEAD]
并且根据 [mode] 有可能更新 index 和 working directory。mode 的取值可以是 hard、soft、mixed、merged、keep。下面来详细说明每种模式的意义和效果。
- –hard:重设(reset) index和working directory,自从 <commit> 以来在 working directory 中的任何改变都被丢弃,并把HEAD指向<commit>。
- –soft:index和working directory中的内容不作任何改变,仅仅把HEAD指向\ <commit>。这个模式的效果是,执行完毕后,自从 <commit> 以来的所有改变都会显示在 git status 的 “Changes to be committed” 中。
- –mixed:仅reset index,但是不 reset working directory。这个模式是默认模式,即当不显示告知 git reset 模式时,会使用 mixed 模式。这个模式的效果是,working directory 中文件的修改都会被保留,不会丢弃,但是也不会被标记成"Changes to be committed",但是会打出什么还未被更新的报告。
远程仓库
这部分见独立博文!
参考
- https://git-scm.com/docs
- https://www.cnblogs.com/yelbosh/p/7471979.html
- git的基本架构欣赏 https://zhuanlan.zhihu.com/p/38245039
- Git的原理简介和常用命令 https://www.cnblogs.com/yelbosh/p/7471979.html
- git工作流程一览 https://www.cnblogs.com/yinn/archive/2018/01/23/7641507.html
- http://blog.didispace.com/gitflow-info/
- https://nvie.com/posts/a-successful-git-branching-model/
转载于:https://blog.csdn.net/ZCShouCSDN/article/details/100808293