Skip to content

Commit f8c511d

Browse files
committed
with some note
1 parent 6f55d3a commit f8c511d

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed

TUTORIAL.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Add subtrac-enhanced submodule to a parent project:
2+
3+
```sh
4+
git clone [email protected]:example/parent.git
5+
cd parent/
6+
git submodule [email protected]:example/dep.git ../dep
7+
git add .gitmodules dep
8+
git commit -m 'add submodule'
9+
cp /path/to/git-subtrac/git-fix-modules.sh .
10+
./git-fix-modules.sh
11+
git subtrac --auto-exclude update
12+
git push origin master master.trac
13+
cd ..
14+
```
15+
16+
Another contributor clones parent repo and makes local change in a submodule:
17+
18+
```sh
19+
git clone --recurse-submodules [email protected]:example/parent.git another-parent
20+
cd another-parent
21+
./git-fix-modules.sh
22+
cd dep
23+
git checkout master
24+
25+
echo 'local change' >> README
26+
git commit -m 'locally patch dep' README
27+
cd ..
28+
git commit -m 'record change in parent' dep
29+
git subtrac --auto-exclude update
30+
git push origin master master.trac
31+
cd ..
32+
```
33+
34+
Bring in changes from upstream and rebase:
35+
36+
```sh
37+
cd parent/dep
38+
git fetch
39+
git rebase origin/master
40+
git commit -m 'rebase dep on upstream changes' dep
41+
git push origin master
42+
cd ../..
43+
```
44+
45+
Share changes with upstream:
46+
47+
```sh
48+
cd parent/dep
49+
git push origin master
50+
cd ../..
51+
```

scripts/git-fix-modules.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/bin/sh
2+
# A more helpful replacement for 'git submodule update --init'.
3+
#
4+
# It leaves the remote 'origin' pointing at the upstream projects, but can
5+
# use local git-subtrac branches as a data source so that most of the time
6+
# it doesn't actually need to fetch from the upstream.
7+
#
8+
# Use this whenever you want to get your submodules back in sync.
9+
#
10+
set -e
11+
cd "$(dirname "$0")" # move to git worktree root
12+
topdir="$PWD" # absolute path of git worktree root
13+
14+
# For initial 'git submodule update', the --no-fetch option is ignored,
15+
# and it tries to talk to the origin repo for no good reason. Let's override
16+
# the origin repo URL to fool git into not doing that.
17+
# 当你首次运行 git submodule update 命令时,尽管你使用了 --no-fetch 选项,
18+
# Git 仍然会尝试从原始的远程仓库(origin repo)获取数据。
19+
# 为了避免 Git 尝试从原始的远程仓库获取数据,你可以更改子模块的远程仓库 URL。
20+
# 这会"欺骗" Git,使其认为远程仓库的位置已经改变,从而避免不必要的数据获取。
21+
git submodule status | while read -r commit path junk; do
22+
git submodule init -- "$path"
23+
done
24+
git config --local --get-regexp '^submodule\..*\.url$' | while read k v; do
25+
git config "$k" .
26+
done
27+
28+
# In each submodule, make sure info/alternates is set up to retrieve
29+
# objects directly from the parent repo (git-subtrac objects), bypassing
30+
# the need to fetch anything. If someone has previously checked out a
31+
# submodule without setting these values, this will fix them up.
32+
# 在每个子模块中设置 info/alternates 文件,以便从父仓库(在这种情况下,是 git-subtrac 对象)
33+
# 直接检索 Git 对象,从而避免任何需要获取(fetch)的操作。
34+
# 在 Git 中,info/alternates 文件是一种机制,它允许一个仓库直接从另一个仓库的对象数据库中读取对象,
35+
# 而无需将这些对象复制或移动到自己的对象数据库中。这在一些情况下可能很有用,例如当你想节省磁盘空间或提高性能时。
36+
# 如果有人以前签出了一个子模块而没有设置这些值,这将修复它们。
37+
for config in .git/modules/*/config; do
38+
[ -f "$config" ] || continue
39+
40+
dir=$(dirname "$config")
41+
echo "$topdir/.git/objects" >"$dir/objects/info/alternates"
42+
done
43+
44+
# Make sure any remaining submodules have been checked out at least once,
45+
# referring to the toplevel repo for all objects.
46+
# 这段代码的目的是确保所有剩余的子模块至少被检出一次,所有对象的引用都指向顶级仓库。
47+
#
48+
# TODO(apenwarr): --merge is not always the right option.
49+
# eg. when checking out old revisions, we'd rather just roll the submodule
50+
# backwards too. But git submodule doesn't have a good way to do that
51+
# safely, so after a checkout, you can run git-stash-all.sh by hand to
52+
# rewind the submodules.
53+
# --merge 并不总是正确的选项。
54+
# 例如,当检出旧的修订版本时,我们宁愿让子模块也回滚到旧版本。
55+
# 然而,git submodule 没有一个好的方法来安全地做这个操作,
56+
# 所以在检出之后,你可以手动运行 git-stash-all.sh 来回滚子模块。
57+
# git submodule update --init --no-fetch --reference="$PWD" --recursive --merge 命令执行了以下操作:
58+
# --init:初始化子模块。如果子模块还没有初始化,这个选项会初始化它们。
59+
# --no-fetch:不获取新的数据。这个选项告诉 Git 不要从远程仓库获取新的数据。
60+
# --reference="$PWD":使用当前工作目录作为引用。这个选项告诉 Git 使用当前工作目录作为所有 Git 对象的引用。
61+
# --recursive:递归处理所有子模块。如果你的子模块中还有子模块,这个选项会告诉 Git 也要处理这些子模块。
62+
# --merge:合并子模块的改变。这个选项告诉 Git 如果子模块的当前提交和新的提交有冲突,应该尝试合并这些更改。
63+
git submodule update --init --no-fetch --reference="$PWD" --recursive --merge
64+
65+
# Make sure all submodules are *now* (after initial checkout) using the
66+
# latest URL from .gitmodules for their 'origin' URL.
67+
# 这段代码的目的是确保所有子模块在初始检出(initial checkout)后都使用 .gitmodules 文件中最新的 URL 作为他们的 'origin' URL。
68+
# 即恢复到原始状态
69+
# --quiet:安静模式。在执行操作时不输出任何信息。
70+
# sync:同步操作。这个命令将更新每个子模块的 'origin' URL,以匹配 .gitmodules 文件中的 URL。
71+
# --recursive:递归处理所有子模块。如果你的子模块中还有子模块,这个选项会告诉 Git 也要处理这些子模块。
72+
git submodule --quiet sync --recursive
73+
74+
git submodule status --cached | while read -r commit path junk; do
75+
# fix superproject conflicts caused by trying to merge submodules,
76+
# if any. These happen when two different commits try to change the
77+
# same submodule in incompatible ways. To resolve it, we'll check out
78+
# the first one and try to git merge the second. (Why git can't just
79+
# do this by itself is... one of the many problems with submodules.)
80+
# 修复由于尝试合并子模块而导致的超级项目冲突,
81+
# 如果有的话。这些冲突发生在两个不同的提交试图以不兼容的方式更改同一个子模块时。
82+
# 为了解决这个问题,我们将检出第一个提交,并尝试将第二个提交进行 git 合并。
83+
# (为什么 Git 不能自动做这个操作是……这是使用子模块的众多问题之一。)
84+
cid2=
85+
cid3=
86+
git ls-files --unmerged -- "$path" | while read -r mode hash rev junk; do
87+
if [ "$rev" = "2" ]; then
88+
(cd "$path" && git checkout "$hash" -- || true)
89+
cid2=$hash
90+
fi
91+
if [ "$rev" = "3" ]; then
92+
cid3=$hash
93+
(cd "$path" && git merge "$hash" -- || true)
94+
git add -- "$path"
95+
fi
96+
done
97+
98+
commit=${commit#-}
99+
commit=${commit#+}
100+
(
101+
cd "$path"
102+
103+
main=$(git rev-parse --verify --quiet main || true)
104+
head=$(git rev-parse --verify HEAD)
105+
106+
if [ -n "$main" ] &&
107+
! git merge-base main "$commit" >/dev/null; then
108+
# main and $commit have no common history.
109+
# It's probably dangerous. Move it aside.
110+
git branch -f -m main main.probably-broken
111+
fi
112+
113+
# update --merge can't rewind the branch, only move it
114+
# forward. Give a warning if we notice this problem.
115+
if [ "$head" != "$commit" ]; then
116+
echo "$path:" >&2
117+
echo " Couldn't checkout non-destructively." >&2
118+
echo " You can try to fix it by hand, or" >&2
119+
echo " use git-stash-all.sh if you want to force it." >&2
120+
fi
121+
)
122+
done

tests/test.sh

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/bin/sh
2+
3+
mkdir playground
4+
cd playground
5+
6+
# make (bare) parent.git repo
7+
mkdir parent
8+
cd parent
9+
git init
10+
echo parent > README
11+
cp ~/src/swanbase/git-fix-modules.sh .
12+
git add README git-fix-modules.sh
13+
git commit -m 'initial parent commit'
14+
mv .git ../parent.git
15+
cd ..
16+
rm -fr parent
17+
cd parent.git
18+
git config --bool core.bare true
19+
cd ..
20+
21+
# make (bare) dep.git repo
22+
mkdir dep
23+
cd dep
24+
git init
25+
echo dep > README
26+
git add README
27+
git commit -m 'initial dep commit'
28+
mv .git ../dep.git
29+
cd ..
30+
rm -fr dep
31+
cd dep.git
32+
git config --bool core.bare true
33+
cd ..
34+
35+
# repo owner: add dep as a subtrac-enhanced submodule
36+
git clone parent.git parent
37+
cd parent/
38+
git submodule add ../dep
39+
git add .gitmodules dep
40+
git commit -m 'add submodule'
41+
./git-fix-modules.sh
42+
git subtrac --auto-exclude update
43+
git push origin master master.trac
44+
cd ..
45+
46+
# repo contributor: clone
47+
git clone --recurse-submodules parent.git another-parent
48+
cd another-parent
49+
./git-fix-modules.sh
50+
cd dep
51+
git checkout master
52+
53+
# repo contributor: make local change
54+
echo 'local change' >> README
55+
git commit -m 'locally patch dep' README
56+
cd ..
57+
git commit -m 'record change in parent' dep
58+
git subtrac --auto-exclude update
59+
git push origin master master.trac
60+
cd ..
61+
62+
# upstream change
63+
git clone dep.git dep
64+
cd dep
65+
echo 'upstream change' >> README
66+
git commit -m 'upstream change' README
67+
git push origin master
68+
cd ..
69+
70+
# rebase parent/dep after upstream change
71+
cd parent/dep
72+
git fetch
73+
git rebase origin/master
74+
git commit -m 'rebase dep on upstream changes' dep
75+
git push origin master
76+
77+
# push parent/dep changes to upstream
78+
cd parent/dep
79+
git push origin master

0 commit comments

Comments
 (0)