[PATCH 3/4] Teach git-local-fetch the --stdin switch
From: Petr Baudis <hidden>
Date: 2016-06-15 22:42:34
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
This makes it possible to fetch many commits (refs) at once, greatly speeding up cg-clone. Signed-off-by: Petr Baudis <redacted> --- Documentation/git-local-fetch.txt | 6 ++++++ fetch.c | 40 +++++++++++++++++++++++++++++++++++++ fetch.h | 6 ++++++ local-fetch.c | 32 ++++++++++++++++++++---------- 4 files changed, 74 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-local-fetch.txt b/Documentation/git-local-fetch.txt
index 87abec1..bd19820 100644
--- a/Documentation/git-local-fetch.txt
+++ b/Documentation/git-local-fetch.txt@@ -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' excepts 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 281df61..2151c7b 100644
--- a/fetch.c
+++ b/fetch.c@@ -7,6 +7,7 @@ #include "tree-walk.h" #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 *pat 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 75e48af..be48c6f 100644
--- 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,
diff --git a/local-fetch.c b/local-fetch.c
index eb19f1a..84b68a6 100644
--- a/local-fetch.c
+++ b/local-fetch.c@@ -8,8 +8,9 @@ #include "fetch.h" 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 * } 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; }