实际开发中,会在当前开发线路上拉出另外的开发线进行开发,比如软件功能已经比较稳定的话,在后续功能的开发过程中,就很可能会拉出独立的支线进行开发,待功能开发完毕后,再将该直线合入稳定的主线中。

当然实际开发中,会有不同的分支策略,这就需要使用到Git的分支。

分支是开发中启动一条单独的开发线的基本方法,使开发过程能够在多个方向上同时进行,并可能产生项目的不同版本。

分支名

版本库中的默认分支名称为master,大多数开发人员在该分支上保持版本库中最强大和最可靠的开发线。同时Git还支持给分支命名,分支命名需要遵守一些规则:

  • 可以使用/创建分层的命名方案,但该分支名不能以/结尾
  • 分支名不能以-开头
  • 以/分割的组件不能以.开头
  • 分支名的任何地方不能包含两个连续的点..
  • 分支名不能包含任何空格或其它空白字符
  • 分支名中不能包含具有特殊含义的字符,包括~,^,:,?,*,[
  • 分支名中不能包含ASCII码控制字符

这些分支的命名规则是由git check-ref-format底层命令强制检测的,以确保分支名容易输入,且在.git目录和脚本中作为一个文件名是可用的。

从这里来看,分支和标签看起来有点相似。但标签和分支用于不同的目的,标签是一个静态的名字,其不随时间的推移而改变。而分支是动态的,并且随着每次提交而移动。

同时分支和标签可以使用相同的名称来命名,如果这样,就需要使用索引名全程来区分。如果不能正确地区分两者使用的区别,就应该避免使用相同的名称。

使用分支

在任何给定的时间中,版本库中可能存在不同的分支,但是最多只有一个当前的或活动的分支。活动分支决定在工作目录中检出哪些文件。

默认情况下,master分支是活动分支,但可以把任何分支设置为活动分支。

每个分支在一个特定的版本库中必须有唯一的名字,该命名始终指向该分支上最近的提交。

一个分支的最近提交称之为该分支的头部head。

Git不会保持分支的起源信息。同时,分支名随着分支上新的提交而增量地向前移动,因此旧提交必须通过散列值或相对名来索引,而如果某个特定提交是特殊的,需要被标记,比如特定的时间点,项目的特定状态等,此时可以使用标签名进行标记。

而一个分支开始时的原始提交没有显示定义,因此该分支的原始提交可以通过从分叉出的新分支的源分支名使用算法找到:

git merge-base original-branch new-branch

因为分支名始终指向该分支上最近提交的版本,还可以将分支名当成一个指向特定提交的指针。同时分支又不仅仅包含该分支最近的提交,其包含了从项目开始到该分支最近提交的所有路径,该路径同时也可能包含其它分支。

每一个分支名和分支上提交的内容一样,都会存放在本地版本库中,而当将版本库提交给他人后,也可以发布或选择使用任意数量的分支和相关的可用提交。而如果复制版本库,分支名和分支名上的开发都将是复制版本库的副本的一部分。

创建分支

创建分支需要基于版本库中现有的提交,因此需要指定哪次提交作为新分支的起始。

同时分支的生命周期也取决于用户的操作。

如果确定从哪个提交开始新分支时,只需要使用git branch命令:

git branch branch [starting-commit]

如果没有指定starting-commit,就默认为当前分支上的最近提交。

需要注意的是,git branch命令只是把分支名引进版本库,并没有改变工作目录使用新的分支。即没有工作目录文件发生变化,没有分支环境发生变化,也没有做出新的提交。也就是说,该命令只是在给定的提交上创建了一个命名的分支,而如果想要使用该分支,需要切换分支。

列出分支名

git branch命令可以列出版本库中的分支名:

$ git branch
* masterother

这里该命令会显示两个特性分支,当前已检出的工作目录中的分支用*标记,另外一个分支名为other。

如果没有额外的参数,则只列出版本库中的特性分支,可以从-r选项列出远程追踪分支,用-a把特性分支和远程分支都列出来。

$ git branch -a
* masterremotes/origin/HEAD -> origin/masterremotes/origin/mainremotes/origin/maintremotes/origin/masterremotes/origin/nextremotes/origin/seenremotes/origin/todo

查看分支

git show-branch命令提供比git branch更为详细的输出,按时间以递序的形式列出对一个或多个分支有贡献的提交。与git branch一样,没有额外参数就列出特性分支,-r显示远程分支,-a显示所有分支。

$ git show-branch
* [master] Merge branch 'other'! [other] commit file4
--
-  [master] Merge branch 'other'
*+ [other] commit file4

上边的输出被--分为两部分。上方列出了分支名,并用[]表示,每行分支名用!或*表示,*表示当前活动分支。同时每个分支都列出该分支最近提交的日志信息。

下部分表示每个分支的提交矩阵,同样每个提交后跟着该提交中的日志信息。如果有+,*,-在分支的列中,对应的提交就会在该分支中显示。+表示提交在一个分支中,*表示存在于当前活动分支的提交,-表示合并提交。

git show-branc命令会遍历所有显示的分支上的提交,直到其最近的共同提交处停止。在第一个共同提交处停止是默认启发策略,该行为也是合理的,到达这里也就能够通过上下文了解分支之间的相互关系。而如果想要更多提交历史记录,则可以使用--more选项来指定在共同提交后看到多少个额外的提交。

同时git show-branch还可以使用一组分支名来作为参数,以限制这些分支的历史记录显示。

$ git show-branch master other
* [master] Merge branch 'other'! [other] commit file4
--
-  [master] Merge branch 'other'
*+ [other] commit file4$ git show-branch master
[master] Merge branch 'other'

对比上面的显示差异,就可以看出两者的不同,同时该命令还支持通配符匹配,这样可以对比一组具有相同特征的分支的差异。

检出分支

之前提到如何创建分支,而创建分支并不意味着可以直接在新分支上工作,这需要切换分支。

切换分支或要在不同的分支上开始工作,就需要git checkout命令,给定一个分支名,就会使该分支变成当前活动分支,它会改变工作目录以匹配给定分支的状态。

简单示例

首先在空目录下执行下面的代码:

git init
echo abc > file1
git add file1
git commit -m "commit file1"
echo abcd > file2
git add file2
git commit -m "commit file2"
git branch other HEAD^
git checkout other
echo abcde > file3
git add file3
git commit -m "commit file3"
echo abcdef > file4
git add file4
git commit -m "commit file4"
git checkout master
git merge master other

使用git branch查看:

$ git branch
* masterother

此时存在两个分支,当前活动分支为master。

如果想要在other中工作,就可以执行:

$ git checkout other
Switched to branch 'other'$ git branchmaster
* other

此时就切换到了other分支。

$ git checkout master
Switched to branch 'master'$ ls
file1  file2  file3  file4$ git checkout other
Switched to branch 'other'$ ls
file1  file3  file4

而从上面的代码也可以看出,此时的工作命令已经发生了更新,以反映新分支的状态和内容。改变分支的影响主要有:

  • 在要被检出的分支中但不在当前分支中的文件和目录,会从对象库中检出并放置在工作目录中
  • 在当前分支中但不在要被检出的分支中的文件和目录,会从工作目录中删除
  • 这两个分支都有的文件会被修改为要被检出的分支的内容

有未提交的更改时进行检出

在检出分支时,Git会删除本地工作目录中数据的删除和修改,而工作目录中未被追踪的文件和目录则不会发生删除或修改。但是如果一个文件的本地修改不同于新分支上的变更,此时检出就会失败。

此时在master分支上,修改文件file2,然后检出other分支,此时会出现错误:

$ git branch
* masterother$ echo 1111 > file2$ git checkout other
error: Your local changes to the following files would be overwritten by checkout:file2
Please commit your changes or stash them before you switch branches.
Aborting

这是因为文件file2只存在于master分支,而不存在于other分支,这会导致检失败。

$ git show other:file2
fatal: path 'file2' exists on disk, but not in 'other'$ git show master:file2
abcd

此时在master分支上,修改文件file1,然后检出other分支,则为:

$ git branch
* masterother$ echo 1111 > file1$ git checkout other
Switched to branch 'other'
M       file1$ git show master:file1
abc$ git show other:file1
abc$ git branchmaster
* other$ cat file1
1111

可见此时该修改对于两个分支都是生效的,并同时修改了检出后分支的对应文件。

此时在master分支上,新建文件file5,然后检出other分支,则为:

$ echo 1111 > file5$ git checkout other
Switched to branch 'other'$ ls
file1  file3  file4  file5$ git status
On branch other
Untracked files:(use "git add <file>..." to include in what will be committed)file5nothing added to commit but untracked files present (use "git add" to track)

此时文件file5出现在了分支other的工作目录,并显示为未追踪状态。

在看最后一种情况前,首先执行下述代码:

git checkout other
echo 1111 > file5
git add file5
git commit -m "commit file5"

此时文件file5只存在于分支other,而不在master。然后在master分支上,新建文件file5,然后检出other分支,则为:

$ git branch
* masterother$ echo 2222 > file5$ git checkout other
error: The following untracked working tree files would be overwritten by checkout:file5
Please move or remove them before you switch branches.
Aborting$ git show master:file5
fatal: path 'file5' exists on disk, but not in 'master'$ git show other:file5
1111

这里也发生了错误,即master分支上未追踪的文件检出到other分支时,遇到同名文件,两者修改不同,便会拒绝检出。

这里可以总结为:

  • 活动分支和检出分支共有的文件,在活动分支上修改后,在检出分支上同样发生修改,如果此时需要在检出分支提交修改,应判断原始活动分支上的同名文件修改是否需要被丢弃,因为通常希望检出的分支是干净的
  • 活动分支上存在而检出分支上不存在的文件,检出后会出现在检出分支的工作目录中,此时该文件会显示为未追踪状态
  • 活动分支上不存在而检出分支上存在的文件,在活动分支上新建会被拒绝检出,此时需要对活动分支上的同名文件做处理,是提交还是丢弃

合并变更到不同分支

之前提到,活动分支工作目录的当前状态如果与检出分支相冲突,就需要将活动分支工作目录的修改和检出分支的文件合并。

因为活动分支和检出分支共有文件,在检出时会直接将修改带入到检出分支,这里主要看一下后两种情况。

这里的合并操作主要是使用git checkout命令的-m选项。

比如上文提到的第二种情况,会变为:

$ git branch
* masterother$ echo 1111 > file2$ git checkout -m other
warning: LF will be replaced by CRLF in file2.
The file will have its original line endings in your working directory
Switched to branch 'other'
A       file2$ git branchmaster
* other$ cat file2
1111

此时,在活动分支修改的文件直接合并到检出分支。

比如上文提到的第三种情况,会变为:

$ git branch
* masterother$ echo 2222 > file5$ git checkout -m other
Switched to branch 'other'
Already up to date!$ git branchmaster
* other$ cat file5
1111$ git show master:file5
fatal: path 'file5' exists on disk, but not in 'master'$ git show other:file5
1111

这里的现象却并不是想象的那样,修改并没有合并,而是other分支上的文件内容。

这些差异也说明了:在检出分支时,最好能够保证当前活动分支是干净的,然后再进行检出。

创建并检出新分支

之前提到的创建分支和检出分支是分步操作的,Git也可以在创建分支的同时进行检出,此时需要使用git checkout的-b选项。

$ git checkout -b temp
Switched to a new branch 'temp'$ git branchmasterother
* temp

这里直接创建了分支temp,并切换到了该分支。

分离HEAD分支

通常情况下,可以直接指出分支名检出分支的头部。也就是说,默认情况下,git checkout会改变期望的分支头部。

同时,也可以检出任何提交,而不仅仅限于分支名,此时Git就会自动创建一种匿名分支,成为分离的HEAD(detached HEAD)。在下面的情况下,Git会创建一个分离的HEAD:

  • 检出的提交不是分支的头部
  • 检出一个追踪分支
  • 检出标签引用的提交
  • 启动git bisect操作
  • 使用git submodule update命令

比如对于git源码:

$ git branch
* master$ git checkout v1.6.0
Updating files: 100% (4338/4338), done.
Note: switching to 'v1.6.0'.You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:git switch -c <new-branch-name>Or undo this operation with:git switch -Turn off this advice by setting config variable advice.detachedHead to falseHEAD is now at ea02eef096 GIT 1.6.0$ git branch
* (HEAD detached at v1.6.0)master$ git checkout -b temp
Switched to a new branch 'temp'$ git branchmaster
* temp

刚开始只有master分支,然后检出标签v1.6.0,此时的分支多了(HEAD detached at v1.6.0),然后在该标签处创建新分支temp,此时的分离分支就变为了temp分支。

删除分支

而如果创建分支后,觉得分支名命名的的不好,需要修改,或者如果该分支在后来的开发中觉得没有必要就可以删除该分支,此时通过git branch的-d选项。

$ git branchmasterother
* temp$ git branch -d temp
error: Cannot delete branch 'temp' checked out at 'C:/Users/wood/Desktop/GIT/tmp'$ git checkout master
Switched to branch 'master'$ git branch -d temp
Deleted branch temp (was c7cf5fb).$ git branch
* masterother

虽然可以删除分支,但却不能在活动分支上删除活动分支。

因为master一般是主分支,会一直存在,可以在master上对其它分支进行删除。

而由于Git不会保持任何形式的关于分支名创建,移动,操作,合并或删除的历史记录,因此某个分支被删除了,该分支就没有了。

同时Git会删除不再被引用的提交和不能从某些命名的引用(分支名或标签名)可达的提交。如果想要保留这些提交,就必须将之合并到不同的分支,为其创建一个分支,或创建标签指向。否则没有它们的引用和提交,blob就不可达,会被git gc工具当作垃圾回收。

因此,删除分支需要在明确删除的后果之后进行操作。

而意外删除分支后,可以使用git reflog或git fsck等命令进行恢复。

Git版本控制管理——分支相关推荐

  1. git版本控制以及分支管理

    git版本控制以及分支管理--一起乘坐时光机 四.深度剖析 一.版本控制---时光机穿梭 1.熟悉版本 2.版本回退 3.管理修改 1.管理修改以及理解工作的原理 2.撤销修改的内容 3.删除文件 二 ...

  2. 《Git版本控制管理(第2版)》——4.3 Git在工作时的概念

    本节书摘来自异步社区<Git版本控制管理(第2版)>一书中的第4章,第4.3节,作者:[美]Jon Loeliger , Matthew McCullough著,更多章节内容可以访问云栖社 ...

  3. 【Git版本控制管理】Gitee(码云)和GitHub的使用

    远程仓库的使用 文章目录 远程仓库的使用 使用码云(Gitee) 使用GitHub 远程仓库是指托管在因特网或其他网络中的你的项目的版本库. 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读 ...

  4. java中git版本控制,git版本控制管理是什么?git如何实现版本控制?

    大家好,今天要跟大家讲的是关于git版本控制管理的一点小知识,git相信程序员小伙伴们都已经很熟悉了,很多项目开发都需要git,所以,git版本控制管理到底是干嘛的呢?Git又如何实现版本控制呢?下面 ...

  5. Git版本控制__分支管理

    文章目录 Git基本操作 1. git 两大特点 2. 安装与配置 3. 创建一个版本库 4.版本创建与回退 4.1 使用 4.2 工作区和版本库 工作区 ( Working Directory ) ...

  6. Git版本控制管理——基本Git概念

    基本概念 版本库 Git版本库(repository)只是一个简单的数据库,其中包括所有用来维护与管理项目的修订版本和历史信息.而Git版本不仅会维护项目整个生命周期的完整副本,还会提供版本库本身的副 ...

  7. Git版本控制管理——合并

    之前提到了分支,既然有分,就一定有合. 在Git中,当一个分支中的修改与另一个分支中的修改不发生冲突的时候,Git会计算合并结果,并创建一个新提交来代表新的统一状态.但是当分支冲突时,Git并不解决冲 ...

  8. Git 版本控制管理(一)

    Git 是一个分布式版本控制工具,它的作者 Linus Torvalds 是这样给我们介绍 Git  -- The stupid content tracker(傻瓜式的内容跟踪器) 关于 Git 的 ...

  9. Git版本控制管理——简介

    说明 在大型项目开发或者多人协作开发时,都希望可以对软件代码进行管理和追踪,以便确认开发的进度和方便问题追溯.这就需要使用到版本控制系统(VCS),比如Git就是一款很优秀的版本控制工具.如今很多项目 ...

最新文章

  1. 简易OA漫谈之工作流设计(四,怎么支持会签)
  2. linux php7 mongodb,CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis
  3. rhel5 给grub 加密,亲测!
  4. 算法高级(41)-推荐算法实现
  5. ASP.NET 2.0 中Cookies的Expires属性详解
  6. Object_C与JavaScript交互使用总结
  7. leetcode 563 二叉树的坡度
  8. m3u8 video ios h5_移动端H5页面踩坑记
  9. linux自带python_【经验总结】linux 安装python (替换系统自带的python版本)
  10. python采集数据搭建小说网站_Python制作爬虫采集小说
  11. [Python3学习笔记-入门到入魔系列] 5分钟彻底搞懂XML文档解析
  12. rust中slice panicked at 'byte index 5 is not a char boundary' 问题解决办法
  13. 怎么还原计算机系统还原,怎么还原以前版本的windows?Win7/Win10系统还原方法
  14. 俞优静的“航海”人生-搜狐财经
  15. 从0到1万字贴心讲解单体架构到分布式架构的演变(第一篇)
  16. 【文本分析】基于粤港澳大湾区博物馆访客评价的文本分析
  17. PL/0 语言简介、PL/0 文法
  18. 计算机中pdf怎么预览,如何在浏览器中开启PDF时默认显示Adobe Reader XI工具栏
  19. H-1B身份六年后的延期问题
  20. 标识别,人脸识别等常用数据集

热门文章

  1. Linux下干净卸载mysql详解
  2. 《OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks》翻译
  3. 匿名内部类的格式和理解
  4. sql2005java驱动_Microsoft SQL Server 2005 JDBC驱动程序
  5. 电脑都面的没电了,我是如何通过腾讯云恐怖的一面面试的?
  6. Keras框架下的loss损失函数
  7. vs开发工具必备插件
  8. CAD闪退的解决方法
  9. 系统默认进程参考与对比
  10. 机器学习张志华讲的太太太好了