从一份经过开发板厂商深度定制过的SDK压缩包,经过整个流程(5份shell脚本+1份python脚本)的处理。
得到一份可以一键式拉取就可以正确编译出镜像,且镜像能够正常运行的深度修复的由若干(一般几十到一百多个)子仓库组成的SDK代码。

4-verify-sync.sh 的 6 项断言结果:重建出来的 58 仓库与只读基线逐字节比对。3 项 FAIL 是逐项判定后接受的差异,不是没跑完 —— 每一项的取舍见下文一、做了什么
输入
厂商给到手的就是一个 tarball,没有任何 repo 链路:
体积 10G
-rwxrwxrwx 1 developer developer 10G Jul 31 19:44 <share>/02.Products/rk3576/rk3576-linux-6.1_20260709.tar.xz
.repo 不存在
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src/rk3576-linux-6.1-readonly$ find . -name ".repo"
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src/rk3576-linux-6.1-readonly$
所有 .git 都是指向那个不存在的 .repo 的软链接
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src/rk3576-linux-6.1-readonly$ find . -name ".git" -exec ls -lhat {} \;
lrwxrwxrwx 1 developer developer 28 Jun 22 17:46 ./u-boot/.git -> ../.repo/projects/u-boot.git
lrwxrwxrwx 1 developer developer 32 Jun 22 17:38 ./kernel-6.1/.git -> ../.repo/projects/kernel-6.1.git
lrwxrwxrwx 1 developer developer 27 Nov 20 2025 ./rkbin/.git -> ../.repo/projects/rkbin.git
lrwxrwxrwx 1 developer developer 47 Jun 22 17:28 ./external/rknn-toolkit2/.git -> ../../.repo/projects/external/rknn-toolkit2.git
lrwxrwxrwx 1 developer developer 41 Jun 22 17:40 ./external/libmali/.git -> ../../.repo/projects/external/libmali.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:42 ./external/rknn-llm/.git -> ../../.repo/projects/external/rknn-llm.git
lrwxrwxrwx 1 developer developer 41 Jun 22 17:38 ./external/uvc_app/.git -> ../../.repo/projects/external/uvc_app.git
lrwxrwxrwx 1 developer developer 44 Jun 22 17:42 ./external/minilogger/.git -> ../../.repo/projects/external/minilogger.git
lrwxrwxrwx 1 developer developer 49 Jun 22 17:37 ./external/security/bin/.git -> ../../../.repo/projects/external/security/bin.git
lrwxrwxrwx 1 developer developer 57 Jun 22 17:37 ./external/security/rk_tee_user/.git -> ../../../.repo/projects/external/security/rk_tee_user.git
lrwxrwxrwx 1 developer developer 57 Jun 22 17:37 ./external/security/librkcrypto/.git -> ../../../.repo/projects/external/security/librkcrypto.git
lrwxrwxrwx 1 developer developer 40 Jun 22 17:37 ./external/rockit/.git -> ../../.repo/projects/external/rockit.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:37 ./external/rkupdate/.git -> ../../.repo/projects/external/rkupdate.git
lrwxrwxrwx 1 developer developer 47 Jun 22 17:37 ./external/rockchip-test/.git -> ../../.repo/projects/external/rockchip-test.git
lrwxrwxrwx 1 developer developer 53 Jun 22 17:38 ./external/camera_engine_rkaiq/.git -> ../../.repo/projects/external/camera_engine_rkaiq.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:38 ./external/chromium/.git -> ../../.repo/projects/external/chromium.git
lrwxrwxrwx 1 developer developer 46 Jun 22 17:37 ./external/rkwifibt-app/.git -> ../../.repo/projects/external/rkwifibt-app.git
lrwxrwxrwx 1 developer developer 37 Jun 22 17:42 ./external/mpp/.git -> ../../.repo/projects/external/mpp.git
lrwxrwxrwx 1 developer developer 45 Jun 22 17:38 ./external/alsa-config/.git -> ../../.repo/projects/external/alsa-config.git
lrwxrwxrwx 1 developer developer 38 Jun 22 17:39 ./external/dpdk/.git -> ../../.repo/projects/external/dpdk.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:37 ./external/rkwifibt/.git -> ../../.repo/projects/external/rkwifibt.git
lrwxrwxrwx 1 developer developer 37 Jun 22 17:38 ./external/avs/.git -> ../../.repo/projects/external/avs.git
lrwxrwxrwx 1 developer developer 46 Jun 22 17:42 ./external/rk_pcba_test/.git -> ../../.repo/projects/external/rk_pcba_test.git
lrwxrwxrwx 1 developer developer 50 Jun 22 17:39 ./external/common_algorithm/.git -> ../../.repo/projects/external/common_algorithm.git
lrwxrwxrwx 1 developer developer 37 Jun 22 17:39 ./external/iva/.git -> ../../.repo/projects/external/iva.git
lrwxrwxrwx 1 developer developer 46 Jun 22 17:39 ./external/ethercat_igh/.git -> ../../.repo/projects/external/ethercat_igh.git
lrwxrwxrwx 1 developer developer 41 Jun 22 17:38 ./external/uac_app/.git -> ../../.repo/projects/external/uac_app.git
lrwxrwxrwx 1 developer developer 41 Jun 22 17:37 ./external/samples/.git -> ../../.repo/projects/external/samples.git
lrwxrwxrwx 1 developer developer 43 Jun 22 17:37 ./external/rktoolkit/.git -> ../../.repo/projects/external/rktoolkit.git
lrwxrwxrwx 1 developer developer 43 Jun 22 17:42 ./external/linux-rga/.git -> ../../.repo/projects/external/linux-rga.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:42 ./external/recovery/.git -> ../../.repo/projects/external/recovery.git
lrwxrwxrwx 1 developer developer 41 Jun 22 17:38 ./external/xserver/.git -> ../../.repo/projects/external/xserver.git
lrwxrwxrwx 1 developer developer 44 Jun 22 17:39 ./external/drm-cursor/.git -> ../../.repo/projects/external/drm-cursor.git
lrwxrwxrwx 1 developer developer 40 Jun 22 17:42 ./external/rkfsmk/.git -> ../../.repo/projects/external/rkfsmk.git
lrwxrwxrwx 1 developer developer 52 Jun 22 17:39 ./external/gstreamer-rockchip/.git -> ../../.repo/projects/external/gstreamer-rockchip.git
lrwxrwxrwx 1 developer developer 44 Jun 22 17:37 ./external/rockit_uvc/.git -> ../../.repo/projects/external/rockit_uvc.git
lrwxrwxrwx 1 developer developer 40 Jun 22 17:33 ./external/rknpu2/.git -> ../../.repo/projects/external/rknpu2.git
lrwxrwxrwx 1 developer developer 27 Jun 22 17:45 ./tools/.git -> ../.repo/projects/tools.git
lrwxrwxrwx 1 developer developer 32 Jun 22 17:35 ./docs/cn/.git -> ../../.repo/projects/docs/cn.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:36 ./docs/cn/RK3576/.git -> ../../../.repo/projects/docs/cn/RK3576.git
lrwxrwxrwx 1 developer developer 26 Jun 22 17:35 ./docs/.git -> ../.repo/projects/docs.git
lrwxrwxrwx 1 developer developer 38 Jun 22 17:38 ./docs/rtt-docs/.git -> ../../.repo/projects/docs/rtt-docs.git
lrwxrwxrwx 1 developer developer 32 Jun 22 17:37 ./docs/en/.git -> ../../.repo/projects/docs/en.git
lrwxrwxrwx 1 developer developer 42 Jun 22 17:38 ./docs/en/RK3576/.git -> ../../../.repo/projects/docs/en/RK3576.git
lrwxrwxrwx 1 developer developer 39 Jun 22 17:29 ./app/rkpartybox/.git -> ../../.repo/projects/app/rkpartybox.git
lrwxrwxrwx 1 developer developer 34 Jun 22 17:29 ./app/rkadk/.git -> ../../.repo/projects/app/rkadk.git
lrwxrwxrwx 1 developer developer 43 Jun 22 17:28 ./app/ipcweb-backend/.git -> ../../.repo/projects/app/ipcweb-backend.git
lrwxrwxrwx 1 developer developer 34 Jun 22 17:29 ./app/rkipc/.git -> ../../.repo/projects/app/rkipc.git
lrwxrwxrwx 1 developer developer 38 Jun 22 17:28 ./app/lvgl_demo/.git -> ../../.repo/projects/app/lvgl_demo.git
lrwxrwxrwx 1 developer developer 116 Jun 22 17:43 ./prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/.git -> ../../../../../.repo/projects/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.git
lrwxrwxrwx 1 developer developer 117 Jun 22 17:42 ./prebuilts/gcc/linux-x86/aarch64/arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-elf/.git -> ../../../../../.repo/projects/prebuilts/gcc/linux-x86/aarch64/arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-elf.git
lrwxrwxrwx 1 developer developer 114 Jun 22 17:44 ./prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/.git -> ../../../../../.repo/projects/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.git
lrwxrwxrwx 1 developer developer 109 Jun 22 17:44 ./prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux/.git -> ../../../../../.repo/projects/prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.git
lrwxrwxrwx 1 developer developer 40 Jun 22 17:33 ./device/rockchip/.git -> ../../.repo/projects/device/rockchip.git
lrwxrwxrwx 1 developer developer 31 Jun 22 17:29 ./buildroot/.git -> ../.repo/projects/buildroot.git
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src/rk3576-linux-6.1-readonly$
输出
| 项目 | 结果 |
|---|---|
| 独立 Git 仓库 | 58 个 |
| 清单仓库 | default.xml(manifest),托管在 <server>/<GROUP>/ |
| 客户端拉取 | 3 条命令(repo init / repo sync -j8 --verify / repo forall -c 'git lfs pull') |
| 体积 | 编译前 ~28G,编译后 ~78G |
| 校验 | 4-verify-sync.sh,6 项自动断言 |
| 交付文档 | 纯命令、零理论;8 类故障 + 对应处置 |
| 验收 | 同事独立编译 + 烧写,均成功 |
客户端拉取(完整,无省略)
repo init -u http://<server>/<GROUP>/manifest.git -b main -m default.xml --no-clone-bundle
repo sync -j8 --verify
repo start main --all
repo forall -c 'git lfs pull'
除了
repo start main --all之外的三条都不能省。--verify少了会停在(yes/always/NO)交互提示上,默认 NO, 于是 repo hook 不执行、空目录不出现、编译可能直接失败;git lfs pull少了只有 17G 而不是 28G,编译报文件损坏。
验收
| 时间点 | 画面 |
|---|---|
00:43 | 烧写开始 |
01:28 | 烧写完成,工具报成功 |
01:39 | 首次启动完成,出现 shell / 登录提示 |
02:13 | DDR 测试开始 |
02:57 | 敲下 reboot |
03:15 | 重启后再次起来 |
DDR 测试未全部跑完,但已验证 bin 可被执行,代表文件系统的基础功能正常。(假设 DDR 若有问题,可能要结合 kernel 进行调试,这属于 BSP 的工作范畴。)
一镜到底表明经过完整的代码控制的sdk是能够编译出可以正常运行的系统完整镜像的,而且这中间的验证过程是后期无感的,不需要特殊调试的,即使用者根本不需要知道到底sdk与原版被厂商毁掉repo的tarball比起来经过哪些修改。

重启可以确保从ROM->uboot->kernel的这条链路能够不止一次的被加载,而且加载成功,一次启动的成功还可能有一些底层软件的原因会被隐藏,但是如果能够两次成功启动,底层软件应是没有问题的。
4-verify-sync.sh 做的是重建结果与只读基线之间的文件级比对。下面是 2026-08-11 10:14 那一次的完整输出,OVERALL: FAIL —— 贴的是带 FAIL 的这一次,没有挑一次全 PASS 的来贴。6 项断言里 Top level、Empty directories、Symlink targets 通过,Structure、Permissions、Content 报 FAIL,这三项为什么可以接受,见下文与第二节。
4-verify-sync.sh 完整输出(点开)
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src$ time /development/src/sdk/linux/SalvageOfSDK.git/4-verify-sync.sh \
--baseline-dir /development/src/sdk/linux/sdk-src/rk3576-linux-6.1-readonly \
--candidate-dir /development/src/sdk/linux/sdk-src/clone-aug06-v2 \
--work-dir ./verify-aug06
==> baseline: /development/src/sdk/linux/sdk-src/rk3576-linux-6.1-readonly
==> candidate: /development/src/sdk/linux/sdk-src/clone-aug06-v2
==> work dir: /development/src/sdk/linux/sdk-src/./verify-aug06 (kept)
==> content: full byte-for-byte comparison
==> listing baseline ...
==> listing candidate ...
==> section 1: top level
==> section 2: structure
==> section 3: empty directories
==> section 4: symlink targets
==> section 5: permissions
==> section 6: content -- reading every byte of both trees, this is the slow part ...
============================================================================
Tree comparison report
============================================================================
generated 2026-08-11 10:14:04 HKT
baseline /development/src/sdk/linux/sdk-src/rk3576-linux-6.1-readonly
candidate /development/src/sdk/linux/sdk-src/clone-aug06-v2
excluded .git, .repo and .hooks directories, everywhere
listings /development/src/sdk/linux/sdk-src/./verify-aug06
An entry "in baseline only" is one the rebuild failed to reproduce. One "in
candidate only" is one it introduced. Neither tree was modified by this run.
SUMMARY
-------
1. Top level PASS (0 differing entries)
2. Structure FAIL (140 differing entries)
3. Empty directories PASS (0 differing directories)
4. Symlink targets PASS (0 differing symlinks)
5. Permissions FAIL (2 differing entries, 0 not umask-consistent)
6. Content FAIL (16 differing files, 0 uncomparable)
OVERALL: FAIL
============================================================================
1. Top level
============================================================================
baseline 18 top-level entries
candidate 18 top-level entries
[PASS] both trees hold the same top-level entries
============================================================================
2. Structure (every entry, with type)
============================================================================
baseline 188793 entries
candidate 188689 entries
IN BASELINE ONLY -- the rebuild did not reproduce these (122):
f external/rkwifibt/drivers/bcmdhd/.Module.symvers.cmd
f external/rkwifibt/drivers/bcmdhd/.aiutils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcm_app_utils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd.ko.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd.mod.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd.mod.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd_pcie.ko.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd_pcie.mod.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd_pcie.mod.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmdhd_pcie.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmevent.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmsdh.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmsdh_linux.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmsdh_sdmmc.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmsdh_sdmmc_linux.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmstdlib_s.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmutils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmwifi_channels.o.cmd
f external/rkwifibt/drivers/bcmdhd/.bcmxtlv.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_ccode.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_cdc.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_cfg80211.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_common.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_config.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_custom_gpio.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_dbg_ring.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_debug.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_debug_linux.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_flowring.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_gpio.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_ip.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_exportfs.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_lb.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_pktdump.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_platdev.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_rx.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_sched.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_tx.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_linux_wq.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_mschdbg.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_msgbuf.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_pcie.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_pcie_linux.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_pno.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_sdio.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_static_buf.o.cmd
f external/rkwifibt/drivers/bcmdhd/.dhd_wlfc.o.cmd
f external/rkwifibt/drivers/bcmdhd/.frag.o.cmd
f external/rkwifibt/drivers/bcmdhd/.fwpkg_utils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.hnd_pktpool.o.cmd
f external/rkwifibt/drivers/bcmdhd/.hnd_pktq.o.cmd
f external/rkwifibt/drivers/bcmdhd/.hndpmu.o.cmd
f external/rkwifibt/drivers/bcmdhd/.linux_osl.o.cmd
f external/rkwifibt/drivers/bcmdhd/.linux_pkt.o.cmd
f external/rkwifibt/drivers/bcmdhd/.linuxerrmap.o.cmd
f external/rkwifibt/drivers/bcmdhd/.modules.order.cmd
f external/rkwifibt/drivers/bcmdhd/.pcie_core.o.cmd
f external/rkwifibt/drivers/bcmdhd/.sbutils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.siutils.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_android.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_android_ext.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfg80211.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfg_btcoex.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfgp2p.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfgscan.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfgvendor.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_cfgvif.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_escan.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_event.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_iapsta.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_iw.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_linux_mon.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_roam.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wl_timer.o.cmd
f external/rkwifibt/drivers/bcmdhd/.wldev_common.o.cmd
f external/rkwifibt/drivers/bcmdhd/Module.symvers
f external/rkwifibt/drivers/bcmdhd/bcmdhd.ko
f external/rkwifibt/drivers/bcmdhd/bcmdhd.mod
f external/rkwifibt/drivers/bcmdhd/bcmdhd.mod.c
f external/rkwifibt/drivers/bcmdhd/bcmdhd_pcie.ko
f external/rkwifibt/drivers/bcmdhd/bcmdhd_pcie.mod
f external/rkwifibt/drivers/bcmdhd/bcmdhd_pcie.mod.c
f external/rkwifibt/drivers/bcmdhd/modules.order
f external/rkwifibt/drivers/bluetooth_uart_driver/.Module.symvers.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_h4.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_ldisc.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_rtk_h5.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_uart.ko.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_uart.mod.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_uart.mod.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.hci_uart.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.modules.order.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/.rtk_coex.o.cmd
f external/rkwifibt/drivers/bluetooth_uart_driver/Module.symvers
f external/rkwifibt/drivers/bluetooth_uart_driver/hci_uart.ko
f external/rkwifibt/drivers/bluetooth_uart_driver/hci_uart.mod
f external/rkwifibt/drivers/bluetooth_uart_driver/hci_uart.mod.c
f external/rkwifibt/drivers/bluetooth_uart_driver/modules.order
f external/rkwifibt/drivers/bluetooth_usb_driver/.Module.symvers.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.modules.order.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_bt.o.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_btusb.ko.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_btusb.mod.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_btusb.mod.o.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_btusb.o.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_coex.o.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/.rtk_misc.o.cmd
f external/rkwifibt/drivers/bluetooth_usb_driver/Module.symvers
f external/rkwifibt/drivers/bluetooth_usb_driver/modules.order
f external/rkwifibt/drivers/bluetooth_usb_driver/rtk_btusb.ko
f external/rkwifibt/drivers/bluetooth_usb_driver/rtk_btusb.mod
f external/rkwifibt/drivers/bluetooth_usb_driver/rtk_btusb.mod.c
f external/xserver/debian/local/xvfb-run.1
f kernel-6.1/.scmversion
f kernel-6.1/drivers/bluetooth/Module.symvers
f kernel-6.1/drivers/net/wireless/rockchip_wlan/Module.symvers
f kernel-6.1/drivers/net/wireless/rockchip_wlan/aic8800/Module.symvers
f kernel-6.1/drivers/net/wireless/rockchip_wlan/rtl8733bu/Module.symvers
f u-boot/.checkpatch.conf
f u-boot/.travis.yml
IN CANDIDATE ONLY -- these are not in the baseline (18):
f buildroot/.gitattributes
f debian/.gitattributes
f device/rockchip/.gitattributes
f docs/.gitattributes
f docs/cn/.gitattributes
f docs/en/.gitattributes
f external/camera_engine_rkaiq/.gitattributes
f external/chromium/.gitattributes
f external/libmali/.gitattributes
f external/rknn-llm/.gitattributes
f external/rknn-toolkit2/.gitattributes
f external/rknpu2/.gitattributes
f kernel-6.1/drivers/gpu/arm/bifrost/.gitignore
f kernel-6.1/tools/testing/selftests/arm64/.gitignore
f prebuilts/gcc/linux-x86/aarch64/arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-elf/.gitattributes
f prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/.gitattributes
f tools/.gitattributes
f ubuntu/.gitattributes
[FAIL] 122 only in baseline, 18 only in candidate
============================================================================
3. Empty directories
============================================================================
baseline 39 empty directories
candidate 39 empty directories
[PASS] both trees hold the same empty directories
Note: git has no way to store an empty directory. One present in the
baseline and absent from the candidate is therefore expected, and will
recur on every fresh sync -- it is not a transient fault. Closing the gap
needs either a placeholder file committed into each such directory, which
makes the candidate differ by that file instead, or a post-sync step that
recreates them from a recorded list.
============================================================================
4. Symlink targets
============================================================================
baseline 535 symlinks
candidate 535 symlinks
[PASS] both trees hold the same symlinks
============================================================================
5. Permissions
============================================================================
Mode histogram, baseline:
16698 d 755
22 d 775
163666 f 644
120 f 664
7739 f 755
13 f 775
535 l 777
Mode histogram, candidate:
16696 d 755
24 d 775
163562 f 644
120 f 664
7739 f 755
13 f 775
535 l 777
2 entries differ. By transition (count, type, baseline, candidate, class):
2 d 755 775 umask
Class 'umask' means the owner's bits are identical and only the group or
other bits differ. Git stores one permission bit per file -- the owner
execute bit -- so it cannot carry the rest; they come from the umask of
the shell that created the file. A whole tree shifted this way points at
the environment, not at the commit: umask 022 yields 755 and 644, umask
002 yields 775 and 664. This is consistency, not proof -- it is what a
umask difference looks like, and nothing here rules out another cause.
Class 'owner-exec' is never dismissed: that bit IS in the commit, so a
difference means the two trees disagree about whether a file is runnable.
Every difference is confined to group and other bits.
full list: /development/src/sdk/linux/sdk-src/./verify-aug06/modes.diff
[FAIL] 2 entries differ, all umask-consistent (see the note above)
============================================================================
6. Content (byte for byte)
============================================================================
Compared with: diff -qr --no-dereference, excluding .git and .repo.
Symlinks are compared as links, not followed.
FILES WHOSE CONTENT DIFFERS (16):
buildroot/.gitignore
device/rockchip/.chips/rk3576/topeet_rk3576_defconfig
device/rockchip/.gitignore
external/camera_engine_rkaiq/.gitignore
external/dpdk/.gitignore
external/mpp/.gitignore
external/mpp/build/.gitignore
external/rkwifibt/.gitignore
external/xserver/.gitignore
kernel-6.1/.gitignore
kernel-6.1/arch/arm64/boot/Image
kernel-6.1/arch/arm64/boot/Image.lz4
kernel-6.1/arch/arm64/kernel/vdso/vdso.so
kernel-6.1/arch/arm64/kernel/vdso/vdso.so.dbg
kernel-6.1/drivers/gpu/arm/mali400/mali/__malidrv_build_info.c
u-boot/.gitignore
[FAIL] 16 file(s) differ, 0 path(s) could not be compared
==> overall: FAIL
==> Read the SUMMARY at the top of the report, then the sections it marks FAIL.
==> Every count in the summary is backed by a file in /development/src/sdk/linux/sdk-src/./verify-aug06,
==> named in the section that reports it.
real 15m46.062s
user 0m7.975s
sys 0m38.760s
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src$
其中 Structure(140 项)是唯一需要逐项人工过的:它筛出两边文件列表的异同,遇到一项就得进到对应目录去看既有的 .gitignore。这个 .gitignore 是核心 —— 若原版目录根本没有这份过滤列表,就只能自建,而自建需要对整个包有「基础 60 分」的理解才写得出来,才有底气判断某个文件到底是不是可以被过滤掉的临时产物。上面记录里的这 140 项,是我逐项筛查过的。
另一类差异是 IN CANDIDATE ONLY -- these are not in the baseline (18):,即只在新 SDK 里才有的文件。这 18 个是 16 个 .gitattributes 加 2 个 .gitignore:.gitattributes 是启用 LFS 之后比旧 SDK 多出来的,那 2 个 .gitignore 是我手动新建的,用来管理对应目录下的文件。
总耗时:1859 分钟(约 31 小时)。
二、难在哪
核心陷阱:.gitignore 并非 100% 可信
上游厂商基于RK的公版SDK进行深度的定制,然后分发给他自己的客户,作为终端客户拿到的只是一个tarball,而不是用repo管理的一个url,虽然RK原版SDK是用Repo(git)进行代码管理。 上游厂商的定制时基本完全抛弃git管理,在被.gitignore拉黑的目录里存在重要的文件。例如以下这六个头文件:
external/camera_engine_rkaiq/.gitignore/rkaiq/algos/ae/rk_aiq_algo_ae_itf.h
external/camera_engine_rkaiq/.gitignore/rkaiq/algos/af/rk_aiq_algo_af_itf.h
external/camera_engine_rkaiq/.gitignore/rkaiq/algos/asd/rk_aiq_algo_asd_itf.h
external/camera_engine_rkaiq/.gitignore/rkaiq/algos/awb/rk_aiq_algo_awb_itf.h
external/camera_engine_rkaiq/.gitignore/rkaiq/algos_camgroup/ae/rk_aiq_algo_camgroup_ae_itf.h
external/camera_engine_rkaiq/.gitignore/rkaiq/algos_camgroup/awb/rk_aiq_algo_camgroup_awb_itf.h
若不将他们放进git的白名单列表,在最终编译的时候将会直接报错“Not such file xxxx”。 可是若直接查看原.gitignore会发现,这里的所有header和source都是黑名单成员:
developer@rk3576-rk3576_ubuntu-22-04:~/sdk/linux/sdk-src/clone-aug06-v2$ cat external/camera_engine_rkaiq/.gitignore | grep algos\/ae
rkaiq/algos/ae/linux/rv1106/aarch64
rkaiq/algos/aeis/linux/
rkaiq/algos/ae/*.cpp
rkaiq/algos/ae/*.h
这是无法全脚本自动化执行的内容,需要工程师以丰富的经验和快速的学习能力去判断是否要相信当前的.gitignore。 所幸的是,大部分错误并不致命,一般在编译阶段都能被发现,只要发现后加入git白名单即可编译通过。
具体战果
| 现象 | 定位 | 处置 |
|---|---|---|
u-boot | descriptor.bin 和 bl31.elf | 放行这 2 个文件 |
kernel-6.1 90 项缺失 | 其中 66 项确为产物 | 逐项判定后放行其余 |
external/mpp build/ 下 41 项被吞 | in-source cmake,该目录全是源码、0 产物 | 白名单放行 |
external/rkwifibt /debian/ 整目录消失 | 父级规则剪掉整个目录,git 不再递归进去 | 删掉父级那一行,不加替代——上游自带的 debian/.gitignore 13 行本就完整 |
external/dpdk | config/ppc 和 devtools 在内的 12 个文件 | 放行 |
external/xserver | 1 个 patch,不知道是否会自动 download,而且才 1.3KB | 放行 |
external/camera_engine_rkaiq 编译失败 | 6 个 rk_aiq_algo_*_itf.h 被吞 | 放行这 6 个头文件 |
上表中大部分能够一眼被我识别,唯独camera_engine_rkaiq这一行值得单独展开一段——那次失败编译花了 2h19min 才报错,
而且改完 .gitignore + repo sync 还不够,必须手工删掉 output/build/camera_engine*才会生效,因为buildroot的编译是把package复制或解压到output/latest/build目录下面进行编译的,唯有删掉这里的临时编译子目录才能触发新版的软件包被复制过来重新编译。
这种「反馈周期两小时」的排错体验,是这个项目难度之一所在,比任何架构图都更能说明问题。它都不致命,但是面对浩瀚的SDK目录树,而且大多数是不够熟悉的,这个挑战并不小。
git 结构性存不下的四类东西
| 类别 | 症状 | 处置 |
|---|---|---|
| 空目录 | 编译失败 | 记录清单,由 repo hook 在 sync 后重放 |
| 权限位 | 40 处 umask 差异 | 接受——验收底线是「能编译」,不是位级一致 |
| 大文件 | 少 11G,编译报文件损坏 | Git LFS + git lfs pull |
| 符号链接 | 6 个顶层链接失效 | 单独记录重建 |
这张表背后是两条原则。
第一:除了一眼就确定是垃圾的文件,我宁可错放,也不可错杀。
第二:我的目标是「能编译 + 能运行」,而不是「位级一致」。 因为上游开发板厂商的习惯可能也很糟糕,时常把临时文件带进最终的分发包里。正是这个思想,让我认为那 40 处 umask 差异可以不修,先看看编译会不会有问题。
四类东西各自的取舍:
- 空目录:不敢不加。所有脚本是否都会先做
mkdir -p并不一定,而且说不定有很多脚本会做if [ -d ${dir_name} ],那就会报错了。 - 大文件:LFS 需要手动
git lfs pull,这也不难,没做的话很快就会编译报错。 - 符号链接:这里最危险,谁也不知道内部做了什么软链接。顶层目录下还可以用 manifest 来创建,子目录里的软链接就都得靠
.gitignore来管理了,否则浩如烟海,所花之功夫甚巨。
三、做了什么判断
判断一:找对不变量
- 我原以为本次的SDK将会是「全树都没有任何
.git」。后来纠正:.git是有的,只是与原先的.repo链路断了。 - 所以项目边界的物证不在清单里,在文件系统里。
.repo/manifests/*.xml会丢、会被改坏、厂商可能根本不给;但每个子项目自己的.git目录一直在原地。
这里我做了一个两次任务的对比:
| 任务 | 项目列表怎么来 | 换一颗 SOC 要做什么 |
|---|---|---|
| RK 原版 SDK(2025) | 逐层 cat manifest XML,手抄进代码 | 全部重抄 |
| 厂商深度定制破坏版 SDK(2026) | find -name .git,自动推导 | 什么都不用改 |
需要说清楚的是:原版 SDK 我没有实际跑过。 上面是关于方法的判断,不是测试结论。
而下一版要做的,正是把这件事从「逻辑上成立」落到「结构上成立」——共性抽成一层,差异集中到另一层:
- 共性层:不依赖清单的判据 ——
.git即项目边界、6 项断言。 这一层对所有 SDK 是同一份代码。 - 差异层:每种 SDK 各自的应对方式 —— 清单在不在、目录布局、要放行哪些
.gitignore—— 全部收到一个地方,按上游项目名索引,而不是散在流程里。
这样加一种新 SDK 只动差异层,共性层一行不碰。也只有做到这一步,第四节那句「第二次比第一次快」才有结构上的依据,而不是一句愿望。
判断二:拒绝 git add -f
AI给过我一个最快的做法是 git add -f 把误杀的文件强行塞进去。可是我思考一会儿之后并没有同意,而是去改 .gitignore 本身。
给.gitignore这一道最佳屏障添加例外,这是一个饮血止渴的做法,这一步走出去,未来如果想回来,比重新做更难,因为要抽丝剥茧知道到底之前放过了什么文件。
「我知道有捷径,我算过代价后选择不走」,这是我的另一个工程思想。
判断三:凭据一次都不落盘
token 只作为参数传入,只在 push 的那一瞬间拼进 URL。
另外 git-lfs 会把带凭据的 push URL 打进日志,所以 3-publish-manifest.sh 只按严格白名单提交(default.xml + .gitignore)。
manifest 用 SSH 拉(不存凭据)、HTTP+PAT 推。例如:
<remote name="origin" fetch="ssh://git@<server>/<GROUP>/" />
这样就可以保证客户端进行拉取代码的时候走ssh,无感于password(gitlab目前是允许http走password验证的方法操作代码的)。
判断四:只读基线不可动摇
我有一份 readonly 的 SDK,这份代码是从 tarball 直接解压之后得到的,我手动设置为 sudo chmod a-x ./rk3576-sdk-readonly -R。
后期的 4-verify-sync.sh 就是一直对照这一份sdk作为baseline来进行比对。因为一旦被 2-rebuild.sh 操作过的sdk,至少内部的.git都会被建立为实际的.git目录。这样就与客户端repo sync下来的sdk有本质的区别了。
判断五:手动建立 main 分支
repo 的标准做法是建立一个detached的HEAD去track一个具体的commit,所以客户端最终修改完代码要提交时,就无法直接git commit & git push,因为没有branch。 我的做法是在每一个客户端拉取代码的时候增加一句代码:
repo start main --all
这样每一个仓库都有一个默认的分支,名为main了。
当然,如果你 2-rebuild.sh里用非main的分支名,那你可以改名,这样能够跟remote origin/${BRANCH_NAME} 一致,避免后期有认知负担,需要一直记得两个分支名,一个是本地分支,一个是远程分支。
附:常见故障与处置
Q1:repo init 失败,提示 fatal: ... unable to resolve "stable"
- 原因:
repo工具默认要检出名为stable的 repo 源码分支,而内部镜像的主分支是main。 - 处置:
repo init时用--repo-branch(或-b)指定正确的分支名。此问题已通过在最终部署命令里带上-b main而规避。
Q2:repo init 失败,提示 fatal: couldn't find remote ref refs/heads/master
原因:
repo默认从清单仓库的master分支取清单文件,而我们的清单仓库主分支是main。处置:
repo init时用-b(即--manifest-branch)指定正确的清单分支名。repo init -u <URL> -b main
Q3:国内无代理环境下,repo init 失败,连不上 gerrit.googlesource.com
原因:
repo启动器默认从 Google 下载它自己的完整程序。处置:管理员先在内部 GitLab 上建一个 repo 工具的镜像仓库(例如
<GROUP>/git-repo),用户repo init时用--repo-url指向这个内部镜像。repo init -u <清单URL> --repo-url=http://<server>/tools/git-repo.git ...
Q4:repo sync 失败,提示 HTTP Basic: Access denied,或被重定向到登录页
原因:走 HTTP 访问私有仓库,没有提供有效的认证信息。
处置一(URL 里嵌 PAT):在
repo init的-u和--repo-url两个 URL 里都嵌入username:PAT@。处置二(
~/.netrc,推荐):在家目录建~/.netrc存 GitLab 的认证信息,git 会自动读取,命令本身不用改。# ~/.netrc machine <server> login <user> password glpat-xxxxxxxx最终我们切换到了 SSH 方案,此问题不再出现。
Q5:repo sync 的 Checking out 阶段失败,提示 ManifestInvalidRevisionError: revision main in ... not found
- 原因:GitLab 上部分子项目仓库没有
main分支(可能保留了原始的master等分支名),与清单文件要求的revision="main"不符。 - 处置(管理员):跑一个脚本(如
migrate_sdk_intelligent_final.py),把所有子项目仓库的主分支统一重命名为main并推送到 GitLab。
Q6:repo sync 过程中出现大量 Invalid clone.bundle file; ignoring. 警告
- 原因:
repo去下载 GitLab 服务器上并不存在的clone.bundle性能优化文件。 - 处置(用户):
repo init时加--no-clone-bundle,可彻底消除这个无害警告。