因为做操作系统实验的原因,所以通读了一遍《Understanding git conceptually》,觉得确实不错,于是就简单地记录一下。有的地方理解的还不是很深,可能不够准确,等抽时间好好读一下《Pro Git》。

作者开篇说到:仅仅记住在什么时候用什么命令是不够的,出问题只是早晚的事。只有理解了Git的工作原理,才算真正学会Git。遗憾的是大部分网上的教程都只是教你在何时使用哪个命令,然后让你去模仿。说得这么好,那就看看作者这篇教程是否把Git的工作原理讲清楚了。注意:以下1.2.1到1.2.3都是本地化操作,不要看到仓库、分支、合并等词语就以为一定是远程操作了,1.2.4才会讲到多人协同开发时的远程操作。


1.Commit Object和Head

使用Git的目的当然就是管理项目文件的版本变化,在Git中保存所有管理信息的数据结构叫做仓库(Repository)。可以在一个文件夹中通过命令git init创建仓库。仓库保存在项目文件目录下的一个叫做.git的文件夹中,它由两部分组成:

  • 提交对象(Commit object):反映项目状态的一组文件、对父提交对象的引用、当前提交对象的SHA-1签名构成了提交对象。父提交对象的引用使得仓库的提交对象形成了一个有向无环图,我们可以一直遍历到第一次提交。每当我们要查询或操作仓库,都应该以如何操作commit object图的角度去思考。
  • 对提交对象的引用(Head):每个Head都有个名字,默认每个仓库都有个叫做master的Head。此外,指向当前活跃Head的引用叫做HEAD(二级引用)。

例如,下面就是提交三次后的对象图:

---->  time  ----->

(A) <-- (B) <-- (C)
^
|
master
^
|
HEAD

我们日常的工作流程一般如下,下面就从图的角度说明一下Git在背后到底做了什么:

  1. 修改一些代码
  2. git log查看历史记录:显示从HEAD到初始提交的所有提交日志。用log命令显示出每个提交对象的SHA-1签名,我们就能控制HEAD的移动。
  3. git status查看修改文件列表:显示当前项目状态与HEAD发生变化的文件列表。
  4. git diff比较修改内容:显示当前项目状态与HEAD发生变化的文件内容。
  5. git commit -am "message"提交修改:创建提交对象,将HEAD作为父提交对象。提交完成后,HEAD将指向刚创建的新提交对象。-a参数相当于git add,自动将修改文件添加到提交列表里。

2.Branching

下面说说Git中的分支(Branch)。在Git中,Branch与Head几乎是等同的。每个Branch都由一个Head来表示。所以,我们用Branch指分支的Head以及它的所有父对象构成的整个历史,用Head指单独一个提交对象,一般是分支中最近的提交。Git分支的最佳实践是:用分支实现新特性,保证master(主干)始终处于可发布的状态。Git用户经常会说:”commits are cheap”,当每个开发者都在自己的分支上提交时是不用担心任何东西的,因为你不会影响到其他人!

继续上面提交三次的那个例子,我们首先用git branch [new-head-name] [reference-to]命令新建一个Head。其中,HEAD^表示HEAD的父级,如果未提供提交对象的话,默认为HEAD。如果只是执行git branch则会列出所有Head:

git branch fix-headers HEAD^

(A) -- (B) ------- (C)
| |
fix-headers master
|
HEAD

要开始在新分支上工作,就要将新创建的Head设置为HEAD,可以通过git checkout [head-name]完成。注意:checkout不只会修改HEAD的指向,它还会重写文件夹中的所有文件来匹配新HEAD指向提交对象所表示的项目状态。所以,checkout之前最好提交所有修改。切换完成后,再提交后对象图就变成了下面的样子:

         +-------------- (D)
/ |
(A) -- (B) -- (C) |
| |
master fix-headers
|
HEAD

现在继续看常用命令,脑海里一定从图的角度思考:

  • git checkout [branch_name]切换分支:切换HEAD指向的位置
  • git checkout -t [branch_name]新建分支

3.Merging

当你在分支上完成开发时就需要将改动Merge回master,命令就是git merge [head]和git pull . [head]。假设当前Head叫做HEAD,分支Head叫做fix-headers,则Git的代码合并过程如下:

  1. 找到HEAD和fix-headers的共同祖先,假设叫ancestor,先看两种简单情况:

    1.1 如果ancestor是fix-headers,则什么都不做

    1.2 如果ancestor是HEAD,则执行fast-forward-merge
  2. 否则,比较出fix-headers在ancestor后的改动,将这些改动合并到HEAD

    2.1 如果没有冲突,则创建一个新的提交对象,以HEAD和fix-headers为父级,并将HEAD指向这个新对象,并更新项目文件

    2.2 如果有冲突,则不创建提交对象,插入冲突的标记,通知用户处理
fast-forward-merge的例子:
+-- (D) -- (E)
/ |
(A) -- (B) -- (C) |
| |
current fix-headers
|
HEAD 执行`git merge fix-headers`合并之后的样子:
+-- (D) -- (E)
/ |
(A) -- (B) -- (C) |
|
fix-headers, current
|
HEAD
复杂情况下的合并例子:
+---------- (D)
/ |
(A) -- (B) -- (C) -------------- (E)
| |
fix-headers master
|
HEAD 执行`git merge fix-headers`合并之后的样子:
+---------- (D) ---------------+
/ | \
(A) -- (B) -- (C) -------------- (E) -- (F)
| |
fix-headers master
|
HEAD

4.协同开发

前面讲到过:Git的重要特点就是Repository与项目文件是保存在一起的,所以Git可以在无需连网的状态下正常工作。但是这也意味着不同的开发者在默认情况下是不共享Repository的。为了实现共享,Git使用分布式模型(Distribution Model)版本管理,既可以无中心化也可以有中心。

首先要访问你朋友的远程仓库就需要一个位置,叫做remote-specification,Git可以通过SSH、HTTP等协议对外提供访问。然后就可以通过git clone [remote-specification]下载远程仓库到本地了。除了简单的拷贝,Git会给远程Repository创建一个reference叫做origin,同时还会给每个Head新建一个Head,名字以”origin/”开头来区分:

远程仓库的样子:
+---------------(E)
/ |
(A) -- (B) -- (C) -- (D) |
| |
master feature
|
HEAD 你clone后的本地仓库是这个样子:
+-------------- (E)
/ |
(A) -- (B) -- (C) -- (D) |
| |
origin/master, master origin/feature
|
HEAD

当远程仓库变化时,我们可以通过git fetch [remote-repository-reference]命令将改动抓取到本地,生成对应的提交对象,再用前面讲过的git pull [remote-repository-reference] [remote-head-name]进行合并。其实,pull命令也会自动进行fetch,所以平时我们直接使用pull就可以了。来看一个例子,假设你朋友在跟你一起开发,他本地的Repository变成了这个样子:

                +-------- (E) -- (F) -- (G)
/ |
(A) -- (B) -- (C) -- (D) -- (H) |
| |
master feature
|
HEAD 在你执行fetch之后你的仓库是这个样子:
+------------ (E) ------------ (F) ---- (G)
/ | |
(A) -- (B) -- (C) -- (D) --------------- (H) |
| | | |
master feature origin/master origin/feature
|
HEAD 注意:你的Head并未受任何影响,变化的只是带有"origin/"的Head。
现在就用pull命令合并,更新你的master和feature,完成后你的仓库就成了这个样子:
+-------- (E) ------------- (F) ----- (G)
/ | |
(A) -- (B) -- (C) -- (D) ------------ (H) |
| | |
feature origin/master, origin/feature
master
|
HEAD

与之相反,将本地修改发送到远程仓库使用git push [remote-repository-reference] [remote-head-name],远程仓库会负责提交对象的创建以及Head的合并移动等工作。要注意的是:向远程仓库push时,要求必须是fast-forward合并。

整理一下这部分的常用命令:

  • git pull [remote-repository-reference] [remote-head-name]下载分支代码

Git幕后的“故事”的更多相关文章

  1. .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练

    写在前面 上篇文章我带着大家通过分析了一遍ASP.NET Core的源码了解了它的启动过程,然后又带着大家熟悉了一遍配置文件的加载方式,最后引出了依赖注入以及控制反转的概念!如果大家把前面几张都理解了 ...

  2. Git 历险记

    Git历险记(一) 作为分布式版本控制系统的重要代表--Git已经为越来越多的人所认识,它相对于我们熟悉的CVS.SVN甚至同时分布式控制系统的Mercurial,有哪些优势和不足呢.这次InfoQ中 ...

  3. Git历险记(二)——Git的安装和配置

    各位同学,上回Git历险记(一)讲了一个 “hello Git” 的小故事.有的同学可能是玩过了其它分布式版本控制系统(DVCS),看完之后就触类旁通对Git就了然于胸了:也有的同学可能还如我当初入手 ...

  4. Git 程序员篇

    关于 Git Git 背后的故事 伟大的作品总是诞生于伟大的时代,正如 Git 同样诞生于一个英雄辈出.极富纷争的年代. 2005 年,Linux 内核开发社区正面临严峻的挑战:他们不能继续使用 Bi ...

  5. No.1__C#

    这是第一篇C#的日记,到现在为止已经学习了一个礼拜的C#了.由于是实习中才开始学习,所以这次不准备像在大学学习那样,拿着课本划重点,背概念.这应当是一门实践的课程,应该一边编程,一边学.这是到公司第一 ...

  6. 深入了解Qt(三)之元signal和slot

    深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt 信号和槽函数这篇文章中已经详细地介绍了信号和槽的使用及注意事项.在这里对其使用方面的知识 ...

  7. 学习UI设计书籍推荐

    在学习UI设计的过程当中,特别想学或者零基础的人来说,需要学习到很多知识,比如软件 PS AI ,理论 色彩 排版 规范 UE 等,这些都是一名UI设计师需要学习的知识,而学习到这些知识,可以通过视频 ...

  8. The Art of Deception

    前言 一些黑客毁坏别人的文件甚至整个硬盘,他们被称为电脑狂人(crackers)或计算机破坏者(vandals).另一些新手省去学习技术的麻烦,直接下载黑客工具侵入别人的计算机,这些人被称为脚本小子( ...

  9. Week2 Teamework from Z.XML 软件分析与用户需求调查(四)Bing桌面及助手的现状与发展

    一.Bing搜索的相关背景 第一,必应搜索前几年的发展重点在于欧美市场,并且取得了一定的成效:根据 Hitwise 的统计数据,Bing 在 2011年3 月份市场占有率突破了 30% 大关,达到 3 ...

随机推荐

  1. Hive&SqlServerql:inner join on条件中如果两边都是空值的情况下,关联结果中会把数据给过滤掉。

    今天遇到的一个大坑,话不多少,看sql和下边的查询结果: --问题:恰好把buildingid is null的记录给过滤掉 ),buildingid ),)); ); ); ); ); ); ); ...

  2. Spring MVC基础学习

    SpringMVC是Spring框架的一个模块,无需通过中间层整合在一起.SpringMVC是一个基于MVC设计模式web框架,MVC-model-view-controller:MVC将服务器端分为 ...

  3. sqli-lab 第一题 单引号 error based single quotes

    一.第一次见面 1.初识 http://localhost/Less-1/ 提示输入id,因此访问http://localhost/Less-1/?id=1 可以继续测试id=2.3.4等的情况,会输 ...

  4. 【Python3.6+Django2.0+Xadmin2.0系列教程之二】学生信息管理系统(入门篇)

    上一篇我们已经创建好了一个Xadmin的基础项目,现在我们将在此基础上构建一个同样很基础的学生信息管理系统. 一.创建模型 模型是表示我们的数据库表或集合类,并且其中所述类的每个属性是表或集合的字段, ...

  5. Mac下安装oh-my-zsh

    Mac下自带的终端并不好用,当你打开终端的时候是一个白花花的窗口,其实Mac自带几种shell,默认使用的是bash,可以通过 cat /etc/shells 查看几种shell bin/bash / ...

  6. [ZJOI 2007]Hide 捉迷藏

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双 ...

  7. [NOIp 2017]逛公园

    Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经 ...

  8. STL rope

    rope的部分简单操作 函数 功能 push_back(x) 在末尾添加x insert(pos,x) 在pos插入x erase(pos,x) 从pos开始删除x个 replace(pos,x) 从 ...

  9. 洛谷mNOIP模拟赛Day1-斐波那契

    题目背景 大样例下发链接:http://pan.baidu.com/s/1c0LbQ2 密码:jigg 题目描述 小 C 养了一些很可爱的兔子. 有一天,小 C 突然发现兔子们都是严格按照伟大的数学家 ...

  10. bzoj省选十连测推广赛

    A.普通计算姬 题意:给丁一棵树,每个点有一个权值,用sum(x)表示以x为根的子树的权值和,要求支持两种操作: 1 u v  :修改点u的权值为v. 2 l  r   :  求∑sum[i] l&l ...