3 # Perform pre-gc linking of packs and objects to forks
5 # It may, under extremely unusual circumstances, be desirable to run git gc
6 # manually. However, running git gc on a project that has forks is dangerous
7 # as it can reap objects not in use by the project itself but which are still
8 # in use by one or more forks which do not have their own copy since they use
9 # an alternates file to refer to them.
11 # Running this script on a project BEFORE manually running git gc on that
12 # project prevents this problem from occuring.
14 # Note that a .nogc file should really be created during the manual gc
15 # operation on a project!
17 # Alternatively, if a project is to be removed but its forks are to be kept
18 # then this script MUST be run before removing the project so as not to corrupt
19 # the forks that will be kept.
21 # Before the new order of gc came along this script did various things to
22 # try and optimize what it hard-linked down into the forks. Now, however,
23 # it just hard-links all packs and loose objects down since with the new order
24 # both packs and objects could end up going away.
26 # This technique is not as optimal as the prior version, but with the advent
27 # of the new order for running gc and the ability to trigger/force a Girocco gc
28 # on a project using the "projtool.pl" command there's really no legitimate
29 # reason to use this script anymore other than when keeping the forks of a
30 # project while discarding the project itself.
32 # In that case all packs and objects must be hard-linked down to the child
33 # fork(s). That functionality is all that remains in this script. It accepts
34 # and ignores the previous options (for backwards compatibility) and just
35 # always does that now.
37 # The single mode of operation makes maintenance of this script easier too.
49 Usage: $(basename "$0") [option ...] <project-name>
50 --force Run even though no .nogc or .bypass file present
51 --single-pack Ignored for backwards compatibility
52 --include-packs Ignored for backwards compatibility
53 <project-name> Name of project (e.g. "git" or "git/fork" etc.)
54 Always hard-links all packs and all loose objects down to forks.
58 --single-pack|
--include-packs)
63 echo "Unknown option: $1" >&2; exit 1;;
69 if [ "$#" -ne 1 ] ||
[ -z "$proj" ]; then
70 echo "I need a project name (e.g. \"$(basename "$0") example\")"
71 echo "(See also help -- \"$(basename "$0") --help\")"
74 if ! cd "$cfg_reporoot/$proj.git"; then
75 echo "no such directory: $cfg_reporoot/$proj.git"
80 { read -r apid ahost ajunk
<gc.pid
; } >/dev
/null
2>&1 ||
:
81 if [ -n "$apid" ] && [ -n "$ahost" ]; then
82 echo "ERROR: refusing to run, $cfg_reporoot/$proj.git/gc.pid file exists"
83 echo "ERROR: is gc already running on machine '$ahost' pid '$apid'?"
87 if [ -z "$force" ] && ! [ -e .nogc
] && ! [ -e .bypass
]; then
88 echo "WARNING: no .nogc or .bypass file found in $cfg_reporoot/$proj.git"
89 echo "WARNING: jobd.pl could run gc.sh while you're fussing with $proj"
90 echo "WARNING: either create one of those files or re-run with --force"
91 echo "WARNING: (e.g. \"$(basename "$0") --force ${singlepack:+--single-pack }$proj\") to bypass this warning"
92 echo "WARNING: please remember to remove the file after you're done fussing"
96 # date -R is linux-only, POSIX equivalent is '+%a, %d %b %Y %T %z'
97 datefmt
='+%a, %d %b %Y %T %z'
99 trap 'echo "hard-linking failed" >&2; exit 1' EXIT
101 if has_forks_with_alternates
"$proj"; then
103 # We have to update the lastparentgc time in the child forks even if they do not get any
104 # new "loose objects" because they need to run gc just in case the parent now has some
105 # objects that used to only be in the child so they can be removed from the child.
106 # For example, a "patch" might be developed first in a fork and then later accepted into
107 # the parent in which case the objects making up the patch in the child fork are now
108 # redundant (since they're now in the parent as well) and need to be removed from the
109 # child fork which can only happen if the child fork runs gc.
111 # It is enough to copy objects just one level down and get_repo_list
112 # takes a regular expression (which is automatically prefixed with '^')
113 # so we can easily match forks exactly one level down from this project
116 get_repo_list
"$forkdir/[^/:][^/:]*:" |
118 # Ignore forks that do not exist or are symbolic links
119 ! [ -L "$cfg_reporoot/$fork.git" ] && [ -d "$cfg_reporoot/$fork.git" ] ||
121 # Or have an empty alternates file
122 ! is_empty_alternates_file
"$cfg_reporoot/$fork.git/objects/info/alternates" ||
124 # Match objects in parent project
125 for d
in objects
/$octet; do
126 [ "$d" != "objects/$octet" ] ||
continue
127 mkdir
-p "$cfg_reporoot/$fork.git/$d"
128 find -L "$d" -maxdepth 1 -type f
-name "$octet19*" -exec \
129 "$var_sh_bin" -c 'ln -f "$@" '"'$cfg_reporoot/$fork.git/$d/'" sh
'{}' + ||
:
131 # Match packs in parent project
132 mkdir
-p "$cfg_reporoot/$fork.git/objects/pack"
133 list_packs
--all --exclude-no-idx objects
/pack | LC_All
=C
sed 'p;s/\.pack$/.idx/' |
134 xargs "$var_sh_bin" -c 'ln -f "$@" '"'$cfg_reporoot/$fork.git/objects/pack/'" sh ||
:
135 if ! [ -e "$cfg_reporoot/$fork.git/.needsgc" ]; then
136 # Trigger a mini gc in the fork if it now has too many packs
137 packs
="$(list_packs --quiet --count --exclude-no-idx --exclude-keep "$cfg_reporoot/$fork.git
/objects
/pack
")" ||
:
138 if [ -n "$packs" ] && [ "$packs" -ge 20 ]; then
139 >"$cfg_reporoot/$fork.git/.needsgc"
142 git
--git-dir="$cfg_reporoot/$fork.git" update-server-info
143 # Update the fork's lastparentgc date
144 git
--git-dir="$cfg_reporoot/$fork.git" config gitweb.lastparentgc
"$(date "$datefmt")"
149 echo "packs and loose objects for $proj have now been linked into child forks (if any)"