zoukankan      html  css  js  c++  java
  • 理解 Git 的基本概念 ( Merging Collaborating Rebasing)

    合并 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.

  • 相关阅读:
    java中public、private、protected区别
    Java构造函数
    吸血鬼数字算法
    JsonConvert.DeserializeObject<T>对象属性为空
    vs2015项目引用其他项目无法引用
    iis express 无法访问此网站
    c#Dictionary保存不同类型
    HttpContext.GetOwinContext().Authentication 报错 解决办法
    CSS基础1
    CSS基础3
  • 原文地址:https://www.cnblogs.com/englefly/p/2687882.html
Copyright © 2011-2022 走看看