合并 Merging

在分支上开发新功能后,如何把新功能加入到主分支,让其它人得到你的修改呢?你需要使用命令 git merge 或 git pull。

这两个命令的语法如下:

git merge [head]
git pull . [head]

这两个命令的结果是一样的(虽然 merge 命令现在看起来要简单一点,但在多个开发者的环境下 pull 命令会显得更加明确,我们会在多人协作开发的章节里讨论这个问题。)

这两个命令执行了下面的操作。我们把当前 head 记作 current, 将要被合并的 head 记作 merge。

  1. 找到 current 和 merge 的共同祖先, 记为 ancestor-commit.
  2. 先处理简单的情况. 如果 ancestor-commit 就是 merge, 那么什么都不用做. 如果 ancestor-commit 是 current, 那么执行 快速向前合并.
  3. 否则, 找出ancestor-commit 和 merge 之间的修改.
  4. 尝试将这些修改添加到 current 上.
  5. 如果没有冲突,那么创建一个新的节点, 新节点有两个父节点,分别是current 和 merge. 将 HEAD 指向新节点, 更新项目文件.
  6. 如果有冲突, 在文件冲突的部位插入相应的标志提示用户. 这种情况下不会创建新的节点.

重要提示: 在文件的修改还没有提交的情况下, 请不要执行合并操作.因为这会导致Git出现意想不到的结果.

So, to complete the above example, say you check out the master head again and finish writing up the new data for your paper. Now you want to bring in those changes you made to the headers.

The repository looks like this:

         +---------- (D)
/ |
(A) -- (B) -- (C) -------------- (E)
| |
fix-headers master
|
HEAD

where (E) is the commit reflecting the completed version with the new data.

You would run:

git merge fix-headers

If there are no conflicts, the resulting respository looks like this:

         +---------- (D) ---------------+
/ | \
(A) -- (B) -- (C) -------------- (E) -- (F)
| |
fix-headers master
|
HEAD

The merge commit is (F), having parents (D) and (E). Because (B) is the common ancestor between (D) and (E), the files in (F) should contain the changes between (B) and (D), namely the heading fixes, incorporated into the files from (E).

Note on terminology: When I say “merge head A into head B,” I mean that head B is the current head, and you are drawing changes from head A into it. Head B gets updated; nothing is done to head A. (If you replace the word “merge” with the word “pull,” it may make more sense.)

Resolving Conflicts

A conflict arises if the commit to be merged in has a change in one place, and the current commit has a change in the same place. Git has no way of telling which change should take precedence.

To resolve the commit, edit the files to fix the conflicting changes. Then run git add to add the resolved files, and run git commit to commit the repaired merge. Git remembers that you were in the middle of a merge, so it sets the parents of the commit correctly.

Fast Forward Merges

A fast forward merge is a simple optimization for merging. Say your repository looks like this:

                +-- (D) -- (E)
/ |
(A) -- (B) -- (C) |
| |
current to-merge
|
HEAD

and you run git merge to-merge. In this case, all Git needs to do is set current to point to (E). Since (C) is the common ancestor, there are no changes to actually “merge.”

Hence, the resulting merged repository looks like:

                +-- (D) -- (E)
/ |
(A) -- (B) -- (C) |
|
to-merge, current
|
HEAD

That is, to-merge and current both point to commit (E), and HEAD still points to current.

Note an important difference: no new commit object is created for the merge. Git only shifts the head pointers around.

Common Merge Use Patterns

There are two common reasons to merge two branches. The first, as explained above, is to draw the changes from a new feature branch into the main branch.

The second use pattern is to draw the main branch into a feature branch you are developing. This keeps the feature branch up to date with the latest bug fixes and new features added to the main branch. Doing this regularly reduces the risk of creating a conflict when you merge your feature into the main branch.

One disadvantage of doing the above is that your feature branch will end up with a lot of merge commits. An alternative that solves this problem is rebasing, although that comes with problems of its own.

Deleting a Branch

After you have merged a development branch into the main branch, you probably don’t need the development branch anymore. Hence, you may want to delete it so it doesn’t clutter your git branch listing.

To delete a branch, use git branch -d [head]. This simply removes the specified head from the repository’s list of heads.

For example, in this repository from above:

         +---------- (D) ---------------+
/ | \
(A) -- (B) -- (C) -------------- (E) -- (F)
| |
fix-headers master
|
HEAD

we probably don’t need the fix-headers head any more. So we can use:

git branch -d fix-headers

and the resulting repository looks like:

         +---------- (D) ---------------+
/ \
(A) -- (B) -- (C) -------------- (E) -- (F)
|
master
|
HEAD

Important notegit branch -d will cause an error if the branch to be deleted is not reachable from another head. Why? Consider the following repository:

         +----------- (E)
/ |
(A) -- (B) -- (C) |
| |
head1 head2

Say you delete head2. Now how can you use commit (E)? You can’t check it out, because it isn’t a head. And it doesn’t appear in any logs or anywhere else, because it isn’t an ancestor of head1. So commit (E) is practically useless. In Git terminology, it is a “dangling commit,” and its information is lost.

Git does allow you to use the -D option to force deletion of a branch that would create a dangling commit. However, it should be a rare situation that you want to do that. Think very carefully before using git branch -D.

理解 Git 的基本概念 ( Merging Collaborating Rebasing)的更多相关文章

  1. Merging 和 Rebasing 的大比拼

    虽然 merging 和 rebasing 在 git 中相似时,但他们提供不同的功能.为了让你的历史尽可能的干净和完整,你应该知道以下几点. git rebase 命令已 神奇的 Git voodo ...

  2. 深入理解git,从研究git目录开始

    转发学习的啦. 似乎很少有人在读某个git快速教程的时候会说:“这个关于git的快速教程太酷了!读完了用起git来超级舒服,并且我一点也不怕自己会破坏什么东西.” 对git的初学者来说,刚接触git时 ...

  3. 理解git经常使用命令原理

    git不同于类似SVN这样的版本号管理系统,尽管熟悉经常使用的操作就能够满足大部分需求,但为了在遇到麻烦时不至于靠蛮力去尝试,了解git的原理还是非常有必要. 文件 通过git管理的文件版本号信息所有 ...

  4. 深入理解Git的实现原理

      0.导读   本文适合对git有过接触,但知其然不知其所以然的小伙伴,也适合想要学习git的初学者,通过这篇文章,能让大家对git有豁然开朗的感觉.在写作过程中,我力求通俗易懂,深入浅出,不堆砌概 ...

  5. 理解git的分支原理,更好地使用git

    文章内容转载于git-scm. 部分内容涉嫌枯燥 一.git分支概念 几乎每一种版本控制系统都以某种形式支持分支.使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作.在很多版本控 ...

  6. 深入理解Git - 一切皆commit

    在对 git 有了基本理解和知道常规操作之后,如何对 git 的使用有进一步的理解? 一切皆 commit 或许是个不错的理解思路. 本文将从『一切皆 commit 』的角度,通过 git 中常见的名 ...

  7. 深入理解Git - Git底层对象

    前篇: 深入理解Git - 一切皆commit 如何从稍微底层一点的角度,从底层实现理解一切皆commit ? 配合希沃白板课件食用,效果更佳: [希沃白板5]课件分享 : <Git 进阶 - ...

  8. [转发]深入理解git,从研究git目录开始

    转发学习的啦. 似乎很少有人在读某个git快速教程的时候会说:“这个关于git的快速教程太酷了!读完了用起git来超级舒服,并且我一点也不怕自己会破坏什么东西.” 对git的初学者来说,刚接触git时 ...

  9. Git 入门:概念、原理、使用

    出处: git入门:概念.原理.使用 git和Github 概念 Git --- 版本控制工具(命令). git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理.git ...

随机推荐

  1. 【巷子】---vue路由懒加载---【vue】

    一.懒加载 也叫延迟加载或者按需加载,即在需要的时候进行加载,   二.为什么要使用懒加载 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要 ...

  2. Oracle下select语句

    先看scott下自带的emp表 empno:编号  ename:名字  Job:职位  mgr:上级编号 hiredate:入职时间 sal:薪水 comm:奖金 deptno:部门编号 部门表dep ...

  3. Oracle开发 之 主-外键约束FK及约束的修改

    试验环境: 1)数据库版本:oracle 11.2.0.4 2)建表脚本:以scott的dept及emp表为基础. 父表:dept -- Create table create table DEPT ...

  4. linux中gdb的可视化调试

    今天get到一个在linux下gdb调试程序的技巧和大家分享一下!平时我们利用gcc进行编程,进行程序调试时,观察程序的跳转等不是这么直观.都是入下的界面! 但是如果我们在编译连接时上加了-g命令生成 ...

  5. 自己主动检測&后台复制光盘内容

    原理:利用python的win32模块,注冊服务,让代码在后台执行,检測光盘并复制文件 启动的方法就是直接在cmd下,main.py install ,然后去windows 的服务下就能够看到The ...

  6. ArcEngine和GDAL读写栅格数据机制对比(一)

    最近应用AE开发插值和栅格转等值线的程序,涉及到栅格读写的有关内容.联想到ArcGIS利用了GDAL的某些东西,从AE的OMD中也发现RasterDataset和RasterBand这些命名和GDAL ...

  7. [3D]第一人称相机类Camera

    自己根据C++ D3D的源码改写一个相机类(第一人称). using System; using System.Collections.Generic; using System.Linq; usin ...

  8. 解决下载ftp文件过程中,浏览器直接解析文件(txt,png等)的问题

    搭建了一个ftp服务器,供用户进行上传下载,在下载过程中发现,一些文件,例如txt,jpg,png,pdf等直接被浏览器解析了.在浏览器中显示其内容,没有下载. 下面通过网上查询得到一些解决方法: 最 ...

  9. Java系列介绍

    Java系列目录 重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述函数 Java 7新增功能 Java应用程序中System.out. ...

  10. 1.2、Django 视图与网址__进阶

    Django 视图与网址进阶 1.1.简单使用: 把我们新定义的app加到settings.py中的INSTALL_APPS中 修改 HelloDjango/HelloDjango/settings. ...