天天看点

Git教程4——Git标签管理

在版本回退里已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

分支的作用很强大,假设你准备开发一个新功能,但是需要两周才能完成,第一周写了部分代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。现在有了分支,你可以创建一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全又不影响别人工作。

分支创建与切换

Git 是怎么创建新分支的呢? 很简单,它只是为你创建了一个可以移动的新的指针。一开始的时候,

master

分支是一条线,Git用

master

指向最新的提交,再用

HEAD

指向

master

,就能确定当前分支,以及当前分支的提交点。每次提交,

master

分支都会向前移动一步,这样,随着你不断提交,

master

分支的线也越来越长。首先,我们来创建dev分支并切换到dev分支上

$ git checkout -b dev

git checkout 命令加上 –b参数表示创建并切换,相当于如下2条命令:

$ git branch dev           
$ git checkout dev           

也就是说,创建分支的命令是

git branch,

这会在当前所在的提交对象上创建一个指针。而要切换到一个已存在的分支,你需要使用 

git checkout

 命令。请牢记:当你切换分支的时候,Git 会重置你的工作目录,使其看起来像回到了你在那个分支上最后一次提交的样子。 Git 会自动添加、删除、修改文件以确保此时你的工作目录和这个分支最后一次提交时的样子一模一样。

你可以简单地使用 

git log

 命令查看各个分支当前所指的对象。 提供这一功能的参数是 

--decorate

可以看到当前 “master” 和 “testdevng” 分支均指向校验和以 

9b1105c

 开头的提交对象。

查看分支

然后,用

git branch

命令查看当前分支(加上-a参数可以查看远程分支,远程分支会用红色表示出来(如果你开了颜色支持的话)):

$ git branch           

git branch查看分支,会列出所有的分支,当前分支前面会添加一个星号。然后,我们就可以在

dev

分支上正常提交,比如对test.txt做个修改,加上一行“777777”,然后提交:

现在,

dev

分支的工作完成,我们就可以切换回

master

分支:

切换回

master

分支后,再查看一个test.txt文件,刚才添加的内容不见了!因为那个提交是在

dev

分支上,而

master

分支此刻的提交点并没有变:

现在我们可以把dev分支上的内容合并到分支master上了,可以在master分支上,使用如下命令 git merge dev :

$ git merge dev           

git merge

命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和

dev

分支的最新提交是完全一样的。

注意到上面的

Fast-forward

信息,Git告诉我们,这次合并是“快进模式”,也就是直接把

master

dev

的当前提交,所以合并速度非常快。

当然,也不是每次合并都能

Fast-forward

,我们后面会讲其他方式的合并。

删除分支

合并完成后,就可以放心地删除

dev

分支了(在Git v1.7.0

之后,删除远程分支可以使用git push origin --delete <branchName>,否则,可以使用这种语法,推送一个空分支到远程分支,其实就相当于删除远程分支:git push origin :<branchName>):

$ git branch -d dev           

删除后,查看

branch

,就只剩下

master

分支了:

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在

master

分支上工作效果是一样的,但过程更安全。

解决冲突

Git虽然很智能了,但毕竟不是人,在合并分支的时候难免会遇到各种问题,这些问题还是需要我们自己解决。现在我们再建一个分支dev1,

在test.txt添加一行内容“888888”,然后提交,如下所示:

现在切换到master分支上,也在test.txt最后一行添加内容,内容为"999999",如下所示:

Git还会自动提示我们当前

master

分支比远程的

master

分支要超前1个提交,在master上提交:

master

分支和

dev1

分支各自都分别有新的提交。这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突:

Git告诉我们,test.txt文件存在冲突,必须手动解决冲突后再提交。

git status

也可以告诉我们冲突的文件:

可以直接查看readme.txt的内容:

Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,其中<<<HEAD是指主分支修改的内容,>>>>>dev1 是指dev1上修改的内容,打开test.txt文件,修改下如下后保存:

现在已经是我们想要的效果了,提交:

用带参数的

git log

也可以看到分支的合并情况:

最后,删除

dev1

分支管理

通常合并分支时,Git会用“

Fast forward”

模式,但这种模式下,删除分支会丢掉分支信息。如果强制禁用“

Fast forward"

模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。现在我们来使用带参数 –no-ff来禁用”Fast forward”模式。

首先,仍然创建并切换

dev

修改test.txt文件,并提交一个新的commit:

现在切换回

master,合并

dev

分支,使用“--

no-ff”

参数。因为本次合并要创建一个新的commit,所以加上

-m

参数,把commit描述写进去。

合并后,我们用git log看看分支历史:

分支策略:首先master主分支应该是非常稳定的,也就是用来发布新版本,一般情况下不允许在上面干活,干活一般情况下在新建的dev分支上干活,也就是说,

dev

分支是不稳定的,到某个时候,比如1.0版本发布时,再把

dev

分支合并到

master

上,在

master

上发布1.0版本。你和你的小伙伴们每个人都在

dev

分支上干活,每个人都有自己的分支,时不时地往

dev

分支上合并就可以了。

现在已经创建、合并、删除了一些分支,让我们看看一些常用的分支管理工具。

git branch

 命令不只是可以创建与删除分支。 如果不加任何参数运行它,会得到当前所有分支的一个列表:

注意 master 分支前的 * 字符:它代表现在检出的那一个分支(也就是说,当前 HEAD 指针所指向的分支)。

这意味着如果在这时候提交,master 分支将会随着新的工作向前移动。 如果需要查看每一个分支的最后一次提交,可以运行 git branch -v 命令:

--merged 与 --no-merged 这两个有用的选项可以过滤这个列表中已经合并或尚未合并到当前分支的分支。 如果要查看哪些分支已经合并到当前分支,可以运行 git branch --merged:

因为之前已经合并了 dev 分支,所以现在看到它在列表中。 在这个列表中分支名字前没有 * 号的分支通常可以使用 git branch -d 删除掉——你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。

查看所有包含未合并工作的分支,可以运行 git branch --no-merged命令。

Bug分支

开发过程中,遇到bug是难免的,有了bug就需要修复,在Git中,分支是很强大的,每个bug都可以通过一个临时分支来修复,修复完成后,合并分支,然后将临时的分支删除掉。假设我在开发中接到一个404 bug,我们可以创建一个404分支来修复它,但是,当前的dev分支上的工作还没有提交。不是我不想提交,而是工作没有完成,我们还无法提交,怎么办呢?还好,Git还提供了一个stash功能,可以把当前工作现场 ”隐藏起来”,等以后恢复现场后继续工作

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支issue-404,现在修复bug,然后提交:

修复完成后,切换到master分支,并完成合并,最后删除issue-404分支:

现在,我们可以回到dev分支上了

工作区是干净的,那么我们工作现场去哪里呢?我们可以使用命令 git stash list来查看下:

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,可以使用如下2个方法:

    1. git stash apply恢复,恢复后,stash内容并不删除,你需要使用命令git stash drop来删除。

    2. 另一种方式是使用git stash pop,恢复的同时把stash内容也删除了。

现在再用git stash list查看,就看不到任何stash内容了

多人协作

当你从远程仓库克隆时,实际上Git自动把本地的

master

分支和远程的

master

分支对应起来了,并且,远程仓库的默认名称是

origin

要查看远程库的信息 使用 git remote,使用使用 git remote –v查看远程库的详细信息

上面显示了可以抓取和推送的

origin

的地址。如果没有推送权限,就看不到push的地址。

推送分支

就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,使用命令git

push origin master,这样,Git就会把该分支推送到远程库对应的远程分支上,如果要推送其他分支,比如

dev

,就改成git

push origin dev

但并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?

  • master

    分支是主分支,因此要时刻与远程同步;
  • dev

    分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
  • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;

抓取分支

多人协作时,大家都会往master分支上推送各自的修改。

首先我的mygit目录的dev分支也要推送到远程去,如下:

现在我们可以模拟另外一个同事,可以在另一台电脑上(注意要把SSH key添加到github上)或者同一台电脑上另外一个目录克隆,新建一个目录名字叫mygit2,克隆远程的库到本地来

现在目录下生成如下所示:

当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的

master

分支

现在我们的小伙伴要在dev分支上做开发,就必须把远程的origin的dev分支克隆到本地来,于是可以使用命令创建本地dev分支:git checkout  –b dev origin/dev

现在小伙伴们就可以在dev分支上做开发了,开发完成后把dev分支推送到远程库时。

小伙伴已经向

origin/dev

分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:

推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用

git pull

把最新的提交从

origin/dev

抓下来,然后,在本地合并,解决冲突,再推送:

git pull

也失败了,原因是没有指定本地

dev

分支与远程

origin/dev

分支的链接,根据提示,设置

dev

origin/dev

的链接:

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的 解决冲突完全一样。解决后,提交,再push,先来看下test.txt内容

手动解决完了再提交,再push到远程库里面去

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用

    git push origin branch-name

    推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更早,需要先用

    git pull

    试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用

    git push origin branch-name

    推送就能成功!

如果

git pull

提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令

git branch --set-upstream branch-name origin/branch-name

这就是多人协作的工作模式,一旦熟悉了,就非常简单。