git 总结

git 阶段整理总结

内容:git服务器阶段整理总结

日期:20140623

作者:王超群

备注:内容来源 pro_git_中文版本.pdf

 

git管理下文件的三种状态

接下来要讲的概念非常重要。对于任何一个文件,在 Git 内都只有三种状态:

已提交(committed),已修改(modified)和已暂存(staged)。

已提交表示该文件已经被安全地保存在本地数据库中了;

已修改表示修改了某个文件,但还没有提交保存;

已暂存表示把已修改的文件放在下次提交时要保存的清单中。

由此我们看到 Git 管理项目时,文件流转的三个工作区域:Git 本地数据目录,工作目录以及暂存区域。

 

每个项目都有一个 git 目录,它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从 git 目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。

所谓的暂存区域只不过是个简单的文件,一般都放在 git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

 

基本的 Git 工作流程如下所示:

1. 在工作目录中修改某些文件。

2. 对这些修改了的文件作快照,并保存到暂存区域。

3. 提交更新,将保存在暂存区域的文件快照转储到 git 目录中。

所以,我们可以从文件所处的位置来判断状态:如果是 git 目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。我们会进一步了解个中细节,并学会如何善用这些状态,以及如何跳过暂存环节。

 

git中获取帮助

$ git help <verb>

$ git <verb> --help

比如,要学习 config 命令可以怎么用,运行:

$ git help config

 

作者author和提交者committer的区别

Author是实际做出修改者

Committer是实际的提交者

 

首次运行git服务器的配置

在 linux系统上

• /etc/gitconfig文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。

• ~/.gitconfig文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。

• 当前项目的 git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以.git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。

在 Windows 系统上,Git 会找寻用户主目录下的 .gitconfig 文件。主目录即 $HOME 变量指定的目录,一般都是 C:\Documents and Settings\$USER。此外,Git 还会尝试找寻 /etc/gitconfig 文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。

例如:

$ git config --global user.name "John Doe"

$ git config --global user.email johndoe@example.com

$ git config --global core.editor emacs

$ git config --global merge.tool vimdiff

$ git config --list

$ git config user.name

 

对已有的项目进行git管理

要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录,执行:

$ git init

初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。不过目前,仅仅是按照既有的结构框架初始化好了里边所有的文件和目录,但我们还没有开始跟踪管理项目中的任何一个文件。如果当前目录下有几个文件想要纳入版本控制,需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交:

 

从已有的仓库clone一份镜像出来

$ git  clone  git://github.com/schacon/grit.git  mygrit

现在我们手上已经有了一个真实项目的 Git 仓库,并从这个仓库中取出了所有文件的工作拷贝。接下来,对这些文件作些修改,在完成了一个阶段的目标之后,提交本次更新到仓库。

 

请记住,工作目录下面的所有文件都不外乎这两种状态:已跟踪或未跟踪。已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是未更新,已修改或者已放入暂存区。而所有其他文件都属于未跟踪文件。它们既没有上次更新时的快照,也不在当前的暂存区域。初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改。

 

个人总结android系统中,第一次clone下来的数据中的文件是全部跟踪的,并且对于我们来说也必须是跟踪的,因为都是源代码,这个时候可以在管理目录下新建一个.gitignore文件,将编译产生的文件放进去,做好之后,当编译android后,执行git  status,只会显示之前你修改的文件,不会把编译产生的文件也显示出来

 

git  add  xx 作用

git add 后可以接要跟踪的文件或目录的路径。如果是目录的话,就说明要递归跟踪所有该目录下的文件

假如编译文件A,B后,git add 后,现在两个文件A,B都已暂存,下次提交时就会一并记录到仓库。假设此时,你想要在文件A里再加条注释,重新编辑存盘后,准备好提交。不过且慢,再运行 git status看看:

A文件出现了两次!一次算未暂存,一次算已暂存,这怎么可能呢?好吧,实际上 Git 只不过暂存了你运行 git add 命令时的版本,如果现在提交,那么提交的是git add 过的版本,而非当前工作目录中的版本。所以,运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来

 

.gitignore文件作用

一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,像是日志或者编译过程中创建的等等。我们可以创建一个名为.gitignore 的文件,列出要忽略的文件模式,要养成一开始就设置好.gitignore 文件的习惯,以免将来误提交这类无用的文件

.gitignore 的格式规范如下:

• 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。

• 可以使用标准的 glob 模式匹配。

• 匹配模式最后跟反斜杠(/)说明要忽略的是目录。

• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 的数字)。

我们再看一个 .gitignore 文件的例子:

此为注释 – 将被 Git 忽略

*.a 忽略所有 .a 结尾的文件

!lib.a # 但 lib.a 除外

/TODO # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO

build/ 忽略 build/ 目录下的所有文件

doc/*.txt 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

 

git  diff 作用

要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 git  diff

此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容

若要看已经暂存起来的文件和上次提交时的快照之间的差异,可以用 git  diff  --cached命令。(Git 1.6.1 及更高版本还允许使用 git diff --staged ,效果是相同的,但更好记些。

 

git  commit 作用

git  commit提交之前请一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。所以,每次准备提交前,先用 git status 看下,是不是都已暂存起来了,然后再运行提交命令 git  commit 这种方式会启动文本编辑器以便输入本次提交的说明。(默认会启用 shell 的环境变量$EDITOR 所指定的软件,一般都是 vim 或 emacs。当然也可以按照第一章介绍的方式,使用 git config --global core.editor 命令设定你喜欢的编辑软件。)编辑器会显示一些文本信息,可以看到,默认的提交消息包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一空行,供你输入提交说明。你完全可以去掉这些注释行,不过留着也没关系,多少能帮你回想起这次更新的内容有哪些。(如果觉得这还不够,可以用 -v 选项将修改差异的每一行都包含到注释中来。)退出编辑器时,Git 会丢掉注释行,将说明内容和本次更新提交到仓库。

也可以使用 -m 参数后跟提交说明的方式,在一行命令中提交更新:

$ git commit -m "Story 182: Fix benchmarks for speed"

记住,提交时记录的是放在暂存区域的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较。

 

跳过使用暂存区域

尽管使用暂存区域的方式可以精心准备要提交的细节,但有时候这么做略显繁琐。Git 提供了一个跳过使用暂存区域的方式,只要在提交的时候,给 git commit 加上 -a 选项Git就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤,git commit -a 注意是将修改的文件暂存后一并调交,是会暂存它的

 

git中删除某些文件

要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。可以用 git  rm 命令完成此项工作(注意,执行git rm 后,要git commit提交才会最终生效),并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changed but not updated” 部分(也就是_未暂存_清单)

 

git取消跟踪但不删除文件

另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。换句话说,仅是从跟踪清单中删除。比如一些大型日志文件或者一堆 .a 编译文件,不小心纳入仓库后,要移除跟踪但不删除文件,以便稍后在 .gitignore文件中补上,用 --cached 选项即可:

$ git rm --cached readme.txt    //此命令会从将readme.txt从暂存区删除,然后刷新暂存区,提交生效

 

注意:后面可以列出文件或者目录的名字,也可以使用 glob 模式。比方说:

$ git rm log/\*.log

注意到星号 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开(译注:实际上不加反斜杠也可以运行,只不过按照 shell 扩展的话,仅仅删除指定目录下的文件而不会递归匹配。上面的例子本来就指定了目录,所以效果等同,但下面的例子就会用递归方式匹配,所以必须加反斜杠。)。此命令删除所有 log/目录下扩展名为 .log 的文件。类似的比如:

$ git rm \*~

会递归删除当前目录及其子目录中所有 结尾的文件。

 

git 文件改名

不像其他的 VCS 系统,Git 并不跟踪文件移动操作。如果在 Git 中重命名了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。不过 Git 非常聪明,它会推断出究竟发生了什么,至于具体是如何做到的,我们稍后再谈。既然如此,当你看到 Git 的 mv 命令时一定会困惑不已。要在 Git 中对文件改名,可以这么做:

$ git  mv  file_from  file_to

如此分开操作,Git 也会意识到这是一次改名,所以不管何种方式都一样。当然,直接用git mv 轻便得多,不过有时候用其他工具批处理改名的话,要记得在提交前删除老的文件名,再添加新的文件名。

 

git  log 妙用

默认不用任何参数的话,git  log 会按提交时间列出所有的更新,最近的更新排在最上面。每次更新都有一个 SHA-1 校验和、作者的名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明.

git log 有许多选项可以帮助你搜寻感兴趣的提交,接下来我们介绍些最常用的。我们常用 -p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新还有个常用的 --pretty 选项,可以指定使用完全不同于默认格式的方式展示提交历史。比如用 oneline 将每个提交放在一行显示,这在提交数很大时非常有用。、

$ git log --pretty=oneline

但最有意思的是 format,可以定制要显示的记录格式,这样的输出便于后期编程提取析,像这样:

$ git log --pretty=format:"%h - %an, %ar : %s"

用 oneline 或 format 时结合 --graph 选项,可以看到开头多出一些 ASCII 字符串表示的简单图形,形象地展示了每个提交所在的分支及其分化衍合情况

有时候图形化工具更容易展示历史提交的变化,随 Git 一同发布的 gitk 就是这样一种工具。它是用 Tcl/Tk 写成的,基本上相当于 git log 命令的可视化版本,凡是 git log可以用的选项也都能用在 gitk 。在项目工作目录中输入 gitk 命令后,就会启动图形界面,上半个窗口显示的是历次提交的分支祖先图谱,下半个窗口显示当前点选的提交对应的具体差异

 

修改最后一次提交

有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用 --amend 选项重新提交:

$ git commit --amend

此命令将使用当前的暂存区域快照提交。如果刚才提交完没有作任何改动,直接运行此命令的话,相当于有机会重新编辑提交说明,而所提交的文件快照和之前的一样。启动文本编辑器后,会看到上次提交时的说明,编辑它确认没问题后保存退出,就会使用新的提交说明覆盖刚才失误的提交。如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 --amend 提交

 

取消已经暂存的文件

可以使用 git  reset  HEAD <file>... 的方式取消暂存

 

查看当前配置有哪些远程仓库

查看当前配置有哪些远程仓库,可以用 git remote 命令,它会列出每个远程库的简短

名字。在克隆完某个项目后,至少可以看到一个名为 origin 的远程库Git 默认使用这个名字来标识你所克隆的原始仓库也可以加上 -v 选项(译注:此为 —verbose 的简写,取首字母),显示对应的克隆地址

 

添加远程仓库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行 git  remote  add  [shortname]  [url]

$ git  remote add  pb  git://github.com/paulboone/ticgit.git

现在可以用字串 pb 指代对应的仓库地址了。比如说,要抓取所有 Paul 有的,但本地仓库没有的信息,可以运行 git fetch pb 现在,paul 的主干分支(master)已经完全可以在本地访问了,对应的名字是 pb/master,你可以将它合并到自己的某个分支,或者切换到这个分支,看看有些什么有趣的更新

 

从远程仓库抓取数据  git  fetch/pull

git  fetch 用法

正如之前所看到的,可以用下面的命令从远程仓库抓取数据到本地

用法:

git  fetch  [remote-name]   //拉取[remote-name]所有的更新,但不合并

如:

git  fetch  origin

此命令会到远程仓库中拉取所有你本地仓库中还没有的数据。运行完成后,你就可以在本地访问该远程仓库中的所有分支,将其中某个分支合并到本地,或者只是取出某个分支,一探究竟.

 

如果是克隆了一个仓库,此命令会自动将远程仓库归于 origin 名下。所以,git  fetch  origin 会抓取从你上次克隆以来别人上传到此远程仓库中的所有更新(或是上次 fetch 以来别人提交的更新)。有一点很重要,需要记住,fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,只有当你确实准备好了,才能手工合并

 

git  pull 用法

用法:

git  pull  [remote-name]  [跟踪远程分支A的本地分支A] //在处于任何分支下,会将远程分支A的更新,直接合并到本地A分支上去

git  pull  //前提是现在所在的分支为跟踪分支,也就是有一个对应的远程分支的本地分支,如本地master分支

如:

git pull  origin  [跟踪了某远程分支A的本地分支A]  //会将远程分支A的更新,直接合并到本地A分支上去

在本地master分支上:git pull //将远程master分支拉取下来,并合并到当前的跟踪分支master

如果设置了某个分支用于跟踪某个远端仓库的分支,可以使用 git pull 命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支。在日常工作中我们经常这么用,既快且好。实际上,默认情况下 git clone 命令本质上就是自动创建了本地的 master 分支用于跟踪远程仓库中的 master 分支(假设远程仓库确实有master 分支)。所以一般我们运行 git  pull目的都是要从原始克隆的远端仓库中抓取数据后,合并到工作目录中当前分支

 

 

 

个人总结:比如两个人同时在 master分支上工作

一个1人修改了A文件,提交后,push到服务器,git  push  origin  master:master,

此时另一2人也修改了A文件的同一个地方,提交后并未上传到服务器,1)此时他 git   fetch  origin,这个时候会拉取服务器上的所有更新数据,但是并不合并,这个时候git checkout origin/master 可以看到1人提交的更新,再git checkout master ,发现自己的本地分支master中并未此更新,这个时候可以再master分支下执行  git  merge origin/master ,自己的本地分支会合并服务器上;2)也可以直接不用git  fetch  origin  直接用 git pull  origin拉取服务器更新,并合并,

同理

比如两个人同时在 origin/s分支上开始建立本地分支1s,2s工作

一个1人修改了A文件,提交后,push到服务器,git  push  origin  1s:s,

此时另一2人也修改了A文件的同一个地方,提交后并未上传到服务器,1)此时他 git   fetch  origin,这个时候会拉取服务器上的所有更新数据,但是并不合并,这个时候git checkout origin/s 可以看到1人提交的更新,再git checkout  1s ,发现自己的本地分支1s中并未此更新,这个时候可以再1s分支下执行  git  merge origin/s ,自己的本地分支会合并服务器上s分支;此时,1人如果在git fetch origin,会把2人的修改更新到自己仓库的origin/s上去,这个时候他需要再git  merge  origin/s 才能将2人的更新合并到自己的2s分支上。

 

重要概念:跟踪分支

注意,本地的master分支和origin/master分支是有对应关系的,本地master更新提交服务器后,origin/master也会移动

 

本地分支推送到远程  git  push

用法:

git  push  [remote-name]  [branch-name] ;//将本地[branch-name]分支更新到远程分支中去,若无对应远程分支则以branch-name建立一个远程分支

git  push  [remote-name]  [branch-name][remote-branch-name]  //将本地分支更新到新建立的[remote-branch-name]远程分支中去,注意[remote-branch-name]是远程分支名,且要去掉[remote-name],如origin/s要写为s  : git push  origin s:s

注意,上面两种方法生成的remote-branch-name 和本地的branch-namepush的关系,也就是,本地branch-name每次执行git  push 会自动的push[remote-branch-name]上去,但是这二者不一定有pull关系

git push //这种用法是将有pull关系的本地分支更新到与之存在pull关系的远程分支中,下面专门讲到

 

将本地分支[branch-name]推送到[remote-name]服务器上的[remote-branch-name]分支上,本地的其他分支不会推送同一时刻没有其他人在推数据,这条命令才会如期完成任务

如果要把本地的 master 分支推送到 origin 服务器上(再次说明下,克隆操作会自动使用默认的master 和 origin 名字),可以运行下面的命令

$ git  push  origin  master 

只有在所克隆的服务器上有写权限,或者同一时刻没有其他人在推数据,这条命令才会如期完成任务。如果在你推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,并到自己的项目中,然后才可以再次推送

 

你的本地分支不会被自动同步到你引入的远程分支中,除非你明确执行推送操作。换句话说,对于无意分享的,你尽可以保留为私人分支,而只推送那些协同工作的特性分支。如果你有个叫 serverfix 的分支需要和他人一起开发,可以运行 git  push  (远程仓库名)  (本地分支名)

git  push  origin  serverfix

这其实有点像条捷径。Git 自动把 serverfix 分支名扩展为 refs/heads/server-fix refs/heads/serverfix,意为“取出我的 serverfix 本地分支,推送它来更新远程仓库的 serverfix 分支”。我们将在第九章进一步介绍 refs/heads/ 部分的细节,不过一般使用的时候都可以省略它。也可以运行 git  push  origin  serverfixserferfix 来实现相同的效果,它的意思是“提取我的 serverfix 并更新到远程仓库的 serverfix”。通过此语法,你可以把本地分支推送到某个命名不同的远程分支:若想把远程分支叫作awesomebranch,可以用 git push origin serverfixawesomebranch 来推送数据。

 

建立一个对应某个远程分支的本地分支

用法:

git  checkout  -b  新建的本地分支名  [remote_name]/远端分支名

接上面,当你的协作者再次从服务器上获取数据时,他们将得到一个新的远程分支origin/serverfix值得注意的是,在 fetch 操作抓来新的远程分支之后,你仍然无法在本地编辑该远程仓库。换句话说,在本例中,你不会有一个新的 serverfix 分支,有的只是一个你无法移动的 origin/serverfix 指针。如果要把该内容合并到当前分支,可以运行: git merge origin/serverfix本地分支合并远程分支如果想要一份自己的 serverfix 来开发,可以在远程分支的基础上分化出一个新的分支来

git  checkout  -b  serverfix  origin/serverfix      //这样添加的本地 serverfix为跟踪分支

Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.

Switched to a new branch "serverfix"

这会切换到新建的 serverfix 本地分支,其内容同远程分支 origin/serverfix 一致,你可以在里面继续开发了

 

git pull 和 git push 不带参数时的用法

当我们查看远程仓库的信息时 git  remote show origin

会有下面信息

  Local branch configured for 'git pull':

    master merges with remote master

  Local refs configured for 'git push':

    master pushes to master (up to date)

    qqq    pushes to qqq    (up to date)

yyy    pushes to yyy    (up to date)

这段信息说明:

当执行 git pull 时,会自动下载远程分支master并和本地的master合并

当执行 git push 时,会自动将本地的masterqqqyyy分支上传到远程分支上,远程分支masterqqqyyy会更新

 

查看远程仓库信息

我们可以通过命令 git remote show [remote-name] 查看某个远程仓库的详细信息,比如要看所克隆的 origin 仓库,可以运行:

$ git  remote  show  origin

 

远程仓库重命名

在新版 Git 中可以用 git remote rename 命令修改某个远程仓库的简短名称,比如想把pb 改成 paul,可以这么运行:

$ git  remote  rename  pb  paul

注意,对远程仓库的重命名,也会使对应的分支名称发生变化,原来的 pb/master 分支现在成了 paul/master

 

远程仓库删除

碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库,可以运行 git  remote  rm 命令:

$ git  remote  rm  paul

 

git中命令及选项Tab键自动匹配

在输入 Git 命令的时候可以敲两次跳格键(Tab),就会看到列出所有匹配的可用命令建议:

$ git co<tab><tab>

commit config

命令的选项也可以用这种方式自动完成,其实这种情况更实用些。比如运行 git log 的时候忘了相关选项的名字,可以输入开头的几个字母,然后敲 Tab 键看看有哪些匹配的:

$ git log --s<tab>

--shortstat --since= --src-prefix= --stat --summary

 

git 命令别名

$ git  config  --global  alias.ci  commit

现在,如果要输入 git commit 只需键入 git ci 即可使用这种技术还可以创造出新的命令,比方说取消暂存文件时的输入比较繁琐,可以自己设置一下:

$ git  config  --global alias.unstage  'reset HEAD --'

这样一来,下面的两条命令完全等同:

$ git unstage fileA

$ git reset HEAD fileA

我们还经常设置 last 命令:

$ git config --global alias.last 'log -1 HEAD'

以看出,实际上 Git 只是简单地在命令中替换了你设置的别名。不过有时候我们希望运行某个外部命令,而非 Git 的附属工具,这个好办,只需要在命令前加上 就行

$ git  config  --global  alias.visual  "!gitk"

 

git 中的分支

Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针

现在来谈分支。Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动.

 

创建一个新的分支指针

新建一个 testing 分支,可以使用 git branch 命令:

$ git  branch  testing

那么,Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针

在 Git 中,它是一个指向你正在工作中的本地分支的指针我们现在转换到新建的 testing 分支:

$ git checkout testing

这样 HEAD 就指向了 testing 分支

 

本地分支删除

使用 git branch 的 -d选项表示删除,-D表示强制删除

$ git branch -d hotfix

 

本地分支间合并

实际操作只需检出(切换到)想要更新的分支(master),并运行 git merge 命令指定合并的来源:

$ git  checkout  master

$ git  merge  iss53   //本地master合并本地iss53分支,新的分支由master指向

 

本地分支和远程分支合并

同本地分支间的合并一样

实际操作只需检出(切换到)想要更新的分支(master),并运行 git merge 命令指定合并的来源:

$ git  checkout  master

$ git  merge  origin/iss53   //本地master合并远程iss53分支,新的分支由master指向

 

合并时冲突的解决

有时候合并操作并不会如此顺利。如果你修改了两个待合并分支里同一个文件的同一部分,Git 就无法干净地把两者合到一起(译注:逻辑上说,这种问题只能由人来解决)Git 作了合并,但没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以用 git status 查阅,任何包含未解决冲突的文件都会以未合并(unmerged)状态列出,可以看到 ======= 隔开的上半部分,是 HEAD(即 master 分支,在运行 merge 命令时检出的分支)中的内容在解决了所有文件里的所有冲突后,运行 git  add 将把它们标记为已解决(resolved)。因为一旦暂存,就表示冲突已经解决。如果你想用一个有图形界面的工具来解决这些问题,不妨运行 git  mergetool,它会调用一个可视化的合并工具并引导你解决所有冲突,退出合并工具以后,Git 会询问你合并是否成功。如果回答是,它会为你把相关文件暂存起来,以表明状态为已解决,如果觉得满意了,并且确认所有冲突都已解决,也就是进入了缓存区,就可以用 git  commit 来完成这次合并提交

 

git branch 作用

git branch 命令不仅仅能创建和删除分支,如果不加任何参数,它会给出当前所有分支的清单若要查看各个分支最后一次 commit 信息,运行

$ git branch -v

从该清单中筛选出你已经(或尚未)与当前分支合并的分支,可以用 --merge 和 --no-merged 选项(Git 1.5.6 以上版本)。比如 git branch -merge 查看哪些分支已被并入当前分支

$ git branch --merged

一般来说,列表中没有 的分支通常都可以用 git branch -d 来删掉。原因很简单,既然已经把它们所包含的工作整合到了其他分支,删掉也不会损失什么

 

长期分支

由于 Git 使用简单的三方合并,所以就算在较长一段时间内,反复多次把某个分支合并到另一分支,也不是什么难事。也就是说,你可以同时拥有多个开放的分支,每个分支用于完成特定的任务,随着开发的推进,你可以随时把某个特性分支的成果并到其他分支中。许多使用 Git 的开发者都喜欢以这种方式来开展工作,比如仅在 master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。与此同时,他们还有一个名为 develop next 的平行分支,专门用于后续的开发,或仅用于稳定性测试 —— 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支,如前例的 iss53)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布

你可以用这招维护不同层次的稳定性。某些大项目还会有个 proposed(建议)或puproposed updates,建议更新)分支,它包含着那些可能还没有成熟到进入 next或 master 的内容。这么做的目的是拥有不同层次的稳定性:当这些分支进入到更稳定的水平时,再把它们合并到更高层分支中去。再次说明下,使用多个长期分支的做法并非必需,

不过一般来说,对于特大型项目或特复杂的项目,这么做确实更容易管理。

 

特性分支

一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支,我们在上节的例子里已经见过这种用法了。我们创建了 iss53 和 hotfix 这两个特性分支,在提交了若干更新后,把它们合并到主干分支,然后删除,该技术允许你迅速且完全的进行语境切换 —— 因为你的工作分散在不同的流水线里,每个分支里的改变都和它的目标

特性相关,浏览代码之类的事情因而变得更简单了。你可以把作出的改变保持在特性分支中几分钟,几天甚至几个月,等它们成熟以后再合并,而不用在乎它们建立的顺序或者进度

 

请务必牢记这些分支全部都是本地分支,这一点很重要。当你在使用分支及合并的时候,一切都是在你自己的 Git 仓库中进行的 —— 完全不涉及与服务器的交互

 

远程分支

远程分支(remote branch)是对远程仓库状态的索引。它们是一些无法移动的本地分支;

我们用(远程仓库名)/(分支名这样的形式表示远程分支。比如我们想看看上次同origin 仓库通讯时 master 的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可能也有一个本地的iss53 分支,但指向服务器上最新更新的却应该是 origin/iss53 分支。假设你们团队有个地址为 git.ourcompany.com 的 Git服务器。如果你从这里克隆,Git 会自动为你将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针,在本地命名为 origin/master,但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 master 分支,始于 origin上 master 分支相同的位置,你可以就此开始工作一次 Git 克隆会建立你自己的本地分支 master 和远程分支 origin/master,它们都指向origin/master 分支的最后一次提交要是你在本地 master 分支做了会儿事情,与此同时,其他人向 git.ourcompany.com 推送了内容,更新了上面的 master 分支,那么你的提交历史会开始朝不同的方向发展。不过只要你不和服务器通讯,你的origin/master 指针不会移动可以运行 git fetch origin 来进行同步。该命令首先找到 origin 是哪个服务器(本例为 git.ourcompany.com),从上面获取你尚未拥有的数据,更新你本地的数据库,然后把origin/master 的指针移到它最新的位置

 

 

跟踪分支

从远程分支检出的本地分支,称为跟踪分支(tracking branch)。跟踪分支是一种和远程分支有直接联系的本地分支。在跟踪分支里输入 git pushGit 会自行推断应该向哪个服务器的哪个分支推送数据。反过来,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。

在克隆仓库时,Git 通常会自动创建一个 master 分支来跟踪 origin/master。这正是git push 和 git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master 之外的其它分支。刚才我们已经看到了这样的一个例子:git  checkout  -b  [分支名]  [远程名]/[分支名]。如果你有 1.6.2 以上版本的 Git,还可以用 --track 选项简化:

$ git  checkout  --track  origin/serverfix

要为本地分支设定不同于远程分支的名字,只需在前个版本的命令里换个名字

$ git  checkout  -b  sf  origin/serverfix

现在你的本地分支 sf 会自动向 origin/serverfix 推送和抓取数据了

有一个问题:如何建立一个自己创建的远程分支的跟踪分支?(wangchaoqun@chinapalms.com)

例如:

git checkout  -b  A  origin/A

git remote  show  origin

  Local branches configured for 'git pull':

    A      merges with remote A

    master merges with remote master

  Local refs configured for 'git push':

    A      pushes to A      (up to date)

    master pushes to master (up to date)

这表明创建的A分支是跟踪分支

 

删除远程分支

如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放稳定代码的地方),可以用这个非常无厘头的语法来删除它:

git  push  [远程名]   [分支名]。如果想在服务器上删除 serverfix 分支,运行下面的命令:

$ git  push  origin    serverfix

有种方便记忆这条命令的方法:记住我们不久前见过的 git push  [远程名]  [本地分支]:[远程分支语法,如果省略 [本地分支],那就等于是在说“在这里提取空白然后把它变成[远程分支]

 

 

衍合

把一个分支整合到另一个分支的办法有两种:merge(合并) 和 rebase(衍合)

最容易的整合分支的方法是 merge 命令,它会把两个分支最新的快照(C3

和 C4)以及二者最新的共同祖先(C2)进行三方合并

其实,还有另外一个选择:你可以把在 C3 里产生的变化补丁重新在 C4 的基础上打一

遍。在 Git 里,这种操作叫做衍合(rebase)。有了 rebase 命令,就可以把在一个分支

里提交的改变在另一个分支里重放一遍

可以运行下面的命令:

$ git checkout experiment

$ git rebase master

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值