git-split-repository
authorRudolf Polzer <rpolzer@nb-04.(none)>
Mon, 18 Jan 2010 12:37:57 +0000 (13:37 +0100)
committerRudolf Polzer <rpolzer@nb-04.(none)>
Mon, 18 Jan 2010 12:37:57 +0000 (13:37 +0100)
git-filter-index [new file with mode: 0755]
git-filter-repository [new file with mode: 0755]
git-pullall
git-split-repository [new file with mode: 0755]

diff --git a/git-filter-index b/git-filter-index
new file mode 100755 (executable)
index 0000000..18ab48b
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my @filters = ();
+for(@ARGV)
+{
+       if(/^
+               (?<want>[-+])
+               s
+                       (?<delimiter>.)
+                       (?<search>.*?)
+                       \k<delimiter>
+                       (?<replace>.*)
+                       \k<delimiter>
+       $/sx)
+       {
+               push @filters, {
+                       search => $+{search},
+                       replace => $+{replace},
+                       want => $+{want} eq '+'
+               };
+       }
+       elsif(/^
+               (?<want>[-+])
+               (?:
+                       m
+                               (?<delimiter>.)
+                       |
+                       (?<delimiter>\/)
+               )
+                       (?<search>.*?)
+                       \k<delimiter>
+       $/sx)
+       {
+               push @filters, {
+                       search => $+{search},
+                       replace => undef,
+                       want => $+{want} eq '+'
+               };
+       }
+       elsif(/^
+               (?<want>[-+])
+       $/sx)
+       {
+               push @filters, {
+                       search => '^',
+                       replace => undef,
+                       want => $+{want} eq '+'
+               };
+       }
+       else
+       {
+               die "Usage: $0 filterexpression filterexpression..., where a filter expression is of the form +s/search/replace/, +m/search/, +, -s/search/replace/, -m/search/, -";
+       }
+}
+
+sub fillin($@)
+{
+       my ($str, @args) = @_;
+       $str =~ s{\\([1-9])|(\&)|(\\)\\}{
+               $1 ? $args[$1] : $2 ? $args[0] : $3
+       }ge;
+       return $str;
+}
+
+my $current_output = $ENV{output};
+sub filter($)
+{
+       my ($s) = @_;
+       for(@filters)
+       {
+               my ($search, $replace, $want) = ($_->{search}, $_->{replace}, $_->{want});
+               my $fn = $s;
+               if($fn =~ s/$search/defined $replace ? fillin $replace, $&, map { substr($s, $-[$_], $+[$_] - $-[$_]) } 0..(@+ - 1) : $&/se)
+               {
+                       $fn = $s unless $want;
+                       return ($fn, $want);
+               }
+       }
+       # nothing matched
+       return ($s, 0);
+}
+
+open my $infh, '-|', 'git', 'ls-files', '-s';
+my $idx = "";
+my $plus = 0;
+my $minus = 0;
+while(<$infh>)
+{
+       chomp;
+       /^(\d+) ([0-9a-f]+) (\d+)\t(.*)$/ or die "invalid index line: $_";
+       my ($mode, $hash, $stageno, $filename) = ($1, $2, $3, $4);
+       my ($filename_new, $want) = filter($filename);
+       if($want)
+       {
+               $idx .= "0 0000000000000000000000000000000000000000 $stageno\t$filename\n"
+                       if $filename ne $filename_new;
+               $idx .= "$mode $hash $stageno\t$filename_new\n";
+               ++$plus;
+       }
+       else
+       {
+               $idx .= "0 0000000000000000000000000000000000000000 $stageno\t$filename\n";
+               ++$minus;
+       }
+}
+close $infh
+       or die "git-ls-files: $!";
+
+print "$plus:$minus\n";
+
+open my $outfh, ">", "/tmp/idxtest";
+print $outfh $idx;
+close $outfh;
+
+open my $outfh, '|-', 'git', 'update-index', '--index-info';
+print $outfh $idx;
+close $outfh
+       or die "git-update-index: $!";
diff --git a/git-filter-repository b/git-filter-repository
new file mode 100755 (executable)
index 0000000..2e088d0
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# expects a filter file of syntax like filter-index
+
+export filterfile="$1"
+git filter-branch --remap-to-ancestor --prune-empty --index-filter '
+       xargs -0r git filter-index < "$filterfile"
+' -- --all
+git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 -r git update-ref -d || true
+git reflog expire --expire=now --all
+git gc --prune=now --aggressive
index c54032c..c29d940 100755 (executable)
@@ -27,7 +27,7 @@ eval `git for-each-ref --shell --format='
        b=${b#refs/heads/};
        if git config branch.$b.merge >/dev/null && git config branch.$b.remote >/dev/null; then
                git checkout "$b";
-               git pull;
+               git pull || true;
        fi;
 ' refs/heads/`
 git checkout "$cur"
diff --git a/git-split-repository b/git-split-repository
new file mode 100755 (executable)
index 0000000..0ea0899
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+set -ex
+
+d="$PWD"
+src=$1
+shift
+
+# expects command line options like
+#      bspfiles='s,^data/(?=.*(?:\.bsp|/lm_.*\.tga)$),,' \
+#      a_nonbsp=
+# i.e. like filter-index, but with reponame= instead of .
+
+repos=`for x in "$@"; do
+       case "$x" in
+               delete=*)
+                       ;;
+               *=*)
+                       echo "${x%%=*}"
+                       ;;
+       esac
+done | sort -u`
+
+export filterfile=`mktemp`
+
+for r in $repos; do
+       rsync -vaSHP --delete "$src" "$r.git/"
+       cd "$r.git"
+       for x in "$@"; do
+               case "$x" in
+                       *=*)
+                               rr=${x%%=*}
+                               f=${x#*=}
+                               if [ x"$r" = x"$rr" ]; then
+                                       printf -- "+%s\0" "$f"
+                               else
+                                       printf -- "-%s\0" "$f"
+                               fi
+                               ;;
+               esac
+       done >"$filterfile"
+       git filter-repository "$filterfile"
+       cd "$d"
+done
+
+rm -f "$filterfile"