What's cooking (2024/04 #07)
[alt-git.git] / Reintegrate
blob63340a9db583a70015683d40c1fe8dc15b9ed26e
1 #!/bin/sh
3 accept_rerere="--rerere-autoupdate"
4 generate=no
5 exec=:
6 update= diff= edit= stop_at_cut= skip_cocci= force_cocci= no_cocci=
7 while case "$#,$1" in 0,*) break;; *,-*) ;; esac
8 do
9 case "$1" in
10 -n) accept_rerere= ;;
11 -e) edit=t ;;
12 -c) stop_at_cut=1 ;;
13 -c?*) stop_at_cut=${1#-c} ;;
14 -d) update=${2?"diff with what?"}
15 diff=yes
16 generate=yes
17 shift ;;
18 -u) update=${2?"update what?"}
19 generate=yes
20 shift ;;
21 -x) exec=${2?exec}; shift ;;
22 -x?*) exec=${1#-x} ;;
23 -ss) skip_cocci=t ;;
24 -fs) force_cocci=t ;;
25 -ns) no_cocci=t ;;
26 *) generate=yes
27 break ;;
28 esac
29 shift
30 done
32 annotate_merge () {
33 test -f Meta/whats-cooking.txt || return 0
35 # NEEDSWORK: unify with cook::wildo_match
36 perl -e '
37 sub wildo_match {
38 s/^\s*//;
39 if (/^Will (?:\S+ ){0,2}(fast-track|hold|keep|merge|drop|discard|cook|kick|defer|eject|be re-?rolled|wait)[,. ]/ ||
40 /^Not urgent/ || /^Not ready/ || /^Waiting for / ||
41 /^Can wait in / || /^Still / || /^Stuck / || /^On hold/ || /^Breaks / ||
42 /^Needs? / || /^Expecting / || /^May want to / || /^Under review/) {
43 return 1;
45 return 0;
48 sub read_message {
49 my ($fh, $branch) = @_;
50 my ($in_section, $in_desc);
51 my @msg = ();
52 while (<$fh>) {
53 chomp;
54 if (/^\* \Q$branch\E /) {
55 $in_section = 1;
56 next;
58 last if (/^[-*\[]/ && $in_section);
59 next unless $in_section;
60 s/^\s+//;
61 if (/^$/) {
62 $in_desc = 1;
64 next unless ($in_section && $in_desc);
65 next if (/Originally merged to '\''next'\'' on ([-0-9]+)/);
66 next if (/^source: /);
67 last if (wildo_match($_));
68 push @msg, "$_\n";
70 return ($in_section, @msg);
73 my ($branch) = $ARGV[0];
74 my ($fh, $in_section, @msg);
75 if (open $fh, "<", "Meta/whats-cooking.txt") {
76 ($in_section, @msg) = read_message($fh, $branch);
78 if (!@msg) {
79 open my $revs, "-|",
80 qw(git -C Meta rev-list -32 HEAD -- whats-cooking.txt);
81 while (my $rev = <$revs>) {
82 chomp($rev);
83 open $fh, "-|",
84 qw(git -C Meta cat-file blob), "$rev:whats-cooking.txt";
85 ($in_section, @msg) = read_message($fh, $branch);
86 last if (@msg);
89 if (@msg) {
90 open(my $fh, "-|", qw(git cat-file commit HEAD));
91 my @original = (<$fh>);
92 close $fh;
93 my @final;
94 $in_section = 0;
95 for (@original) {
96 if (!$in_section) {
97 $in_section = 1 if (/^$/);
98 next;
100 if (/^Conflicts:$/ && $in_section == 2) {
101 $in_section = 3;
104 if ($in_section == 3) {
105 $_ = "# $_";
107 push @final, $_;
108 if (/^$/ && $in_section == 1) {
109 push @final, @msg;
110 push @final, "\n";
111 $in_section = 2;
114 open($fh, "|-", qw(git commit --amend -F -));
115 print $fh @final;
116 close $fh;
118 ' "$1"
121 cocci_mark="treewide: apply cocci patch"
123 case "$generate" in
125 accept_rerere () {
126 git ls-files -u -z |
127 perl -0 -e '
128 my %path_stage = ();
129 my @to_remove = ();
130 while (<>) {
131 my ($mode, $sha1, $stage, $path) =
132 /^([0-7]+) ([0-9a-f]+) ([0-3]) (.*)$/;
133 $path_stage{$path} ||= 0;
134 $path_stage{$path} |= (1 << ($stage - 1));
137 while (my ($path, $bits) = each %path_stage) {
138 if ($bits == 3 || $bits == 5) {
139 push @to_remove, $path;
142 if (@to_remove) {
143 system(qw(git rm -f), @to_remove);
147 if ! git write-tree 2>/dev/null >/dev/null
148 then
149 git rerere remaining
150 return 1
151 else
152 GIT_EDITOR=: git commit --no-verify
153 echo "Accepted previous resolution"
154 return 0
158 mark_cut () {
159 test -n "$stop_at_cut" && return
161 count_since_last_cut=$(( $count_since_last_cut + 1 ))
162 test -z "$prev_cut" && return
163 git commit --allow-empty -m "$prev_cut"
164 prev_cut=
167 detach () {
168 if original_branch=$(git symbolic-ref HEAD 2>/dev/null)
169 then
170 original_branch=${original_branch#refs/heads/}
171 git checkout --quiet --detach
172 into="--into $original_branch"
173 else
174 original_branch=
175 into=
180 leave () {
181 if test -n "$original_branch" && ! git symbolic-ref HEAD 2>/dev/null
182 then
183 git checkout --quiet -B "$original_branch"
185 if test -n "$1"
186 then
187 exit "$1"
191 detach
192 cut_seen=0 prev_cut= count_since_last_cut=0 cocci_count=0
194 while read branch eh
196 case "$branch" in '###') cut_seen=$(( $cut_seen + 1 )) ;; esac
197 if test -n "$stop_at_cut" && test $stop_at_cut -le $cut_seen
198 then
199 continue ;# slurp the remainder and skip
202 case "$branch" in
203 '###')
204 if test "$count_since_last_cut" = 0
205 then
206 prev_cut=
207 else
208 echo >&2 "$branch $eh"
209 prev_cut="$branch $eh"
210 count_since_last_cut=0
212 continue ;;
213 '#cocci')
214 if test -n "$no_cocci"
215 then
216 continue
217 elif test 0 = "$cocci_count" && test -z "$force_cocci"
218 then
219 continue
222 if test -n "$skip_cocci" && test -n "$eh"
223 then
224 git cherry-pick --no-commit "$eh"
225 else
226 rm -f contrib/coccinelle/*.patch
227 Meta/Make -j8 coccicheck
228 if grep coccicheck-pending Makefile >/dev/null
229 then
230 Meta/Make -j8 coccicheck-pending
232 cat contrib/coccinelle/*.patch >cocci.patch
233 if ! test -s cocci.patch
234 then
235 leave 0
237 git apply --index -3 cocci.patch || leave $?
238 rm cocci.patch
239 git diff --quiet HEAD && continue
241 git commit -m "$cocci_mark" || leave $?
243 mark_cut
244 continue
246 '#'* | '')
247 continue ;;
248 esac
250 case "$eh" in
251 "" | "#"* | [0-9][0-9]-[0-9][0-9]*)
252 echo >&2 "* $branch"
254 save=$(git rev-parse --verify HEAD) &&
255 tip=$(git rev-parse --verify "$branch^0") &&
256 mb=$(git merge-base "$tip" "$save") ||
257 leave $?
259 test "$mb" = "$tip" && continue
261 mark_cut
262 cocci_count=$(( $cocci_count + 1 ))
264 rebuild=$(git config "branch.$branch.rebuild" || :)
266 GIT_EDITOR=: git merge --no-ff $into $rebuild $accept_rerere --edit "$branch" ||
267 accept_rerere ||
268 leave $?
270 annotate_merge "$branch" || leave $?
271 test -z "$edit" ||
272 git commit --amend || leave $?
274 this=$(git rev-parse --verify HEAD)
275 if test "$this" = "$save"
276 then
278 elif git show-ref -q --verify "refs/merge-fix/$branch"
279 then
280 echo >&2 "Fixing up the merge"
281 git cherry-pick --no-commit "refs/merge-fix/$branch" &&
282 git diff --stat HEAD &&
283 GIT_EDITOR=: git commit --amend -a || leave $?
286 pick" "*)
287 echo >&2 "* $eh"
289 mark_cut
291 git cherry-pick "$branch" || leave $? ;;
292 *) echo >&2 "Eh? $branch $eh"; leave $? ;;
293 esac
295 eval "$exec" || leave $?
296 done
297 leave $?
299 esac
301 if test -n "$update" && test $# = 0
302 then
303 set x $(sed -n -e '2s/^# //p' <"$update") &&
304 shift
307 # Generation (or updating)
309 x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
310 x40="$x40$x40$x40$x40$x40$x40$x40$x40"
311 LF='
314 show_merge () {
315 case "$msg" in
316 "Merge branch '"*"'"*)
317 branch=$(expr "$msg" : "Merge branch '\(.*\)'")
318 merge_hier=heads/
320 "Merge remote branch '"*"'"*)
321 branch=$(expr "$msg" : "Merge remote branch '\(.*\)'")
322 merge_hier=
325 echo 2>&1 "Huh?: $msg"
326 return
328 esac &&
329 tip=$(git rev-parse --verify "refs/$merge_hier$branch" 2>/dev/null) &&
330 merged=$(git name-rev --refs="refs/$merge_hier$branch" "$other" 2>/dev/null) &&
331 merged=$(expr "$merged" : "$x40 \(.*\)") &&
332 test "$merged" != undefined || {
333 other=$(git log -1 --pretty='format:%s' $other) &&
334 merged="$branch :rebased? $other"
338 show_pick () {
339 case "$msg" in
340 "### "* | "###")
341 merged="$msg$LF"
344 merged="$(git rev-parse --verify "$commit") pick $msg"
346 esac
350 generate () {
351 PROGRAM=$1
352 shift
353 echo '#!/bin/sh'
354 echo "# $1"
355 echo 'case "$#,$1" in'
356 echo '1,-u|1,-d)'
357 echo " exec $PROGRAM" '"$1" "$0"'
358 echo 'esac'
359 echo "$PROGRAM" '"$@" <<\EOF'
360 git log --no-decorate --pretty=oneline --first-parent "$1" |
362 series=
363 while read commit msg
365 if other=$(git rev-parse -q --verify "$commit^2")
366 then
367 show_merge
368 elif test "$msg" = "$cocci_mark"
369 then
370 merged="#cocci "$(git rev-parse "$commit^0")
371 else
372 show_pick
375 if test -z "$series"
376 then
377 series="$merged"
378 else
379 series="$merged$LF$series"
381 done
382 echo "$series"
384 echo EOF
387 if test -z "$update"
388 then
389 generate "$0" "$@"
390 elif test -z "$diff"
391 then
392 generate "$0" "$@" | diff -w -u "$update" -
393 if test $? = 0
394 then
395 echo >&2 "No changes."
396 else
397 echo >&2 -n "Update [y/N]? "
398 read yesno
399 case "$yesno" in
400 [Yy]*)
401 generate "$0" "$@" |
402 sed -e 's/ :rebased?.*//' >"$update" ;;
404 echo >&2 "No update then." ;;
405 esac
407 else
408 generate "$0" "$@" | diff -w -u "$update" -