之前在局域网搭建了Git环境,觉得Git的工作方式非常有效,在这里也做一个总结。
希望这篇文件也能帮助到开始学习Git的朋友,此文只介绍Git的相关知识,对于git的使用经验留在以后介绍。
这里暂时不考虑分支的命令,将在下一节中具体介绍。下面的命令按照一般的操作流程的顺序一一介绍。
命令 |
用法 |
作用 |
clone |
git clone url repname |
克隆一个git仓库 |
init |
git init |
初始化一个git仓库 |
status |
git status |
查看当前工作目录下的状态,一般会显示文件的变化情况 |
add |
git add filename |
将当前工作目录下的文件添加到stage(稍后会解释) |
commit |
git commit - m “msg” |
将当前stage中的内容存在一个新的commit中 |
push |
git push origin master |
将本地ref更新到远程服务端 |
pull |
git pull |
将远程仓库的变化合并到本地 |
上面的这些命令,接下来通过情景的方式来介绍。
开发人员Jim进入项目开发团队,首先从Git远程库clone项目下来。Jim打开Bash或者其他git界面工具,Jim开始输入下面的命令行并执行。
(这个例子中使用HTTP协议,局域网中安装了gitstack)
通过这个clone命令将远程端的prjx项目拷贝到了本地。这个时候出现了Prjx这个文件夹,在Prjx中会有有一个.git的文件夹(.git将在后面介绍Git内部原理的时候再进行介绍)。
好了,Jim已经有了当前远程端最新的项目。Jim开始开发,添加了一个非常不错的功能,由此引入了xxx.cpp文件。这个时候Jim打算将这个功能并入远程端,Jim使用git status查看了一下当前工作目录下的状态。
然后使用git add xxx.cpp,将xxx.cpp文件加入了stage中。
Jim随后又使用git commit –m “new feature2.1”,将当前stage中的内容放入一个新的commit中。
Jim检测无误之后,决定将这一切提交到服务器上去。于是Jim便使用了git push origin master。这样一套流程就走完了。
第二天,Jim开始进行工作前,首先使用git pull将服务端最新的项目更新下来。
……
此图便是使用git本地文件的变化图(此图来自“pro git”)。
我们在工作目录下行添加一个文件A,这个新加的文件处于一个untracked状态。如果此时我们使用git add 命令,文件A将直接进入stage。
但我们再去修改文件A后,文件A的这个变化,并未进入stage,在stage中的只是修改前的文件A。我们要将最新的文件A加入stage,还是使用git add。
使用git commit之后,stage中的内容被提交到新的commit中。
Git的分支概念是其中一个最为有用的功能。首先简单介绍与分支相关的几个命令。
命令 |
用法 |
作用 |
branch |
git branch |
查看当前所有的分支 |
branch |
git branch branchname |
创建一个新的分支 |
checkout |
git checkout branchname |
切换到指定分支 |
merge |
git merge xxx |
将分支xxx合并到当前分支 |
rebase |
git merge br_a br_b |
衍合操作 |
此图是经过四次commit的master分支图。每一次commit,git会将master指针移动到最新的commit结点,比如当前的master处在C3。
gitbranch br_1
当我们创建一个新的分支br_1时,git只是生成一个类似于master的新指针,并指向当前master指向的commit结点。由此可以发现其实对于git来说创建一个分支的开销非常小。
git内部会维护一个HEAD指针,这个指针存放的便是当前的分支指针,可以这里理解HEAD是当前分支指针的别名。
git checkout br_1,HEAD=br_1
git checkout master ,HEAD = master
接下来是我们这一节的重点内容。
(1)首先我们切换到br_1之后,持续开发后又提交了两次。
gitcheckout br_1
gitcommit –m “C4”
gitcommit –m “C5”
经过这些操作,分支流图就会变成上图所示情况,br_1指向C5,master仍旧停留在C3。
(2)经过测试,我们发现C4和C5是稳定有效的功能提交。我们打算将这两个提交合并到master中去。所以我们先切换到master。
gitcheckout master
gitmerge br_1
我们可以发现,这个时候的合并只是简单的将master指针移动到br_1处。
接下来看一下比较复杂的合并。
(3)我们创建新分支br_2,在br_2分支流上提交C6,在br_1分支流上提交C7。
gitbranch br_2
gitcheckout br_2
gitcommit –m ”C6”
gitcheckout br_1
gitcommit –m “C7”
执行完这些操作后,结果变成上图所示。
(4)我们开始将br_1合并到master
gitcheckout master
gitmerge br_1
(5)接着再将br_2合并到master。
gitmerge br_2
在C7处的master合并在C6处的br_2。结果就会变成上图所示。
我们先来看实例,首先我们回到上一节的第四个步骤“(4)我们开始将br_1合并到master”
当前我们的分支流图是上图所示。
现在我们合并br_2 和 master,使用衍合操作试试,效果会如何。
这里git的做法是,br_2将当前的C6做一个补丁C6’直接打到master分支流上。最终结果就如上图所示。
衍合会放弃了当前的分支。所以在使用的时候要格外小心,比如分支br_2,已经提交到远程服务器,就不要使用衍合操作了。
对于git的内部原理,我们可以打开.git文件夹。
上面的文件和文件夹,我需要特别关注refs、objects和HEAD。
HEAD就是第二节中HEAD指针。
objects存放的便是git的文件快照。
refs存放的是git的分支指针。
我们还是通过实例来介绍git的文件快照机制。
(1)我们在一个空的git本地仓库中,添加文件1.txt,在1.txt写入“HelloWorld”,保存后add到stage中。
gitadd 1.txt
打开.git/objects文件夹,发现出现了一个文件夹5e,而5e内部存放了一个文件1c309dae7f45e0f39b1bf3ac3cd9db12e7d689。
其实git对于一个文件的做法,便是将文件变化内容做特殊的hash(sha1)处理之后,截取头两个字母做文件夹名称,后38位做文件名称存放在objects文件夹中。上述的文件1.txt对应的文件快照名称是
5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689。
我们使用cat-file 命令查看一下这个文件快照里面的内容是什么。
gitcat-file –p 5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689
输出内容便是Hello World,其实就是1.txt。
(2)修改1.txt,添加字符“Test Git”,再次add。按照上述方式,查看快照文件ff75b86b8ab9128431a56785d1f25ddf9965bf47。
发现便是新的1.txt。
git对于文件便是如上操作存放起来的。
(1)在commit之前我们先来看一下ref/head,发现里面什么都没有。
承接上面的操作,我们直接commit
gitcommit –m “C1”
再去看ref/head发现多了一个master文件。打开此文件后发现里面存放的是b87f30e98b7b31b48d281987b1fdf30b9b13ddbc。去object查找,发现它的存放方式和文件快照的存放是一样的。
(2)再使用cat-file
gitcat-file -p b87f30e98b7b31b48d281987b1fdf30b9b13ddbc
发现这个文件和之前的文件快照不太一样。里面存放的是一个tree。
(3)查看tree
发现里面存放的是一个blob,而且是我们之前创建的1.txt,它对应的快照名称也是ff75b86b8ab9128431a56785d1f25ddf9965bf47。
为了更加形象展现git文件树,我们这边在做一些小操作。
(4)添加文件2.txt 并提交
git add 2.txt
git commit –m “C2”
我们来看一下当前的文件树。
master变成了a5791eb37be360b030e013fee532ffc276f32787。
查看tree
tree adc1c0e82bbc6ce4dc116d0c8dd52a7616432e7d下有两个blob节点,就是当前的两个文件。
现在我们用图来展示一下
图3.1
我们看到,commit2处也就是master指针指向的地方是一个tree(adc1c0)该树有两个blob节点,分别是我们的1.txt和2.txt文件。这两个文件通过各自的40位的文件快照号就能具体找到这两个文件的内容。
我们再来回忆一下,分支的内容。
(1)在上面的基础上,我么再创建一个新分支br_1
git branch br_1
图3.2
在创建分支对于git来说再简单不过,就是添加了一个新指针br_1,并指向当前节点commit2。我们在看一下ref/head文件夹,发现多了一个文件br_1。打开它和master对比一下。
发现这两个文件内容是一模一样的。
(2)切换分支
git checkout br_1
图3.3
git将HEAD指向br_1,这样就完成了分支的切换。
我们打开HEAD文件,发现里面你内容由ref: refs/heads/master变成了ref: refs/heads/br_1。
git的介绍先到这里。
此文如有纰漏,请多多包涵。
之后会带来一些关于git使用上的一些经验介绍。
原文地址:http://blog.csdn.net/stan1989/article/details/42779597