分享

Git rebase 的應用經驗

 jemeen 2012-02-14

為了玩 Android,學會了 git 的初步使用。不過僅止於基本的 git checkoutgit loggit diffgit statusgit commit 等。

這幾天為了協助同事將 Android 移植到廠商的板子上,必須將廠商提供的 kernel Android kernel 做結合。為此請教一些 git 高手。經過一番練習,總算對 git rebase 的使用有了初步的掌握。也漸漸了解了 git 的強大威力,為什麼高手都愛用… 特別將這段經驗記載在這邊,給有興趣的人參考。

有兩個 git repositories 要做合併。一個是廠商提供的 kernel

git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/samsung-ap-2.6.git

另一個是 Android kernel

git://android.git.kernel.org/kernel/common.git

首先,先建立一個工作目錄

$ mkdir kernel-git

$ cd kernel-git

$ git init

Initialized empty Git repository in /home/cwhuang/git/kernel-git/.git/

然後加入兩個遠端的 repositories

$ git remote add samsung git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/samsung-ap-2.6.git

$ git remote add android git://android.git.kernel.org/kernel/common.git

將遠端 repositories 的資料取回:

$ git fetch samsung

remote: Counting objects: 11677, done.

remote: Compressing objects: 100% (2462/2462), done.

remote: Total 10383 (delta 7976), reused 10138 (delta 7743)

Receiving objects: 100% (10383/10383), 5.04 MiB, done.

Resolving deltas: 100% (7976/7976), completed with 324 local objects.

From git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/samsung-ap-2.6.git

 * [new branch]      master     -> samsung/master

 * [new tag]         v2.6.28.6-samsung-v1 -> v2.6.28.6-samsung-v1

From git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/samsung-ap-2.6.git

 * [new tag]         v2.6.28-rc4-s3c64xx -> v2.6.28-rc4-s3c64xx

 * [new tag]         v2.6.28-rc4-s5pc1xx -> v2.6.28-rc4-s5pc1xx

 * [new tag]         v2.6.28-rc5-s3c64xx -> v2.6.28-rc5-s3c64xx

 * [new tag]         v2.6.28-rc5-s5pc1xx -> v2.6.28-rc5-s5pc1xx

 * [new tag]         v2.6.28-rc6-s3c64xx -> v2.6.28-rc6-s3c64xx

 * [new tag]         v2.6.28-rc6-s5pc1xx -> v2.6.28-rc6-s5pc1xx

 * [new tag]         v2.6.28-rc7-s3c64xx -> v2.6.28-rc7-s3c64xx

 * [new tag]         v2.6.28-rc7-s5pc1xx -> v2.6.28-rc7-s5pc1xx

 * [new tag]         v2.6.28-rc8-s3c64xx -> v2.6.28-rc8-s3c64xx

 * [new tag]         v2.6.28-rc8-s5pc1xx -> v2.6.28-rc8-s5pc1xx

 * [new tag]         v2.6.28-rc8-s5pc1xx-v1 -> v2.6.28-rc8-s5pc1xx-v1

 * [new tag]         v2.6.28.6-samsung -> v2.6.28.6-samsung

 

$ git fetch android

remote: Counting objects: 1077412, done.

remote: Compressing objects: 100% (176782/176782), done.

Receiving objects: 100% (1077412/1077412), 263.30 MiB | 28369 KiB/s, done.

remote: Total 1077412 (delta 896526), reused 1076403 (delta 895639)

Resolving deltas: 100% (896526/896526), done.

From git://android.git.kernel.org/kernel/common.git

 * [new branch]      2.6.27     -> android/2.6.27

 * [new branch]      2.6.29     -> android/2.6.29

From git://android.git.kernel.org/kernel/common.git

 * [new tag]         v2.6.12    -> v2.6.12

 * [new tag]         v2.6.12-rc2 -> v2.6.12-rc2

(skipped...)

 * [new tag]         v2.6.29-rc8 -> v2.6.29-rc8

看看有哪些 branches?

$ git branch -a

  android/2.6.27

  android/2.6.29

  samsung/master

在合併之前,先了解一下已存在的 branches。我們可以先看看這些 branches 的共同祖先(common ancestor)

$ git merge-base samsung/master android/2.6.27

3fa8749e584b55f1180411ab1b51117190bac1e5

 

$ git show 3fa8749e584b55f1180411ab1b51117190bac1e5

commit 3fa8749e584b55f1180411ab1b51117190bac1e5

Author: Linus Torvalds

Date:   Thu Oct 9 15:13:53 2008 -0700

 

    Linux 2.6.27

 

diff --git a/Makefile b/Makefile

index ce9eceb..16e3fbb 100644

--- a/Makefile

+++ b/Makefile

@@ -1,7 +1,7 @@

 VERSION = 2

 PATCHLEVEL = 6

 SUBLEVEL = 27

-EXTRAVERSION = -rc9

+EXTRAVERSION =

 NAME = Rotary Wombat

 

 # *DOCUMENTATION*

 

$ git merge-base samsung/master android/2.6.29

4a6908a3a050aacc9c3a2f36b276b46c0629ad91

 

$ git show 4a6908a3a050aacc9c3a2f36b276b46c0629ad91

commit 4a6908a3a050aacc9c3a2f36b276b46c0629ad91

Author: Linus Torvalds

Date:   Wed Dec 24 15:26:37 2008 -0800

 

    Linux 2.6.28

 

    Happy holidays..

 

diff --git a/Makefile b/Makefile

index 4c8d797..71e98e9 100644

--- a/Makefile

+++ b/Makefile

@@ -1,7 +1,7 @@

 VERSION = 2

 PATCHLEVEL = 6

 SUBLEVEL = 28

-EXTRAVERSION = -rc9

+EXTRAVERSION =

 NAME = Erotic Pickled Herring

 

 # *DOCUMENTATION*

因此 branch samsung/master android/2.6.27 都是從 v2.6.27 來的,而 samsung/master android/2.6.29 則從 v2.6.28 而來。事實上,不難驗證 samsung/master 是從 v2.6.28.6 改來的。

可以用 gitk 這個圖形化工具來看看從 v2.6.27 android/2.6.27 的變化:

$ gitk v2.6.27..android/2.6.27

同樣的,samsung/master 的變化是:

$ gitk v2.6.28..samsung/master

我們要決定如何進行合併。可以將 samsung 的修改合併到 Android kernel,也可以將 Android 的修改合併到 samsung kernel。我決定選擇後者,因為從 gitk 可以看出 Android 的變化相當簡單而清楚,就是單線發展而已。相對的,samsung kernel 就併來併去,線條亂七八糟,看得眼花瞭亂。因此將 Android 的修改併到 samsung kernel,應該比較簡單而容易成功。

可以用 git rebase 來進行合併。首先,建立一個新的本地 branch 來保存合併結果:

$ git branch --track samsung-android samsung/master

然後用 git rebase 指令,將 v2.6.27 android/2.6.27 的修改,一個一個的 apply samsung-android 這個 branch 中:

$ git rebase --whitespace=fix --onto samsung-android v2.6.27 android/2.6.27

First, rewinding head to replay your work on top of it...

Applying: PM: Add wake lock api.

Applying: PM: Add early suspend api.

Applying: PM: Implement wakelock api.

Applying: PM: Implement early suspend api

Applying: PM: Enable early suspend through /sys/power/state

Applying: PM: Add user-space wake lock api.

Applying: PM: wakelock: Abort task freezing if a wake lock is held.

Applying: PM: earlysuspend: Add console switch when user requested sleep state changes.

Applying: PM: earlysuspend: Removing dependence on console.

Applying: rtc: Add android alarm driver.

Applying: rtc: Try to prevent RTC errors from accumulating.

Applying: ledtrig-sleep: Add led trigger for sleep debugging.

error: patch failed: drivers/leds/Makefile:29

error: drivers/leds/Makefile: patch does not apply

Using index info to reconstruct a base tree...

Falling back to patching base and 3-way merge...

Auto-merged drivers/leds/Kconfig

Auto-merged drivers/leds/Makefile

Applying: PM: Wait for console in resume.

Applying: PM: Fix suspend_console/resume_console use only one semaphore.

Applying: switch: switch class and GPIO drivers.

Applying: lowmemorykiller: Initial support for 2.6.27

error: patch failed: drivers/misc/Kconfig:475

error: drivers/misc/Kconfig: patch does not apply

error: patch failed: drivers/misc/Makefile:30

error: drivers/misc/Makefile: patch does not apply

Using index info to reconstruct a base tree...

Falling back to patching base and 3-way merge...

Auto-merged drivers/misc/Kconfig

CONFLICT (content): Merge conflict in drivers/misc/Kconfig

Auto-merged drivers/misc/Makefile

CONFLICT (content): Merge conflict in drivers/misc/Makefile

Failed to merge in the changes.

Patch failed at 0016.

由這些訊息可看出,前 15 個修改被成功的 apply 上去,但第 16 個產生 conflicts。先用 git status 看看問題出在哪裡:

$ git status

drivers/misc/Kconfig: needs merge

drivers/misc/Makefile: needs merge

# Not currently on any branch.

# Changes to be committed:

#   (use "git reset HEAD ..." to unstage)

#

#       new file:   drivers/misc/lowmemorykiller.c

#

# Changed but not updated:

#   (use "git add ..." to update what will be committed)

#

#       unmerged:   drivers/misc/Kconfig

#       unmerged:   drivers/misc/Makefile

#

可以看出有兩個檔案有 conflicts,必須手動修改。例如,在 drivers/misc/Makefile conflicts 大約在 35 39 行:

<<<<<<< HEAD:drivers/misc/Makefile

obj-$(CONFIG_C2PORT)            += c2port/

=======

obj-$(CONFIG_LOW_MEMORY_KILLER) += lowmemorykiller.o

>>>>>>> lowmemorykiller: Initial support for 2.6.27:drivers/misc/Makefile

不難看出,這兩行都要加到 Makefile 中。因此我改成:

obj-$(CONFIG_C2PORT)            += c2port/

obj-$(CONFIG_LOW_MEMORY_KILLER) += lowmemorykiller.o

接著

$ git add drivers/misc/Makefile

用同樣的方法修改 drivers/misc/Kconfig,然後

$ git rebase --continue

如此會繼續合併的過程。當然可能產生其它的 conflicts,都用類似的方法修正,直到 rebase 完成。

如果覺得某個產生 conflicts 的修改是不必要的,可以跳過:

$ git rebase --skip

如果覺得 conflicts 太複雜了,不知要麼修改,想要放棄,可以

$ git rebase --abort

如此會放棄所有的合併結果,而將 source tree 回到合併前的狀態。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多