本篇提要:git的核心理念、结构、代码库的建立和Mergegit
从开始使用git至今看过无数文章,大多时候是为了解决一个特定问题,寻求一个特定的解决方案,偶尔也会看一些新手向的教程。对于前者,可能须要你具有必定的git能力,这无可厚非。但大多新手向的教程主要铺陈git的经常使用命令,看的时候以为本身懂了,但实际使用时就会问题重重。github
磕磕绊绊至今,我对git也算是有了一些了解,固然都是使用向而不是原理向。在此但愿可以以我本身理解的方式,描述我在使用git时的一些心得,但愿可以帮助一些新手或者经常被git困扰的伙伴。编程
五花八门的命令是使用git的手段,并非git的核心。在我看来,与其掌握100条命令,不如先大体了解一下git的思想和大致架构。从使用者角度出发,git的目的就是为了方便咱们随时找到须要的代码并进行处理,而咱们经常使用的大多数命令,都是为了这一点服务的,确切的来讲这一点就是一条commit。bash
从结构来讲,git主要有工做区、暂存区和版本库三大区域。工做区就是咱们写代码的地方,git会追踪你干了什么,并告诉你你的操做和版本库有哪些不一样。暂存区就是对你如今的工做拍照,也就是所谓快照,继续在工做区操做,暂存区仍是会停留在拍照那一刻,就像手机截屏同样。版本库就是当你以为暂存区的代码没问题以后,就能够入库了,这时候git就真正把你所作的事变成了一条有价值的commit。微信
使git变得错综复杂的概念是分支,但分支又是必不可少的,不少时候你不得不放下手头的工做,先去处理其余的问题,处理完后再回来继续工做。这种状况下,必需要保证的是被中断的工做就停留在它刚才的状态,不然现有的工做就没法继续下去了。分支看起来就像一个副本(虽然git确定不是这么实现的,但咱们仍是能够简单的理解它就是复制了一次),确保了在某个分支上操做,不会影响到其余分支的内容。架构
以上就是咱们平常使用git的所有了,在工做区工做,到某个节点拍照存到暂存区,确认无误后合并到版本库。偶尔来个突发事件,停下手头的工做到另外一个分支处理,结束后回来继续工做。不过这都是概念性的,至关于定义了游戏规则,接下来就是看git给咱们提供了哪些手段来完成此事。ide
在正式操做git命令以前,我以为对概念建模能对咱们理解git提供有效帮助。咱们把git看作一片竹林,我是一个园丁,我和其余的园丁一块儿照料这片林子,只不过这里的每根竹子要生长一节都是咱们园丁说了算,而不是大地(看起来咱们都是上帝?)。而咱们每一个人的工做,就是决定什么时间让竹子长一节,记录咱们工做的工具是分配给每一个人的一台电脑。工具
咱们的模型就是这么简单,一堆人一块儿“造”竹子,接下来跟随着时间的脚步看下咱们的模型如何运做吧。(PS:看起来怪怪的,莫不是咱们开了一个竹子蜡像馆?问题是能吸引来哪怕一个游客吗?无论那么多了,老板的想法不是咱们普通工人应该琢磨的,有钱拿就好了。。。)fetch
一开始咱们很穷,除了钱什么都没有。要想造竹子,得先有地盘吧,因此咱们就拿钱买了块地,它大概是ui
好了,不开玩笑,它大概这么大:
打开你的命令行,输入如下字母,你就获得了同样大的土地:
mkdir first_git
cd ./first_git/
git init
复制代码
当你看到这样的输出,就成功了:
这里看到了 master,这是git默认给咱们建立的分支,也叫主分支,毕竟git须要在某个分支工做。给咱们的模型挖一个坑,稍大一点,之后就是咱们的明星产品了。
我(飞机酱)和个人小伙伴(姑且叫他路人丙)深得老板器重,因此这块地目前所有属于咱们。虽然说咱们只有两我的,但也要衡量谁作的多作的好,发给每一个人的电脑就是用来记录咱们天天都作了什么,最后每一个人的成果还要汇总一下交给老板。因此还须要一台公共的电脑用来汇总咱们的信息,把咱们各自的工做整理后发到这台电脑上,最终整合成美观的结果报告等待老板查阅。既然这台电脑已经开了头,就把它充公吧。
事情要由老板牵头,因此老板在这台电脑上签了名,并写下如下内容:“竹林001号项目启动”。接下来就什么都无论了...
使用git完成老板的操做可不简单,你得依次作如下几个事情:
git config --global user.name "boss"
git config --global user.email "boss@git.com"
复制代码
以上就是老板签名的步骤,--global
是说这个电脑上的所有项目都是老板的,操做者也是他本身,并且他也不必每次开一个项目都再次签名认证了(这样一来,路人丙若是想捣乱,老板必定会发现他)。
接下来老板新建了一个README.txt
并将内容竹林001号项目启动
写进去保存了起来
echo 竹林001号项目启动 > README.txt
复制代码
写好了开场白,还得按照规矩把它存到版本库里,否则事情就白作了。先用 git status
看看如今版本库的状态:
那个红色的 README.txt 就是咱们的工做区,git发现了工做区改动,可是暂存区里没有它,版本库里也没有。既然用git工具,就务必按照规则来,先把工做区拍照存到暂存区,再进入版本库:
// 添加到暂存区
git add README.txt
复制代码
再看看状态,发现红色变成绿色了,这时候就进了暂存区:
最后,终于能够入库了,咱们的项目也算正式启动。
// 并入版本库
git commit -m "老板写下了启动标语"
复制代码
-m 后边加的内容表示此次作了什么,方便之后查阅。执行完成以后,咱们就拥有了第一个commit,也就是第一个有价值的节点。
使用 git log
能够看看咱们作过什么:
commit 后边那个长长的字符串,它是此次commit的惟一标识,后边咱们会明白它的意义。
如今,咱们有了第一节竹子(画图很差,勿吐槽):
老板只在公共的电脑上写下了标语,咱们本身的电脑尚未呢,总不能让老板挨个写吧?(老板:……)因此咱们要有个办法把公共电脑的内容搞过来,这就是git clone
。咱们只要在本身的电脑上,执行 git clone + 版本库的路径
,就能把代码同步过来,我这里只能在同一个电脑操做,因此用仓库名称进行 clone(同时在源版本库执行git config receive.denyCurrentBranch warn
):
能够看到老板修改的内容已通过来了。路人丙也执行了一样的操做,这样就能够各作各的。为了知道是谁作的工做,咱们还分别设置了本身的名字,这样之后的每一个commit都会携带做者(路人丙干了坏事,咱们看看 git log 就能抓到他!)。若是只有一个项目,能够不加--global
。如今咱们的土地上有了三根同样的竹子:
一切准备就绪,接下来就能够开始干活了,飞机酱和路人丙都在全力造竹子,并记录到本身的电脑里,此时公共电脑并不知道他们干了什么。第一天由于没有经验,工做中出现了屡次失误,飞机酱只造好了一竹节,路人丙好一些,造好了两节。因此他们的竹子是这样的:
在他们本身的版本库里,都在 work_01.txt
文件里记录了本身的工做,并保存到了版本库:
下班后,飞机酱把记录同步到了公共电脑上,而后开心的回家了。他是这么操做的:
git push origin master:master
复制代码
origin是远程版本库名称,虽然咱们没有配置它,但它默认就是origin,第一个master是飞机酱电脑上使用的分支,第二个master是远程版本库的分支。(飞机酱可能提早补课了,命令写的很全)
接下来到路人丙同步了,他也使用了相似的操做,可是却发生了意外:
同样的操做,结果却迥异,路人丙的心里必定是凌乱的,但他还认识几个单词,大体明白了提示的意思。原来飞机酱在他前面进行了push操做,致使他这里文件不够新,git就拒绝了他。因此他按照提示中 (e.g., 'git pull ...') before pushing again.
又试了一次。结果在git pull
时再次发生意外:
conflict的意思是冲突,conflict出如今对同一个文件的同一行进行了不一样修改的时候。咱们记得飞机酱和路人丙都建立了 work_01.txt
文件并写入了内容,因此git合并时发现第一行都写入了内容,就无法决定让谁的修改在前,就会要求咱们手动解决。如今咱们打开路人丙的 work_01.txt
,看看它的内容:
能够看到,两人输入的内容用 <<<<HEAD...====...>>>>{commitId}
这样的格式包裹起来了。前面是路人丙的内容,后边是飞机酱的内容。想要合并到远程版本库,就必定要先解决掉这个问题,不然老板看到就要发火了~因此路人丙改了它,并把飞机酱的内容放在了下边(老板确定会先看到前面的内容):
由于又发生了修改,因此内容如今还在工做区,就须要再次把它加到暂存区,再入库。一通操做后,总算合并成功了:
如今让咱们更新一下当前模型的状态,路人丙为了解决冲突增长了一个commit,这时候公共电脑的log看起来是这样的:
是否是理所固然的认为竹子长这样呢:
看起来没有问题,并且git log显示也是如此。可是这里有个问题,你们都是今天干完的活,都要把本身的竹子安到明星产品上,凭什么你先放?路人丙的工做又快又好,难道不是更有资格先放吗?路人丙认为把两我的的竹子拧在一块儿,最后再用灰色的那节整合在一块儿最公平了,老板一眼就明白咱们是同时完成的工做:
看起来很奇怪吧?好好的竹子由于互相争抢鼓了一个包,看起来十分不美观(话说这样老板不会生气吗?仍是可能会吸引来奇怪的旅客?)。
实际上git pull
操做是由两个命令组成的,第一个是git fetch
,表示把远端版本库的内容拉取到本地,第二步才是执行git merge
操做把拉取下来的新内容和咱们本身的内容合并在一块儿。既然都想占第一个位置,干脆git帮你整合一下,而后用一个新的commit代替就行了。要想证实事实上的确如此,使用上面的 git log
是不行的,你要在后边加上 --pretty=raw
:
git log --pretty=raw
复制代码
commit较多,但最后一条显示不全的是老板的提交,并不影响咱们分析它。咱们主要看每条commit的parent字段,能够发现最上方的那一条有两个parent,分别指向了飞机酱的第一条和路人丙的第二条,而被指向的这两条数据的parent都是老板的那次提交,这和咱们预期的彻底一致。
解决了问题,路人丙很开心。关掉电脑,背上背包,正准备回去美餐一顿,老板却过来视察工做了,先是夸了一顿路人丙工做努力,转眼看到造好的竹子,怒发冲冠,责令路人丙立刻把问题解决掉!
这问题难不倒他,既然能把竹子合起来,再拆开岂不是至关容易,因而他拿起那台公共电脑,输入了如下命令:
// reset --merge 重置merge,后边跟上以前的commitId,就能够回到过去
git reset --merge 2b0218d74edbea391c8b7853580c99164af8d32a
复制代码
再看看日志,完蛋,纸飞机的记录不见了,被路人丙的记录取而代之!
这下可怎么好,明天飞机酱来了很差交代呀,并且把别人的工做整丢也不符合道义,有后悔药吃就行了。这时候一边的老板看不下去了,拿起电脑飞快的敲了一条指令:
git reset --hard HEAD@{1}
复制代码
而后把电脑交回路人丙,丢下一句:好了,后悔药吃下去了。(路人丙:我@#$*&^^,发生了什么事?)再一看,果真又回到刚才的状态了,原来老板是大神呀,惋惜太冷漠,苦事还得我来作。
检查一下刚才的 git reset xxx
,后边跟了路人丙的commitId,结果就剩下了他的工做,这里一共两条路,指到飞机酱那边是否是就行了呢,再试一次,反正有老板在随时能吃后悔药(话说这么大胆的么)。
git reset --merge ba65055dab9700d0e814719bbf23713c163ade76
复制代码
果真是,我路人丙就是个天才,哈哈哈!
等等,这不是飞机酱离开时的状态吗,刚刚的路行不通,我该怎么办好呢?回想一下刚恰好像是由于冲突才多了一个commit,那若是我不让它冲突岂不就行了?这工做记录都写一个文件里看着也有些乱,我再换个文件也许就行了呢。路人丙用求助的眼神看着老板,意思是但愿老板能把他本身的工做记录删一下,他已经有了好的idea想再试一下。接下来又是老板炫技的时间,不过此次是在路人丙的电脑上:
git log
// 重置到老板本身的commitId
git reset --hard 420e8fe77141a4f6c9cfed2518c65b04d21bcec0
复制代码
因而路人丙的工做全不见了,一切仿佛回到了刚开始。
此次路人丙给文件起了一个不同的名字 lurenbing_01.txt
,又把工做记录写了进去,再次进行提交:
果真仍是须要先pull,再pull一下看看结果:
此次确实没有了冲突,可是弹出了一个框,内容说明这是一次merge,先无论它,直接下一步,再看git log --pretty=raw
:
为何,都不在一块儿了仍是这样,路人丙都要崩溃了。必定是刚刚pull的问题,我要是先pull,再写个人工做记录是否是就行了。再次让老板帮忙重置后,路人丙先pull了一次:
这下飞机酱的工做记录都到我这了,我再写应该没问题了吧,一顿操做下来,这一次顺利的合并了进去,既没有冲突,也没有弹出框。到公共电脑上一看,很好很顺利:
时间太晚,工做也马马虎虎算搞定了,老板打算放过路人丙,但临走前问了一个令路人丙瞬间凌乱的问题:若是每次都要先pull再开始写你本身的commit,那你天天都要等飞机酱下班后才开始工做?(路人丙:那我天天岂不是比飞机酱多工做一倍的时间?明天我要找他研究研究,这实在不是人干的事啊~)
最后更新一下咱们的模型,能够看到路人丙的竹节最后仍是放在了上边,因此干的又快又好有什么用呢,快要快在关键时刻。
第一天的工做就到此结束了,能够看到,只要路人丙但愿两我的的工做可以平等的占据第一的位置,就必定会造成鼓包,经过一个新竹节把这两条路归一。而若是他自愿把工做放在后边,一切就很顺畅,有时候真的是退一步海阔天空啊。
我是飞机酱,若是您喜欢个人文章,能够关注个人微信公众号: 大大纸飞机
或者扫描下方二维码直接添加:
您也能够关注个人github:github.com/LtLei/artic…
编程之路,道阻且长。惟,路漫漫其修远兮,吾将上下而求索。