git merge簡介

湖冰2019發表於2012-06-14

git merge的基本用法為把一個分支或或某個commit的修改合併到現在的分支上。
我們可以執行git merge -hgit merge --help檢視其命令,後者會直接轉到一個網頁(git的幫助文件),更詳細。
usage: git merge [options] [<commit>...]
   or: git merge [options] <msg> HEAD <commit>
   or: git merge --abort

    -n                    do not show a diffstat at the end of the merge
    --stat                show a diffstat at the end of the merge
    --summary             (synonym to --stat)
    --log[=<n>]           add (at most <n>) entries from shortlog to merge commi                                                                                                                t message
    --squash              create a single commit instead of doing a merge
    --commit              perform a commit if the merge succeeds (default)
    -e, --edit            edit message before committing
    --ff                  allow fast-forward (default)
    --ff-only             abort if fast-forward is not possible
    --rerere-autoupdate   update the index with reused conflict resolution if po                                                                                                                ssible
    -s, --strategy <strategy>
                          merge strategy to use
    -X, --strategy-option <option=value>
                          option for selected merge strategy
    -m, --message <message>
                          merge commit message (for a non-fast-forward merge)
    -v, --verbose         be more verbose
    -q, --quiet           be more quiet
    --abort               abort the current in-progress merge
    --progress            force progress reporting
    -S, --gpg-sign[=<key id>]
                          GPG sign commit
    --overwrite-ignore    update ignored files (default)
git merge [options] <msg> HEAD <commit> 這裡的 HEAD 其實就是分支名,用於說明把 HEAD  分支合併到當前分支。

--squash選項的含義是:本地檔案內容與不使用該選項的合併結果相同,但是不保留待合併分支上的歷史資訊,也不提交、不移動HEAD,因此需要一條額外的commit命令。其效果相當於將another分支上的多個commit合併成一個,放在當前分支上,原來的commit歷史則沒有拿過來。

   判斷是否使用--squash選項最根本的標準是,待合併分支上的歷史是否有意義。

如果在開發分支上提交非常隨意,甚至寫成微博體,那麼一定要使用--squash選項。版本歷史記錄的應該是程式碼的發展,而不是開發者在編碼時的活動。

只有在開發分支上每個commit都有其獨自存在的意義,並且能夠編譯通過的情況下(能夠通過測試就更完美了),才應該選擇預設的合併方式來保留commit歷史。

--no-ff 

Create a merge commit even when the merge resolves as a fast-forward. This is the default behaviour when merging an annotated (and possibly signed) tag. 

我們在將Develop分支釋出到Master分支時,可能採用如下的命令:

  # 切換到Master分支

  git checkout master

  # 對Develop分支進行合併

  git merge --no-ff develop

這裡稍微解釋一下,上一條命令的--no-ff引數是什麼意思。

這個命令要通過git merge --help檢視其命令,後者會直接轉到一個網頁,才能看到其詳細說明

預設情況下,Git執行"快進式合併"(fast-farward merge),會直接將Master分支指向Develop分支。

示圖1-1

git merge簡介 - hubingforever - 民主與科學

 

示圖1-2

命令:

git checkout master

git merge robin_local

git merge簡介 - hubingforever - 民主與科學

 使用--no-ff引數後,會執行正常合併,在Master分支上生成一個新節點。為了保證版本演進的清晰,我們希望採用這種做法。關於合併的更多解釋,請參考Benjamin Sandofsky的《Understanding the Git Workflow》。示圖2-1

git merge簡介 - hubingforever - 民主與科學

 

示圖2-2

命令:

git checkout master

git merge robin_local

git merge簡介 - hubingforever - 民主與科學

 

圖3

git merge簡介 - hubingforever - 民主與科學

 
以下是一篇來自於哈佛大學關於git merge的文章

英文地址:http://www.eecs.harvard.edu/~cduan/technical/git/git-3.shtml 

Merging

After you have finished implementing a new feature on a branch, you want to bring that new feature into the main branch, so that everyone can use it. You can do so with the git merge or git pull command.

The syntax for the commands is as follows:

git merge [head] 
git pull . [head] 

They are identical in result. (Though the merge form seems simpler for now, the reason for the pull form will become apparent when discussing multiple developers.)

These commands perform the following operations. Let the current head be called current, and the head to be merged calledmerge.

  1. Identify the common ancestor of current and merge. Call it ancestor-commit.
  2. Deal with the easy cases. If the ancestor-commit equals merge, then do nothing. If ancestor-commit equals current, then do a fast forward merge.
  3. Otherwise, determine the changes between the ancestor-commit and merge.
  4. Attempt to merge those changes into the files in current.
  5. If there were no conflicts, create a new commit, with two parents, current and merge. Set current (and HEAD) to point to this new commit, and update the working files for the project accordingly.
  6. If there was a conflict, insert appropriate conflict markers and inform the user. No commit is created.

Important note: Git can get very confused if there are uncommitted changes in the files when you ask it to perform a merge. So make sure to commit whatever changes you have made so far before you merge.

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 rungit 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.

 

如果沒有衝突的話,merge完成。有衝突的話,git會提示那個檔案中有衝突,比如有如下衝突:

<<<<<<< HEAD:test.c

printf (“test1″);

=======

printf (“test2″);

>>>>>>> issueFix:test.c

可以看到 ======= 隔開的上半部分,是 HEAD(即 master 分支,在執行 merge 命令時檢出的分支)中的內容,下半部分是在 issueFix 分支中的內容。解決衝突的辦法無非是二者選其一或者由你親自整合到一起。比如你可以通過把這段內容替換為下面這樣來解決:

printf (“test2″);

這個解決方案各採納了兩個分支中的一部分內容,而且刪除了 <<<<<<<,=======,和>>>>>>> 這些行。

在解決了所有檔案裡的所有衝突後,執行git add 將把它們標記為已解決(resolved)。

然後使用git commit命令進行提交,merge就算完成了

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.

碼農學演講:

拔草還是種花

小城故事

相關文章