一、什么是Git?

  Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。

  Git是Linus Torvalds为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

二、分布式VS集中式

  VisualSVN、TortoiseSVN、Bazzar为集中式版本控制系统,而Mercurial、Git、Bitkeeper为分布式版本控制系统。

  1. 集中式版本控制

    优点:可以对具体的文件或目录进行权限控制,有全局的版本号。

    缺点:所有操作都需要联网中心服务器。

  2. 分布式版本控制

    优点:

      i. 分支管理。

      ii. 完整性和安全性更高,各客户端保留有完整的版本库。

      iii. 绝大部分操作都是本地化的,支持离线。

    缺点:

      i. 对版本库的目录和文件无法做到精细化的权限控制。

      ii. 无全局性的版本号。

  通过以上分析的集中式和分布式版本控制的优缺点,我们就能总结出以Git为代表的分布式版本控制和以SVN为代表的集中式版本控制之间的区别。

  3. Git和SVN的区别

  • 最核心的区别当然是分布式和集中式。
  • 处理数据的方式不同,Git以元数据方式存储数据,SVN按照文件存储,对应的取出数据方式也不一样。
  • 分支管理或分支模型(下文会详解)。
  • 全局性的版本号。
  • 数据的完整性和安全性,分布式的更好。

三、常用的Git解决方案和代码托管平台

  1.开源软件解决方案:Gitea、GitLab

  2.代码托管平台:码云(Gitee)、码市(Coding)、GitHub、GitLab、Bitbucket

四、Git的基石SHA-1

  In cryptography, SHA-1 (Secure Hash Algorithm 1) is a cryptographichash function which takes an input and produces a 160-bit (20-byte) hash value known as a message digest – typically rendered as ahexadecimal number, 40 digits long. It was designed by the UnitedStates National Security Agency, and is a U.S. Federal InformationProcessing Standard.

  以上摘自维基百科,主要说明了SHA是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。SHA-1长度为20字节,160位,熟悉网络编程的都知道,4位可以转换成一个十六进制的数字,所以一个SHA-1散列可以展示为40长度的十六进制的数字。

  SHA-1的计算方法伪代码:

  1. 1 //Note: All variables are unsigned 32 bits and wrap modulo 232 when calculating
  2. 2
  3. 3 //Initial variables:
  4. 4 h0 := 0x67452301
  5. 5 h1 := 0xEFCDAB89
  6. 6 h2 := 0x98BADCFE
  7. 7 h3 := 0x10325476
  8. 8 h4 := 0xC3D2E1F0
  9. 9
  10. 10 //Pre-processing:
  11. 11 append the bit '1' to the message
  12. 12 append k bits '0', where k is the minimum number >= 0 such that the resulting message
  13. 13 length (in bits) is congruent to 448(mod 512)
  14. 14 append length of message (before pre-processing), in bits, as 64-bit big-endian integer
  15. 15
  16. 16 //Process the message in successive 512-bit chunks:
  17. 17 break message into 512-bit chunks
  18. 18 for each chunk
  19. 19 break chunk into sixteen 32-bit big-endian words w[i], 0 i 15
  20. 20
  21. 21 //Extend the sixteen 32-bit words into eighty 32-bit words:
  22. 22 for i from 16 to 79
  23. 23 w[i] := (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
  24. 24
  25. 25 //Initialize hash value for this chunk:
  26. 26 a := h0
  27. 27 b := h1
  28. 28 c := h2
  29. 29 d := h3
  30. 30 e := h4
  31. 31
  32. 32 //Main loop:
  33. 33 for i from 0 to 79
  34. 34 if 0 i 19 then
  35. 35 f := (b and c) or ((not b) and d)
  36. 36 k := 0x5A827999
  37. 37 else if 20 i 39
  38. 38 f := b xor c xor d
  39. 39 k := 0x6ED9EBA1
  40. 40 else if 40 i 59
  41. 41 f := (b and c) or (b and d) or(c and d)
  42. 42 k := 0x8F1BBCDC
  43. 43 else if 60 i 79
  44. 44 f := b xor c xor d
  45. 45 k := 0xCA62C1D6
  46. 46 temp := (a leftrotate 5) + f + e + k + w[i]
  47. 47 e := d
  48. 48 d := c
  49. 49 c := b leftrotate 30
  50. 50 b := a
  51. 51 a := temp
  52. 52
  53. 53 //Add this chunk's hash to result so far:
  54. 54 h0 := h0 + a
  55. 55 h1 := h1 + b
  56. 56 h2 := h2 + c
  57. 57 h3 := h3 + d
  58. 58 h4 := h4 + e
  59. 59
  60. 60 //Produce the final hash value (big-endian):
  61. 61 digest = hash = h0 append h1 append h2 append h3 append h4

  虽然SHA-1作为数字签名的算法不安全,但是作为日常项目代码管理来说却足够能够保证其唯一性。

  我们已经了解到SHA-1摘要的长度是20字节,也就是160位。要确保有50%的概率出现一次冲突,需要2^80个随机散列的对象(计算冲突概率的公式是p=(n(n-1)/2)*(1/2^160))。2^80=1.2*10^24,也就是一亿亿亿,这是地球上沙粒总数的1200倍。即使按照目前公开的2005年CRYPTO会议中由王小云提出的更具效率的SHA-1攻击法,也需要2^63=9.2*10^18,也就是九十二亿亿,虽然不及地球上的沙粒数也是一个很大的数字。

  超大型项目Linux内核有超过45万次提交,包含360万个对象,也至多需要前11个字符就能够保证SHA-1的唯一性。

  Git根据文件内容或目录结构计算出SHA-1散列值,然后通过散列值存储、检索和处理信息。

五、Git模型

  1. 区域模型

  Git项目中的主要区域:Git目录(仓库)、工作目录和暂存区(索引)

 

  Git目录也称为Git仓库或Git数据库,是保存Git项目元数据和对象数据库的地方。是Git最重要的部分,当从其它计算机中克隆项目时需要复制的内容。

  工作目录是项目某个版本的单次检出。这些文件从Git仓库中提取出来,放置在磁盘上使用和修改。我们平时码代码时的区域就是在工作目录中,因为这里是唯一提供了对文件进行编辑的地方。

  暂存区也称为索引,是一个文件,一般位于Git目录中。保存了下次所要提交内容的相关信息。Git的add命令就是将工作目录中的内容添加到暂存区中。

  2. 分支模型

  分支模型是Git的精髓,被称为Git的“杀手锏特性”。

  分支意味着偏离开发主线并继续你自己的工作而不影响主线开发。在其它很多版本控制工具中,有较昂贵的成本,因为常常需要去对整个源代码目录进行一次复制,特别对于大型项目,这样的复制时间成本是很高的。

  Git的分支与众不同的地方在于,极致的轻量,几乎即时就可以完成分支操作,分支间的切换操作也很方便。

  Git以快照的方式存储数据。

  当发起提交时,Git存储的是提交对象(commit object),其中包含了指向暂存区快照的指针。提交对象也包含作者的姓名和邮箱地址、已输入的提交信息以及指向其父提交的指针。初始提交没有父提交,而一般的提交会有一个父提交;对于两个或更多分支的合并提交,存在多个父提交。

  当执行git commit进行提交时,Git会先为每个子目录计算校验和,然后再把这些树对象(tree object)保存到Git仓库中,Git随后会创建提交对象,其中包括元数据以及指向项目根目录的树对象的指针,以便有需要的时候重新创建这次快照。

  Git分支只不过是一个指向某次提交的轻量级的可移动指针。Git默认的分支名称是master。当你发起提交时,你的当前分支比如master分支就会移动指向你刚刚的提交。

  git init命令默认创建的就是master分支。

  Git的分支实际上就是一个简单的文件,其中只包含了该分支所指向提交的长度为40个字符的SHA-1校验和。正因如此,Git分支的创建和删除成本就很低。创建新分支就如同向文件写入40个字符外加一个换行符一件简单方便。

  提交时Git保存了父对象的指针,当进行合并操作时Git会自动寻找适当的合并基础,创建新分支并在其上coding,然后把多个分支间的代码进行合并很方便,所以Git鼓励开发人员创建和使用分支。

  接下来我们来了解几个分支概念

  长期分支VS主题分支

  主题分支是指短期的、用于实现某一特定功能及其相关工作的分支。与之相对的就是长期分支,长期分支是在整个项目中会一直保持,用于合并主题分支或版本控制和代码发布的分支。比如在master分支上存放稳定版的代码,develop上进行开发,test分支上进行测试,在iss-email上进行email的主题开发。

  远程分支VS跟踪分支

  远程分支是指向远程仓库的分支的指针,这些指针存在于本地且无法被移动。基于远程分支创建的本地分支就是其远程分支的跟踪分支(tracking branch),有时也叫做上游分支(upstream branch)。远程分支我们能够理解是在服务器上的分支,那跟踪分支呢?我随便创建的本地分支都是跟踪分支吗?本地非跟踪分支和跟踪分支又有什么区别呢?

  当你克隆一个远程仓库时,Git默认情况下会自动创建跟踪着远程origin/master分支的本地master分支。当你试图执行分支切换操作时,如果该分支尚未被创建,并且该分支名称和某个远程分支名称一致,那么Git会帮你创建跟踪分支。当设置成为跟踪分支后,使用Git命令时可以简化操作,比如在master分支上push代码到远程仓库上,可以直接使用git push,如果没设置跟踪分支需要使用git push origin/master。

  1. $git checkout --track origin/serverfix
  2. Branch serverfix set up to track remote branch serverfix from origin.
  3. Switched to new Branch 'serverfix'
  1. $git checkout -b sf origin/serverfix
  2. Branch sf set up to track remote branch serverfix from origin.
  3. Switch to a new branch 'sf'

  当我们了解了Git的分支模型后,分支模型正确的打开方式是什么样的呢?

  假设你在master分支上做了一些项目起始的工作,之后为了实现某个需求,创建并切换到主题分支sub-record,并在其上做了一些开发工作。之后,你又尝试另一种能实现需求的方式,创建并切换到新的分支sub-recordv1。接着你又切换回master分支并继续工作了一段时间,最后你创建了新的分支dumb-idea来实现你的一个不确定的想法。

  

  最后你觉得sub-recordv1方案效率比较高,而在dumb-idea上的工作同事们都觉得很有意义,那么把主题分支上的提交合并合并入长期分支master,舍弃掉sub-record上的C5和C6提交。

  

  根据项目的需要,为实现一个需求或一个子需求甚至一个想法创建一个分支。合并代码的时候只需要合并需要的,那些暂时没能合并入的代码也许以后要么直接或间接就可以用上,如果没能用上也可以借鉴和参考。毕竟创建和使用Git分支的成本很低而且方便有效,这样才是Git分支模型的正确打开方式。

  3. 对象模型

  对象模型分为:主要对象和标签对象。主要对象又分为blob对象、树对象和提交对象。

  blob对象是保存到Git仓库的文件当前版本或者称为元数据。可以理解为文件内容。

  树对象解决的是文件名的存储问题。可以认为是目录,对应为Unix目录项。单个树对象包含一个或多个树条目,每个条目包含一个指向blob对象或子树的指针以及相关模式、类型和文件名。

  提交对象指定了此刻项目快照的顶层树对象、作者/提交者信息、提交时间戳、一个空行以及提交消息。指向的是树对象。

  标签对象与提交对象非常相似,包含了标签的创建者、日期、标签消息和一个指针。通常指向提交对象也可以指向blob对象。是不可变的分支引用,总是指向相同的提交对象或blob对象。

  4. “三棵树”模型

  将Git类比为三棵树的内容管理器。“树”实际上指的是“文件的集合”,并非特定的数据结构。

三棵树 HEAD 最近提交的快照,下次提交的父提交
索引 预计的下一次提交的快照
工作目录 沙盒

  HEAD和索引着两棵树把数据以一种高效但不够直观的方式保存在.git目录中。而工作目录则将其提取成实际的文件,以便于编辑。可以把工作目录当作沙盒,在将内容提交到暂存区(索引)并写入历史记录之前,你可以随意修改。

  三棵树之间的切换  

  

  1. $git status
  2.  
  3. Changes to be committed:
  4. (use "git restore --staged <file>..."to unstage)
  5.  
  6. Changes not staged for commit:
  7. (use "git add <file>..." to update what will be committed)
  8. (use "git restore <file>..." to discard changes in working directory)

  其中Changes not staged for commit提示的是索引和工作目录之间的差异。

  其中Changes to be committed提示的是HEAD和索引之间的差异。

  通过以上我们了解到,Git通过操作三棵树的状态来记录项目的快照。

  通过学习了三棵树模型,我们将运用所学来理解Git的重置,包括两个命令:reset和checkout。

  reset命令会以特定的次序重写这三棵树,操作方式如下:

  (1)移动HEAD分支的指向(指定了--soft选项,则在此停止)。

  (2)使索引看起来像HEAD(默认行为,或指定了--mixed选项,则在此停止)。

  (3)使工作目录看起来像索引(指定了--hard选项,则在此停止)。

  checkout命令操作三棵树有两种方式:

  方式一(不使用路径):

  (1)与reset --hard不同,checkout不会影响工作目录。他会确保不会破坏已更改的文件。

  (2)更新HEAD的方式。reset移动的是HEAD指向的分支,而checkout移动的是HEAD,使其指向其他分支。

  假设我们有两个分支:master和develop,分别指向不同的提交。我们当前处在develop分支(因为HEAD也指向该分支)。如果执行git reset master,那么develop会与master一样,指向同一提交。如果执行的是git checkout master,那么发生移动的会是HEAD,而不是develop。HEAD将会指向master。

  方式二(使用路径):

  加上文件路径,与reset一样,不会移动HEAD。会使用提交中的文件来更新索引,但是也会覆盖工作目录中对应的文件。

  reset和checkout命令速查表 

操作 HEAD 索引 工作目录 工作目录是否安全?
提交级别 reset --soft [commit] REF
reset [commit] REF
reset --hard [commit] REF
checkout [commit] HEAD
文件级别 reset (commit) [file]
checkout (commit) [file]

  HEAD一列中的REF表示该命令移动了HEAD指向的引用(分支),HEAD表示移动了HEAD自身。

  注意:“工作目录是否安全”一列,如果显示是否,应当慎重,执行前要考虑清楚,否则可能丢失工作成果。

六、文件状态的生命周期

  

七、提交史观

代表观点 提交史观 代表命令
“史书”、“记录” Git仓库提交历史就是实际发生过的事件的记录 merge
“故事” Git提交历史是关于项目如何构建的故事 rebase

  变基操作是把某条分支线上的工作在另一个分支线上按顺序重现。而合并操作则是找出两个分支的末端,并把它们合并到一起。

  最好的操作方式是,在本地尚未推送的更改进行变基操作,从而简化提交历史,单决不能对任何已经推送到服务器的更改进行变基操作。

八、分布式工作流

  1.  集中式工作流

  一个中枢(或是仓库)接受代码,所有人以此同步各自的工作。

  

  2. 集成管理者工作流

  (1)项目维护人员推送到公开仓库。

  (2)贡献者克隆该仓库,作出自己的修改。

  (3)贡献者推送到自己的公开仓库副本。

  (4)贡献者向维护人员发送电子邮件,要求合并变更。

  (5)维护人员将贡献者的仓库添加为远程仓库并在本地进行合并。

  (6)维护人员将合并后的变更推送到主仓库。  

  

  3. 司令官与副官工作流

  (1)普通开发人员使用自己的主题分支,根据参考仓库(reference repository)拉取项目或进行变基。

  (2)副官将开发人员的主题分支合并入master分支。

  (3)司令官将副官的master分支合并入自己的master分支。

  (4)司令官将其master分支推送到参考仓库,同时其他开发人员以此为基础进行变基操作。

  

参考资料

[1] Scott Chacon,Ben Straub《精通Git》(第2版)

[2] 维基百科

[3] https://www.sohu.com/a/234659269_575744

[4] https://www.runoob.com/git/git-tutorial.html

从本质彻底精通Git——4个模型1个周期1个史观1个工作流的更多相关文章

  1. GIT分支管理模型

    GIT分支管理模型 link: git-branching-model 主分支(Main branches) 项目两个常驻分支: master 主干分支(锁定),仅用于发布新版本,平时不能在上面干活, ...

  2. Git Flow 工作模型与使用

    一. Git Flow 工作模型的原理 无规矩不成方圆,但是规矩太多了,则感觉到束缚.我们一个人工作的时候喜欢无拘无束,想怎么干就怎么干,没有人评判,没有人检验.时间久了就会盲目自大,以为增删改查熟悉 ...

  3. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  4. 成功的GIT开发分支模型和策略

    详细图文并茂以及git flow工具解释参考: http://danielkummer.github.io/git-flow-cheatsheet/index.zh_CN.html 原文地址:http ...

  5. CoreData 从入门到精通(六)模型版本和数据迁移

    前面几篇文章中讲的所有内容,都是在同一个模型版本上进行操作的.但在真实开发中,基本上不会一直停留在一个版本上,因为需求是不断变化的,说不定什么时候就需要往模型里添加新的字段,添加新的模型,甚至是大规模 ...

  6. 5分钟精通git教程

    git是一个版本控制工具,就要先弄清楚什么是版本 版本: 对外发布的版本如v1.0.0,v1.1.0 叫version 内部代码的版本叫commit,如:修改了一个错别字 顾名思义一个version就 ...

  7. 30 天精通 Git 版本控管

    https://github.com/doggy8088/Learn-Git-in-30-days

  8. 微信小程序之结构目录、视图层、双线程模型、生命周期、事件传递冒泡、组件、request、登录授权及支付

    结构目录与配置介绍 视图层与基础语法 双线程模型 生命周期 事件.传递和冒泡 组件.自定义组件.组件事件传递页面 Request.路由跳转.本地存储 登录(后端实现) | 授权(后端实现) 支付(后端 ...

  9. asp.net 管道模型+生命处理周期

    http://www.cnblogs.com/qianlifeng/archive/2010/12/16/1908568.html https://msdn.microsoft.com/zh-cn/l ...

随机推荐

  1. 读写 LED 作业 台灯的 频闪研究1

    读写 LED 作业 台灯的 频闪研究: 核心提示: 随着科技的持续发展,目前已经商业化的照明产品从第一代的白炽灯: 第二代的荧光灯.卤灯: 第三代的高强度气体放电灯; 以及当下主流的, 第四代的发光二 ...

  2. Generator function vs Async/Await

    Generator function vs Async/Await generator async /await refs xgqfrms 2012-2020 www.cnblogs.com 发布文章 ...

  3. Node.js Learning Paths

    Node.js Learning Paths Node.js in Action Node.js Expert situations / scenario Restful API OAuth 2.0 ...

  4. where is the storage location of the browser's HTTP cache? disk or memory

    where is the storage location of the browser's HTTP cache? disk or memory HTTP cache & storage l ...

  5. c++ readIntger writeIntger

    类似CE的read/writeIntger函数(外部) #include <iostream> #include <Windows.h> #include <TlHelp ...

  6. vue 使用stylus

    λ yarn add stylus stylus-loader --dev <style scoped lang="stylus"> div color #ff4488 ...

  7. NGK公链助力医疗行业数据安全

    近年来医疗领域的数据泄露事件时有发生,医疗行业数据面临着医疗数据获得不易及缺乏有效管理和数据安全机制问题.而区块链的去中心化.分布式账本等特点正好契合医疗领域的需求点. 医疗数据市场痛点 一.医疗信息 ...

  8. Nginx之Location匹配规则

    概述 经过多年发展,nginx凭借其优异的性能征服了互联网界,成为了各个互联网公司架构设计中不可获取的要素.Nginx是一门大学问,但是对于Web开发者来说,最重要的是需要能捋的清楚Nginx的请求路 ...

  9. 推荐一款好用的免费远程控制软件——ToDesk

    创作立场声明:我在本文中评测的软件为自用,感觉不错并且全免费,第一时间发出来和大家分享,欢迎理性观点交流碰撞. 疫情刚开始的时候,待在家里不能上班,但是还是有很多工作需要在线完成,常常需要跑回办公室拿 ...

  10. Python列表元组和字典解析式

    目录 列表解析式List comprehensive 集合解析式Set comprehensive 字典解析式Dict comprehensive 总结 以下内容基于Python 3x 列表解析式Li ...