Git-basis is a perl script that remembers bases for use by git-bundle. Code from rev-parse was borrowed to allow git-bundle to handle --stdin. Signed-off-by: Adam Brewster <adambrewster@xxxxxxxxx> --- As promised, here's another patch with documentation. The code is identical to the previous version. I know this is a minor patch, but I think the result is a more usable git-bundle feature, and I'd like to see it included in future releases if there are no objections. Documentation/git-basis.txt | 82 +++++++++++++++++++++++++++++++++++++++++++ bundle.c | 22 ++++++++++- git-basis | 71 +++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 Documentation/git-basis.txt create mode 100755 git-basis diff --git a/Documentation/git-basis.txt b/Documentation/git-basis.txt new file mode 100644 index 0000000..3624890 --- /dev/null +++ b/Documentation/git-basis.txt @@ -0,0 +1,82 @@ +git-basis(1) +============ + +NAME +---- +git-basis - Track sets of references available on remote systems (bases) + +SYNOPSIS +-------- +[verse] +'git-basis' <basis> [<basis>...] +'git-basis' --update <basis> [<basis>...] < <object list or bundle> + +DESCRIPTION +----------- +Maintains lists of objects that are known to be accessible on remote +computer systems that are not accessible by network. + +OPTIONS +------- + +basis:: + List of bases to operate on. Any valid filename can be + the name of a basis. Bases that do not exist are taken + to be empty. + +--update:: + Tells git-basis to read a list of objects from stdin and + add them to each of the given bases. git-basis produces + no output when this option is given. Bases will be created + if necessary. + +object list or bundle:: + Git-basis --update reads object names, one per line from stdin. + Leading caret ("^") characters are ignored, as is anything + after the object name. Lines that don't begin with an object + name are ignored. The output of linkgit:git-ls-remote[1] or a + bundle created by linkgit:git-bundle[1] are both suitable input. + +DISCUSSION +---------- +git-basis is probably only useful with linkgit:git-bundle[1]. + +To create a bundle that excludes all objects that are part of my-basis, +use + +git-basis my-basis | git-bundle create my-bundle --all --stdin + +To add the objects in my-bundle to my-basis, use + +git-basis --update my-basis < my-bundle + +DETAILS +------- +Bases are stored as plain text files under .git/bases/. One object +entry per line. + +git-basis without --update reads all of the basis names given on the +command line, and outputs the intersection of them to stdout, with each +object prefixed by "^". + +git-basis --update reads object names from stdin, and adds all of the +references to each of the bases listed. Duplicate references will not +be listed twice, but otherwise redundant information will be included. + +BUGS +---- +Likely. + +Bug reports are welcome, and patches are encouraged. + +SEE ALSO +-------- +linkgit:git-bundle[1] + +AUTHOR +------ +Written by Adam Brewster <asb@xxxxxx> + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/bundle.c b/bundle.c index 0ba5df1..0af12d7 100644 --- a/bundle.c +++ b/bundle.c @@ -227,8 +227,26 @@ int create_bundle(struct bundle_header *header, const char *path, /* write references */ argc = setup_revisions(argc, argv, &revs, NULL); - if (argc > 1) - return error("unrecognized argument: %s'", argv[1]); + + for (i = 1; i < argc; i++) { + if ( !strcmp(argv[i], "--stdin") ) { + char line[1000]; + while (fgets(line, sizeof(line), stdin) != NULL) { + int len = strlen(line); + if (len && line[len - 1] == '\n') + line[--len] = 0; + if (!len) + break; + if (line[0] == '-') + die("options not supported in --stdin mode"); + if (handle_revision_arg(line, &revs, 0, 1)) + die("bad revision '%s'", line); + } + continue; + } + + return error("unrecognized argument: %s'", argv[i]); + } for (i = 0; i < revs.pending.nr; i++) { struct object_array_entry *e = revs.pending.objects + i; diff --git a/git-basis b/git-basis new file mode 100755 index 0000000..891635c --- /dev/null +++ b/git-basis @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +use strict; + +use Git; + +my $r = Git->repository(); +my $d = $r->repo_path(); + +if ( ! -d "$d/bases" ) { + system( "mkdir '$d/bases'" ); +} + +if ( $#ARGV == -1 ) { + print "usage: git-basis [--update] basis1...\n"; + exit; +} elsif ( $ARGV[0] eq '--update' ) { + shift @ARGV; + + my %new = (); + while (<STDIN>) { + if (!/^^?([a-z0-9]{40})/) {next;} + $new{$1} = 1; + } + + foreach my $f (@ARGV) { + my %these = (); + open F, "<$d/bases/$f" || die "Can't open bases/$f: $!"; + while (<F>) { + if (!/^([a-z0-9]{40})/) {next;} + $these{$1} = 1; + } + close F; + open F, ">>$d/bases/$f" || die "Can't open bases/$f: $!"; + print F "\#" . `date`; + foreach my $b (keys %new) { + if (exists($these{$b})) {next;} + print F "$b\n"; + } + close F; + } +} else { + my $n = 0; + my %basis = (); + + my $f = shift @ARGV; + open F, "<$d/bases/$f" || die "Can't open bases/$f: $!"; + while (<F>) { + if (!/^([a-z0-9]{40})/) {next;} + $basis{$1} = $n; + } + close F; + + foreach $f (@ARGV) { + open F, "<$d/bases/$f" || die "Can't open bases/$f: $!"; + while (<F>) { + if (!/^([a-z0-9]{40})/) {next;} + if (!exists($basis{$1})) {next;} + + if ($basis{$1} == $n) {$basis{$1}++;} + else {delete $basis{$1};} + } + close F; + $n++; + } + + foreach my $b (keys %basis) { + if ( $basis{$b} != $n ) {next;} + print "^$b\n"; + } +} -- 1.5.5.1.211.g65ea3.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html