|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Topgit 本地和远程分支的删除同步以及 git fetch --prune 分析" |
| 4 | +--- |
| 5 | + |
| 6 | +在 Google Group (需翻墙)上网友提了一个问题:“[Topgit 本地特性分支删除后,如何清理远程版本库中相应分支?](https://groups.google.com/forum/?fromgroups#!topic/gotgit/CSHRbi_JAcA)” |
| 7 | + |
| 8 | +这是一个非常好的问题,我也曾遇到,一直是以手工清除远程分支(及 Topgit 跟踪分支)的。 |
| 9 | + |
| 10 | + $ git push origin :t/feature-branch |
| 11 | + $ git push origin :top-bases/t/feature-branch |
| 12 | + |
| 13 | +好吧,为什么不“懒惰”一点,把清理远程版本库对应分支的工作写在 Topgit 代码中呢?于是写了一个补丁, |
| 14 | +见: |
| 15 | + |
| 16 | +* <https://github.com/ossxp-com/topgit/blob/master/debian/patches/t/delete-remote-branch.diff> |
| 17 | + |
| 18 | +同步删除远程版本库的 Topgit 特性分支和跟踪分支只完成了硬币的一面,另外一面是当远程版本库的 Topgit |
| 19 | +特性分支和跟踪分支被他人删除后,如何本地获知? |
| 20 | + |
| 21 | +直觉告诉我只要把 `tg-remote.sh` 代码中的 `git fetch` 命令换做 `git fetch --prune` 即可。 |
| 22 | +可是一试之下,大失所望,竟然将本地版本库所有 `refs/remotes/origin/top-bases/` 下的引用全部删除! |
| 23 | +难道这是 `git fetch --prune` 的 Bug? |
| 24 | + |
| 25 | +重新编译Git(去掉 -O2 增加 -ggdb 编译参数),以便用 `gdb` 调试。 |
| 26 | + |
| 27 | + $ gdb --args git fetch --prune |
| 28 | + |
| 29 | +最终从 `builtin/fetch.c` 的函数 `query_refspecs()` 返回值中看出端倪。 |
| 30 | + |
| 31 | +首先一个 Topgit 管理下的版本库,配置文件中会有如下的 fetch 配置: |
| 32 | + |
| 33 | + [remote "origin"] |
| 34 | + fetch = +refs/heads/*:refs/remotes/origin/* |
| 35 | + url = ... |
| 36 | + fetch = +refs/top-bases/*:refs/remotes/origin/top-bases/* |
| 37 | + |
| 38 | +其中的两条 `fetch` 配置,将远程版本库的 `refs/heads/*` 和 `refs/top-bases/*` 两个名字空间的引用 |
| 39 | +都获取到本地 `refs/remotes/origin` 名字空间下。 |
| 40 | + |
| 41 | +为清理本地陈旧的远程分支,先要根据上面两条 `fetch` 配置指令,反查出在远程版本库中的引用名称(见 |
| 42 | +`remote.c` 的 `match_name_with_pattern()` 函数)。对于 `refs/remotes/origin/top-bases/t/feature` 名字 |
| 43 | +的引用,在反查时上面两条 `fetch` 都能够返回查询结果,分别为: |
| 44 | + |
| 45 | +* `refs/heads/top-bases/t/feature` 和 |
| 46 | +* `refs/top-bases/t/feature` |
| 47 | + |
| 48 | +两个查询结果,前一个错,后一个对。按照上面顺序出现的 `fetch` 指令,导致解析出来的引用名称为前一个(错误的), |
| 49 | +显然无法在远程版本库的引用中找到,于是认为是过时的,于是将 `refs/remotes/origin/top-bases/t/feature` 删除。 |
| 50 | +一个最简单的解决方案是将上述两条 `fetch` 语句颠倒顺序,即可成功实现 `git fetch --prune` 。 |
| 51 | + |
| 52 | +Topgit 实现获取远程服务器特性分支时自动清理本地远程分支的补丁如下: |
| 53 | + |
| 54 | +* <https://github.com/ossxp-com/topgit/blob/master/debian/patches/t/prune-stale-remote-branch.diff> |
0 commit comments