Skip to content

Commit 952ea77

Browse files
committed
add git-shallow-maker
1 parent 4e7c3fc commit 952ea77

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

git/git-shallow-maker

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#! /usr/bin/env bash
2+
3+
# git-shallow-maker
4+
# copy only needed commits to a new repo
5+
# MIT license
6+
7+
set -e
8+
9+
if [[ $# != 2 ]]; then
10+
echo usage: git-shallow-maker path/to/old/repo path/to/new/repo
11+
exit 1
12+
fi
13+
14+
old="$1"
15+
new="$2"
16+
17+
if ! [ -d "$old" ]; then
18+
echo "error: old is not a directory: $old"
19+
exit 1
20+
fi
21+
22+
if [ -e "$new" ]; then
23+
echo "warning: new exists: $new"
24+
echo "hit enter to continue"
25+
read
26+
fi
27+
28+
# get absolute paths
29+
old_abs=$(readlink -f "$old")
30+
new_abs=$(readlink -f "$new")
31+
32+
# https://stackoverflow.com/questions/38171899/how-to-reduce-the-depth-of-an-existing-git-clone
33+
34+
# git formats
35+
# https://git-scm.com/docs/pretty-formats
36+
37+
# TODO store in variable
38+
echo "size before:"
39+
du -sh "$old"/.git
40+
41+
# debug: list branches
42+
echo "branches:"
43+
TZ=UTC0 git -C "$old" branch --list --format '%(objectname) %(authordate:iso-local) %(refname)'
44+
45+
# get head commit of all branches (including master/main/...)
46+
# https://stackoverflow.com/questions/36026185/name-only-option-for-git-branch-list
47+
# https://stackoverflow.com/questions/51362007/collecting-a-list-of-all-branches-in-a-repository-in-a-special-format-git
48+
branch_revs=$(git -C "$old" branch --list --format '%(objectname)')
49+
50+
# find oldest commit shared by all branches
51+
# https://git-scm.com/docs/git-merge-base
52+
# octopus: find the best common ancestor of *all* commits
53+
# all: print all results if ambiguous
54+
if false; then
55+
# manually set oldest_commit
56+
# useful when working with broken repos
57+
oldest_commit=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
58+
else
59+
oldest_commit=$(git -C "$old" merge-base --octopus --all $branch_revs)
60+
if [[ -z "$oldest_commit" ]]; then
61+
echo "error: oldest_commit was not found"
62+
exit 1
63+
fi
64+
if [[ $(echo "$oldest_commit" | wc -l) != 1 ]]; then
65+
# TODO no error?
66+
echo "error: oldest_commit is ambiguous:"
67+
echo "$oldest_commit"
68+
exit 1
69+
fi
70+
fi
71+
72+
echo "found oldest commit:"
73+
#git show $oldest_commit
74+
echo $oldest_commit
75+
# TODO fix format
76+
#TZ=UTC0 git show --format '%(objectname) %(authordate:iso-local) %(refname)' $oldest_commit
77+
78+
if false; then
79+
# delete all remote branches
80+
# https://stackoverflow.com/a/73330580/10440128
81+
# TODO delete only unused branches
82+
#git branch -rd $(git branch -r | grep -v 'origin/HEAD')
83+
extra_remote_branches=$(git -C "$old" branch -r | grep -v -F '/HEAD -> ' || true)
84+
if [[ -n "$extra_remote_branches" ]]; then
85+
git -C "$old" branch -rd $extra_remote_branches
86+
fi
87+
fi
88+
89+
# what did not work ...
90+
if false; then
91+
# delete old commits
92+
# https://stackoverflow.com/questions/4698759/converting-git-repository-to-shallow/7937916#7937916
93+
# https://stackoverflow.com/questions/33906288/delete-history-in-local-repository-instead-of-cloning-it-again-with-depth-1
94+
echo "deleting commits before $oldest_commit"
95+
echo "hit enter to continue"
96+
read
97+
echo $oldest_commit > .git/shallow
98+
(set -x
99+
#git reflog expire --expire=0
100+
# In order to remove all references, add --all to the reflog command --Jiyong Park
101+
git -C "$old" reflog expire --expire=now --all
102+
git -C "$old" prune
103+
#error: Could not read 29026cc404895cc9f9afa55c4e2d53b7a4a5a319
104+
#fatal: Failed to traverse parents of commit 0478f8b360288a4be8c71bf11e42fcaf09b8b773
105+
git -C "$old" prune-packed
106+
)
107+
elif false; then
108+
echo $oldest_commit > .git/shallow
109+
(set -x
110+
git -C "$old" gc
111+
git -C "$old" repack -Ad # kills in-pack garbage
112+
git -C "$old" repack -Ad || true
113+
# error: Could not read 29026cc404895cc9f9afa55c4e2d53b7a4a5a319
114+
# fatal: Failed to traverse parents of commit 0478f8b360288a4be8c71bf11e42fcaf09b8b773
115+
# fatal: failed to run repack
116+
#
117+
# -> some commits are missing, repo is broken
118+
# solution: patch parents
119+
# broken_commit=0478f8b360288a4be8c71bf11e42fcaf09b8b773; git replace --graft $oldest_commit $broken_commit
120+
git -C "$old" prune # kills loose garbage
121+
)
122+
123+
# what *does* work
124+
elif true; then
125+
# https://stackoverflow.com/questions/49039959/git-clone-specific-list-of-branches
126+
# https://stackoverflow.com/questions/54181901/fetching-only-the-range-of-commits-not-present-in-base-branch
127+
echo "creating shallow repo: $new"
128+
mkdir -p "$new"
129+
git -C "$new" init
130+
branch_refs=$(git -C "$old" branch --list --format '%(refname)')
131+
main_branch=refs/heads/master # TODO
132+
echo "looping branches:"
133+
echo "$branch_refs"
134+
# "git rev-list" fails on a broken repo:
135+
# git -C nixpkgs/ rev-list --count b00aa8ded74..master
136+
# error: Could not read 29026cc404895cc9f9afa55c4e2d53b7a4a5a319
137+
# fatal: revision walk setup failed
138+
# -> use git log + grep -m1
139+
# git -C nixpkgs/ log --format=%H master | grep -m1 -n ^b00aa8ded74
140+
# 48272:b00aa8ded743862adc8d6cd3220e91fb333b86d3
141+
for branch in $branch_refs; do
142+
echo "branch: $branch"
143+
# https://stackoverflow.com/questions/31997999/number-of-commits-between-two-commitishes
144+
#depth=$(git -C "$old" TODO)
145+
146+
if branch_base=$(git -C "$old" merge-base $main_branch $branch); then
147+
148+
#depth=$(git -C "$old" rev-list --count $branch_base..$branch)
149+
depth=$(git -C "$old" log --format=%H $branch | grep -m1 -n -x $branch_base | cut -d: -f1)
150+
if [[ "$depth" == 0 ]]; then
151+
# branch is main branch
152+
#continue
153+
branch_base=$oldest_commit
154+
#depth=$(git -C "$old" rev-list --count $branch_base..$branch)
155+
depth=$(git -C "$old" log --format=%H $branch | grep -m1 -n -x $branch_base | cut -d: -f1)
156+
fi
157+
depth=$((depth + 1))
158+
echo "branch_base: $branch_base"
159+
echo "depth: $depth"
160+
(set -x
161+
#git -C "$new" fetch file://$old $oldest_commit..$branch:$branch # invalid refspec
162+
#git -C "$new" fetch file://$old $oldest_commit...$branch:$branch # invalid refspec
163+
git -C "$new" fetch file://$old_abs $branch:$branch --depth $depth
164+
)
165+
166+
else
167+
echo "dangling branch: no path to master branch"
168+
echo "fetching the whole branch"
169+
git -C "$new" fetch file://$old_abs $branch:$branch
170+
fi
171+
#exit # debug
172+
done
173+
else
174+
echo noop
175+
fi
176+
177+
echo "size after:"
178+
du -sh "$new"/.git

0 commit comments

Comments
 (0)