clone/update: mark project changed on failure
[girocco.git] / toolbox / perform-pre-gc-linking.sh
blob174776e506ba3efe0056f02cfa2c8f06115041db
1 #!/bin/sh
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.
39 set -e
41 . @basedir@/shlib.sh
43 umask 002
45 force=
46 while case "$1" in
47 --help|-h)
48 cat <<EOT; exit 0;;
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.
55 EOT
56 --force)
57 force=1;;
58 --single-pack|--include-packs)
60 --)
61 shift; break;;
62 -?*)
63 echo "Unknown option: $1" >&2; exit 1;;
65 ! :;;
66 esac; do shift; done
68 proj="${1%.git}"
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\")"
72 exit 1
74 if ! cd "$cfg_reporoot/$proj.git"; then
75 echo "no such directory: $cfg_reporoot/$proj.git"
76 exit 1
78 apid=
79 ahost=
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'?"
84 exit 1
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"
93 exit 1
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
115 forkdir="$proj"
116 get_repo_list "$forkdir/[^/:][^/:]*:" |
117 while read fork; do
118 # Ignore forks that do not exist or are symbolic links
119 ! [ -L "$cfg_reporoot/$fork.git" ] && [ -d "$cfg_reporoot/$fork.git" ] ||
120 continue
121 # Or do not have a non-zero length alternates file
122 [ -s "$cfg_reporoot/$fork.git/objects/info/alternates" ] ||
123 continue
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 '{}' + || :
130 done
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")"
145 done
148 trap - EXIT
149 echo "packs and loose objects for $proj have now been linked into child forks (if any)"