X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=badcommit-fixup;h=58ad12d7d6e5e36d97f557c0d1d6436634e8be60;hb=24f011f59d9efa76f4af945d67dc388a6d8eeac0;hp=9cc61a9673fa9e52060a84bc774be0def321859e;hpb=cc1275a952f6bb82d160eb27cfebad01bda4959a;p=dgit-junk.git diff --git a/badcommit-fixup b/badcommit-fixup index 9cc61a9..58ad12d 100755 --- a/badcommit-fixup +++ b/badcommit-fixup @@ -1,18 +1,124 @@ -#!/bin/bash +#!/usr/bin/perl -w + +use strict; + +use POSIX; +use IPC::Open2; + +$!=0; $?=0; +my $refs=`git-for-each-ref`; +die "$? $!" if $?; + +chomp $refs; + +my $gcfpid = open2 \*GCFO, \*GCFI, 'git cat-file --batch' or die $!; + +sub getobj ($$) { + my ($obj, $type) = @_; + print GCFI $obj, "\n" or die $!; + my $x = ; + $x =~ m/^\w+ (\w+) (\d+)\n/ or die "$obj ?"; + my ($gtype, $gsize) = ($1,$2,$3); + $gtype eq $type or die "$obj $gtype != $type ?"; + my $gdata; + read GFCO, $gdata, $gsize == $gsize or die "$obj $!"; + $x = ; + $x eq "\n" or die "$obj $!"; + return $gdata; +} + +our %memo; +our %count; + +sub rewrite_commit ($) { + my ($obj) = @_; + my $m = \ $memo{$obj}; + return $$m if defined $$m; + my $olddata = getobj $obj, 'commit'; + die "$obj ?" unless $old; + $olddata =~ m/(?<=\n)(?=\n)/ or die "$obj ?"; + my $msg = $'; + $_ = $`; + s{^(parent )(\w+)$}{ $1 . rewrite_commit($2) }gme; + $count{fix_overwrite} += s{^commiter }{committer }gm; + if (!m{^author }m && !m{^committer }m) { + m{^parent (\w+)}m or die "$obj ?"; + my $parent = getobj $1, 'commit'; + $parent =~ m/^(?:.+\n)+(author .*\ncommitter .*\n)/; + m/\n$/ or die "$obj ?"; + $_ .= $1; + $count{fix_import}++; + } + $newdata = $_.$msg; + my $newobj; + if ($newdata eq $olddata) { + $newobj = $oldobj; + } else { + my $gwopid = open2 \*GWO, \*GWI, + 'git hash-object -t comit --stdin' + or die $!; + print GWI $newdata or die $!; + close GWI or die $!; + $_ = ; + close GWO or die $!; + waitpid $gwopid,0 == $gwopid or die $!; + die $? if $?; + m/^(\w+)\n/ or die "$_ ?"; + $newobj = $1; + $count{commits}++; + } + $$m= $newobj; + return $newobj; +} + +sub rewrite_tag ($) { + my ($obj) = @_; + $_ = getobj $obj, 'tag'; + m/^type (\w+)\n/m or die "$obj ?"; + if ($1 ne 'commit') { + $count{"oddtags $1"}++; + return; + } + m/^object (\w+)\n/m or die "$obj ?"; + my $oldref = $1; + my $newref = rewrite_commit $oldref; + if ($oldref eq $newref) { + return $obj; + } + s/^(?<=object )\w+(?=\n)/$newref/m or die "$obj ?"; + +} + +foreach my $rline (split /\n/, $refs) { + die "$_ ?" unless m/^(\w+)\s+(\w+)\s+(\S.*)/; + my ($obj, $type, $refname) = @_; + my $rewrite; + if ($type eq 'commit') { + $rewrite = rewrite_commit($obj); + } elsif ($type eq 'tag') { + my $rewrite = rewrite_tag($obj); + } else { + warn "ref $refname refers to $type\n"; + next; + } + next if $refname eq $rewrite; + push @updates, [ $refname, $rewrite ]; +} -set -e -set -o pipefail -tmp=.git/dgit-badcommit-fixup-tmp -rm -rf $tmp -mkdir $tmp -LC_MESSAGES=C git fsck --no-dangling >$tmp/gfo 2>&1 || test $? = 1 +if git-symbolic-ref HEAD >/dev/null 2>&1; then + refs+=' HEAD' -perl -ne ' - print $1, "\n" or die $! if - m/^error in commit (\w+):.*invalid format - expected '\''committer/; -' <$tmp/gfo >$tmp/bad + + +my $gfo = `LC_MESSAGES=C git fsck --no-dangling 2>&1`; +$? == 256 or die "$? $!" + + + + + m/^error in commit (\w+):.*invalid format - expected 'committer/; case `wc -l <$tmp/bad` in 0) @@ -29,7 +135,13 @@ esac args="$nots" -for head in HEAD `git-for-each-ref --format='%(refname)'`; do +refs=`git-for-each-ref --format='%(refname)'` + +if git-symbolic-ref HEAD >/dev/null 2>&1; then + refs+=' HEAD' +fi + +for head in $refs; do exec <$tmp/bad needed=false for bad in $bads; do @@ -42,14 +154,10 @@ for head in HEAD `git-for-each-ref --format='%(refname)'`; do args+=" $head" done -cat >$tmp/flt <<'END' -#!/usr/bin/perl -w -use strict; -undef $/; -$_ = ; -s/^(\w+.*\n)*commiter /$1committer /; -END - git filter-branch --original dgit-badcommit --commit-filter ' +echo >&2 "FOO $*" +cat >&2 +echo >&2 ==== +false sed -e '\''1,/^$/ s/^commiter /committer /'\'' ' $args