编辑推荐: |
本文主要介绍git的基本工作原理,以及如何运用git到我们的实际开发中,希望通过本文的学习大家对git有个全面的认识和学习。
本文来自于SegmentFault,由火龙果软件Alice编辑、推荐。 |
|
版本库
先说为什么要使用版本控制吧,我们在写文档或者是写程序的过程中,可能会在在写的时候有不同的想法,因此要对前一个修改,但是我们还需要保证前一个的存在,因此我们可能会采取的方式是将前一个文件编号然后保存下来,但是当我们的文件多了的时候,这将变得很繁琐了,因此出现了一些版本管理控制工具,这个工具能够像是一个日志记录工具,记录下来我们的每一次变动,当我们出现了问题的时候,我们可以会退到历史版本中。传统的一些版本控制工具有SVN,这些传统的工具的一大特点是1对N,也就是一个版本库对应这多个的开发者。
如下图
对于项目的变更记录全部在一个集中的服务器上,然后程序员各自向其进行提交,程序员的本地只有一个本地工作目录,也就是项目的最新版本,而我们在和服务器没有连接的情况下是无法查看历史版本的。而git是一种分布式的版本库,每个人的本地都有本地工作目录和自己的版本库,在修改了代码之后我们将其commit到我们自己的版本库中,然后通过push到服务器上,其它程序员就可以获得我们的修改,同时也会更新自己本地的版本库。版本库在本地为.git后缀的文件。
Git工作方式
工作目录树
工作目录树是.git文件所在的父目录,该目录会被作为工作目录树。创建的方式通过clone和git的初始化命令。
代码修改文件同步
当多个程序员在对自己的代码进行修改之后,每次修改在提交的时候,也就是commit的时候被记录下来,每次提交都会有一个新的版本产生,为了方便以后历史版本的回退需要我们对这些信息进行记录,也就是一个提交留言,通过一个简短的留言记录下来我们的改动,方便在以后的时候查找代码中的问题。当我们在本地修改好了之后,我们需要让别人来同步我们的修改,因此需要我们将自己的本地提交到上游版本库,在push到上游服务器的时候,我们需要首先将服务器上的版本库的内容fetch到本地,然后进行merge,因为这个操作是先后的两步操作,因此git又产生了一个新的命令pull是拉回合并。这个时候你可能要问的一个问题是如果两个人同时修改了同一个文件怎么办呢?是不是应该采取,文件锁的机制,当某些人在改的时候,其它人就不可以修改了,而git则认为这种情况是较少的,所以没有采取锁的机制,只是在我们提交的时候,拉回本地的版本,git会进行自动合并,如果有冲突,git也会提供相应的解决方案。
Git对文件的跟踪
对于一些传统的项目管理工具是以文件为单位的,当版本变化较大的时候,需要我们做较大的变动,因此我们需要很大的一些版本库的记录空间,但是git是对其文件中的内容进行控制,跟踪文件代码行和字符。这样可以很好地帮助我们其中函数,类在文件中的移动。
分支
前面所讲的我们都是在主分支上进行的,我们的修改会被提交上去,系统上的也就是我们当前的修改版本,但是有些时候,有些开发我们无法保证其正确性,因此我们可能在开发的时候,进行一些试验性的修改,这个时候,我们不能够将其在放到我们的主分支了,因为我们无法保证其正确性,而提交被他人使用后,将造成很大错误,因此我们可以在本地在开一个分支,然后在子分支上进行修改,改动后,当正确后,再将其合并到我们主分支再提交,在进行试验性的修改的时候,还不改变原项目的结构。
合并
对于不同的分支进行合并的时候,git会对不同的地方进行自动合并,不能合并的时候会提示合并冲突,对于冲突的处理,git也提供了一些解决工具。
Git使用
了解了git的基本工作原理,接下来需要要做的事运用git到我们的实际开发中了,运用git的过程也就是熟悉其命令,然后按照其命令来解决项目版本控制中的一些问题。这里通过在github上建立一个项目开始,项目呢就是LintCode的题解。
(1)来github上创建一个repository(既然你在看这篇文章了,那这个也就不需要讲了)
(2)在本地初始化一个仓库,与其同名,也可以将github上的库clone下来,两种方式,随意选择。这里采取第一种。第二种较为简单。
(3)项目建好了,首先要写的就是README,要让别人知道我们的项目是要干什么的,这里我们在其目录下创建一个md格式的README来描述我们的项目
(4)文件创建好了,是不是就结束了,加入到版本库了呢?不是的,本地是有三个存放文件的地方,大致结构如下图
这个时候比较让人摸不到头脑的是,我直接提交不就好了,为什么要先放到暂缓区,这不是让我们的操作更麻烦了吗?暂缓区在这里起到一个什么作用呢?对于我们新添加文件或者变更的文件,有的时候我们并不想提交到版本库,这个时候,它的作用发生了,可以通过add进行选择,将一部分加入到暂缓区,然后不想提交的就不做变更,暂缓区起到了一个筛选的作用。下面的讲解思路是按照每一步的操作进行深入的讲解,包括对于给命令的具体的使用和其功能。
add
通过git add -i 我们可以启动交互命令提示符。
先看下。
接下来从这几个命令逐个讲起。通过名字,我们便可理解其意思,具体能够起到的功能有哪些呢?先看下status,没有任何显示,因为我们现在还没有添加任何文件到暂缓区之中,或者说这些文件是没有被git追踪的,只有通过add命令之后,在以后的操作中才会对其进行追踪,只要被添加过一次便可以了,而不需要多次添加,因为我们还未添加过所以当前没有文件被追踪,通过add
untracked来添加一个文件。
通过该命令可以找到我们当前目录下未被追踪的文件,然后可以将其添加到路径。现在再看下其status。
现在对其进行修改,之后再查看其状态。现在明显发生了变化,然后需要我们进行更新,然后提交到暂缓区,显而易见需要通过update来更新。
然后对其进行更新。
当我们更新到暂缓区后,我们发现了其中的问题不想在继续更新了怎么办?需要通过revert,其作用方式和update相反,操作不难理解。
这个时候将其移除了我们的暂缓区,我们也就追踪不到这个文件了。现在还patch和diff的命令没有演示,现在再将其加入到我们的目录中,然后来演示这两个命令的作用。
我们可以看到我们的修改变化的位置,然后来确定我们对修改部分如何做处理,输入y表示接受修改,输入n表示忽略修改,输入a或者d,表示添加修改部分或者是舍弃修改部分。记不住,我们可以通过?来进行提示。
到这里,对于将文件提交到暂缓区的内容,我们就结束了,接下来是讲我们的文件提交到版本库中。这个时候会不会有个疑问,当我们提交一个文件到版本库之后,是不是会有三个文件了呢?这个一会将会解释。
(5)提交修改
现在我们需要将我们所做的修改提交到版本库,版本库需要记录我们的每一次变更,对于变更要记录下些什么呢?谁提交的?提交修改了些什么?提交时间?同时要对每一次的提交要有一个唯一的标示。现在提交一次看下,注意每次的提交我们都要写一个提交留言。
提交到版本库之后,git使用SHA-1哈希算法生成一个40为的哈希码,显示的时候只是显示了7位,如果要查看全部可通过git
log
此时我们可以看懂具体的提交信息了。通过git log -1,我们可以对输出的条目进行限制。
commit有三种方式,常用的一种方式是将暂缓区中的内容提交到版本库,然后还有两种方式是将目录树中的即使是未被git追踪的也加入到版本库中。命令分别为
git commit -m
git commit -a
git commit -m fileName
三种提交方式分别为提交暂存区中的内容,然后是提交目录树中全部的内容,然后是制定相应的文件进行提交也是从工作目录树中。
(6)查看文件状态
使用命令:git status
通过git status,我们可以查看暂缓区中那些文件未被提交,那些文件在目录树中未加到暂缓区.
(7)查看文件改动
使用命令:git diff
通过这个命令在默认的情况下查看的是工作目录树和暂存区的差别,而我们可以通过参数的调整来查看暂缓区和版本库的差别。
git diff --cached
git diff --head
通过该命令我们可以查看缓存区和我们的版本库中的差别。通过添加一个head参数,我们可以查看未加入到缓存区中的版本库中的进行对比。
(8)文件操作
我们的文件中有时候,我们会有移动和修改文件或者是重命名文件的需求,这里git提供了便捷的管理方式。下面对文件操作的命令进行一下介绍。
git mv
通过git mv我们可以实现将我们的文件进行重命名,重命名之后,我们还需要将其提交到版本库中,因此在使用该命令之后,我们还需要将其提交到主版本库中。
(9)分支处理
分支可以说是git的精髓之处了,但是我们平日里似乎又很少用到,因为我们没有合作,大多是自己写个小项目,因此这种东西似乎是用大不大到的,前面也讲了为什么要用分支,还有使用分支的好处,可以使得项目并行演进。一个团队在主分支进行项目的开发,分支上进行写重构,或者处理一些bug,接下来,我们将针对分支进行进一步的详细的介绍和学习。
介绍第一个命令:git branch
通过这个命令,我们可以查看我们当前分支的名称。
那如果我们要修改这个分支的名称要如何修改
修改分支名称
git branch -m master mymaster
创建新的分支
git branch newmaster
检出分支
git checkout newmaster
创建和检出分支
git checkout -b newmaster master
分支合并间修改
直接合并 git merge newmaster
压合合并 git merge --squash newmaster
拣选合并 git cherry-pick 3221d76f
删除分支
git branch -d newmaster
git branch -D newmaster
创建分支的时候,如果不指定一个分支,则会默认的在我们的当前分支上,在其末梢创建出一个分支来,我们可以通过git
checkout 来进行分支的切换和检出,合并分支有三种方式,直接合并会将所有的历史记录合并进来,通过压合合并,会将所有的记录作为一次提交进行提交,通过拣选合并,我们可以挑选自己合适的部分来有所选择的进行提交。
(10)git 历史记录查询
普通查询
git log
git log newmaster+hashcode
git log -1(查看一个)
指定范围查询
git log --since="5 hours"
git log --before="5 hours"
git log hashcode1...hashcode2(两个版本之间的所有版本)
git log hashcode...HEAD(指定版本到当前版本)
git log HEAD^^ git log HEAD~2(^表示父节点,~2表示其上面父辈的个数)
git diff hashcode(查看版本之间的差别)
(11)远程版本库协作
网络协议:git/http/https/ssh
git协议是无加密匿名,不适合在项目协作中进行使用,可用于只可以看不可以更改的项目,ssh是较为安全的,提交用户需要检测每一个用户的证书。大多数
Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。在我们的本地生成一个公钥,然后在服务器中填写该公钥,作为对我们的鉴别。
下面是和远程版本库的几个交互命令
git push
推入改动
git pull
将远程版本库拉回并合并
git remote add name mastername ://url
手动添加一个远程版本库
git remote rm name
删除一个远程版本库
新学了一些
git checkout -- file
将文件回滚到最后一次添加到暂缓区的状态。
git reset HEAD file
将暂缓区或者是最新的提交回滚
在我们本地的文件被删除之后,git远程还会继续追踪,需要我们通过git rm将远程的删除,本地的如果误删除了,通过git
reset将其进行恢复。
下面讲一下自己在公司使用Git的一些问题。
项目在远程开启了三个分支,一个master分支,一个preview分支,还有一个dev分支,三个分支分别为一个是上线使用分支,一个是上线前测试使用的分支,一个是开发使用的分支,我们可以拉下来dev分支,通过gitclone,由于公司项目一般为私密项目,所以需要我们进行验证,这个时候在我们要clone的地址的后面加上我们的用户名作为前缀,然后通过密码作为验证即可将其从线上拉下来,然后我们可以对其进行修改,每次一个功能的完成,作为一次提交,然后push到线上,这个时候很容易出现冲突,或者是线上的版本要比我们线下的版本要新了,所以我们需要先将线上的最新版本fetch下来,然后和我们本地的进行合并,这个时候可能会出现一些冲突,我们需要处理这些冲突,处理完成之后,将其重新进行add到暂缓区,然后提交到本地版本库,然后将其push到远程分支,这个时候我们就实现对于远程版本的一个更新。
坑先挖到这里,对于git的高阶功能,以后用到了再继续挖。后面将开展Java代码优化和小坑总结系列和Android进阶系列,欢迎各位一起交流讨论。
实战积累和坑
本地创建分支,然后推到远程分支
git checkout -b newbranch
git push origin newbranch:newbranch
第二个推送命令,需要的是三个参数,而不是5个。push + origin + (newbranch:newbranch)
本地版本回滚
git reset --hard commit id
soft – 缓存区和工作目录都不会被改变
mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
hard – 缓存区和工作目录都同步到你指定的提交
|