引言

Git是工作中最常用的版本控制工具,本文中将介绍其常用的命令。

根据作用的不同,可以分为基本命令、撤销命令、合并命令与远程仓库命令,下面将依次介绍这些命令。

基本原理

git 中提供了底层api供我们直接对底层数据结构进行调用,其中git cat-file [-t] [-p] hashcode,其中-t可以查看hash值对应文件的类型,-p可以查看hash之对应的内容

基本对象

在最初的版本里实际上只有3种对象,分别是blob,tree和changeset(后续被改名为commit).本文主要对这三种对象进行介绍。基本的对象有tag域与binary data域。

Blob

在blob对象中,其tag的取值为blob,并在binary data域中存储了文件的内容,是最简单的object。但并不会保存文件名相关的信息。那么在一个工程项目中,我们有时候仅会对文件的名字进行改动,这时候则需要引出tree对象对这一变化进行追踪。

tree

tree的tag值为tree,binary data中维护了一个list。list的每一个item可以是一个tree对象,也可以是一个blob对象。 在每一个item中,有如下的属性:

  • 权限和类型
  • 路径
  • 对象的sha1(类似于指针)

    从这个角度来看,tree的list中既可以引用blob对象,也可以引用tree对象,循环往复,构成一颗文件结构树。

    tree结构图[1]

利用tree与blob进行项目的追踪与维护

我们知道,若文件内容发生变化,则会生成新的blob对象与新的sha1值。对于tree对象,我们使用sha1值作为对blob对象的引用,那么该目录中的文件内容发生变化而引起对应的blob对象发生变化是,会导致tree维护的list中的内容发生变化,那么tree本身的sha1值也会发生变化。这就意味着,我们需要生成一个新的tree对象,来维护这一变化。

举个例子

对于如下结构的目录:

.

├── foo

│ └── a.txt

└── b.txt

如果我们将a.txt中的内容从"111"修改为"222", 那么整体的tree将会有如下结构:



可以看到新内容与旧内容分别维护了各自的根目录对应的tree,并复用没有修改内容的blob节点。

commit

仅靠tree对象与blob对象并不能记录与提交版本相关的信息。为了回溯任意一个版本,我们还需要一个对象对版本的提交信息进行维护——commit对象。

commit对象的tag是commit,binaray data域有以下内容:

  • tree相关的信息
  • parent
  • author
  • committer

    其中,当我们提交一个新的commit时,会有一个对应的tree对象的与之关联。parent的个数可以是0个或者多个,维护着到上一个commit的sha1指针。可以通过该指针回溯到任意一个历史版本。从这个角度看,我们可以将git理解为基于一个key-value的数据库与默克尔树形成的有向无环图(DAG)的存储系统[3]。

tag

tag代表将分支永久化,生成tag后,这个tag对应的内容将永不可变,所以一般应用或者软件版本的发布一般用tag。

索引区

在我们的tree结构中,如果要访问一个具体的blob对象,需要使用深度优先遍历,通过路径上的信息来得到最终blob的完整路径。如果我们想要对比不同commit版本的文件之间的差异的话,就需要对两棵不同版本的tree进行深度遍历,当树很深时会涉及大量磁盘i/o。

为了提高i/o的速度,可以引入一个缓存,来提高文件读取的速度,这就是暂存区。通常相关的数据存储在./git/index。git使用mmap技术,访问文件内容。这里的文件内容指的是一系列entry对象,每一个entry对象中维护了对应的blob对象的映射与完整路径与其他相关的信息,entry对象在内存中按完整路径进行升序排列。这样,在后续的比较中就可以使用二分查找快速定位到相同文件名的不同版本完整地址,并进行比较。


命令

1. 基本命令

1.1 git add

当输入git add命令后,git会将文件生成对应的blob文件,并保存在git仓库中。但是并没有在tree上进行相应的结构映射,而只是在索引区建立了直接的索引。而tree结构的建立,需要等到commit命令才执行。

1.2 git commit

git commit后就会生成本次版本的对应树结构,涉及到一系列tree对象与commit对象的生成。(注意,blob对象在git add时就已经生成)

1.3 git checkout

该命令根据参数的不同,有许多效果。其主要的作用是在不同的分支之间切换。

查看代码[4]
git checkout # 列出本地所有分支
git checkout [<branch>] # 切换到该分支
git checkout -b [<branch>] # 创建并切换到该分支
git checkout -d [<branch>] # 删除该分支
-f # 强制执行

其余的一些命令参数如--merge,可以通过与其他命令的组合来实现,对结果把控更可靠。

2. 撤销命令

git reset

这条命令指定退回到某一个版本的提交。

查看代码
--mixed # 工作区不变,其余内容退回到指定版本
-hard # 所有内容退回到指定版本
-soft # 回退到指定版本
该命令后可以指定文件名,用于对指定文件进行版本回退
需要谨慎使用 --hard参数,该参数会删除回退版本后的commit版本。另外永远不要将已经push并merge到origin中的branch的内容进行回退,否则会导致本地仓库的不同步。如果非要使用,后续则需要git push -f进行强制推送

git revert

其用法与 git reset类似,但是与reset不同的是,其不会删除一些历史commit记录,而是使用创建一个新的commit的方式来达到撤销历史修改的记录。对于一些已经push或产生其他副作用的修改,最好使用revert方式进行撤销操作。而reset则多用于本地的撤销修改。注:revert的commitid选则回退版本后一个的commitid。

关于Revert功能的一个小插曲

3. 合并命令

git merge

会在两个parent commit上创建一个新的分支,若不存在冲突,则直接fast-forward merge。

查看代码
git merge [<branch>] # 将指定的分支合并到当前分支上

若合并产生冲突,会在日志中提示,并且在合并操作产生的commit中,会标出冲突的部位。当我们以手动的方式修改完冲突后,使用git add 通知git已完成冲突合并,并用commit完成这次merge(此时会自动带上 merge的message)

git rebase

从字面上来理解,是为当前分支重新确定一个基。达到的效果与merge类似,但是其commit的拓扑结构是不一致的。当执行完rebase后,是将当前分支以“类似”嫁接的形式,嫁接到某个指定的分支上,而不是类似于merge,将两个分支合并起来。

举个例子

当前我们的分支结构如下:



我们正在dev分支上,想将dev的修改记录应用到master分支上,但又不想以merge的方式进行。此时我们可以使用rebase,为dev分支重新确定一个基。执行完git rebase master后,效果如下:



完成了类似嫁接的操作, 将dev的原始分叉点重新定位在master分支的最新的commit上,并生成了与dev分支长度相同的新的一系列commit。

4. 远程仓库命令

git fetch

该命令会在本地仓库中更新所有在远程端被追踪的分支,并用灰色的标记来标记这些属于remote的分支

举个例子

远程与本地分支的原始状态



执行完git fetch后本地仓库的状态:

git pull

该命令相当于一条组合命令,在默认的参数下相当于git fetch + git merge [<remote_branch>],当然我们可以指定参数git>],当然我们可以指定参数git pull --rebase,那么就会使用git rebase来替代第二条命令。注意,默认只会将当前分支对应的远程分支合并进来。

举个例子

原始状态



执行完git pull

git push

该命令会将本地分支的内容推送到对应的远程分支上。从理论上来讲,所有的push操作都应该进行fast-forward merge,若仍存在一些不同则会发生reject错误。遇到这种情况时,通常需要先将远程的内容pull到本地进行合并后,再进行push。

参考

[1]Git Internals

[2]Explain Git with D3 (onlywei.github.io)

[3]这才是Git原理

[4]Git-SCM

[Git][基本原理与命令]的更多相关文章

  1. 【原理、命令】Git基本原理、与Svn的区别、命令

    一.Git是什么? Git是目前世界上最先进的分布式版本控制系统.工作原理 / 流程:Workspace:工作区Index / Stage:暂存区Repository:仓库区(或本地仓库)Remote ...

  2. Git 基本原理与经常使用命令

    平时使用过两种版本号控制软件 SVN 和 Git,平心而论,假设纯粹自己使用,那么绝对 Git 更加适合,本地库.远程库.离线工作.强大而灵活的分支.大名鼎鼎的Github, 这些都是选择 Git 的 ...

  3. git基本原理

    git基本原理 一.总结 一句话总结:把原理那张图图背下来 1.git中的四大区,除了远程仓库和本地仓库,剩下两个是什么? 解答:工作区和暂存区. 2.git中的四大区(例如远程仓库和本地仓库),他们 ...

  4. GIT 版本控制常用命令学习汇总

    GIT 版本控制常用命令汇总 git version 查看当前git版本信息 git help 获取全部命令帮助信息 git help <command> 获取指定命令帮助信息 git c ...

  5. git的一些命令行

    以下代码均在命令行中执行:在目标文件夹目录下: 1.初始化一个Git仓库,使用git init命令. 2.添加文件到Git仓库,分两步: 第一步,使用命令git add <file>,注意 ...

  6. git log 常用命令及技巧

    git log常用命令以及技巧 1.git log 如果不带任何参数,它会列出所有历史记录,最近的排在最上方,显示提交对象的哈希值,作者.提交日期.和提交说明.如果记录过多,则按Page Up.Pag ...

  7. Git基本常用命令

    Git基本常用命令如下: mkdir: XX (创建一个空目录 XX指目录名) pwd: 显示当前目录的路径. git init 把当前的目录变成可以管理的git仓库,生成隐藏.git文件. git ...

  8. git workflow常用命令

    git init git status git add readme.txt git add --all         Adds all new or modified files git comm ...

  9. git的一些命令

    因为项目的原因,大家把项目托管到git上,然后我不会,队友就传了一个廖雪峰的git教程,讲的很详细,不会用git的同学,可以在http://pan.baidu.com/s/1pKizolP上下载,这是 ...

  10. 关于Git的stash命令

    add 添加新文件到 Git 代码仓库的索引中 $ git add filename mv 移动或重命名文件 $ git mv old-filename new-filename rm 从工作目录和 ...

随机推荐

  1. A星、Floyod、Bellman-Ford

    A 星算法 A 星和 Dijkstra 算法唯一区别在于堆中排序的依据.distance 数组仍然保存实际代价,预估代价只影响堆的弹出顺序. Dijkstra 根据源点到当前点的实际代价进行排序. A ...

  2. Machine Learning Week_1 Introduction 5-8

    目录 1.5 Vedio: Supervised Learning unfamiliar words 1.6 Reading: Supervised Learning unfamiliar words ...

  3. [网鼎杯 2020 朱雀组]phpweb

    打开靶机,抓包分析,获得连个关键参数func和p,根据初始页面提示了解连个参数大概是功能和功能参数 测试func=system&p=ls提示hacker..说明有检测过滤 那么我们先读取源码看 ...

  4. 有Redis为什么还要本地缓存?谈谈你对本地缓存的理解?

    本地缓存是将数据存储在应用程序所在的本地内存中的缓存方式.既然,已经有了 Redis 可以实现分布式缓存了,为什么还需要本地缓存呢?接下来,我们一起来看. 为什么需要本地缓存? 尽管已经有 Redis ...

  5. 海外模组联网非常难?不往忘了APN配置…

    ​ 除了中国之外,国外的4G信号都比较差劲. 做海外的设备,如果忽视了射频的信号质量,肯定是要吃大亏的! 所以,海外模组的联网问题,会比国内要多不少. 客户在实际应用中或多或少都会遇到: 网络相关问题 ...

  6. AT开发HTTP应用:Air780EP低功耗4G模组

    ​ 已经写了一篇基于Air780EP模组AT开发的FOTA远程升级指南,有客户朋友询问能否讲讲HTTP应用部分?本期特别安排--涵盖HTTP基本应用流程.GET/POST/SSL请求示例.断点续传.常 ...

  7. python通过实例方法名字的字符串调用方法

    目录 方式1 - 反射 hasattr 方法 判断当前实例中是否有着字符串能映射到的属性或者方法, 一般会在 getattr 之前作为判断防止报错 getattr 方法 获取到当前实例中传入字符串映射 ...

  8. Java Cache系列之Cache概述和Simple Cache

    前记:最近公司在做的项目完全基于Cache(Gemfire)构建了一个类数据库的系统,自己做的一个小项目里用过Guava的Cache,以前做过的项目中使用过EHCache,既然和Cache那么有缘,那 ...

  9. Java垃圾回收器总结

    什么是Java垃圾回收器 Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation).自动回收( ...

  10. 一款.NET开源的Windows资源管理器标签页工具

    前言 今天大姚给大家分享一款基于.NET开发的可以让你在Windows资源管理器中使用Tab多标签功能的小工具:QTTabBar. 工具介绍 QTTabBar是一款基于.NET开发的可以让你在Wind ...