From 6eb996b5707b6d14cf9875a9231f4e909a443665 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 5 Aug 2009 01:01:53 -0400 Subject: [PATCH 01/42] Add support for external programs for handling native fetches transport_get() can call transport_native_helper_init() to have list and fetch-ref operations handled by running a separate program as: git remote- [] This program then accepts, on its stdin, "list" and "fetch " commands; the former prints out a list of available refs and either their hashes or what they are symrefs to, while the latter fetches them into the local object database and prints a newline when done. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Documentation/git-remote-helpers.txt | 71 +++++++++++ Makefile | 1 + transport-helper.c | 168 +++++++++++++++++++++++++++ transport.h | 3 + 4 files changed, 243 insertions(+) create mode 100644 Documentation/git-remote-helpers.txt create mode 100644 transport-helper.c diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt new file mode 100644 index 0000000000..173ee232f2 --- /dev/null +++ b/Documentation/git-remote-helpers.txt @@ -0,0 +1,71 @@ +git-remote-helpers(1) +===================== + +NAME +---- +git-remote-helpers - Helper programs for interoperation with remote git + +SYNOPSIS +-------- +'git remote-' + +DESCRIPTION +----------- + +These programs are normally not used directly by end users, but are +invoked by various git programs that interact with remote repositories +when the repository they would operate on will be accessed using +transport code not linked into the main git binary. Various particular +helper programs will behave as documented here. + +COMMANDS +-------- + +Commands are given by the caller on the helper's standard input, one per line. + +'capabilities':: + Lists the capabilities of the helper, one per line, ending + with a blank line. + +'list':: + Lists the refs, one per line, in the format " + [ ...]". The value may be a hex sha1 hash, "@" for + a symref, or "?" to indicate that the helper could not get the + value of the ref. A space-separated list of attributes follows + the name; unrecognized attributes are ignored. After the + complete list, outputs a blank line. + +'fetch' :: + Fetches the given object, writing the necessary objects to the + database. Outputs a blank line when the fetch is + complete. Only objects which were reported in the ref list + with a sha1 may be fetched this way. ++ +Supported if the helper has the "fetch" capability. + +If a fatal error occurs, the program writes the error message to +stderr and exits. The caller should expect that a suitable error +message has been printed if the child closes the connection without +completing a valid response for the current command. + +Additional commands may be supported, as may be determined from +capabilities reported by the helper. + +CAPABILITIES +------------ + +'fetch':: + This helper supports the 'fetch' command. + +REF LIST ATTRIBUTES +------------------- + +None are defined yet, but the caller must accept any which are supplied. + +Documentation +------------- +Documentation by Daniel Barkalow. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index daf4296706..504646a768 100644 --- a/Makefile +++ b/Makefile @@ -549,6 +549,7 @@ LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += trace.o LIB_OBJS += transport.o +LIB_OBJS += transport-helper.o LIB_OBJS += tree-diff.o LIB_OBJS += tree.o LIB_OBJS += tree-walk.o diff --git a/transport-helper.c b/transport-helper.c new file mode 100644 index 0000000000..c982bb2575 --- /dev/null +++ b/transport-helper.c @@ -0,0 +1,168 @@ +#include "cache.h" +#include "transport.h" + +#include "run-command.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" + +struct helper_data +{ + const char *name; + struct child_process *helper; + unsigned fetch : 1; +}; + +static struct child_process *get_helper(struct transport *transport) +{ + struct helper_data *data = transport->data; + struct strbuf buf = STRBUF_INIT; + struct child_process *helper; + FILE *file; + + if (data->helper) + return data->helper; + + helper = xcalloc(1, sizeof(*helper)); + helper->in = -1; + helper->out = -1; + helper->err = 0; + helper->argv = xcalloc(4, sizeof(*helper->argv)); + strbuf_addf(&buf, "remote-%s", data->name); + helper->argv[0] = strbuf_detach(&buf, NULL); + helper->argv[1] = transport->remote->name; + helper->argv[2] = transport->url; + helper->git_cmd = 1; + if (start_command(helper)) + die("Unable to run helper: git %s", helper->argv[0]); + data->helper = helper; + + write_in_full(data->helper->in, "capabilities\n", 13); + file = fdopen(helper->out, "r"); + while (1) { + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + + if (!*buf.buf) + break; + if (!strcmp(buf.buf, "fetch")) + data->fetch = 1; + } + return data->helper; +} + +static int disconnect_helper(struct transport *transport) +{ + struct helper_data *data = transport->data; + if (data->helper) { + write_in_full(data->helper->in, "\n", 1); + close(data->helper->in); + finish_command(data->helper); + free((char *)data->helper->argv[0]); + free(data->helper->argv); + free(data->helper); + data->helper = NULL; + } + return 0; +} + +static int fetch_with_fetch(struct transport *transport, + int nr_heads, const struct ref **to_fetch) +{ + struct child_process *helper = get_helper(transport); + FILE *file = fdopen(helper->out, "r"); + int i; + struct strbuf buf = STRBUF_INIT; + + for (i = 0; i < nr_heads; i++) { + struct ref *posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + write_in_full(helper->in, "fetch ", 6); + write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40); + write_in_full(helper->in, " ", 1); + write_in_full(helper->in, posn->name, strlen(posn->name)); + write_in_full(helper->in, "\n", 1); + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + } + return 0; +} + +static int fetch(struct transport *transport, + int nr_heads, const struct ref **to_fetch) +{ + struct helper_data *data = transport->data; + int i, count; + + count = 0; + for (i = 0; i < nr_heads; i++) + if (!(to_fetch[i]->status & REF_STATUS_UPTODATE)) + count++; + + if (!count) + return 0; + + if (data->fetch) + return fetch_with_fetch(transport, nr_heads, to_fetch); + + return -1; +} + +static struct ref *get_refs_list(struct transport *transport, int for_push) +{ + struct child_process *helper; + struct ref *ret = NULL; + struct ref **tail = &ret; + struct ref *posn; + struct strbuf buf = STRBUF_INIT; + FILE *file; + + helper = get_helper(transport); + write_in_full(helper->in, "list\n", 5); + + file = fdopen(helper->out, "r"); + while (1) { + char *eov, *eon; + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + + if (!*buf.buf) + break; + + eov = strchr(buf.buf, ' '); + if (!eov) + die("Malformed response in ref list: %s", buf.buf); + eon = strchr(eov + 1, ' '); + *eov = '\0'; + if (eon) + *eon = '\0'; + *tail = alloc_ref(eov + 1); + if (buf.buf[0] == '@') + (*tail)->symref = xstrdup(buf.buf + 1); + else if (buf.buf[0] != '?') + get_sha1_hex(buf.buf, (*tail)->old_sha1); + tail = &((*tail)->next); + } + strbuf_release(&buf); + + for (posn = ret; posn; posn = posn->next) + resolve_remote_symref(posn, ret); + + return ret; +} + +int transport_helper_init(struct transport *transport) +{ + struct helper_data *data = xcalloc(sizeof(*data), 1); + char *eom = strchr(transport->url, ':'); + if (!eom) + return -1; + data->name = xstrndup(transport->url, eom - transport->url); + + transport->data = data; + transport->get_refs_list = get_refs_list; + transport->fetch = fetch; + transport->disconnect = disconnect_helper; + return 0; +} diff --git a/transport.h b/transport.h index 51b539778c..df87264637 100644 --- a/transport.h +++ b/transport.h @@ -77,4 +77,7 @@ void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); char *transport_anonymize_url(const char *url); +/* Transport methods defined outside transport.c */ +int transport_helper_init(struct transport *transport); + #endif From a2d725b7bdf756ade7680945ebc3fb62e5dd8bcc Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 5 Aug 2009 01:01:56 -0400 Subject: [PATCH 02/42] Use an external program to implement fetching with curl Use the transport native helper mechanism to fetch by http (and ftp, etc). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Makefile | 5 ++ remote-curl.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ transport.c | 136 +----------------------------------------------- 3 files changed, 145 insertions(+), 135 deletions(-) create mode 100644 remote-curl.c diff --git a/Makefile b/Makefile index 504646a768..35117fcf43 100644 --- a/Makefile +++ b/Makefile @@ -981,6 +981,7 @@ else CURL_LIBCURL = -lcurl endif BUILTIN_OBJS += builtin-http-fetch.o + PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X EXTLIBS += $(CURL_LIBCURL) LIB_OBJS += http.o http-walker.o curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) @@ -1491,6 +1492,10 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +git-remote-http$X git-remote-https$X git-remote-ftp$X: remote-curl.o http.o http-walker.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h diff --git a/remote-curl.c b/remote-curl.c new file mode 100644 index 0000000000..ad6a1637b5 --- /dev/null +++ b/remote-curl.c @@ -0,0 +1,139 @@ +#include "cache.h" +#include "remote.h" +#include "strbuf.h" +#include "walker.h" +#include "http.h" + +static struct ref *get_refs(struct walker *walker, const char *url) +{ + struct strbuf buffer = STRBUF_INIT; + char *data, *start, *mid; + char *ref_name; + char *refs_url; + int i = 0; + int http_ret; + + struct ref *refs = NULL; + struct ref *ref = NULL; + struct ref *last_ref = NULL; + + refs_url = xmalloc(strlen(url) + 11); + sprintf(refs_url, "%s/info/refs", url); + + http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); + switch (http_ret) { + case HTTP_OK: + break; + case HTTP_MISSING_TARGET: + die("%s not found: did you run git update-server-info on the" + " server?", refs_url); + default: + http_error(refs_url, http_ret); + die("HTTP request failed"); + } + + data = buffer.buf; + start = NULL; + mid = data; + while (i < buffer.len) { + if (!start) { + start = &data[i]; + } + if (data[i] == '\t') + mid = &data[i]; + if (data[i] == '\n') { + data[i] = 0; + ref_name = mid + 1; + ref = xmalloc(sizeof(struct ref) + + strlen(ref_name) + 1); + memset(ref, 0, sizeof(struct ref)); + strcpy(ref->name, ref_name); + get_sha1_hex(start, ref->old_sha1); + if (!refs) + refs = ref; + if (last_ref) + last_ref->next = ref; + last_ref = ref; + start = NULL; + } + i++; + } + + strbuf_release(&buffer); + + ref = alloc_ref("HEAD"); + if (!walker->fetch_ref(walker, ref) && + !resolve_remote_symref(ref, refs)) { + ref->next = refs; + refs = ref; + } else { + free(ref); + } + + strbuf_release(&buffer); + free(refs_url); + return refs; +} + +int main(int argc, const char **argv) +{ + struct remote *remote; + struct strbuf buf = STRBUF_INIT; + const char *url; + struct walker *walker = NULL; + + setup_git_directory(); + if (argc < 2) { + fprintf(stderr, "Remote needed\n"); + return 1; + } + + remote = remote_get(argv[1]); + + if (argc > 2) { + url = argv[2]; + } else { + url = remote->url[0]; + } + + do { + if (strbuf_getline(&buf, stdin, '\n') == EOF) + break; + if (!prefixcmp(buf.buf, "fetch ")) { + char *obj = buf.buf + strlen("fetch "); + if (!walker) + walker = get_http_walker(url, remote); + walker->get_all = 1; + walker->get_tree = 1; + walker->get_history = 1; + walker->get_verbosely = 0; + walker->get_recover = 0; + if (walker_fetch(walker, 1, &obj, NULL, NULL)) + die("Fetch failed."); + printf("\n"); + fflush(stdout); + } else if (!strcmp(buf.buf, "list")) { + struct ref *refs; + struct ref *posn; + if (!walker) + walker = get_http_walker(url, remote); + refs = get_refs(walker, url); + for (posn = refs; posn; posn = posn->next) { + if (posn->symref) + printf("@%s %s\n", posn->symref, posn->name); + else + printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name); + } + printf("\n"); + fflush(stdout); + } else if (!strcmp(buf.buf, "capabilities")) { + printf("fetch\n"); + printf("\n"); + fflush(stdout); + } else { + return 1; + } + strbuf_reset(&buf); + } while (1); + return 0; +} diff --git a/transport.c b/transport.c index de0d5874a3..9935c85cf3 100644 --- a/transport.c +++ b/transport.c @@ -1,9 +1,6 @@ #include "cache.h" #include "transport.h" #include "run-command.h" -#ifndef NO_CURL -#include "http.h" -#endif #include "pkt-line.h" #include "fetch-pack.h" #include "send-pack.h" @@ -352,45 +349,6 @@ static int rsync_transport_push(struct transport *transport, return result; } -/* Generic functions for using commit walkers */ - -#ifndef NO_CURL /* http fetch is the only user */ -static int fetch_objs_via_walker(struct transport *transport, - int nr_objs, const struct ref **to_fetch) -{ - char *dest = xstrdup(transport->url); - struct walker *walker = transport->data; - char **objs = xmalloc(nr_objs * sizeof(*objs)); - int i; - - walker->get_all = 1; - walker->get_tree = 1; - walker->get_history = 1; - walker->get_verbosely = transport->verbose >= 0; - walker->get_recover = 0; - - for (i = 0; i < nr_objs; i++) - objs[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1)); - - if (walker_fetch(walker, nr_objs, objs, NULL, NULL)) - die("Fetch failed."); - - for (i = 0; i < nr_objs; i++) - free(objs[i]); - free(objs); - free(dest); - return 0; -} -#endif /* NO_CURL */ - -static int disconnect_walker(struct transport *transport) -{ - struct walker *walker = transport->data; - if (walker) - walker_free(walker); - return 0; -} - #ifndef NO_CURL static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { @@ -432,96 +390,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons return !!err; } -static struct ref *get_refs_via_curl(struct transport *transport, int for_push) -{ - struct strbuf buffer = STRBUF_INIT; - char *data, *start, *mid; - char *ref_name; - char *refs_url; - int i = 0; - int http_ret; - - struct ref *refs = NULL; - struct ref *ref = NULL; - struct ref *last_ref = NULL; - - struct walker *walker; - - if (for_push) - return NULL; - - if (!transport->data) - transport->data = get_http_walker(transport->url, - transport->remote); - - walker = transport->data; - - refs_url = xmalloc(strlen(transport->url) + 11); - sprintf(refs_url, "%s/info/refs", transport->url); - - http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); - switch (http_ret) { - case HTTP_OK: - break; - case HTTP_MISSING_TARGET: - die("%s not found: did you run git update-server-info on the" - " server?", refs_url); - default: - http_error(refs_url, http_ret); - die("HTTP request failed"); - } - - data = buffer.buf; - start = NULL; - mid = data; - while (i < buffer.len) { - if (!start) - start = &data[i]; - if (data[i] == '\t') - mid = &data[i]; - if (data[i] == '\n') { - data[i] = 0; - ref_name = mid + 1; - ref = xmalloc(sizeof(struct ref) + - strlen(ref_name) + 1); - memset(ref, 0, sizeof(struct ref)); - strcpy(ref->name, ref_name); - get_sha1_hex(start, ref->old_sha1); - if (!refs) - refs = ref; - if (last_ref) - last_ref->next = ref; - last_ref = ref; - start = NULL; - } - i++; - } - - strbuf_release(&buffer); - - ref = alloc_ref("HEAD"); - if (!walker->fetch_ref(walker, ref) && - !resolve_remote_symref(ref, refs)) { - ref->next = refs; - refs = ref; - } else { - free(ref); - } - - strbuf_release(&buffer); - free(refs_url); - return refs; -} - -static int fetch_objs_via_curl(struct transport *transport, - int nr_objs, const struct ref **to_fetch) -{ - if (!transport->data) - transport->data = get_http_walker(transport->url, - transport->remote); - return fetch_objs_via_walker(transport, nr_objs, to_fetch); -} - #endif struct bundle_transport_data { @@ -950,14 +818,12 @@ struct transport *transport_get(struct remote *remote, const char *url) } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { + transport_helper_init(ret); #ifdef NO_CURL error("git was compiled without libcurl support."); #else - ret->get_refs_list = get_refs_via_curl; - ret->fetch = fetch_objs_via_curl; ret->push = curl_transport_push; #endif - ret->disconnect = disconnect_walker; } else if (is_local(url) && is_file(url)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); From 1088261f6fc90324014b5306cca4171987da85ce Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 5 Aug 2009 01:01:59 -0400 Subject: [PATCH 03/42] git-http-fetch: not a builtin This splits up git-http-fetch so that it isn't built-in. It also removes the general dependency on curl, because it is no longer used by any built-in code. Because they are no longer LIB_OBJS, add LIB_H to the dependencies of http-related object files, and remove http.h from the dependencies of transport.o Signed-off-by: Linus Torvalds Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Makefile | 10 ++++++---- git.c | 3 --- builtin-http-fetch.c => http-fetch.c | 5 ++++- transport-helper.c | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) rename builtin-http-fetch.c => http-fetch.c (95%) diff --git a/Makefile b/Makefile index 35117fcf43..0ebf9dd95c 100644 --- a/Makefile +++ b/Makefile @@ -980,10 +980,7 @@ else else CURL_LIBCURL = -lcurl endif - BUILTIN_OBJS += builtin-http-fetch.o PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X - EXTLIBS += $(CURL_LIBCURL) - LIB_OBJS += http.o http-walker.o curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1486,8 +1483,13 @@ git-imap-send$X: imap-send.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) -http.o http-walker.o http-push.o transport.o: http.h +http.o http-walker.o http-push.o: http.h +http.o http-walker.o: $(LIB_H) + +git-http-fetch$X: revision.o http.o http-push.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) diff --git a/git.c b/git.c index 807d875ae0..c1e8f05e5f 100644 --- a/git.c +++ b/git.c @@ -309,9 +309,6 @@ static void handle_internal_command(int argc, const char **argv) { "get-tar-commit-id", cmd_get_tar_commit_id }, { "grep", cmd_grep, RUN_SETUP | USE_PAGER }, { "help", cmd_help }, -#ifndef NO_CURL - { "http-fetch", cmd_http_fetch, RUN_SETUP }, -#endif { "init", cmd_init_db }, { "init-db", cmd_init_db }, { "log", cmd_log, RUN_SETUP | USE_PAGER }, diff --git a/builtin-http-fetch.c b/http-fetch.c similarity index 95% rename from builtin-http-fetch.c rename to http-fetch.c index f3e63d7206..e8f44babd9 100644 --- a/builtin-http-fetch.c +++ b/http-fetch.c @@ -1,8 +1,9 @@ #include "cache.h" #include "walker.h" -int cmd_http_fetch(int argc, const char **argv, const char *prefix) +int main(int argc, const char **argv) { + const char *prefix; struct walker *walker; int commits_on_stdin = 0; int commits; @@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) int get_verbosely = 0; int get_recover = 0; + prefix = setup_git_directory(); + git_config(git_default_config, NULL); while (arg < argc && argv[arg][0] == '-') { diff --git a/transport-helper.c b/transport-helper.c index c982bb2575..43fdc0a434 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -75,7 +75,7 @@ static int fetch_with_fetch(struct transport *transport, struct strbuf buf = STRBUF_INIT; for (i = 0; i < nr_heads; i++) { - struct ref *posn = to_fetch[i]; + const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; write_in_full(helper->in, "fetch ", 6); From f395cd06755c7563df7d0a0408807199c3f60635 Mon Sep 17 00:00:00 2001 From: Mike Ralphson Date: Thu, 6 Aug 2009 14:14:44 +0100 Subject: [PATCH 04/42] Add transport native helper executables to .gitignore Signed-off-by: Mike Ralphson Signed-off-by: Junio C Hamano --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 41c0b20a76..096857e42d 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,9 @@ git-receive-pack git-reflog git-relink git-remote +git-remote-ftp +git-remote-http +git-remote-https git-repack git-repo-config git-request-pull From ae209bd34914c05d141030b3affcf276f07e2490 Mon Sep 17 00:00:00 2001 From: Mike Ralphson Date: Thu, 6 Aug 2009 14:14:45 +0100 Subject: [PATCH 05/42] http-fetch: Fix Makefile dependancies Specify git-http-fetch's dependancies explicitly rather than inheriting from git-http-push, as that may not be built if the libcurl version is too old or NO_EXPAT is defined Signed-off-by: Mike Ralphson Signed-off-by: Junio C Hamano --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0ebf9dd95c..2900057fbf 100644 --- a/Makefile +++ b/Makefile @@ -1487,7 +1487,7 @@ http.o http-walker.o http-push.o: http.h http.o http-walker.o: $(LIB_H) -git-http-fetch$X: revision.o http.o http-push.o $(GITLIBS) +git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) From 17fd9f571f5596b0e69e143bf6d72a19c780dd25 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 7 Aug 2009 00:21:33 -0400 Subject: [PATCH 06/42] Makefile: git-http-fetch does not need expat This appears to be a bad cut-and-paste in commit 1088261f. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2900057fbf..e29b15f2e0 100644 --- a/Makefile +++ b/Makefile @@ -1489,7 +1489,7 @@ http.o http-walker.o: $(LIB_H) git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ - $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) + $(LIBS) $(CURL_LIBCURL) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) From 611c7f6a373fc6e7140f81bf9c26bde9f78390d4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 6 Aug 2009 22:08:09 -0700 Subject: [PATCH 07/42] Makefile: do not link three copies of git-remote-* programs Instead, link only one and make the rest hardlinks/copies, like we do for the built-ins. Signed-off-by: Junio C Hamano --- Makefile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e29b15f2e0..5f4d0c95e5 100644 --- a/Makefile +++ b/Makefile @@ -980,7 +980,8 @@ else else CURL_LIBCURL = -lcurl endif - PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X + CURL_SYNONYMS = git-remote-https$X git-remote-ftp$X + PROGRAMS += git-remote-http$X $(CURL_SYNONYMS) git-http-fetch$X curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1256,6 +1257,7 @@ ifndef V QUIET_LINK = @echo ' ' LINK $@; QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; + QUIET_LNCP = @echo ' ' LN/CP $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ $(MAKE) $(PRINT_DIR) -C $$subdir @@ -1494,10 +1496,16 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -git-remote-http$X git-remote-https$X git-remote-ftp$X: remote-curl.o http.o http-walker.o $(GITLIBS) +git-remote-http$X: remote-curl.o http.o http-walker.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +$(CURL_SYNONYMS): git-remote-http$X + $(QUIET_LNCP)$(RM) $@ && \ + ln $< $@ 2>/dev/null || \ + ln -s $< $@ 2>/dev/null || \ + cp $< $@ + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h From ad17f01399a9220b78678b322bd42b0a29898e01 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 7 Aug 2009 12:09:29 -0700 Subject: [PATCH 08/42] Makefile: install hardlinks for git-remote- supported by libcurl if possible Instead of installing/copying three programs separately, just install one and try to make hardlinks to the other two. Signed-off-by: Junio C Hamano --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5f4d0c95e5..438cffb442 100644 --- a/Makefile +++ b/Makefile @@ -383,7 +383,8 @@ BUILT_INS += git-stage$X BUILT_INS += git-status$X BUILT_INS += git-whatchanged$X -# what 'all' will build and 'install' will install, in gitexecdir +# what 'all' will build and 'install' will install in gitexecdir, +# excluding programs for built-in commands ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in gitexecdir @@ -1661,7 +1662,7 @@ export gitexec_instdir install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' + $(INSTALL) $(filter-out $(CURL_SYNONYMS), $(ALL_PROGRAMS)) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL @@ -1687,6 +1688,12 @@ endif ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git$X" "$$execdir/$$p" || exit; \ done; } && \ + { for p in $(CURL_SYNONYMS); do \ + $(RM) "$$execdir/$$p" && \ + ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ + ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ + cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \ + done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: From 7e787953fb89fbe403060585f7c39f0c75f29318 Mon Sep 17 00:00:00 2001 From: Peter Krefting Date: Thu, 3 Sep 2009 13:15:00 +0100 Subject: [PATCH 09/42] import-tars: Allow per-tar author and commit message. If the "--metainfo=" option is given on the command line, a file called "." will be used to create the commit message for "", instead of using "Imported from filename.tar". The author and committer of the tar ball can also be overridden by embedding an "Author:" or "Committer:" header in the metainfo file. Signed-off-by: Peter Krefting Signed-off-by: Junio C Hamano --- contrib/fast-import/import-tars.perl | 50 +++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 78e40d2a13..a909716682 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -8,9 +8,20 @@ ## perl import-tars.perl *.tar.bz2 ## git whatchanged import-tars ## +## Use --metainfo to specify the extension for a meta data file, where +## import-tars can read the commit message and optionally author and +## committer information. +## +## echo 'This is the commit message' > myfile.tar.bz2.msg +## perl import-tars.perl --metainfo=msg myfile.tar.bz2 use strict; -die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV; +use Getopt::Long; + +my $metaext = ''; + +die "usage: import-tars [--metainfo=extension] *.tar.{gz,bz2,Z}\n" + unless GetOptions('metainfo=s' => \$metaext) && @ARGV; my $branch_name = 'import-tars'; my $branch_ref = "refs/heads/$branch_name"; @@ -109,12 +120,43 @@ foreach my $tar_file (@ARGV) $have_top_dir = 0 if $top_dir ne $1; } + my $commit_msg = "Imported from $tar_file."; + my $this_committer_name = $committer_name; + my $this_committer_email = $committer_email; + my $this_author_name = $author_name; + my $this_author_email = $author_email; + if ($metaext ne '') { + # Optionally read a commit message from .msg + # Add a line on the form "Committer: name " to override + # the committer and "Author: name " to override the + # author for this tar ball. + if (open MSG, '<', "${tar_file}.${metaext}") { + my $header_done = 0; + $commit_msg = ''; + while () { + if (!$header_done && /^Committer:\s+([^<>]*)\s+<(.*)>\s*$/i) { + $this_committer_name = $1; + $this_committer_email = $2; + } elsif (!$header_done && /^Author:\s+([^<>]*)\s+<(.*)>\s*$/i) { + $this_author_name = $1; + $this_author_email = $2; + } elsif (!$header_done && /^$/ { # empty line ends header. + $header_done = 1; + } else { + $commit_msg .= $_; + $header_done = 1; + } + } + close MSG; + } + } + print FI < $author_time +0000 -committer $committer_name <$committer_email> $commit_time +0000 +author $this_author_name <$this_author_email> $author_time +0000 +committer $this_committer_name <$this_committer_email> $commit_time +0000 data < Date: Thu, 3 Sep 2009 13:15:00 +0100 Subject: [PATCH 10/42] Add script for importing bits-and-pieces to Git. Allows the user to import version history that is stored in bits and pieces in the file system, for instance snapshots of old development trees, or day-by-day backups. A configuration file is used to describe the relationship between the different files and allow describing branches and merges, as well as authorship and commit messages. Output is created in a format compatible with git-fast-import. Full documentation is provided inline in perldoc format. Signed-off-by: Peter Krefting Signed-off-by: Junio C Hamano --- contrib/fast-import/import-directories.perl | 416 ++++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100755 contrib/fast-import/import-directories.perl diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl new file mode 100755 index 0000000000..5782d80e26 --- /dev/null +++ b/contrib/fast-import/import-directories.perl @@ -0,0 +1,416 @@ +#!/usr/bin/perl -w +# +# Copyright 2008-2009 Peter Krefting +# +# ------------------------------------------------------------------------ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# ------------------------------------------------------------------------ + +=pod + +=head1 NAME + +import-directories - Import bits and pieces to Git. + +=head1 SYNOPSIS + +B F F + +=head1 DESCRIPTION + +Script to import arbitrary projects version controlled by the "copy the +source directory to a new location and edit it there"-version controlled +projects into version control. Handles projects with arbitrary branching +and version trees, taking a file describing the inputs and generating a +file compatible with the L format. + +=head1 CONFIGURATION FILE + +=head2 Format + +The configuration file is based on the standard I<.ini> format. + + ; Comments start with semi-colons + [section] + key=value + +Please see below for information on how to escape special characters. + +=head2 Global configuration + +Global configuration is done in the B<[config]> section, which should be +the first section in the file. Configuration can be changed by +repeating configuration sections later on. + + [config] + ; configure conversion of CRLFs. "convert" means that all CRLFs + ; should be converted into LFs (suitable for the core.autocrlf + ; setting set to true in Git). "none" means that all data is + ; treated as binary. + crlf=convert + +=head2 Revision configuration + +Each revision that is to be imported is described in three +sections. Revisions should be defined in topological order, so +that a revision's parent has always been defined when a new revision +is introduced. All the sections for one revision must be defined +before defining the next revision. + +Each revision is assigned a unique numerical identifier. The +numbers do not need to be consecutive, nor monotonically +increasing. + +For instance, if your configuration file contains only the two +revisions 4711 and 42, where 4711 is the initial commit, the +only requirement is that 4711 is completely defined before 42. + +=pod + +=head3 Revision description section + +A section whose section name is just an integer gives meta-data +about the revision. + + [3] + ; author sets the author of the revisions + author=Peter Krefting + ; branch sets the branch that the revision should be committed to + branch=master + ; parent describes the revision that is the parent of this commit + ; (optional) + parent=1 + ; merges describes a revision that is merged into this commit + ; (optional; can be repeated) + merges=2 + ; selects one file to take the timestamp from + ; (optional; if unspecified, the most recent file from the .files + ; section is used) + timestamp=3/source.c + +=head3 Revision contents section + +A section whose section name is an integer followed by B<.files> +describe all the files included in this revision. If a file that +was available previously is not included in this revision, it will +be removed. + +If an on-disk revision is incomplete, you can point to files from +a previous revision. There are no restriction as to where the source +files are located, nor to the names of them. + + [3.files] + ; the key is the path inside the repository, the value is the path + ; as seen from the importer script. + source.c=ver-3.00/source.c + source.h=ver-2.99/source.h + readme.txt=ver-3.00/introduction to the project.txt + +File names are treated as byte strings (but please see below on +quoting rules), and should be stored in the configuration file in +the encoding that should be used in the generated repository. + +=head3 Revision commit message section + +A section whose section name is an integer followed by B<.message> +gives the commit message. This section is read verbatim, up until +the beginning of the next section. As such, a commit message may not +contain a line that begins with an opening square bracket ("[") and +ends with a closing square bracket ("]"), unless they are surrounded +by whitespace or other characters. + + [3.message] + Implement foobar. + ; trailing blank lines are ignored. + +=cut + +# Globals +use strict; +use integer; +my $crlfmode = 0; +my @revs; +my (%revmap, %message, %files, %author, %branch, %parent, %merges, %time, %timesource); +my $sectiontype = 0; +my $rev = 0; +my $mark = 1; + +# Check command line +if ($#ARGV < 1 || $ARGV[0] =~ /^--?h/) +{ + exec('perldoc', $0); + exit 1; +} + +# Open configuration +my $config = $ARGV[0]; +open CFG, '<', $config or die "Cannot open configuration file \"$config\": "; + +# Open output +my $output = $ARGV[1]; +open OUT, '>', $output or die "Cannot create output file \"$output\": "; +binmode OUT; + +LINE: while (my $line = ) +{ + $line =~ s/\r?\n$//; + next LINE if $sectiontype != 4 && $line eq ''; + next LINE if $line =~ /^;/; + my $oldsectiontype = $sectiontype; + my $oldrev = $rev; + + # Sections + if ($line =~ m"^\[(config|(\d+)(|\.files|\.message))\]$") + { + if ($1 eq 'config') + { + $sectiontype = 1; + } + elsif ($3 eq '') + { + $sectiontype = 2; + $rev = $2; + # Create a new revision + die "Duplicate rev: $line\n " if defined $revmap{$rev}; + print "Reading revision $rev\n"; + push @revs, $rev; + $revmap{$rev} = $mark ++; + $time{$revmap{$rev}} = 0; + } + elsif ($3 eq '.files') + { + $sectiontype = 3; + $rev = $2; + die "Revision mismatch: $line\n " unless $rev == $oldrev; + } + elsif ($3 eq '.message') + { + $sectiontype = 4; + $rev = $2; + die "Revision mismatch: $line\n " unless $rev == $oldrev; + } + else + { + die "Internal parse error: $line\n "; + } + next LINE; + } + + # Parse data + if ($sectiontype != 4) + { + # Key and value + if ($line =~ m"^\s*([^\s].*=.*[^\s])\s*$") + { + my ($key, $value) = &parsekeyvaluepair($1); + # Global configuration + if (1 == $sectiontype) + { + if ($key eq 'crlf') + { + $crlfmode = 1, next LINE if $value eq 'convert'; + $crlfmode = 0, next LINE if $value eq 'none'; + } + die "Unknown configuration option: $line\n "; + } + # Revision specification + if (2 == $sectiontype) + { + my $current = $revmap{$rev}; + $author{$current} = $value, next LINE if $key eq 'author'; + $branch{$current} = $value, next LINE if $key eq 'branch'; + $parent{$current} = $value, next LINE if $key eq 'parent'; + $timesource{$current} = $value, next LINE if $key eq 'timestamp'; + push(@{$merges{$current}}, $value), next LINE if $key eq 'merges'; + die "Unknown revision option: $line\n "; + } + # Filespecs + if (3 == $sectiontype) + { + # Add the file and create a marker + die "File not found: $line\n " unless -f $value; + my $current = $revmap{$rev}; + ${$files{$current}}{$key} = $mark; + my $time = &fileblob($value, $crlfmode, $mark ++); + + # Update revision timestamp if more recent than other + # files seen, or if this is the file we have selected + # to take the time stamp from using the "timestamp" + # directive. + if ((defined $timesource{$current} && $timesource{$current} eq $value) + || $time > $time{$current}) + { + $time{$current} = $time; + } + } + } + else + { + die "Parse error: $line\n "; + } + } + else + { + # Commit message + my $current = $revmap{$rev}; + if (defined $message{$current}) + { + $message{$current} .= "\n"; + } + $message{$current} .= $line; + } +} +close CFG; + +# Start spewing out data for git-fast-import +foreach my $commit (@revs) +{ + # Progress + print OUT "progress Creating revision $commit\n"; + + # Create commit header + my $mark = $revmap{$commit}; + + # Branch and commit id + print OUT "commit refs/heads/", $branch{$mark}, "\nmark :", $mark, "\n"; + + # Author and timestamp + die "No timestamp defined for $commit (no files?)\n" unless defined $time{$mark}; + print OUT "committer ", $author{$mark}, " ", $time{$mark}, " +0100\n"; + + # Commit message + die "No message defined for $commit\n" unless defined $message{$mark}; + my $message = $message{$mark}; + $message =~ s/\n$//; # Kill trailing empty line + print OUT "data ", length($message), "\n", $message, "\n"; + + # Parent and any merges + print OUT "from :", $revmap{$parent{$mark}}, "\n" if defined $parent{$mark}; + if (defined $merges{$mark}) + { + foreach my $merge (@{$merges{$mark}}) + { + print OUT "merge :", $revmap{$merge}, "\n"; + } + } + + # Output file marks + print OUT "deleteall\n"; # start from scratch + foreach my $file (sort keys %{$files{$mark}}) + { + print OUT "M 644 :", ${$files{$mark}}{$file}, " $file\n"; + } + print OUT "\n"; +} + +# Create one file blob +sub fileblob +{ + my ($filename, $crlfmode, $mark) = @_; + + # Import the file + print OUT "progress Importing $filename\nblob\nmark :$mark\n"; + open FILE, '<', $filename or die "Cannot read $filename\n "; + binmode FILE; + my ($size, $mtime) = (stat(FILE))[7,9]; + my $file; + read FILE, $file, $size; + close FILE; + $file =~ s/\r\n/\n/g if $crlfmode; + print OUT "data ", length($file), "\n", $file, "\n"; + + return $mtime; +} + +# Parse a key=value pair +sub parsekeyvaluepair +{ +=pod + +=head2 Escaping special characters + +Key and value strings may be enclosed in quotes, in which case +whitespace inside the quotes is preserved. Additionally, an equal +sign may be included in the key by preceeding it with a backslash. +For example: + + "key1 "=value1 + key2=" value2" + key\=3=value3 + key4=value=4 + "key5""=value5 + +Here the first key is "key1 " (note the trailing white-space) and the +second value is " value2" (note the leading white-space). The third +key contains an equal sign "key=3" and so does the fourth value, which +does not need to be escaped. The fifth key contains a trailing quote, +which does not need to be escaped since it is inside a surrounding +quote. + +=cut + my $pair = shift; + + # Separate key and value by the first non-quoted equal sign + my ($key, $value); + if ($pair =~ /^(.*[^\\])=(.*)$/) + { + ($key, $value) = ($1, $2) + } + else + { + die "Parse error: $pair\n "; + } + + # Unquote and unescape the key and value separately + return (&unescape($key), &unescape($value)); +} + +# Unquote and unescape +sub unescape +{ + my $string = shift; + + # First remove enclosing quotes. Backslash before the trailing + # quote leaves both. + if ($string =~ /^"(.*[^\\])"$/) + { + $string = $1; + } + + # Second remove any backslashes inside the unquoted string. + # For later: Handle special sequences like \t ? + $string =~ s/\\(.)/$1/g; + + return $string; +} + +__END__ + +=pod + +=head1 EXAMPLES + +B F + +=head1 AUTHOR + +Copyright 2008-2009 Peter Krefting Epeter@softwolves.pp.se> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation. + +=cut From c9e388bb48bdafdf19574add915ab0ce33a1907d Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 3 Sep 2009 22:13:49 -0400 Subject: [PATCH 11/42] Make the "traditionally-supported" URLs a special case Instead of trying to make http://, https://, and ftp:// URLs indicative of some sort of pattern of transport helper usage, make them a special case which runs the "curl" helper, and leave the mechanism by which arbitrary helpers will be chosen entirely to future work. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Makefile | 17 ++--------------- transport-helper.c | 7 ++----- transport.c | 2 +- transport.h | 2 +- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 438cffb442..8c44e357c8 100644 --- a/Makefile +++ b/Makefile @@ -981,8 +981,7 @@ else else CURL_LIBCURL = -lcurl endif - CURL_SYNONYMS = git-remote-https$X git-remote-ftp$X - PROGRAMS += git-remote-http$X $(CURL_SYNONYMS) git-http-fetch$X + PROGRAMS += git-remote-curl$X git-http-fetch$X curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1497,16 +1496,10 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -git-remote-http$X: remote-curl.o http.o http-walker.o $(GITLIBS) +git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -$(CURL_SYNONYMS): git-remote-http$X - $(QUIET_LNCP)$(RM) $@ && \ - ln $< $@ 2>/dev/null || \ - ln -s $< $@ 2>/dev/null || \ - cp $< $@ - $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h @@ -1688,12 +1681,6 @@ endif ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git$X" "$$execdir/$$p" || exit; \ done; } && \ - { for p in $(CURL_SYNONYMS); do \ - $(RM) "$$execdir/$$p" && \ - ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ - ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ - cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \ - done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: diff --git a/transport-helper.c b/transport-helper.c index 43fdc0a434..4684877723 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -152,13 +152,10 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) return ret; } -int transport_helper_init(struct transport *transport) +int transport_helper_init(struct transport *transport, const char *name) { struct helper_data *data = xcalloc(sizeof(*data), 1); - char *eom = strchr(transport->url, ':'); - if (!eom) - return -1; - data->name = xstrndup(transport->url, eom - transport->url); + data->name = name; transport->data = data; transport->get_refs_list = get_refs_list; diff --git a/transport.c b/transport.c index 9935c85cf3..b654d71d5a 100644 --- a/transport.c +++ b/transport.c @@ -818,7 +818,7 @@ struct transport *transport_get(struct remote *remote, const char *url) } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { - transport_helper_init(ret); + transport_helper_init(ret, "curl"); #ifdef NO_CURL error("git was compiled without libcurl support."); #else diff --git a/transport.h b/transport.h index df87264637..b49c10f57d 100644 --- a/transport.h +++ b/transport.h @@ -78,6 +78,6 @@ int transport_disconnect(struct transport *transport); char *transport_anonymize_url(const char *url); /* Transport methods defined outside transport.c */ -int transport_helper_init(struct transport *transport); +int transport_helper_init(struct transport *transport, const char *name); #endif From 2d14d65ce7b136b0fb18dcf27e5caff67829f658 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 3 Sep 2009 22:13:51 -0400 Subject: [PATCH 12/42] Use a clearer style to issue commands to remote helpers This style is overkill for some commands, but it's worthwhile to use the same style to issue all commands, and it's useful to avoid open-coding string lengths. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- transport-helper.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/transport-helper.c b/transport-helper.c index 4684877723..b1ea7e6f40 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -37,7 +37,10 @@ static struct child_process *get_helper(struct transport *transport) die("Unable to run helper: git %s", helper->argv[0]); data->helper = helper; - write_in_full(data->helper->in, "capabilities\n", 13); + strbuf_addstr(&buf, "capabilities\n"); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); + file = fdopen(helper->out, "r"); while (1) { if (strbuf_getline(&buf, file, '\n') == EOF) @@ -78,11 +81,12 @@ static int fetch_with_fetch(struct transport *transport, const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; - write_in_full(helper->in, "fetch ", 6); - write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40); - write_in_full(helper->in, " ", 1); - write_in_full(helper->in, posn->name, strlen(posn->name)); - write_in_full(helper->in, "\n", 1); + + strbuf_addf(&buf, "fetch %s %s\n", + sha1_to_hex(posn->old_sha1), posn->name); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); + if (strbuf_getline(&buf, file, '\n') == EOF) exit(128); /* child died, message supplied already */ } @@ -119,7 +123,10 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) FILE *file; helper = get_helper(transport); - write_in_full(helper->in, "list\n", 5); + + strbuf_addstr(&buf, "list\n"); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); file = fdopen(helper->out, "r"); while (1) { From d071d942963fa76b11826f25c54fdfd8b09d7626 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 7 Sep 2009 01:56:00 -0700 Subject: [PATCH 13/42] Wrap rewrite globals in a struct in preparation for adding another set remote.c has a global set of URL rewrites, accessed by alias_url and make_rewrite. Wrap them in a new "struct rewrites", passed to alias_url and make_rewrite. This allows adding other sets of rewrites. Signed-off-by: Josh Triplett Signed-off-by: Junio C Hamano --- remote.c | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/remote.c b/remote.c index 4b5b905979..ff8e71f0b9 100644 --- a/remote.c +++ b/remote.c @@ -28,6 +28,11 @@ struct rewrite { int instead_of_nr; int instead_of_alloc; }; +struct rewrites { + struct rewrite **rewrite; + int rewrite_alloc; + int rewrite_nr; +}; static struct remote **remotes; static int remotes_alloc; @@ -41,14 +46,12 @@ static struct branch *current_branch; static const char *default_remote_name; static int explicit_default_remote_name; -static struct rewrite **rewrite; -static int rewrite_alloc; -static int rewrite_nr; +static struct rewrites rewrites; #define BUF_SIZE (2048) static char buffer[BUF_SIZE]; -static const char *alias_url(const char *url) +static const char *alias_url(const char *url, struct rewrites *r) { int i, j; char *ret; @@ -57,14 +60,14 @@ static const char *alias_url(const char *url) longest = NULL; longest_i = -1; - for (i = 0; i < rewrite_nr; i++) { - if (!rewrite[i]) + for (i = 0; i < r->rewrite_nr; i++) { + if (!r->rewrite[i]) continue; - for (j = 0; j < rewrite[i]->instead_of_nr; j++) { - if (!prefixcmp(url, rewrite[i]->instead_of[j].s) && + for (j = 0; j < r->rewrite[i]->instead_of_nr; j++) { + if (!prefixcmp(url, r->rewrite[i]->instead_of[j].s) && (!longest || - longest->len < rewrite[i]->instead_of[j].len)) { - longest = &(rewrite[i]->instead_of[j]); + longest->len < r->rewrite[i]->instead_of[j].len)) { + longest = &(r->rewrite[i]->instead_of[j]); longest_i = i; } } @@ -72,10 +75,10 @@ static const char *alias_url(const char *url) if (!longest) return url; - ret = xmalloc(rewrite[longest_i]->baselen + + ret = xmalloc(r->rewrite[longest_i]->baselen + (strlen(url) - longest->len) + 1); - strcpy(ret, rewrite[longest_i]->base); - strcpy(ret + rewrite[longest_i]->baselen, url + longest->len); + strcpy(ret, r->rewrite[longest_i]->base); + strcpy(ret + r->rewrite[longest_i]->baselen, url + longest->len); return ret; } @@ -103,7 +106,7 @@ static void add_url(struct remote *remote, const char *url) static void add_url_alias(struct remote *remote, const char *url) { - add_url(remote, alias_url(url)); + add_url(remote, alias_url(url, &rewrites)); } static void add_pushurl(struct remote *remote, const char *pushurl) @@ -169,22 +172,22 @@ static struct branch *make_branch(const char *name, int len) return ret; } -static struct rewrite *make_rewrite(const char *base, int len) +static struct rewrite *make_rewrite(struct rewrites *r, const char *base, int len) { struct rewrite *ret; int i; - for (i = 0; i < rewrite_nr; i++) { + for (i = 0; i < r->rewrite_nr; i++) { if (len - ? (len == rewrite[i]->baselen && - !strncmp(base, rewrite[i]->base, len)) - : !strcmp(base, rewrite[i]->base)) - return rewrite[i]; + ? (len == r->rewrite[i]->baselen && + !strncmp(base, r->rewrite[i]->base, len)) + : !strcmp(base, r->rewrite[i]->base)) + return r->rewrite[i]; } - ALLOC_GROW(rewrite, rewrite_nr + 1, rewrite_alloc); + ALLOC_GROW(r->rewrite, r->rewrite_nr + 1, r->rewrite_alloc); ret = xcalloc(1, sizeof(struct rewrite)); - rewrite[rewrite_nr++] = ret; + r->rewrite[r->rewrite_nr++] = ret; if (len) { ret->base = xstrndup(base, len); ret->baselen = len; @@ -355,7 +358,7 @@ static int handle_config(const char *key, const char *value, void *cb) subkey = strrchr(name, '.'); if (!subkey) return 0; - rewrite = make_rewrite(name, subkey - name); + rewrite = make_rewrite(&rewrites, name, subkey - name); if (!strcmp(subkey, ".insteadof")) { if (!value) return config_error_nonbool(key); @@ -433,10 +436,10 @@ static void alias_all_urls(void) if (!remotes[i]) continue; for (j = 0; j < remotes[i]->url_nr; j++) { - remotes[i]->url[j] = alias_url(remotes[i]->url[j]); + remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites); } for (j = 0; j < remotes[i]->pushurl_nr; j++) { - remotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j]); + remotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites); } } } From 929e37d3dfef13895ef6e4b54c7d45962b234461 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Mon, 7 Sep 2009 10:48:01 +0200 Subject: [PATCH 14/42] grep: fix exit status if external_grep() punts If external_grep() is called and punts, grep_cache() mistakenly reported a hit, even if there were none. The bug can be triggered by calling "git grep --no-color" from a subdirectory. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- builtin-grep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-grep.c b/builtin-grep.c index f88a912ace..da2f4fe1b8 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -448,6 +448,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) hit = external_grep(opt, paths, cached); if (hit >= 0) return hit; + hit = 0; } #endif From 493b7a08d80535def6756b281873e4e0937ba6c2 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Sat, 5 Sep 2009 14:31:17 +0200 Subject: [PATCH 15/42] grep: accept relative paths outside current working directory "git grep" would barf at relative paths pointing outside the current working directory (or subdirectories thereof). Use quote_path_relative(), which can handle such cases just fine. [jc: added tests.] Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- builtin-grep.c | 38 +++++++++++--------------------------- grep.h | 1 + t/t7002-grep.sh | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index da2f4fe1b8..eda2c88487 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -11,6 +11,7 @@ #include "tree-walk.h" #include "builtin.h" #include "grep.h" +#include "quote.h" #ifndef NO_EXTERNAL_GREP #ifdef __unix__ @@ -114,8 +115,8 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char unsigned long size; char *data; enum object_type type; - char *to_free = NULL; int hit; + struct strbuf pathbuf = STRBUF_INIT; data = read_sha1_file(sha1, &type, &size); if (!data) { @@ -123,26 +124,13 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char return 0; } if (opt->relative && opt->prefix_length) { - static char name_buf[PATH_MAX]; - char *cp; - int name_len = strlen(name) - opt->prefix_length + 1; - - if (!tree_name_len) - name += opt->prefix_length; - else { - if (ARRAY_SIZE(name_buf) <= name_len) - cp = to_free = xmalloc(name_len); - else - cp = name_buf; - memcpy(cp, name, tree_name_len); - strcpy(cp + tree_name_len, - name + tree_name_len + opt->prefix_length); - name = cp; - } + quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix); + strbuf_insert(&pathbuf, 0, name, tree_name_len); + name = pathbuf.buf; } hit = grep_buffer(opt, name, data, size); + strbuf_release(&pathbuf); free(data); - free(to_free); return hit; } @@ -152,6 +140,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) int i; char *data; size_t sz; + struct strbuf buf = STRBUF_INIT; if (lstat(filename, &st) < 0) { err_ret: @@ -176,8 +165,9 @@ static int grep_file(struct grep_opt *opt, const char *filename) } close(i); if (opt->relative && opt->prefix_length) - filename += opt->prefix_length; + filename = quote_path_relative(filename, -1, &buf, opt->prefix); i = grep_buffer(opt, filename, data, sz); + strbuf_release(&buf); free(data); return i; } @@ -582,6 +572,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int i; memset(&opt, 0, sizeof(opt)); + opt.prefix = prefix; opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt.relative = 1; opt.pathname = 1; @@ -857,15 +848,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) verify_filename(prefix, argv[j]); } - if (i < argc) { + if (i < argc) paths = get_pathspec(prefix, argv + i); - if (opt.prefix_length && opt.relative) { - /* Make sure we do not get outside of paths */ - for (i = 0; paths[i]; i++) - if (strncmp(prefix, paths[i], opt.prefix_length)) - die("git grep: cannot generate relative filenames containing '..'"); - } - } else if (prefix) { paths = xcalloc(2, sizeof(const char *)); paths[0] = prefix; diff --git a/grep.h b/grep.h index a67005de62..5b767c931c 100644 --- a/grep.h +++ b/grep.h @@ -59,6 +59,7 @@ struct grep_opt { struct grep_pat *pattern_list; struct grep_pat **pattern_tail; struct grep_expr *pattern_expression; + const char *prefix; int prefix_length; regex_t regexp; unsigned linenum:1; diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index 7868af8f18..fe87834fbe 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -212,4 +212,21 @@ test_expect_success 'grep with CE_VALID file' ' git checkout t/t ' +test_expect_success 'grep from a subdirectory to search wider area (1)' ' + mkdir -p s && + ( + cd s && git grep "x x x" .. + ) +' + +test_expect_success 'grep from a subdirectory to search wider area (2)' ' + mkdir -p s && + ( + cd s || exit 1 + ( git grep xxyyzz .. >out ; echo $? >status ) + ! test -s out && + test 1 = $(cat status) + ) +' + test_done From 1c2eafb89bcaf2ddbf4dfb93df19673c0fadaaeb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 7 Sep 2009 01:56:33 -0700 Subject: [PATCH 16/42] Add url..pushInsteadOf: URL rewriting for push only This configuration option allows systematically rewriting fetch-only URLs to push-capable URLs when used with push. For instance: [url "ssh://example.org/"] pushInsteadOf = "git://example.org/" This will allow clones of "git://example.org/path/to/repo" to subsequently push to "ssh://example.org/path/to/repo", without manually configuring pushurl for that remote. Includes documentation for the new option, bash completion updates, and test cases (both that pushInsteadOf applies to push, that it does not apply to fetch, and that it is ignored when pushURL is already defined). Signed-off-by: Josh Triplett Signed-off-by: Junio C Hamano --- Documentation/config.txt | 13 +++++++ Documentation/urls.txt | 18 ++++++++++ contrib/completion/git-completion.bash | 2 +- remote.c | 36 +++++++++++++++----- t/t5516-fetch-push.sh | 47 ++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 10 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 5256c7fb81..38c708642d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1500,6 +1500,19 @@ url..insteadOf:: never-before-seen repository on the site. When more than one insteadOf strings match a given URL, the longest match is used. +url..pushInsteadOf:: + Any URL that starts with this value will not be pushed to; + instead, it will be rewritten to start with , and the + resulting URL will be pushed to. In cases where some site serves + a large number of repositories, and serves them with multiple + access methods, some of which do not allow push, this feature + allows people to specify a pull-only URL and have git + automatically use an appropriate URL to push, even for a + never-before-seen repository on the site. When more than one + pushInsteadOf strings match a given URL, the longest match is + used. If a remote has an explicit pushurl, git will ignore this + setting for that remote. + user.email:: Your email address to be recorded in any newly created commits. Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 5355ebc0f3..d813ceb723 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -67,3 +67,21 @@ For example, with this: a URL like "work:repo.git" or like "host.xz:/path/to/repo.git" will be rewritten in any context that takes a URL to be "git://git.host.xz/repo.git". +If you want to rewrite URLs for push only, you can create a +configuration section of the form: + +------------ + [url ""] + pushInsteadOf = +------------ + +For example, with this: + +------------ + [url "ssh://example.org/"] + pushInsteadOf = git://example.org/ +------------ + +a URL like "git://example.org/path/to/repo.git" will be rewritten to +"ssh://example.org/path/to/repo.git" for pushes, but pulls will still +use the original URL. diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index bf688e12e6..98592040d1 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1532,7 +1532,7 @@ _git_config () url.*.*) local pfx="${cur%.*}." cur="${cur##*.}" - __gitcomp "insteadof" "$pfx" "$cur" + __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur" return ;; esac diff --git a/remote.c b/remote.c index ff8e71f0b9..73d33f2584 100644 --- a/remote.c +++ b/remote.c @@ -47,6 +47,7 @@ static const char *default_remote_name; static int explicit_default_remote_name; static struct rewrites rewrites; +static struct rewrites rewrites_push; #define BUF_SIZE (2048) static char buffer[BUF_SIZE]; @@ -104,17 +105,25 @@ static void add_url(struct remote *remote, const char *url) remote->url[remote->url_nr++] = url; } -static void add_url_alias(struct remote *remote, const char *url) -{ - add_url(remote, alias_url(url, &rewrites)); -} - static void add_pushurl(struct remote *remote, const char *pushurl) { ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc); remote->pushurl[remote->pushurl_nr++] = pushurl; } +static void add_pushurl_alias(struct remote *remote, const char *url) +{ + const char *pushurl = alias_url(url, &rewrites_push); + if (pushurl != url) + add_pushurl(remote, pushurl); +} + +static void add_url_alias(struct remote *remote, const char *url) +{ + add_url(remote, alias_url(url, &rewrites)); + add_pushurl_alias(remote, url); +} + static struct remote *make_remote(const char *name, int len) { struct remote *ret; @@ -358,8 +367,13 @@ static int handle_config(const char *key, const char *value, void *cb) subkey = strrchr(name, '.'); if (!subkey) return 0; - rewrite = make_rewrite(&rewrites, name, subkey - name); if (!strcmp(subkey, ".insteadof")) { + rewrite = make_rewrite(&rewrites, name, subkey - name); + if (!value) + return config_error_nonbool(key); + add_instead_of(rewrite, xstrdup(value)); + } else if (!strcmp(subkey, ".pushinsteadof")) { + rewrite = make_rewrite(&rewrites_push, name, subkey - name); if (!value) return config_error_nonbool(key); add_instead_of(rewrite, xstrdup(value)); @@ -433,14 +447,18 @@ static void alias_all_urls(void) { int i, j; for (i = 0; i < remotes_nr; i++) { + int add_pushurl_aliases; if (!remotes[i]) continue; - for (j = 0; j < remotes[i]->url_nr; j++) { - remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites); - } for (j = 0; j < remotes[i]->pushurl_nr; j++) { remotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites); } + add_pushurl_aliases = remotes[i]->pushurl_nr == 0; + for (j = 0; j < remotes[i]->url_nr; j++) { + if (add_pushurl_aliases) + add_pushurl_alias(remotes[i], remotes[i]->url[j]); + remotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites); + } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2d2633f3f8..6889a53cf9 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -122,6 +122,23 @@ test_expect_success 'fetch with insteadOf' ' ) ' +test_expect_success 'fetch with pushInsteadOf (should not rewrite)' ' + mk_empty && + ( + TRASH=$(pwd)/ && + cd testrepo && + git config "url.trash/.pushInsteadOf" "$TRASH" && + git config remote.up.url "$TRASH." && + git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" && + git fetch up && + + r=$(git show-ref -s --verify refs/remotes/origin/master) && + test "z$r" = "z$the_commit" && + + test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + ) +' + test_expect_success 'push without wildcard' ' mk_empty && @@ -162,6 +179,36 @@ test_expect_success 'push with insteadOf' ' ) ' +test_expect_success 'push with pushInsteadOf' ' + mk_empty && + TRASH="$(pwd)/" && + git config "url.$TRASH.pushInsteadOf" trash/ && + git push trash/testrepo refs/heads/master:refs/remotes/origin/master && + ( + cd testrepo && + r=$(git show-ref -s --verify refs/remotes/origin/master) && + test "z$r" = "z$the_commit" && + + test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + ) +' + +test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' ' + mk_empty && + TRASH="$(pwd)/" && + git config "url.trash2/.pushInsteadOf" trash/ && + git config remote.r.url trash/wrong && + git config remote.r.pushurl "$TRASH/testrepo" && + git push r refs/heads/master:refs/remotes/origin/master && + ( + cd testrepo && + r=$(git show-ref -s --verify refs/remotes/origin/master) && + test "z$r" = "z$the_commit" && + + test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + ) +' + test_expect_success 'push with matching heads' ' mk_test heads/master && From fadd069d036c9d376769692e2726c5a1600d281c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 7 Sep 2009 22:43:11 -0700 Subject: [PATCH 17/42] merge-recursive: give less scary messages when merge did not start When unpack_trees() three-way merge logic is called from merge-recursive and finds that local changes are going to be clobbered, its plumbing level messages were given as errors first, and then the merge driver added even more scary message "fatal: merging of trees and failed". This is most often encountered by new CVS/SVN migrants who are used to start a merge from a dirty work tree. The saddest part is that the merge refused to run to prevent _any_ damage from being done to your work tree when these messages are given, but the messages look a lot more scarier than the conflicted case where the user needs to resolve them. Replace the plumbing level messages so that they talk about what it is protecting the user from, and end the messages with "Aborting." so that it becomes clear that the command did not do any harm. The final "merging of trees failed" message is superfluous, unless you are interested in debugging the merge-recursive itself. Squelch the current die() message by default, but allow it to help people who debug git with verbosity level 4 or greater. Unless there is some bug, an inner merge that does not touch working tree should not trigger any such error, so emit the current die() message when we see an error return from it while running the inner merge, too. It would also help people who debug git. We could later add instructions on how to recover (i.e. "stash changes away or commit on a side branch and retry") instead of the silent exit(128) I have in this patch, and then use Peff's advice.* mechanism to squelch it (e.g. "advice.mergeindirtytree"), but they are separate topics. Tested-by: Nanako Shiraishi Signed-off-by: Junio C Hamano --- merge-recursive.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 10d7913b06..f55b7ebe11 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -170,6 +170,18 @@ static int git_merge_trees(int index_only, int rc; struct tree_desc t[3]; struct unpack_trees_options opts; + static const struct unpack_trees_error_msgs msgs = { + /* would_overwrite */ + "Your local changes to '%s' would be overwritten by merge. Aborting.", + /* not_uptodate_file */ + "Your local changes to '%s' would be overwritten by merge. Aborting.", + /* not_uptodate_dir */ + "Updating '%s' would lose untracked files in it. Aborting.", + /* would_lose_untracked */ + "Untracked working tree file '%s' would be %s by merge. Aborting", + /* bind_overlap -- will not happen here */ + NULL, + }; memset(&opts, 0, sizeof(opts)); if (index_only) @@ -181,6 +193,7 @@ static int git_merge_trees(int index_only, opts.fn = threeway_merge; opts.src_index = &the_index; opts.dst_index = &the_index; + opts.msgs = msgs; init_tree_desc_from_tree(t+0, common); init_tree_desc_from_tree(t+1, head); @@ -1188,10 +1201,14 @@ int merge_trees(struct merge_options *o, code = git_merge_trees(o->call_depth, common, head, merge); - if (code != 0) - die("merging of trees %s and %s failed", - sha1_to_hex(head->object.sha1), - sha1_to_hex(merge->object.sha1)); + if (code != 0) { + if (show(o, 4) || o->call_depth) + die("merging of trees %s and %s failed", + sha1_to_hex(head->object.sha1), + sha1_to_hex(merge->object.sha1)); + else + exit(128); + } if (unmerged_cache()) { struct string_list *entries, *re_head, *re_merge; From 3de8ba021718e80ef1bbf8a5a541beec86930f4c Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Tue, 8 Sep 2009 21:50:59 -0400 Subject: [PATCH 18/42] INSTALL: Update description of our SHA-1 code We haven't had Mozilla's code or an ARM optimized algorithm since 30ae47b. Reword the paragraph to give credit but not authorship to Mozilla. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- INSTALL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index ae7f7508f8..5267468f09 100644 --- a/INSTALL +++ b/INSTALL @@ -56,8 +56,8 @@ Issues of note: library from here. If you don't have openssl, you can use one of the SHA1 libraries - that come with git (git includes the one from Mozilla, and has - its own PowerPC and ARM optimized ones too - see the Makefile). + that come with git (git includes one inspired by Mozilla's and a + PowerPC optimized one too - see the Makefile). - libcurl library; git-http-fetch and git-fetch use them. You might also want the "curl" executable for debugging purposes. From aaa68dd50f7b4226fdfdfbbe8bbb2dfd9a9e6d66 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 3 Sep 2009 22:27:24 +0200 Subject: [PATCH 19/42] git.el: Use git-add-file for unmerged files, remove git-resolve-file Use `git-add-file' to mark unmerged files as resolved in the *git-status* buffer to be consistent with git's CLI instructions. Also remove `git-resolve-file' to make it clear that that "R" is a now a free keybinding. Signed-off-by: Martin Nordholts Acked-by: Alexandre Julliard Signed-off-by: Junio C Hamano --- contrib/emacs/git.el | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 8c70ad8b7f..214930a021 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -1046,7 +1046,7 @@ The FILES list must be sorted." (defun git-add-file () "Add marked file(s) to the index cache." (interactive) - (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored)))) + (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored 'unmerged)))) ;; FIXME: add support for directories (unless files (push (file-relative-name (read-file-name "File to add: " nil nil t)) files)) @@ -1119,15 +1119,6 @@ The FILES list must be sorted." (when buffer (with-current-buffer buffer (revert-buffer t t t))))) (git-success-message "Reverted" names)))))) -(defun git-resolve-file () - "Resolve conflicts in marked file(s)." - (interactive) - (let ((files (git-get-filenames (git-marked-files-state 'unmerged)))) - (when files - (when (apply 'git-call-process-display-error "update-index" "--" files) - (git-update-status-files files) - (git-success-message "Resolved" files))))) - (defun git-remove-handled () "Remove handled files from the status list." (interactive) @@ -1556,7 +1547,6 @@ amended version of it." (define-key map "P" 'git-prev-unmerged-file) (define-key map "q" 'git-status-quit) (define-key map "r" 'git-remove-file) - (define-key map "R" 'git-resolve-file) (define-key map "t" toggle-map) (define-key map "T" 'git-toggle-all-marks) (define-key map "u" 'git-unmark-file) @@ -1598,7 +1588,6 @@ amended version of it." ("Merge" ["Next Unmerged File" git-next-unmerged-file t] ["Prev Unmerged File" git-prev-unmerged-file t] - ["Mark as Resolved" git-resolve-file t] ["Interactive Merge File" git-find-file-imerge t] ["Diff Against Common Base File" git-diff-file-base t] ["Diff Combined" git-diff-file-combined t] From 0460dba4b4c47ac0b11ccb85b319792280422bc9 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Tue, 8 Sep 2009 09:54:38 -0400 Subject: [PATCH 20/42] Makefile: Add NEEDS_CRYPTO_WITH_SSL The Makefile comment for NEEDS_SSL_WITH_CRYPTO says to define it "if you need -lcrypto with -lssl (Darwin)." However, what it actually does is add -lssl when you use -lcrypto and not the other way around. However, libcrypto contains a majority of the ERR_* functions from OpenSSL (at least on OS X) so we need it both ways. So, add NEEDS_CRYPTO_WITH_SSL which adds -lcrypto to the OpenSSL link flags and clarify the difference between it and NEEDS_SSL_WITH_CRYPTO. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a614347568..1cc9a4183a 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,9 @@ all:: # Define PPC_SHA1 environment variable when running make to make use of # a bundled SHA1 routine optimized for PowerPC. # -# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). +# Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin). +# +# Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin). # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). # @@ -704,6 +706,7 @@ ifeq ($(uname_S),SCO_SV) TAR = gtar endif ifeq ($(uname_S),Darwin) + NEEDS_CRYPTO_WITH_SSL = YesPlease NEEDS_SSL_WITH_CRYPTO = YesPlease NEEDS_LIBICONV = YesPlease ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2) @@ -1007,6 +1010,9 @@ ifndef NO_OPENSSL else OPENSSL_LINK = endif + ifdef NEEDS_CRYPTO_WITH_SSL + OPENSSL_LINK += -lcrypto + endif else BASIC_CFLAGS += -DNO_OPENSSL BLK_SHA1 = 1 From 1d7367dce7b55cbb1804c4863c56bd20ab12bda8 Mon Sep 17 00:00:00 2001 From: Reilly Grant Date: Thu, 10 Sep 2009 00:02:38 -0700 Subject: [PATCH 21/42] git-p4: Avoid modules deprecated in Python 2.6. The popen2, sha and sets modules are deprecated in Python 2.6 (sha in Python 2.5). Both popen2 and sha are not actually used in git-p4. Replace usage of sets.Set with the builtin set object. The built-in set object was added in Python 2.4 and is already used in other parts of this script, so this dependency is nothing new. Signed-off-by: Reilly Grant Signed-off-by: Junio C Hamano --- contrib/fast-import/git-p4 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 38438f3c4a..e710219ca5 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -8,12 +8,10 @@ # License: MIT # -import optparse, sys, os, marshal, popen2, subprocess, shelve -import tempfile, getopt, sha, os.path, time, platform +import optparse, sys, os, marshal, subprocess, shelve +import tempfile, getopt, os.path, time, platform import re -from sets import Set; - verbose = False @@ -864,8 +862,8 @@ class P4Sync(Command): self.usage += " //depot/path[@revRange]" self.silent = False - self.createdBranches = Set() - self.committedChanges = Set() + self.createdBranches = set() + self.committedChanges = set() self.branch = "" self.detectBranches = False self.detectLabels = False @@ -1662,7 +1660,7 @@ class P4Sync(Command): if len(self.changesFile) > 0: output = open(self.changesFile).readlines() - changeSet = Set() + changeSet = set() for line in output: changeSet.add(int(line)) From 26d9443925517f6d93dbcb6f4eca30af82703de3 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Tue, 8 Sep 2009 21:51:00 -0400 Subject: [PATCH 22/42] INSTALL: Reorder dependencies, split shell and Perl The most important and non-optional dependencies should go first, so put them there. While we're moving them, the descriptions for shell and perl were archaic, referring to "bare-bones Porcelainish scripts" that have become powerful and essential. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- INSTALL | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/INSTALL b/INSTALL index 5267468f09..7ab2580ede 100644 --- a/INSTALL +++ b/INSTALL @@ -52,6 +52,15 @@ Issues of note: - "zlib", the compression library. Git won't build without it. + - "ssh" is used to push and pull over the net. + + - A POSIX-compliant shell is required to run many scripts needed + for everyday use (e.g. "bisect", "pull"). + + - "Perl" is needed to use some of the features (e.g. preparing a + partial commit using "git add -i/-p", interacting with svn + repositories with "git svn"). + - "openssl". Unless you specify otherwise, you'll get the SHA1 library from here. @@ -70,11 +79,6 @@ Issues of note: - "wish", the Tcl/Tk windowing shell is used in gitk to show the history graphically, and in git-gui. - - "ssh" is used to push and pull over the net - - - "perl" and POSIX-compliant shells are needed to use most of - the bare-bones Porcelainish scripts. - - Some platform specific issues are dealt with Makefile rules, but depending on your specific installation, you may not have all the libraries/tools needed, or you may have From 5beb577db8c61a7a511fac1d970a5ae3dde11eca Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Thu, 10 Sep 2009 16:28:19 -0400 Subject: [PATCH 23/42] INSTALL: Describe dependency knobs from Makefile We said that some of our dependencies were optional, but didn't say how to turn them off. Add information for that and mention where to save the options close to the top of the file. Also, standardize on both using quotes for the names of the dependencies and tabs for indentation of the list. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- INSTALL | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/INSTALL b/INSTALL index 7ab2580ede..be504c95e1 100644 --- a/INSTALL +++ b/INSTALL @@ -13,6 +13,10 @@ that uses $prefix, the built results have some paths encoded, which are derived from $prefix, so "make all; make prefix=/usr install" would not work. +The beginning of the Makefile documents many variables that affect the way +git is built. You can override them either from the command line, or in a +config.mak file. + Alternatively you can use autoconf generated ./configure script to set up install paths (via config.mak.autogen), so you can write instead @@ -48,7 +52,9 @@ Issues of note: export GIT_EXEC_PATH PATH GITPERLLIB - Git is reasonably self-sufficient, but does depend on a few external - programs and libraries: + programs and libraries. Git can be used without most of them by adding + the approriate "NO_=YesPlease" to the make command line or + config.mak file. - "zlib", the compression library. Git won't build without it. @@ -59,25 +65,29 @@ Issues of note: - "Perl" is needed to use some of the features (e.g. preparing a partial commit using "git add -i/-p", interacting with svn - repositories with "git svn"). + repositories with "git svn"). If you can live without these, use + NO_PERL. - - "openssl". Unless you specify otherwise, you'll get the SHA1 - library from here. + - "openssl" library is used by git-imap-send to use IMAP over SSL. + If you don't need it, use NO_OPENSSL. - If you don't have openssl, you can use one of the SHA1 libraries - that come with git (git includes one inspired by Mozilla's and a - PowerPC optimized one too - see the Makefile). + By default, git uses OpenSSL for SHA1 but it will use it's own + library (inspired by Mozilla's) with either NO_OPENSSL or + BLK_SHA1. Also included is a version optimized for PowerPC + (PPC_SHA1). - - libcurl library; git-http-fetch and git-fetch use them. You + - "libcurl" library is used by git-http-fetch and git-fetch. You might also want the "curl" executable for debugging purposes. - If you do not use http transfer, you are probably OK if you - do not have them. + If you do not use http:// or https:// repositories, you do not + have to have them (use NO_CURL). - - expat library; git-http-push uses it for remote lock - management over DAV. Similar to "curl" above, this is optional. + - "expat" library; git-http-push uses it for remote lock + management over DAV. Similar to "curl" above, this is optional + (with NO_EXPAT). - - "wish", the Tcl/Tk windowing shell is used in gitk to show the - history graphically, and in git-gui. + - "wish", the Tcl/Tk windowing shell is used in gitk to show the + history graphically, and in git-gui. If you don't want gitk or + git-gui, you can use NO_TCLTK. - Some platform specific issues are dealt with Makefile rules, but depending on your specific installation, you may not From e019961d7f55ff76eff93d74e7705d6bd55218eb Mon Sep 17 00:00:00 2001 From: Nicolas Sebrecht Date: Fri, 11 Sep 2009 02:09:20 +0200 Subject: [PATCH 24/42] mailinfo: add '--scissors' to usage message Signed-off-by: Nicolas Sebrecht Signed-off-by: Junio C Hamano --- builtin-mailinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 03cbcad1ff..7d22fd733a 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -1004,7 +1004,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused) } static const char mailinfo_usage[] = - "git mailinfo [-k] [-u | --encoding= | -n] msg patch info"; + "git mailinfo [-k] [-u | --encoding= | -n] [--scissors] msg patch < mail >info"; int cmd_mailinfo(int argc, const char **argv, const char *prefix) { From 434a6db7dcf8688fe08098e218113c18b7c9aeaf Mon Sep 17 00:00:00 2001 From: Nicolas Sebrecht Date: Fri, 11 Sep 2009 02:29:58 +0200 Subject: [PATCH 25/42] add documentation for mailinfo.scissors and '--no-scissors' Signed-off-by: Nicolas Sebrecht Signed-off-by: Junio C Hamano --- Documentation/git-am.txt | 5 ++++- Documentation/git-mailinfo.txt | 5 +++++ builtin-mailinfo.c | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 87781f4a77..67ad5da9cc 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -13,7 +13,7 @@ SYNOPSIS [--3way] [--interactive] [--committer-date-is-author-date] [--ignore-date] [--ignore-space-change | --ignore-whitespace] [--whitespace=