Git魔法魔法BenLynn中文版PDF版本下载:Git_Magic_CN.
pdf译自:http://www-cs-students.
stanford.
edu/~blynn/gitmagicGit魔法魔法ByBenLynn前言前言51.
致谢!
52.
许可.
53.
链接.
5免费Git服务器.
61.
入门入门.
71.
1.
游戏人生71.
2.
版本控制.
71.
3.
分布控制.
81.
3.
1.
一个误区.
81.
4.
冲突合并.
92.
基本技巧基本技巧102.
1.
保存状态.
102.
1.
1.
添加、删除、重命名.
102.
2.
进阶撤销、重做112.
2.
1还原122.
3.
下载文件122.
4.
前沿.
132.
5.
即时发布.
132.
6.
我们已经做了什么143.
克隆进阶克隆进阶153.
1.
计算机间的同步.
153.
2.
典型源码控制.
153.
3.
项目分叉163.
4.
终极备份173.
5.
轻快多任务.
173.
6.
游击版本控制.
174.
分支向导分支向导194.
1.
老板键.
194.
2.
脏活.
204.
3.
快速修订214.
4.
不间断工作流.
214.
5.
重组杂乱.
224.
6.
管理分支234.
7.
临时分支.
234.
8.
按你希望的方式工作.
245.
关于历史关于历史255.
1.
改正标准.
255.
2.
在这之后255.
3.
本地变更最后部分.
265.
4.
重写历史.
265.
5.
制造历史.
275.
6.
哪儿错了285.
7.
谁让事情变糟了295.
8.
个人经验296.
Git大师大师.
316.
1.
源码发布.
316.
2.
历史记录生成.
316.
3.
通过SSH,HTTP使用Git.
316.
4.
提交变更326.
5.
我的提交太大了!
326.
6.
别丢了你的HEAD.
336.
7.
猎捕HEAD336.
8.
在Git上编译346.
9.
大胆的绝技.
357.
解密解密.
377.
1.
大象无形377.
2.
数据完整性.
377.
3.
智能387.
4.
索引.
387.
5.
裸资源库.
397.
6.
Git起源.
398.
Git的缺点的缺点408.
1.
微软Windows.
408.
2.
无关的文件.
408.
3.
谁在编辑什么408.
4.
文件历史408.
5.
初始克隆418.
6.
不稳定的项目.
418.
7.
全局计数器.
428.
8.
空子目录428.
9.
初始提交42前言前言Git(http://git.
or.
cz/)是一个版本控制的瑞士军刀.
一个可靠通用多用途版本控制工具,它超强的灵活性使得一般人学着使用它没那么直白,更别说掌握它了.
我把到目前为止弄明白的记下来,因为在我试图理解Git用户手册(http://www.
kernel.
org/pub/software/scm/git/docs/user-manual.
html)的时候也是困难重重;希望对别人有用.
正如ArthurC.
Clarke所发现的,所有称得上先进的技术都和魔法难以区分.
这是接近Git的一个很不错的办法:新手们可以忽略它内部机理,只把Git看作一个小发明,用它强大的功能让朋友吃惊,让敌人发狂.
我们提供大面上的指导,而不是陷入细节.
在重复使用之后,慢慢地你会明白每个小技巧是如何工作的,并且还会知道如何合理剪裁以适应您的需要.
1.
致谢!
致谢!
感谢DustinSallings,AlbertoBertogli,JamesCameron,DouglasLivingstone,MichaelBudde,RichardAlbury,Tarmigan和DerekMahar提出的建议和改进.
[如果我漏掉了谁请告诉我因为我经常忘记更新这一节]2.
许可许可本指南在GNUGeneralPublicLicense版本3之下发布(http://www.
gnu.
org/licenses/gpl-3.
0.
html).
3.
链接链接我曾经罗列了一些参考文献,但这维护起来太费时了.
除此之外,也可以简单地使用搜索引擎(http://www.
google.
com/)来获得一些Git指导(http://www.
google.
com/searchq=git+tutorial),指南(http://www.
google.
com/searchq=git+guide)以及比较(http://www.
google.
com/searchq=git+comparison)附带Subversion(http://www.
google.
com/searchq=git+subversion),或者Mercurial(http://www.
google.
com/searchq=git+mercurial),以及其他的版本控制系统.
免费免费Git服务器服务器http://repo.
or.
cz/提供自由项目伺服服务,包括本文档(http://repo.
or.
cz/w/gitmatic.
git).
http://gitorious.
org是另一个支持Git的开源项目伺服器.
http://github.
com提供免费的开源项目伺服服务,包括本文档也在其中(http://github.
com/blynn/gitmagic/tree/master),也包括一些私有的付费项目.
1.
入门入门我将用类比的方式来介绍版本控制.
更严谨些的解释可以参见Wikipedia版本修订控制条目(http://en.
wikipedia.
org/wiki/Revision_control).
1.
1.
游戏人生游戏人生我几乎一生下来就开始玩电脑游戏,直到现在.
然而,我仅在我长大之后才开始使用版本控制系统.
我想我的情况并非是极个别的,比较这两者也许可以使得一些概念更容易解释和理解.
把编辑代码或文档,或无论什么,当作玩游戏.
一旦你已经取得了很多进展,你会想到保存.
你会点击值得信赖的编辑器的保存按钮来进行保存.
但这将覆盖旧版本.
就像那些在学校里玩的老游戏那样,只有一个保存条:你确实可以保存,但一旦保存就不能回到原来的状态.
这太不应该了,因为可能你之前的存档恰好在这个游戏特别有意思一关,也许某天你想重新回顾一下.
或者更糟糕的,你当前的存档是个败局,你不得不重玩.
1.
2.
版本控制版本控制在编辑的时候,如果想保留旧版本,你可以将文件"另存为"一个不同的文件,或在保存之前将文件拷贝到别处.
或许还会把这些文件进行压缩,来节省空间.
这是一个原始的费功夫的版本控制形式.
计算机游戏很久以前就改良了这块,很多都提供了多个基于时间戳的自动保存记录功能.
让我们看一些更复杂的情况.
比如你有很多在一起的文件,比如项目的源代码,或网站的文件.
现在如果你想保留旧版本你不得不存储拷贝整个目录.
手工保存很多个版本不方便,并且很快会变得高昂.
对一些电脑游戏而言,一个保存的游戏记录实际上是包括一个充满文件的目录.
这些游戏对玩家屏蔽了具体细节,并提供一个方便的界面来管理目录里的不同版本.
版本控制系统也没有两样.
两者都有友好的界面来管理目录里的内容.
你频繁保存目录的状态,也可以在之后加载任一旧状态.
不像大多计算机游戏,版本控制系统通常精于节省空间.
比如说,如果两个版本间只有少数文件的改变,那就只存储差异的部分以节省存储空间,而不是把所有的都保存下来.
1.
3.
分布控制分布控制现在设想有一个非常难的计算机游戏.
太难打了,以至于全世界很多高级玩家决定组队,分享他们保存的游戏记录以攻克它.
Speedrun们就是真实生活中的例子:在同一个游戏里,玩家们专注攻克不同的等级,这样的协同工作创造了惊人的战绩.
如何搭建一个系统,使得他们可以很容易得到其他人的保存记录并且很容易上载新的记录在过去,每个项目都使用中心式版本控制.
一个服务器存放所有保存的游戏记录.
其他人都不用.
每个玩家在他们机器上最多保留几个游戏记录.
当一个玩家想更新进度时候,他们需要把最新进度从主服务器下载下来,玩一会儿,保存并上载到主服务器以供其他人使用.
假如一个玩家由于某种原因,想得到一个较旧版本的游戏进度怎么样或许当前保存的游戏是一个败局,因为某人在第三级忘记捡某个物品,并且他们希望能找到最后一个可以完成游戏的记录.
或者他们想比较两个旧版本间的差异,来估算某个特定玩家干了多少活.
查看旧版本的理由有很多,但检查的办法都是一样的.
他们必须去问中心服务器要那个旧版本的记录.
需要的旧版本越多,需要和服务器的交互就越多.
新一代的版本控制系统,Git就是其中之一,是分布式系统,可以被认作广义上的中心式系统.
一个玩家从主服务器下载所有保存的记录,不仅是最新版.
这看起来好像他们把中心服务器做了个镜像.
最初的克隆操作可能比较费时,特别历史记录很长的时候,但最终这个本地镜像备份会带来很多优势.
一个显而易见的好处是,当查看一个旧版本时,不再需要和中心服务器通讯了.
1.
3.
1.
一个误区一个误区一一个很常见的错误观念是,分布式系统不太适合需要正式中心存储的项目.
这与事实并不相符.
给某人照相并不会导致他们的灵魂被偷走.
类似地,对主存储进行克隆并不降低它的重要性.
一般来说,一个中心版本控制能做的任何事,一个良好设计的分布式系统会做得更好.
网络资源总要比本地资源耗费更多资源.
不过我们应该在稍后分析分布式方案的缺点,这样人们才不会按照习惯做出错误的比较.
一个小项目或许只需要这种系统提供的一小部分功能.
但你在计算较小数目的时候会使用罗马数字吗而且,你的项目的增长可能会超出你最初的预期.
从一开始就使用Git好似带着一把瑞士军刀,尽管你很多时候只是用它来开瓶盖.
到你迫切需要一把改锥的那一天,你就会庆幸你有的不单单是一个启瓶器.
1.
4.
冲突合并冲突合并对于这个话题,我们计算机游戏的类比显得太单薄了.
那么让我们再来看看文档编辑的情况吧.
假设Alice在文件开头插入一行,并且Bob在文件末尾添加一行.
他们都上传了他们的改动.
大多数系统将自动给出一个合理的处理方式:接受且合并他们的改动,这样Alice和Bob两人的改动都会生效.
现在假设Alice和Bob对文件的同一行做了不同的改动.
如果没有人工参与的话,这个冲突是无法解决的.
第二个人在上载文件时,会收到合并冲突的通知,并且他们必须选择要么用一个人的改动覆盖另一个的,要么完全修订这一行.
更复杂的情况也可能出现.
版本控制系统自己处理相对简单的情况,把困难的情况留给人来处理.
他们的行为通常都是可配置的.
2.
基本技巧基本技巧与其一头扎进Git命令的海洋中,不如使用一些基本的例子,湿湿脚.
例子尽管很简单但都很有用.
实际上,我开始使用Git的头几个月,从来没觉得本章介绍的命令不够用.
2.
1.
保存状态保存状态要不要来点猛的在做之前,先为当前目录所有文件做个快照,使用下列命令:$gitinit$gitadd.
$gitcommit-m"Myfirstbackup"上面的这组命令应该牢记,或放到脚本里,因为他们会常常被用到.
现在如果你的文件编辑乱了,运行:$gitreset--hard可以回到你原来编辑的地方.
再次保存状态:$gitcommit-a-m"Anotherbackup"2.
1.
1.
添加、删除、重命名添加、删除、重命名以上的命令将只对在你第一次运行gitadd命令时就已经存在的文件有用.
如果要添加新文件或子目录,你需要告诉Git:$gitaddNEWFILES.
.
.
类似地,如果你想让Git忘记某些文件(或许是由于你已经删除了他们):$gitrmOLDFILES.
.
.
重命名一个文件和先删除旧文件,再添加新文件的一样.
也有一个快捷方式gitmv,这和mv命令的语法一样.
例如:$gitmvOLDFILENEWFILE2.
2.
进阶撤销、重做进阶撤销、重做有时候你只想把某个时间点之后的所有改动都回滚掉,因为这些的改动是不正确的.
那么可以使用:$gitlog显示最近提交列表,以及他们的SHA1哈希值.
下面,键入:$gitreset--hardSHA1_HASH来恢复到一个指定的提交状态,并从记录里永久抹掉所有比该记录更新的提交.
另一些时候你想简单地跳到一个旧状态.
这种情况,键入:$gitcheckoutSHA1_HASH这个操作将把你带回过去,同时保存较新提交.
然而,像科幻电影里时光旅行一样,如果你这时编辑并提交的话,你将身处另一个现实里,因为你的动作与开始时相比是完全不同的.
这另一个现实叫作分支(branch),之后我们会对这点多讨论一些.
至于现在,只要记住:$gitcheckoutmaster会把你带到当下来.
在你运行checkout命令时,并不提交时光旅行中的改变.
再次用计算机游戏做类比:gitreset--hard::加载一个旧的游戏存档,并删除所有比它新的存档.
gitcheckout::加载旧游戏存档,但如果你从这个存档开始玩,游戏状态将有别于你之前保存的更新的记录.
此后任何记录都保存到另一个分支中,代表你进入的另一个现实.
后面会详细讲.
你可以选择只恢复特定文件或子目录,把这些加到该命令后面就可以了.
不喜欢剪切粘贴哈希值那么用:$gitcheckout"@{10minutesago}"其他的时间格式也是可以的.
比如,你可以要求倒数第五次保存状态:$gitcheckout"@{5}"2.
2.
1还原还原在法庭上,事件可以从法庭记录里追踪出来.
同样,你可以选择还原特定的提交.
$gitcommit-a$gitrevertSHA1_HASH将还原特定哈希值的提交.
运行gitlog显示该还原记录为一个新的提交.
2.
3.
下载文件下载文件得到一个由Git管理的项目的拷贝,键入:$gitclonegit://server/path/to/files例如,得到我用来创建该站的所有文件:$gitclonegit://git.
or.
cz/gitmagic.
git我们很快会对clone命令谈的更多.
2.
4.
前沿前沿如果你已经使用gitclone命令得到了一个项目的一份拷贝,你可以更新到最新版:$gitpull2.
5.
即时发布即时发布假设你已经写了一个脚本,你想和他人分享.
你可以只告诉他们从你的计算机下载,但如果在你正在改进你的脚本,或加入试验性质的改动时,他们下载了你的脚本,他们可能由此陷入困境.
当然,这就是发布周期存在的原因.
开发人员可能频繁进行项目修改,但他们只在他们觉得代码可以见人的时候才择时发布.
用Git来完成这项,需要进入你的脚本所在目录:$gitinit$gitadd.
$gitcommit-m"Firstrelease"然后告诉你的用户去运行:$gitcloneyour.
computer:/path/to/script来下载你的脚本.
这要假设他们有ssh访问权限.
如果他们没有,你需要运行gitdaemon并告诉你的用户去运行:$gitclonegit://your.
computer/path/to/script从现在开始,每次你的脚本准备好发布时,就运行:$gitcommit-a-m"Nextrelease"并且你的用户可以通过进入包含你脚本的目录,并键入下列命令,来更新他们的版本:$gitpull你的用户永远也不会取到你不想让他们看到的脚本版本.
显然这个技巧对所有的东西都是可以,不仅是对脚本.
2.
6.
我们已经做了什么我们已经做了什么找出自从上次提交之后你已经做了什么改变:$gitdiff或者自昨天:$gitdiff"@{yesterday}"或者一个特定的版本和版本2之间:$gitdiffSHA1_HASH"@{2}"除了直接运行log和diff,有时我也用qgit浏览历史(http://sourceforge.
net/projects/qgit),因为它的图形界面很养眼,或者用tig(http://jonas.
nitro.
dk/tig),一个文本界面东西,在网速不快的情况下也工作的很好.
另外,安装一个Web服务器,运行gitinstaweb,那就可以用任意的浏览器浏览了.
3.
克隆进阶克隆进阶在旧一代的版本控制系统里,checkout是获取文件的标准操作.
你将获得一组期望状态下的文件.
在Git和其他分布式版本控制系统里,克隆是标准的操作.
通过创建整个资源库的克隆来获得文件.
或者说,你实际上把整个服务器做了个镜像.
主资源库上能做的是,你都能做.
3.
1.
计算机间的同步计算机间的同步这也是我第一次使用Git的原因.
我可以忍受制作tar包或利用rsync来作备份或者作简单的同步.
但我时而在我笔记本上编辑,时而在台式机上,而且这两台电脑之间也许不能交互.
在一个机器上初始化一个Git资源库并提交你的文件.
然后转到另一台机器上:$gitcloneother.
computer:/path/to/files创建这些文件和Git资源库的第二个拷贝.
从现在开始:$gitcommit-a$gitpullother.
computer:/path/to/files将从另一台机器拷贝文件到你正工作的机器上.
如果你最近对同一个文件做了有冲突的修改,Git将通知你,而你也应该在解决冲突之后再次提交.
3.
2.
典型源码控制典型源码控制为你的文件初始化Git资源库:$gitinit$gitadd.
$gitcommit-m"Initialcommit"在中心服务器,初始化一个空的Git资源库,如果需要的话,启动Git守护进程:$GIT_DIR=proj.
gitgitinit$gitdaemon--detach#itmightalreadyberunning一些公用主机,比如repo.
or.
cz(http://repo.
or.
cz),通过不同于以上的方法来搭建最初空Git资源库,比如在网页上填一个表单.
把你的项目推到中心服务器:$gitpushgit://central.
server/path/to/proj.
gitHEAD这样我们准备好了.
一个开发人员可以这样checkout源码:$gitclonegit://central.
server/path/to/proj.
git在做了改动之后,checkin源码到主服务器:$gitcommit-a$gitpush如果主服务器已经更新了,最新版在push之前需要checkout.
同步到最新版:$gitcommit-a$gitpull3.
3.
项目分叉项目分叉项目走歪了吗或者认为你可以做得更好那么在服务器上:$gitclonegit://main.
server/path/to/files之后告诉每个相关的人你服务器上项目的分支.
在之后的时间,你可以合并来自原先项目的改变,使用命令:$gitpull3.
4.
终极备份终极备份会有很多禁止篡改的不同位置上的冗余存档吗如果你的项目有很多开发人员,那干脆别想了.
你的每份代码克隆是一个有效备份.
不仅当前状态,还包括你项目整个历史.
感谢哈希加密算法,如果任何人的克隆被损坏,只要他们与其他的交互,这个克隆就会打上记号.
如果你的项目并不是那么流行,那就找尽可能多的主服务器来放克隆.
真正的偏执狂应该总是把HEAD最近20字节的SHA1哈希值写到安全的地方.
应该保证安全,而不是把它藏起来.
比如,把它发布到报纸上就不错,因为对攻击者而言,更改每份报纸是很难的.
3.
5.
轻快多任务轻快多任务比如你想并行开发多个功能.
那么提交你的项目并运行:$gitclone.
/some/new/directoryGit使用硬链接和文件共享来尽可能安全地创建克隆,因此它一眨眼就完成了,因此你现在可以并行操作两个没有相互依赖的功能.
例如,你可以编辑一个克隆,同时编译另一个.
在任何时间,你都可以从另一个克隆提交或拿下变更.
$gitpull/the/other/clone3.
6.
游击版本控制游击版本控制你正做一个使用其他版本控制系统的项目,而你非常怀念Git那么在你的工作目录初始化一个Git资源库:$gitinit$gitadd.
$gitcommit-m"Initialcommit"然后以很快的速度克隆它:$gitclone.
/home/new/directory现在转到新目录并在这个目录工作,在你心里的内容上使用Git.
过一会,一旦你想和其他每个人同步,在这种情况下,转到原来的目录,用其他的版本控制工具同步,并键入:$gitadd.
$gitcommit-m"Syncwitheveryoneelse"然后转到新目录并运行:$gitcommit-a-m"Descriptionofmychanges"$gitpull把你的变更提交给他人的过程依赖于其他版本控制系统.
这个新目录包含你的改动的文件.
需要运行其他版本控制系统的命令来上载这些变更到中心资源库.
命令gitsvn为Subversion资源库自动化了以上步骤,并且也可以用作Git项目导出到一个Subversion资源库(参见http://google-opensource.
blogspot.
com/2008/05/export-git-project-to-google-code.
html).
4.
分支向导分支向导瞬间就能完成的分支和合并是Git最致命的杀手锏.
问题问题:外部因素不可避免地使场景切换成为必须.
在发布版本中没有任何前兆的突然出现了一个严重臭虫,并且必须不惜一切代价尽快修复.
某个特性的截至日期就要来临.
写这个功能的家伙正打算离职,因此你应该停下所有你正在做的,抓住他帮你理解这个功能.
中断连贯的思维会降低你的生产力,并且切换上下文也比较缓慢,不方便,中断的越长损失越大.
使用中心版本控制我们必须从中心服务器下载一个崭新的工作拷贝.
分布式系统的情况就好多了,因为我们能够在本地克隆所需要的版本.
但是克隆仍然需要拷贝整个工作目录,以及一直到指定点的整个历史记录.
尽管Git使用文件共享和硬链接减少了花费,项目文件自身必须在新的工作目录里重新创建.
方案方案:针对这些情况,Git有一个更好的工具,比克隆更快速而且节省空间:gitbranch在这个神奇的世界里,你目录里的文件突然从一个版本变到另一个版本.
除了只是在历史记录里前前后后的转变之外,这个转换还可以做更多.
你的文件可以从上一个版本变到实验版本到当前开发版本到你朋友的版本等等.
4.
1.
老板键老板键曾经玩过那样的游戏吗按一个键("老板键"),屏幕立即显示一个电子表格或别的那么如果老板走进办公室,而你正在玩游戏,就可以用这个功能来遮掩一下.
在某个目录:$echo"I'msmarterthanmyboss">myfile.
txt$gitinit$gitadd.
$gitcommit-m"Initialcommit"我们已经创建了一个Git资源库,该资源库记录一个包含特定信息的文件.
现在我们键入:$gitcheckout-bboss#之后似乎没啥改变$echo"Mybossissmarterthanme">myfile.
txt$gitcommit-a-m"Anothercommit"看起来我们刚刚只是覆盖了原来的文件并提交了它.
但这是个错觉.
键入:$gitcheckoutmaster#切到原来版本的文件嘿真快!
这个文件就恢复了.
并且如果老板决定窥视这个目录,键入:$gitcheckoutboss#切到适合老板眼睛的版本你可以在两个版本之间相切多少次就切多少次,而且每个版本都可以独立提交.
4.
2.
脏活脏活比如你正在开发某个特性,并且由于某种原因,你需要回到一个旧版本,临时加进几行打印语句来看看一些东西是如何工作的.
那么:$gitcommit-a$gitcheckoutSHA1_HASH现在你可以满世界加丑陋的临时代码.
你甚至可以提交这些改动.
当你做完的时候,$gitcheckoutmaster来返回到你原来的工作.
观察任何未提交变更都转结了.
如果你想之后保存临时变更怎么办简单:$gitcheckout-bdirty并且在切换到主分支之前提交.
无论你什么时候想返回脏的变更,只需键入:$gitcheckoutdirty当我们讨论加载旧状态的时候,我们在较早章节曾接触过这个命令.
最终我们把故事说全:文件改变成请求的状态,但我们必须离开主分支.
从现在开始任何提交都会将你的文件提交到另一条不同的路,这个路可以之后命名.
换一个说法,在checkout一个旧状态之后,Git自动把你放到一个新的,未命名的分支,这个分支可以使用gitcheckout-b来命名和保存.
4.
3.
快速修订快速修订你正在做某件事的当间,被告知先停下来所有的事情去修理一个新近发现的臭虫:$gitcommit-a$gitcheckout-bfixesSHA1_HASH那么一旦你修正了这个臭虫:$gitcommit-a-m"Bugfixed"$gitpush#到中心资源库$gitcheckoutmaster并可以继续你原来的任务.
4.
4.
不间断工作流不间断工作流一些项目要求在你提交你的代码之前需要审批.
为了让审批代码的过程更简单,如果你有一个大的改动,你可能会将它分成两个或更多的部分,进行单独的审批.
如果在第一部有获得准许并提交之前,第二部分不能写怎么办在许多版本控制系统中,你不得不先将第一部分发送给审批者,然后等待,直到这部分获得批准后,才可以开始第二部分的工作.
实际上那并非全是真的,但在这些系统中,在第一部分提交前,就编辑第二部分会引入很多痛苦和困难.
在Git里,分支和合并是无痛的(快速和本地的一个技术词汇).
因此在你提交第一部分内容并发送给审批者后:$gitcheckout-bpart2接下来,为这个大变动的第二部分进行编码,不必等待第一部分的接受.
在第一部分获得批准并提交后:$gitcheckoutmaster$gitmergepart2$gitbranch-dpart2#不在需要这个分支并且第二部分也准备好审批.
不过等等!
如果没那么简单怎么办比如你在第一部分犯了一个错误,在你提交之前你不得不更正它.
没问题!
首先,转到主分支:$gitcheckoutmaster修复第一部分变更里的这个问题,并希望它得到批准.
如果没获得批准就简单重复这一步.
你或许希望将第一部分修改后的版本合并到第二部分:$gitcheckoutpart2$gitmergemaster现在它和以前一样了.
一旦第一部分获得批准并提交:$gitcheckoutmaster$gitmergepart2$gitbranch-dpart2并且再次,第二部分也准备好审批了.
这个技巧可以很容易地被扩展,来处理任意多数目的部分.
4.
5.
重组杂乱重组杂乱或许你喜欢在同一个分支下完成工作的方方面面.
你想为自己保留工作进度并希望其他人只能看到你仔细整理过后的提交.
开启一对分支:$gitcheckout-bsanitized$gitcheckout-bmedley接下来,可以做任何事情:修臭虫,加特性,加临时代码,诸如此类,经常按这种方式提交.
然后:$gitcheckoutsanitized$gitcherry-pickSHA1_HASH在"sanitized"分支应用给定提交.
在分支上选择一个最合适的点,你可以建设一个只包含永久代码,有关提交组合在一起的分支.
4.
6.
管理分支管理分支键入:$gitbranch来列出所有分支.
总有一个叫做"master",并且你默认从这开始.
一些人主张别碰"master"分支,而是创建你自己版本的新分支.
使用-d-m选项来删除、移动(重命名)分支.
参见githelpbranch.
.
4.
7.
临时分支临时分支很快你会发现你经常会因为一些相同的原因创建短期的分支.
或许有些时候你创建分支只是为了保存当前状态,同时你方便在上一个保存状态执行一些操作,诸如修复高优先级的臭虫之类.
可以和电视的换台做类比,临时切到别的频道,来看看那正演什么,但并不是简单地按几个按钮,你必须创建,检出,删除并提交临时分支.
幸运的是,Git已经有了和电视机遥控器一样方便的功能:$gitstash这个命令保存当前状态到一个临时的地方(一个隐藏的地方)并且恢复之前状态.
你的工作目录看起来和你开始编辑之前一样,并且你可以修复臭虫,引入之前变更等.
当你想回到隐藏状态的时候,键入:$gitstashapply#你可能需要解决一些冲突你可以有多个隐藏,并用不同的方式来操作他们.
参见githelpslash.
.
4.
8.
按你希望的方式工作按你希望的方式工作诸如MozzilaFirefox(http://www.
mozilla.
com/)允许你打开多个标签和多个窗口.
切换标签可以在同一个窗口展示不同内容.
Git的分支就像是你工作目录的标签.
继续这个类比,Git克隆好似打开一个新的窗口.
这两种操作的易用性提高了用户体验.
在更高层,几个Linux窗口管理器允许你有多个桌面:你可以立即切到一个显示器另一个相似的例子是screen(http://www.
gnu.
org/software/screen/)工具.
这个好东西允许你在同一个终端上创建,销毁终端会话,还可以在多个终端会话之间切换.
不是打开一个新的终端(类似于克隆),如果你使用screen(类似于分支),你可以使用同一个终端.
实际上,你还可以利用screen做更多的事,不过这是另一个话题的内容了.
在Git里,克隆、分支和合并是本地操作,很快.
促使你能使用最适合你的组合.
Git让你能按你确切想要的工作.
5.
关于历史关于历史Git一系列的分布式特性使得历史可以很容易的被修改掉.
但如果你篡改了过去,需要小心:只重写你独自拥有的那部分.
如同民族间会无休止的争论谁犯下了什么暴行一样,如果在另一个人的克隆里,历史版本与你的不同,这时如果合并的话,你会遇到一致性方面的问题.
当然,如果你掌管所有分支的话,那就没啥问题了,既然你可以覆盖他们的.
一些开发人员强烈地感觉历史应该永远不变,无论不好的部分或这所有的部分.
另一些觉得代码树在向外发布之前,应该整得漂漂亮亮的.
Git支持两者的观点.
像克隆,分支和合并一样,重写历史只是Git给你的另一强大功能,至于如何使用它,那是你的事了.
5.
1.
改正标准改正标准已经提交了,但你期望你已经输入了另外的信息那么键入:$gitcommit--amend来改变上一条信息.
意识到你还忘记了加一个文件运行gitadd来加,然后与性上面的命令.
希望在上次提交里包括多一点的改动那么就做这些改动并运行:$gitcommit--amend-a5.
2.
在这之后在这之后假设前面的问题还要糟糕十倍.
在很长一段时间里我们做了一系列的提交.
但你不太喜欢他们的组织方式,而且一些提交信息需要重写.
那么键入:$gitrebase-iHEAD~10并且后10个提交会出现在你喜爱的$EDITOR.
一个例子:pick5c6eb73Addedrepo.
or.
czlinkpicka311a64Reorderedanalogiesin"WorkHowYouWant"pick100834fAddedpushtargettoMakefile之后:通过删除行来移去提交.
通过为行重新排序来为提交重新排序.
用"edit"来替换"pick"来标志一个提交可修改.
用"squash"来替换"pick"来将一个提交和前一个合并.
如果你把一个提交标记为可编辑,那么运行$gitcommit--amend或者,运行:$gitrebase--continue这样尽早提交,经常提交都没关系:你可以之后使用rebase来梳理清楚.
5.
3.
本地变更最后部分本地变更最后部分你正在一个活跃的项目上工作.
随着时间推移,你做了几个本地提交,然后你使用合并与官方版本同步.
在你准备好提交到中心分支之前,这个循环会重复几次.
但现在你本地Git克隆的变更历史与官方变更乱成了一锅粥.
你会更期望在变更列表里,你所有的变更能够连续的这就是上面提到的gitrebase的工作.
在很多情况下你可以使用--onto标记以避免交互.
另外参见githelprebase,以获取这个让人惊奇的命令更详细的例子.
你可以拆分提交.
你甚至可以重新组织一棵树的分支.
5.
4.
重写历史重写历史偶尔,你需要做一些代码控制,好比从正式的照片中去除一些人一样,需要从历史记录里面彻底的抹掉他们.
例如,假设我们要发布一个项目,但由于一些原因,项目中的某个文件不能公开.
或许我把我的信用卡号记录在了一个文本文件里,而我又意外的把它加入到了这个项目中.
仅仅删除这个文件是不够的,因为从别的提交记录中还是可以访问到这个文件.
因此我们必须从所有的提交记录中彻底删除这个文件.
$gitfilter-branch--tree-filter`rmtop/secret/file`HEAD参见githelpfilter-branch,那讨论这个例子并给出一个更快的方法.
一般地,filter-branch允许你使用一个单一命令来大范围地更改历史.
事后,你必须使用你更改过的版本替换你项目的克隆,如果你希望之后和他们交互的话.
5.
5.
制造历史制造历史想把一个项目迁移到Git吗如果这个项目是用一些比较有名的系统管理着,那可以使用一些其他人已经写好的脚本,把整个项目历史记录导出到Git里.
否则,看一下gitfast-import,这个命令会从一个特定格式的文本读入,从头来创建Git历史记录.
通常可以很快地组织一个包含这个命令的脚本,运行一次就可以一次迁移整个项目.
作为一个例子,粘贴以下所列到临时文件,比如/tmp/history:commitrefs/heads/mastercommitterAliceThu,01Jan197000:00:00+0000dataintmain(){printf("Hello,world!
\n");return0;}EOTcommitrefs/heads/mastercommitterBobTue,14Mar200001:59:26-0800dataintmain(){write(1,"Hello,world!
\n",14);return0;}EOT之后从这个临时文件创建一个Git资源库,键入:$mkdirproject;cdproject;gitinit$gitfast-import使用:$gitcheckoutmaster.
5.
6.
哪儿错了哪儿错了你刚刚发现程序里有一个功能出错了,而你十分确定几个月以前它运行的很正常.
天啊!
这个臭虫是从哪里冒出来的要是那时候能按照开发的内容进行过测试该多好啊.
现在说这个已经太晚了.
然后即使你过去经常提交变更,Git还是可以精确的找出问题所在:$gitbisectstart$gitbisectbadSHA1_OF_BAD_VERSION$gitbisectgoodSHA1_OF_GOOD_VERSIONGit从历史记录中检出一个中间的状态.
在这个状态上测试功能,如果还是错误的:$gitbisectbad如果可以工作了,则把"bad"替换成"good".
Git会再次帮你找到一个以确定的好版本和坏版本之间的状态,通过这种方式缩小范围.
经过一系列的迭代,这种二进制查询会帮你找到导致这个错误的那次提交.
一旦完成了问题定位的调查,你可以返回到原始状态,键入:$gitbisectreset不需要手工测试每一次改动,执行如下命令可以自动的完成上面的搜索:$gitbisectrunCOMMANDGit使用指定命令(通常是一个一次性的脚本)的返回值来决定一次改动是否是正确的:命令退出时的代码0代表改动是正确的,125代表要跳过对这次改动的检查,1到127之间的其他数值代表改动是错误的.
返回负数将会中断整个bisect的检查.
你还能做更多的事情:帮助文档解释了如何展示bisects,检查或重放bisect的日志,并可以通过排除对已知正确改动的检查,得到更好的搜索速度.
5.
7.
谁让事情变糟了谁让事情变糟了和其他许多版本控制系统一样,Git也有一个"blame"命令:$gitblameFILE这个命令可以标注出一个指定的文件里每一行内容的最后修改者,和最后修改时间.
但不像其他版本控制系统,Git的这个操作是在线下完成的,它只需要从本地磁盘读取信息.
5.
8.
个人经验个人经验在一个中心版本控制系统里,历史的更改是一个困难的操作,并且只有管理员才有权这么做.
没有网络,克隆,分支和合并都没法做.
像一些基本的操作如浏览历史,或提交变更也是如此.
在一些系统里,用户使用网络连接仅仅是为了查看他们自己的变更,或打开文件进行编辑.
中心系统排斥离线工作,也需要更昂贵的网络设施,特别是当开发人员增多的时候.
最重要的是,通常当用户试图避免使用那些能不用则不用的高级命令时,所有操作都变得很慢.
在极端的情况下,即使是最基本的命令也会变慢.
当用户必须运行慢的命令的时候,由于工作流被打断,生产力降低.
我有这些现象的一手经验.
Git是我使用的第一个版本控制系统.
我很快变得适应了它,用了它提供的许多功能.
我简单地假设其他系统也是相似的:选择一个版本控制系统应该和选择一个编辑器或浏览器没啥两样.
在我之后被迫使用中心系统的时候,我被震惊了.
我那有些脆弱的网络连接没给Git带来大麻烦,但是当它需要像本地硬盘一样稳定的时候,它使开发困难重重.
另外,我发现我自己有选择地避免特定的命令,以避免踏雷,这极大地影响了我,使我不能按照我喜欢的方式工作.
当我不得不运行一个慢的命令的时候,这种等待极大地破坏了我思绪连续性.
在等待服务器通讯完成的时候,我选择做其他的事情以度过这段时光,比如查看邮件或写其他的文档.
当我返回我原先的工作场景的时候,这个命令早已结束,并且我还需要浪费时间试图记起我之前正在做什么.
人类不擅长场景间的切换.
还有一个有意思的大众悲剧效应:预料到网络拥挤,为了减少将来的等待时间,每个人将比以往消费更多的带宽在各种操作上.
共同的努力加剧了拥挤,这等于是鼓励个人下次消费更多带宽以避免更长时间的等待.
6.
Git大师大师这个有点自夸的标题下是我压箱底的Git不在编的技巧.
6.
1.
源码发布源码发布就我的项目而言,Git确切跟踪了我想打包并发布给用户的文件.
创建一个源码包,我运行:$gitarchive--format=tar--prefix=proj-1.
2.
3/HEAD6.
2.
历史记录生成历史记录生成保留一份历史记录是一个好实践(http://en.
wikipedia.
org/wiki/Changelog),这甚至是一些项目所要求的.
如果你变更提交的很频繁,这是应该的,可以生成一份历史记录,通过键入:$gitlog>Changelog6.
3.
通过通过SSH,,HTTP使用使用Git假设你有一台web服务器的ssh访问权限,但上面并没有安装Git.
没有比服务器上自带协议更省事的方法的,Git可以通过HTTP来进行通信.
那么在你的帐户下下载,编译并安装Git.
在你的Web目录里创建一个Git资源库:$GIT_DIR=proj.
gitgitinit在目录"proj.
git"目录,运行$git--bareupdate-server-info$chmoda+xhooks/post-update从你的计算机通过SSH推送:$gitpushwe.
server:/path/to/proj.
gitmaster别人可以通过如下命令,得到你的项目:$gitclonehttp://web.
server/proj.
git6.
4.
提交变更提交变更对特定项目,当你加入、删除、重命名一些文件时,告诉Git这个操作是有困难的.
你可以键入:$gitadd.
$gitadd-uGit会查看当前目录的这些文件,并独立计算出所有细节.
如果你还试图同时提交的话,可以不使用第二个添加命令,而是运行gitcommit-a.
也可以用单独的一行完成以上的任务:$gitls-files-d-m-o-z|xargs-0gitupdate-index--add--remove这里-z和-0选项可以避免文件名中包含特殊字符带来的错误.
注意该命令也添加应该被忽略的文件.
这时你或许希望使用-x或-X选项.
6.
5.
我的提交太大了!
我的提交太大了!
是不是太长时间忘记了提交痴迷地编码,以至到现在才想起有源码控制工具这回事提交一系列不相关的变更,因为那是你的风格别着急,运行:$gitadd-p为你做的每次修改,Git将为你展示变动的代码,并询问该变动是否应是下一次提交的一部分.
回答"y"或者"n".
也有其他选项,比如延迟决定:键入""来学习更多.
一旦你满意,键入$gitcommit来精确地提交你所选择的变更(阶段变更).
确信你没加上"-a"选项,否则Git将提交所有修改.
如果你修改了许多地方的许多文件怎么办一个一个地查看变更令人沮丧,心态麻木.
这种情况下,使用gitadd-i,界面不是很直观,但更灵活.
敲几个键,你可以一次决定阶段提交几个文件,或查看并检查特定文件的变更.
作为另一种选择,你还可以运行gitcommit--interactive,这个命令会在你操作完后自动进行提交.
6.
6.
别丢了你的别丢了你的HEADHEAD好似一个游标,通常指向最新提交,随最新提交向前移动.
Git提供了命令来移动它.
例如:$gitresetHEAD~3将立即向回移动HEAD三个提交.
这样所有Git命令都表现得好似你没有做那最后三个提交,然而你的文件保持在现在的状态.
具体应用参见gitreset手册页.
但如何回到将来呢过去的提交对将来一无所知.
如果你有原先Head的SHA1值,那么:$gitresetSHA1但假设你从来没有记下呢别着急,像这些命令,Git保存原先的Head为一个叫ORGI_HEAD的标记,你可以安全体面的返回:$gitresetORIG_HEAD6.
7.
猎捕猎捕HEAD或许ORG_HEAD不够.
或许你刚认识到你犯了个历史性的错误,你需要回到一个早已忘记的分支上的一个远古的提交.
默认,Git保存一个提交至少两星期,即使你命令Git摧毁该提交所在的分支.
难点是找到相应的哈希值.
你可以查看在.
git/objects里所有的哈希值并尝试找到你期望的.
但有更容易的办法.
Git把算出的提交哈希值记录在.
git/logs.
这个子目录引用包括所有分支上所有活动的历史,同时文件HEAD显示它曾经有过的所有哈希值.
后者可以被用来分支上一些不小心丢掉的提交的哈希值.
命令reflog为访问这些日志提供文件友好的接口,试试$gitreflog更多信息参见其文档页.
你或许期望去为已删除的提交设置一个更长的保存周期.
例如:$gitconfiggc.
pruneexpire"30days"意思是一个被删除的提交会在删除30天后,且运行gitgc以后,被永久丢弃.
你或许还想关掉gitgc的自动运行:$gitconfiggc.
auto0在这种情况下提交将只在你手工运行gitgc的情况下才永久删除.
6.
8.
在在Git上编译上编译依照真正的UNIX风格,Git的设计允许其可以被很容易用作其他程序的底层组件.
有图形界面,Web界面,可选择的命令行界面,并且或许很快你将有一个或两个你自己的脚本,调用Git.
一个简单的技巧是,用Git内建alias命令来缩短你最常用命令的长度:$gitconfig--globalalias.
cocheckout$gitconfig--global--get-regexpalias#显示当前别名alias.
cocheckout$gitcofoo#和'gitcheckoutfoo'一样另一个是在提示符或窗口标题上打印当前分支.
调用:$gitsymbolic-refHEAD显示当前分支名.
在实际应用中,你可能最想去掉"refs/heads/"并忽略错误:$gitsymbolic-refHEAD2>/dev/null|cut-b12-更多例子参见Git主页(http://git.
or.
cz/).
6.
9.
大胆的绝技大胆的绝技最近版本的Git使得用户意外销毁数据变得更困难了.
这或许是升级的最令人瞩目的原因了.
虽然如此,有时你的确想销毁数据.
我们展示如何覆盖为通用命令所设的防卫设施.
只在你知道你在做什么的时候使用他们.
Checkout:如果你有未提交的变更,平常的checkout会失败.
销毁你的变更,并无论如何都checkout一个指定的提交,使用强制选项:$gitcheckout-fCOMMIT另外,如果你为checkout指定的路径,那就没有安全检查了.
提供的路径将被不加提示地覆盖.
如果你使用这种方式的checkout,一定要小心.
重置:重置:在有未提交变更的情况下,重置也会失败.
强制其通过,运行:$gitreset--hard[COMMIT]分支:分支:如果删除一个分支会导致变更丢失的,删除操作会失败.
强制删除,键入:$gitbranch-DBRANCH#注意不是-d类似地,试图通过移动覆盖一个分支也会失败,如果数据确信会丢失的话.
强制移动分支,键入:$gitbranch-M[SOURCE]TARGET#注意不是-m不像checkout和重置,这两个命令延迟数据销毁的时间.
这个变更仍然存储在.
git的子目录里,并且可以通过恢复.
git/logs里的相应哈希值获取到(参见上面"猎捕HEAD"一节).
默认情况下,这些数据会保存至少两星期.
7.
解密解密我们揭开Git神秘面纱,往里瞧瞧它是如何创造奇迹的.
我会跳过细节.
更深入的描述参见用户手册(http://www.
kernel.
org/pub/software/scm/git/docs/user-manual.
html).
7.
1.
大象无形大象无形Git怎么这么谦逊寡言呢除了偶尔提交和合并外,你可以如常工作,就像不知道版本控制系统存在一样.
那是,直到你需要它,而且那时候你也很高兴Git一直默默注视着你整个的工作.
其他版本控制系统可不许你忘记他们.
在你显示地告诉服务器你打算编辑哪些文件前,文件权限也许是只读的.
中心服务器可能正跟踪什么人,什么时候checkout了什么代码.
当网络连接断了的时候,你就遭殃了.
开发人员不断地与这些版本控制系统的种种限制作斗争.
秘诀就在你工作目录里的.
git目录.
Git在这里记录你项目的历史.
最前面的".
"使这个文件在ls的输出中不显示.
除了你的提交或同步变更以外,所有版本控制操作都在这个目录里操作.
你对你文件的命运有完全的掌控,因为Git根本不关心你对他们做了什么.
Git可以很容易地从.
git里重新创建出一个保存状态.
7.
2.
数据完整性数据完整性很多人把加密和保持信息机密性关联起来,但一个同等重要的目标是保证信息的安全性.
合理使用哈希加密功能可以防止意外地或恶意地数据损坏.
一个SHA1哈希值是一个160位的ID数,用它可以唯一标识你一生中遇到的每个二进制字符串.
实际上不止如此:任何人几辈子用到的所有字符串都可以用它来唯一标识.
对一个文件而言,其整体内容的哈希值可以被看作这个文件的唯一标识ID数.
一个重要的发现是,一个SHA1哈希值本身也是一个二进制字符串,因此我们可以为包含其他哈希值的字符串生成哈希值.
大略地讲,所有Git处理的文件通过他们的唯一ID来引用,而不是通过他们的文件名.
所有数据保存在".
git/objects"子目录里,那里你找不到任何标准的文件名.
文件内容都是我们叫做'blobs'的二进制字符串,这些二进制字符串跟他们的文件名也是剥离的.
而文件名会被记录在别的地方.
他们被存储在'树'对象里,这里记录着文件名和他们内容的ID值对应关系列表.
既然树本身是一个二进制字符串,它也有一个唯一ID,这也是它是如何被存储在".
git/objects"子目录里的办法.
树可以出现在其他树的列表里,因此一个目录树和其所有文件可以被表达为树和blob.
最终,一个'提交'包含一条消息:一些树ID和他们之间如何关联的信息.
一个提交也是一个二进制字符串,因为它也有一个唯一ID.
你可以自己看看:在.
git/objects目录里随便找一个哈希值,然后键入:$gitcat-file-pSHA1_HASH现假设某人试图重写历史记录,并准备更改一个古老版本里一个文件的内容.
那么这个文件的ID将被更改,因为这个文件变成了另一个二进制字符串.
这会影响每一个引用这个文件的的树对象,并导致所有与该树相关的已提交对象都需要被更改.
因为有多个文件中包含着错误的ID,当人们完成提交操作时,就会发现这个遭到破坏的资源库.
我已经忽略了诸如文件权限和签名之类的细节.
但简单地讲,只要20字节的长度就能代表最后的提交是安全的,破坏Git资源库是不可能的.
7.
3.
智能智能Git是如何知道你重命名了一个文件,即使你从来没有明确提及这个事实当然,你或许是运行了gitmv,但这个命令和gitadd紧接gitrm是完全一致的.
Git启发式地找出相连版本之间的重命名和拷贝.
实际上,它能检测文件之间代码块的移动或拷贝!
虽然它不能包揽所有的情况,但它已经做的很好了,并且这个功能也总在改进改进.
如果它在你那儿不工作的话,可以尝试打开开销更高的拷贝检测选项,并考虑升级.
7.
4.
索引索引为每个跟踪的文件,Git在一个名为index的文件里记录其诸如大小,创建时间和最后修改时间的信息.
Git比较其当前与在index里的统计资料,以确定文件是否更改.
如果一致,那Git就避免重新读取该文件.
因为调用统计资料比读文件内容的开销小很多,如果你仅仅编辑了少数几个文件,Git几乎不需要什么时间就能更新他们的状态.
7.
5.
裸资源库裸资源库你或许想知道那些在线Git资源库用的是什么格式.
他们除了具有类似proj.
git的名字以外,和你的.
git目录一样,是无格式的.
另一个不同点是他们没有关联任何工作目录.
大多数Git命令默认Git的索引是存放在.
git目录,但在这些裸资源库上并不是这样,所以会导致命令执行失败.
为了解决这个问题,可以设置环境变量GIT_DIR来指定裸资源库所在路径,或者在裸资源库的目录里运行Git时加上--bare选项.
7.
6.
Git起源起源Linux内核邮件列表上的一则帖子(http://lkml.
org/lkml/2005/4/6/121)描述了形成Git的一系列事件.
对Git史学家而言,整个的讨论是一个令人着迷的历史探索过程.
8.
Git的缺点的缺点我避开了对一些Git现存问题的讨论.
有些可以通过脚本或回调方法轻易地解决,有些需要重组或重定义项目,还有少数无解问题,只能暂时等待.
更好的办法是,投入进来,一起解决这些问题.
我对版本控制系统已经有了一些想法,并基于Git写了一个实验性系统(http://www-cs-students.
stanford.
edu/~blynn/gg/),并解决了一部分问题.
8.
1.
微软微软WindowsGit在微软Windows上可能有些繁琐:Cygwin(http://cygwin.
com),一个Windows下的类Linux的环境,里面有一个Windows移植Git(http://cygwin.
com/package/git/).
GitonMSys(http://code.
google.
com/p/msysgit/)是另一个,要求最小运行时支持,不过一些命令不能马上工作.
8.
2.
无关的文件无关的文件如果你的项目非常大,包含很多无关的文件,而且正在不断改变,Git可能比其他系统更不管用,因为独立的文件是不被跟踪的.
Git跟踪整个项目的变更,这通常才是有益的.
一个方案是将你的项目拆成小块,每个都由相关文件组成.
如果你仍然希望在同一个资源库里保存所有内容的话,可以使用gitsubmodule.
8.
3.
谁在编辑什么谁在编辑什么一些版本控制系统在编辑前强迫你显示地用某个方法标记一个文件.
尽管这种要求很繁琐,特别是这个动作需要和中心服务器通讯时.
它还是有以下两个好处的:1.
比较速度快,因为只有被标记的文件需要检查.
2.
通过查询在中心服务器上谁把某个文件标记为编辑状态,人员可以获知还有谁正在编辑这个文件.
使用适当的脚本,你也可以使用Git达到同样的效果.
这要求程序员协同工作,当他编辑一个文件的时候还要运行特定的脚本.
8.
4.
文件历史文件历史因为Git记录的是项目范围的变更,重造单一文件的变更历史比其他跟踪单一文件的版本控制系统要稍微麻烦些.
好在麻烦还不大,也是值得的,因为Git其他的操作难以置信地高效.
例如,gitcheckout比cp-a都快,而且项目范围的delta压缩也比基于文件delta集合的做法好多了.
8.
5.
初始克隆初始克隆当一个项目有相当长度的历史后,与在其他版本系统里的检出代码相比,创建一个克隆的开销会大的多.
从长时间使用看,初始的代价还是值得付出的,因为大多将来的操作将由此变得很快,并可以离线完成.
然而,在一些情况下,使用--depth创建一个浅克隆比较划算些.
这种克隆初始化的更快,但生成的克隆仅具有较少的功能.
8.
6.
不稳定的项目不稳定的项目Git是变更的大小决定写入的速度快慢.
一般人做了小的改动就会提交新版本.
这里一行臭虫修改,那里一个新功能,修改掉的注释等等.
但如果你的文件在相邻版本之间存在极大的差异,那每次提交时,你的历史记录会以整个项目的大小增长.
任何版本控制系统对此都束手无策,但标准的Git用户将遭受更多,因为一般来说,历史记录也会被克隆.
应该检查一下变更巨大的原因.
或许文件格式需要改变一下.
小修改应该仅仅导致几个文件的细小改动.
又或许,数据库或备份/打包方案才是正选,而不是版本控制系统.
例如,版本控制就不适宜用来管理网络摄像头周期性拍下的照片.
如果这些文件实在需要持续更改,实在需要版本控制,一个可能的办法是以中心的方式使用Git.
可以创建浅克隆,这样检出的较少,也没有项目的历史记录.
当然,很多Git工具就不能用了,并且修复必须以补丁的形式提交.
这也许还不错,因为似乎没人需要大幅度变化的不稳定文件历史.
另一个例子是基于固件的项目,使用巨大的二进制文件形式.
用户对固件文件的变化历史没有兴趣,更新的压缩比很低,因此固件修订将使资源库无谓的变大.
这种情况,源码应该保存在一个Git资源库里,二进制文件应该单独保存.
为了简化问题,应该发布一个脚本,使用Git克隆源码,对固件只做同步或Git浅克隆.
8.
7.
全局计数器全局计数器一些中心版本控制系统维护一个正整数,当一个新提交被接受的时候这个整数就增长.
Git则是通过哈希值来记录所有变更,这在大多数情况下都工作的不错.
但一些人喜欢使用整数的方法.
幸运的是,很容易就可以写个脚本,这样每次更新,中心Git资源库就增大这个整数,或使用tag的方式,把最新提交的哈希值与这个整数关联起来.
每个克隆都可以维护这么个计数器,但这或许没什么用,因为只有中心资源库以及它的计数器对每个人才有意义.
8.
8.
空子目录空子目录空子目录不可追踪.
可以通过创建一个空文件以绕过这个问题.
Git的当前实现,而不是它的设计,是造成这个缺陷的原因.
如果运气好,一旦Git得到更多关注,更多用户要求这个功能,这个功能就会被实现.
8.
9.
初始提交初始提交传统的计算机系统从0计数,而不是1.
不幸的是,关于提交,Git并不遵从这一约定.
很多命令在初始提交之前都不友好.
另外,一些极少数的情况必须作特别地处理.
例如重订一个使用不同初始提交的分支.
Git将从定义零提交中受益:一旦一个资源库被创建起来,HEAD将被设为包含20个零字节的字符串.
这个特别的提交代表一棵空的树,没有父节点,早于所有Git资源库.
然后运行gitlog,比如,通知用户至今还没有提交过变更,而不是报告致命错误并退出.
BuyVM 商家算是有一些年头,从早年提供低价便宜VPS主机深受广大网友抢购且也遭到吐槽的是因为审核账户太过于严格。毕竟我们国内的个人注册账户喜欢账户资料乱写,毕竟我们看英文信息有些还是比较难以识别的,于是就注册信息的时候随便打一些字符,这些是不能通过的。前几天,我们可以看到BUYVM商家有新增加迈阿密机房,而且商家有提供大硬盘且不限制流量的VPS主机,深受有一些网友的喜欢。目前,BUYVM商家有...
vinahost怎么样?vinahost是一家越南的主机商家,至今已经成13年了,企业运营,老牌商家,销售VPS、虚拟主机、域名、邮箱、独立服务器等,机房全部在越南,有Viettle和VNPT两个机房,其中VNPT机房中三网直连国内的机房,他家的产品优势就是100Mbps不限流量。目前,VinaHost商家发布了新的优惠,购买虚拟主机、邮箱、云服务器、VPS超过三个月都有赠送相应的时长,最高送半年...
妮妮云的来历妮妮云是 789 陈总 张总 三方共同投资建立的网站 本着“良心 便宜 稳定”的初衷 为小白用户避免被坑妮妮云的市场定位妮妮云主要代理市场稳定速度的云服务器产品,避免新手购买云服务器的时候众多商家不知道如何选择,妮妮云就帮你选择好了产品,无需承担购买风险,不用担心出现被跑路 被诈骗的情况。妮妮云的售后保证妮妮云退款 通过于合作商的友好协商,云服务器提供2天内全额退款,超过2天不退款 物...