git rebase 经验

作者通过Git命令实现两个Kernel的合并,并分享了合并过程中的经验与技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

By cwhuang, 2009 年 06 月 17 日為了玩 Android,學會了 git 的初步使用。不過僅止於基本的 git checkout、git log、git diff、git status、git 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 initInitialized 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 samsungremote: 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-v1From 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 androidremote: 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.29From 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.273fa8749e584b55f1180411ab1b51117190bac1e5$ git show 3fa8749e584b55f1180411ab1b51117190bac1e5commit 3fa8749e584b55f1180411ab1b51117190bac1e5Author: Linus Torvalds Date: Thu Oct 9 15:13:53 2008 -0700 Linux 2.6.27diff --git a/Makefile b/Makefileindex 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.294a6908a3a050aacc9c3a2f36b276b46c0629ad91$ git show 4a6908a3a050aacc9c3a2f36b276b46c0629ad91commit 4a6908a3a050aacc9c3a2f36b276b46c0629ad91Author: Linus Torvalds Date: Wed Dec 24 15:26:37 2008 -0800 Linux 2.6.28 Happy holidays..diff --git a/Makefile b/Makefileindex 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.27First, 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 apiApplying: PM: Enable early suspend through /sys/power/stateApplying: 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:29error: drivers/leds/Makefile: patch does not applyUsing index info to reconstruct a base tree...Falling back to patching base and 3-way merge...Auto-merged drivers/leds/KconfigAuto-merged drivers/leds/MakefileApplying: 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.27error: patch failed: drivers/misc/Kconfig:475error: drivers/misc/Kconfig: patch does not applyerror: patch failed: drivers/misc/Makefile:30error: drivers/misc/Makefile: patch does not applyUsing index info to reconstruct a base tree...Falling back to patching base and 3-way merge...Auto-merged drivers/misc/KconfigCONFLICT (content): Merge conflict in drivers/misc/KconfigAuto-merged drivers/misc/MakefileCONFLICT (content): Merge conflict in drivers/misc/MakefileFailed to merge in the changes.Patch failed at 0016. 由這些訊息可看出,前 15 個修改被成功的 apply 上去,但第 16 個產生 conflicts。先用 git status 看看問題出在哪裡:$ git statusdrivers/misc/Kconfig: needs mergedrivers/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/Makefileobj-$(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 回到合併前的狀態。
<think>我们被要求详细解释git rebase的操作流程。根据引用内容,我们可以总结出以下步骤和注意事项: 1. **git rebase的基本概念**: - Rebase用于将当前分支的提交移动到另一个分支的顶端,从而创建更线性的提交历史[^3]。 - 与`git merge`不同,rebase不会产生合并提交,而是通过重新应用提交来重写历史[^4]。 2. **git rebase的标准操作流程**(以将feature分支rebase到master分支为例): a. 切换到feature分支:`git checkout feature` b. 执行rebase命令:`git rebase master` - 这相当于将feature分支的基底从原来的提交改为master分支的最新提交[^3]。 c. 如果遇到冲突,需要解决冲突: - 使用`git status`查看冲突文件[^2]。 - 编辑冲突文件,解决冲突。 - 将解决后的文件添加到暂存区:`git add <file>` 或 `git add -u`(添加所有已跟踪文件的修改)[^2]。 - 继续rebase过程:`git rebase --continue`[^2]。 d. 如果解决冲突过程中想放弃本次rebase,可以执行:`git rebase --abort`[^2]。 3. **交互式rebase(Interactive Rebase)**: - 使用`git rebase -i <base_branch>`或`git rebase -i HEAD~n`(n表示最近n次提交)进入交互模式[^1]。 - 在交互式界面中,可以修改提交(如合并提交、修改提交信息、重新排序提交等)。 4. **单人开发时使用rebase的好处**: - 当拉取公共分支(如master)最新代码时,使用`git pull --rebase`(或`git pull -r`)可以使提交历史更简洁[^4]。 5. **注意事项**: - Rebase会改变提交历史,因此不推荐在公共分支(多人协作的分支)上使用,以免造成混乱[^4]。 - 使用rebase后,当前分支的基底会改变,因此可能无法直接看出该分支最初是从哪个分支拉出来的[^4]。 下面详细说明操作步骤: ### 详细操作步骤 #### 场景:将feature分支rebase到master分支的最新提交 1. **确保当前分支是feature分支**: ```bash git checkout feature ``` 2. **执行rebase命令**: ```bash git rebase master ``` - 执行此命令后,Git会尝试将feature分支上的提交逐个应用到master分支的顶端。 3. **处理冲突**: - 如果在rebase过程中出现冲突,Git会暂停并提示冲突信息。此时需要: a. 使用`git status`查看冲突文件(标记为“Unmerged paths”)[^2]。 b. 手动编辑这些文件,解决冲突(删除冲突标记,保留所需内容)。 c. 将解决后的文件添加到暂存区: ```bash git add <file1> <file2> ... # 或一次性添加所有已跟踪文件的修改 git add -u ``` d. 继续rebase: ```bash git rebase --continue ``` - 重复此过程,直到所有提交都成功应用。 4. **跳过冲突提交或终止rebase**: - 如果想跳过当前冲突的提交(丢弃该提交的更改),可执行: ```bash git rebase --skip ``` - 如果想完全放弃rebase操作,回到rebase前的状态,执行: ```bash git rebase --abort ``` 5. **完成rebase**: - 当所有提交成功应用后,feature分支的基点就变成了master分支的最新提交,形成线性历史。 #### 交互式rebase操作流程 1. **启动交互式rebase**: ```bash git rebase -i master # 对当前分支基于master进行交互式rebase # 或 git rebase -i HEAD~3 # 修改最近3次提交 ``` 2. **编辑提交列表**: - 文本编辑器会打开一个提交列表,例如: ``` pick 1a2b3c Commit message 1 pick 4d5e6f Commit message 2 pick 7g8h9i Commit message 3 ``` - 可以修改命令(如将`pick`改为`squash`、`edit`、`reword`等)并调整提交顺序。 3. **保存退出后,根据指令操作**: - 如果使用`squash`,Git会合并提交并提示编辑新的提交信息。 - 如果使用`edit`,Git会在应用该提交时暂停,允许修改提交内容(修改后使用`git commit --amend`,然后`git rebase --continue`)。 ### 总结 - **主要命令**:`git rebase <base_branch>`, `git rebase --continue`, `git rebase --abort` - **冲突解决**:编辑冲突文件 → `git add` → `git rebase --continue` - **交互模式**:`git rebase -i` 用于修改提交历史[^1][^4] 使用rebase可以使提交历史更清晰,但需注意避免在公共分支上使用[^4]。 §§相关问题§§ 1. `git rebase`和`git merge`有什么区别? 2. 如何解决rebase过程中的冲突? 3. 交互式rebasegit rebase -i)有哪些常用操作?</think>### Git Rebase 操作流程详解 `git rebase` 用于将当前分支的提交移动到目标分支的顶端,实现线性提交历史。以下是标准操作流程和注意事项: --- #### **一、基础操作流程** 1. **切换到待变基分支** ```bash git checkout feature # 切换到需要变基的分支 ``` 2. **执行 rebase 命令** ```bash git rebase master # 将 feature 分支的提交移动到 master 分支顶端[^3] ``` - 等价命令:`git rebase master feature`[^3] 3. **处理冲突(如有)** - 若发生冲突,按顺序解决: ```bash git status # 查看冲突文件[^2] # 手动编辑冲突文件,解决冲突 git add -u # 将解决后的文件加入暂存区[^2] git rebase --continue # 继续变基过程[^2] ``` - 若需放弃变基: ```bash git rebase --abort # 完全终止变基[^1] ``` 4. **完成变基** - 无冲突时自动完成,历史变为线性结构。 --- #### **二、关键场景详解** 1. **单人开发更新公共分支** ```bash git pull --rebase # 拉取远程最新代码并变基[^4] ``` - 优势:避免冗余合并提交,历史更简洁[^4] - 注意:会改变提交基底,可能丢失原始分支信息[^4] 2. **交互式变基(修改提交历史)** ```bash git rebase -i HEAD~3 # 修改最近3次提交 ``` - 常用操作: - `pick`:保留提交 - `squash`:合并到前一个提交 - `edit`:修改提交内容 - `drop`:删除提交[^1] --- #### **三、注意事项** 1. **禁止在公共分支使用** - 已推送到远程的分支**禁止**变基,会破坏他人历史记录[^4]。 2. **冲突解决循环** 典型工作流: ```bash while (存在冲突) { git status → 编辑冲突 → git add -u → git rebase --continue if (需终止) { git rebase --abort; break; } }[^2] ``` 3. **与 merge 对比** | **操作** | 提交历史 | 适用场景 | |----------|----------|------------------| | `rebase` | 线性 | 本地分支整理 | | `merge` | 有合并点 | 公共分支协作 | --- #### **四、操作示意图** ```mermaid gitGraph commit id: "A" branch feature checkout feature commit id: "B" commit id: "C" checkout main commit id: "D" checkout feature rebase main # 将 B、C 移动到 D 之后 ``` > **结果**:提交顺序变为 A → D → B' → C'(B/C 生成新哈希值) --- **总结流程**: 1. 切到待变基分支 → 2. 执行 `git rebase 目标分支` → 3. 解决冲突(循环) → 4. 完成线性历史 谨慎用于公共分支,推荐本地分支整理[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值