Teach git-local-fetch the --stdin switch
authorPetr Baudis <pasky@suse.cz>
Thu, 27 Jul 2006 21:56:19 +0000 (23:56 +0200)
committerJunio C Hamano <junkio@cox.net>
Fri, 28 Jul 2006 02:33:48 +0000 (19:33 -0700)
This makes it possible to fetch many commits (refs) at once, greatly
speeding up cg-clone.

Signed-off-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-local-fetch.txt
fetch.c
fetch.h
local-fetch.c

index 87abec1c4e46ad53e018264046091af4455da307..2fbdfe086a4c974d19c3d8f4c6a1722728b0114a 100644 (file)
@@ -29,6 +29,12 @@ OPTIONS
         Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
         the local end after the transfer is complete.
 
+--stdin::
+       Instead of a commit id on the commandline (which is not expected in this
+       case), 'git-local-fetch' expects lines on stdin in the format
+
+               <commit-id>['\t'<filename-as-in--w>]
+
 Author
 ------
 Written by Junio C Hamano <junkio@cox.net>
diff --git a/fetch.c b/fetch.c
index 281df61e7be1a998c4b384ee06bcdabaecd83504..2151c7b78c34f06f38f538f155169a0501c2ff54 100644 (file)
--- a/fetch.c
+++ b/fetch.c
@@ -7,6 +7,7 @@
 #include "tag.h"
 #include "blob.h"
 #include "refs.h"
+#include "strbuf.h"
 
 int get_tree = 0;
 int get_history = 0;
@@ -210,6 +211,45 @@ static int mark_complete(const char *path, const unsigned char *sha1)
        return 0;
 }
 
+int pull_targets_stdin(char ***target, const char ***write_ref)
+{
+       int targets = 0, targets_alloc = 0;
+       struct strbuf buf;
+       *target = NULL; *write_ref = NULL;
+       strbuf_init(&buf);
+       while (1) {
+               char *rf_one = NULL;
+               char *tg_one;
+
+               read_line(&buf, stdin, '\n');
+               if (buf.eof)
+                       break;
+               tg_one = buf.buf;
+               rf_one = strchr(tg_one, '\t');
+               if (rf_one)
+                       *rf_one++ = 0;
+
+               if (targets >= targets_alloc) {
+                       targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
+                       *target = xrealloc(*target, targets_alloc * sizeof(**target));
+                       *write_ref = xrealloc(*write_ref, targets_alloc * sizeof(**write_ref));
+               }
+               (*target)[targets] = strdup(tg_one);
+               (*write_ref)[targets] = rf_one ? strdup(rf_one) : NULL;
+               targets++;
+       }
+       return targets;
+}
+
+void pull_targets_free(int targets, char **target, const char **write_ref)
+{
+       while (targets--) {
+               free(target[targets]);
+               if (write_ref[targets])
+                       free((char *) write_ref[targets]);
+       }
+}
+
 int pull(int targets, char **target, const char **write_ref,
          const char *write_ref_log_details)
 {
diff --git a/fetch.h b/fetch.h
index 75e48af78029d0ca352f2e429c62248d05a70db1..be48c6f19092a81672dd24eb38e9ffca39f5b53c 100644 (file)
--- a/fetch.h
+++ b/fetch.h
@@ -40,6 +40,12 @@ extern int get_recover;
 /* Report what we got under get_verbosely */
 extern void pull_say(const char *, const char *);
 
+/* Load pull targets from stdin */
+extern int pull_targets_stdin(char ***target, const char ***write_ref);
+
+/* Free up loaded targets */
+extern void pull_targets_free(int targets, char **target, const char **write_ref);
+
 /* If write_ref is set, the ref filename to write the target value to. */
 /* If write_ref_log_details is set, additional text will appear in the ref log. */
 extern int pull(int targets, char **target, const char **write_ref,
index 1be73904f1b56fe0981973e9c21a368a4bba7975..b216bdd55742ef8214ed1193ef184f8bba70eb70 100644 (file)
@@ -8,8 +8,9 @@
 static int use_link = 0;
 static int use_symlink = 0;
 static int use_filecopy = 1;
+static int commits_on_stdin = 0;
 
-static char *path; /* "Remote" git repository */
+static const char *path; /* "Remote" git repository */
 
 void prefetch(unsigned char *sha1)
 {
@@ -194,7 +195,7 @@ int fetch_ref(char *ref, unsigned char *sha1)
 }
 
 static const char local_pull_usage[] =
-"git-local-fetch [-c] [-t] [-a] [-v] [-w filename] [--recover] [-l] [-s] [-n] commit-id path";
+"git-local-fetch [-c] [-t] [-a] [-v] [-w filename] [--recover] [-l] [-s] [-n] [--stdin] commit-id path";
 
 /*
  * By default we only use file copy.
@@ -202,10 +203,11 @@ static const char local_pull_usage[] =
  * If -s is specified, then a symlink is attempted.
  * If -n is _not_ specified, then a regular file-to-file copy is done.
  */
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-       const char *write_ref = NULL;
-       char *commit_id;
+       int commits;
+       const char **write_ref = NULL;
+       char **commit_id;
        int arg = 1;
 
        setup_git_directory();
@@ -230,20 +232,30 @@ int main(int argc, char **argv)
                else if (argv[arg][1] == 'v')
                        get_verbosely = 1;
                else if (argv[arg][1] == 'w')
-                       write_ref = argv[++arg];
+                       write_ref = &argv[++arg];
                else if (!strcmp(argv[arg], "--recover"))
                        get_recover = 1;
+               else if (!strcmp(argv[arg], "--stdin"))
+                       commits_on_stdin = 1;
                else
                        usage(local_pull_usage);
                arg++;
        }
-       if (argc < arg + 2)
+       if (argc < arg + 2 - commits_on_stdin)
                usage(local_pull_usage);
-       commit_id = argv[arg];
-       path = argv[arg + 1];
+       if (commits_on_stdin) {
+               commits = pull_targets_stdin(&commit_id, &write_ref);
+       } else {
+               commit_id = (char **) &argv[arg++];
+               commits = 1;
+       }
+       path = argv[arg];
 
-       if (pull(1, &commit_id, &write_ref, path))
+       if (pull(commits, commit_id, write_ref, path))
                return 1;
 
+       if (commits_on_stdin)
+               pull_targets_free(commits, commit_id, write_ref);
+
        return 0;
 }