diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt index b58165a5fc..cfc7b62f31 100644 --- a/Documentation/git-clone-pack.txt +++ b/Documentation/git-clone-pack.txt @@ -8,26 +8,17 @@ git-clone-pack - Clones a repository by receiving packed objects. SYNOPSIS -------- -'git-clone-pack' [-q] [--keep] [--exec=] [:] [...] +'git-clone-pack' [--exec=] [:] [...] DESCRIPTION ----------- Clones a repository into the current repository by invoking 'git-upload-pack', possibly on the remote host via ssh, in -the named repository, and invoking 'git-unpack-objects' locally -to receive the pack. +the named repository, and stores the sent pack in the local +repository. OPTIONS ------- --q:: - Pass '-q' flag to 'git-unpack-objects'; this makes the - cloning process less verbose. - ---keep:: - Do not invoke 'git-unpack-objects' on received data, but - create a single packfile out of it instead, and store it - in the object database. - --exec=:: Use this to specify the path to 'git-upload-pack' on the remote side, if it is not found on your $PATH. diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index c0b5aac5f2..71693650c4 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -25,6 +25,11 @@ OPTIONS ------- include::pull-fetch-param.txt[] +-a, \--append:: + Append ref names and object names of fetched refs to the + existing contents of $GIT_DIR/FETCH_HEAD. Without this + option old data in $GIT_DIR/FETCH_HEAD will be overwritten. + -u, \--update-head-ok:: By default 'git-fetch' refuses to update the head which corresponds to the current branch. This flag disables the diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 952779292b..bae05dee99 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -24,6 +24,10 @@ OPTIONS ------- include::pull-fetch-param.txt[] +-a, \--append:: + Append ref names and object names of fetched refs to the + existing contents of $GIT_DIR/FETCH_HEAD. Without this + option old data in $GIT_DIR/FETCH_HEAD will be overwritten. Author ------ diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 809ac8ba06..f45ac5ee49 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -21,6 +21,15 @@ OPTIONS ------- include::pull-fetch-param.txt[] +\--all:: + Instead of naming each ref to push, specifies all refs + to be pushed. + +-f, \--force:: + Usually, the command refuses to update a local ref that is + not an ancestor of the remote ref used to overwrite it. + This flag disables the check. What this means is that the + local repository can lose commits; use it with care. Author ------ diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 51222b6f3f..e8db9d7ca5 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -75,13 +75,3 @@ Some short-cut notations are also supported. pushing. That is, do not store it locally if fetching, and update the same name if pushing. --a, \--append:: - Append ref names and object names of fetched refs to the - existing contents of $GIT_DIR/FETCH_HEAD. Without this - option old data in $GIT_DIR/FETCH_HEAD will be overwritten. - --f, \--force:: - Usually, the command refuses to update a local ref that is - not an ancestor of the remote ref used to overwrite it. - This flag disables the check. What this means is that the - local repository can lose commits; use it with care. diff --git a/clone-pack.c b/clone-pack.c index f9b263a441..4f4975b4ab 100644 --- a/clone-pack.c +++ b/clone-pack.c @@ -3,10 +3,8 @@ #include "pkt-line.h" #include -static int quiet; -static int keep_pack; static const char clone_pack_usage[] = -"git-clone-pack [-q] [--keep] [--exec=] [:] []*"; +"git-clone-pack [--exec=] [:] []*"; static const char *exec = "git-upload-pack"; static void clone_handshake(int fd[2], struct ref *ref) @@ -114,41 +112,6 @@ static void write_refs(struct ref *ref) free(head_path); } -static int clone_by_unpack(int fd[2]) -{ - int status; - pid_t pid; - - pid = fork(); - if (pid < 0) - die("git-clone-pack: unable to fork off git-unpack-objects"); - if (!pid) { - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - execlp("git-unpack-objects", "git-unpack-objects", - quiet ? "-q" : NULL, NULL); - die("git-unpack-objects exec failed"); - } - close(fd[0]); - close(fd[1]); - while (waitpid(pid, &status, 0) < 0) { - if (errno != EINTR) - die("waiting for git-unpack-objects: %s", strerror(errno)); - } - if (WIFEXITED(status)) { - int code = WEXITSTATUS(status); - if (code) - die("git-unpack-objects died with error code %d", code); - return 0; - } - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); - die("git-unpack-objects died of signal %d", sig); - } - die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status); -} - static int finish_pack(const char *pack_tmp_name) { int pipe_fd[2]; @@ -294,35 +257,13 @@ static int clone_pack(int fd[2], int nr_match, char **match) } clone_handshake(fd, refs); - if (keep_pack) - status = clone_without_unpack(fd); - else - status = clone_by_unpack(fd); + status = clone_without_unpack(fd); if (!status) write_refs(refs); return status; } -static int clone_options(const char *var, const char *value) -{ - if (!strcmp("clone.keeppack", var)) { - keep_pack = git_config_bool(var, value); - return 0; - } - if (!strcmp("clone.quiet", var)) { - quiet = git_config_bool(var, value); - return 0; - } - /* - * Put other local option parsing for this program - * here ... - */ - - /* Fall back on the default ones */ - return git_default_config(var, value); -} - int main(int argc, char **argv) { int i, ret, nr_heads; @@ -330,25 +271,20 @@ int main(int argc, char **argv) int fd[2]; pid_t pid; - git_config(clone_options); nr_heads = 0; heads = NULL; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (*arg == '-') { - if (!strcmp("-q", arg)) { - quiet = 1; + if (!strcmp("-q", arg)) continue; - } if (!strncmp("--exec=", arg, 7)) { exec = arg + 7; continue; } - if (!strcmp("--keep", arg)) { - keep_pack = 1; + if (!strcmp("--keep", arg)) continue; - } usage(clone_pack_usage); } dest = arg; diff --git a/daemon.c b/daemon.c index 9ea6c31cd1..c3381b344c 100644 --- a/daemon.c +++ b/daemon.c @@ -13,7 +13,9 @@ static int log_syslog; static int verbose; -static const char daemon_usage[] = "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all] [directory...]"; +static const char daemon_usage[] = +"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n" +" [--timeout=n] [--init-timeout=n] [directory...]"; /* List of acceptable pathname prefixes */ static char **ok_paths = NULL; @@ -21,6 +23,9 @@ static char **ok_paths = NULL; /* If this is set, git-daemon-export-ok is not required */ static int export_all_trees = 0; +/* Timeout, and initial timeout */ +static unsigned int timeout = 0; +static unsigned int init_timeout = 0; static void logreport(int priority, const char *err, va_list params) { @@ -170,6 +175,8 @@ static int upload(char *dir) /* Enough for the longest path above including final null */ int buflen = strlen(dir)+10; char *dirbuf = xmalloc(buflen); + /* Timeout as string */ + char timeout_buf[64]; loginfo("Request for '%s'", dir); @@ -190,8 +197,10 @@ static int upload(char *dir) */ signal(SIGTERM, SIG_IGN); + snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout); + /* git-upload-pack only ever reads stuff, so this is safe */ - execlp("git-upload-pack", "git-upload-pack", ".", NULL); + execlp("git-upload-pack", "git-upload-pack", "--strict", timeout_buf, ".", NULL); return -1; } @@ -200,7 +209,9 @@ static int execute(void) static char line[1000]; int len; + alarm(init_timeout ? init_timeout : timeout); len = packet_read_line(0, line, sizeof(line)); + alarm(0); if (len && line[len-1] == '\n') line[--len] = 0; @@ -598,6 +609,12 @@ int main(int argc, char **argv) export_all_trees = 1; continue; } + if (!strncmp(arg, "--timeout=", 10)) { + timeout = atoi(arg+10); + } + if (!strncmp(arg, "--init-timeout=", 10)) { + init_timeout = atoi(arg+15); + } if (!strcmp(arg, "--")) { ok_paths = &argv[i+1]; break; diff --git a/fetch-pack.c b/fetch-pack.c index 969e72a781..8566ab1744 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -12,31 +12,66 @@ static const char fetch_pack_usage[] = "git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory ..."; static const char *exec = "git-upload-pack"; +#define COMPLETE (1U << 0) + static int find_common(int fd[2], unsigned char *result_sha1, struct ref *refs) { int fetching; static char line[1000]; - int count = 0, flushes = 0, retval; + static char rev_command[1024]; + int count = 0, flushes = 0, retval, rev_command_len; FILE *revs; - revs = popen("git-rev-list $(git-rev-parse --all)", "r"); - if (!revs) - die("unable to run 'git-rev-list'"); - + strcpy(rev_command, "git-rev-list $(git-rev-parse --all)"); + rev_command_len = strlen(rev_command); fetching = 0; for ( ; refs ; refs = refs->next) { unsigned char *remote = refs->old_sha1; - unsigned char *local = refs->new_sha1; + struct object *o; - if (!memcmp(remote, local, 20)) + /* + * If that object is complete (i.e. it is an ancestor of a + * local ref), we tell them we have it but do not have to + * tell them about its ancestors, which they already know + * about. + * + * We use lookup_object here because we are only + * interested in the case we *know* the object is + * reachable and we have already scanned it. + */ + if (((o = lookup_object(remote)) != NULL) && + (o->flags & COMPLETE)) { + struct commit_list *p; + struct commit *commit = + (struct commit *) (o = deref_tag(o)); + if (!o) + goto repair; + if (o->type != commit_type) + continue; + p = commit->parents; + while (p && + rev_command_len + 44 < sizeof(rev_command)) { + snprintf(rev_command + rev_command_len, 44, + " ^%s", + sha1_to_hex(p->item->object.sha1)); + rev_command_len += 43; + p = p->next; + } continue; + } + repair: packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); fetching++; } packet_flush(fd[1]); if (!fetching) return 1; + + revs = popen(rev_command, "r"); + if (!revs) + die("unable to run 'git-rev-list'"); + flushes = 1; retval = -1; while (fgets(line, sizeof(line), revs) != NULL) { @@ -81,7 +116,6 @@ static int find_common(int fd[2], unsigned char *result_sha1, return retval; } -#define COMPLETE (1U << 0) static struct commit_list *complete = NULL; static int mark_complete(const char *path, const unsigned char *sha1) @@ -89,10 +123,13 @@ static int mark_complete(const char *path, const unsigned char *sha1) struct object *o = parse_object(sha1); while (o && o->type == tag_type) { + struct tag *t = (struct tag *) o; + if (!t->tagged) + break; /* broken repository */ o->flags |= COMPLETE; - o = parse_object(((struct tag *)o)->tagged->sha1); + o = parse_object(t->tagged->sha1); } - if (o->type == commit_type) { + if (o && o->type == commit_type) { struct commit *commit = (struct commit *)o; commit->object.flags |= COMPLETE; insert_by_date(commit, &complete); diff --git a/git-count-objects.sh b/git-count-objects.sh index 74ee4f371f..843d2fd9f2 100755 --- a/git-count-objects.sh +++ b/git-count-objects.sh @@ -2,7 +2,7 @@ . git-sh-setup -echo $(find "$GIT_DIR/objects"/?? -type f -print | wc -l) objects, \ +echo $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \ $({ echo 0 # "no-such" is to help Darwin folks by not using xargs -r. diff --git a/http-fetch.c b/http-fetch.c index efa6e82329..a7dc2cc3bd 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -100,6 +100,8 @@ static char *ssl_key = NULL; static char *ssl_capath = NULL; #endif static char *ssl_cainfo = NULL; +static long curl_low_speed_limit = -1; +static long curl_low_speed_time = -1; struct buffer { @@ -158,6 +160,17 @@ static int http_options(const char *var, const char *value) } #endif + if (!strcmp("http.lowspeedlimit", var)) { + if (curl_low_speed_limit == -1) + curl_low_speed_limit = (long)git_config_int(var, value); + return 0; + } + if (!strcmp("http.lowspeedtime", var)) { + if (curl_low_speed_time == -1) + curl_low_speed_time = (long)git_config_int(var, value); + return 0; + } + /* Fall back on the default ones */ return git_default_config(var, value); } @@ -246,6 +259,13 @@ static CURL* get_curl_handle(void) curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); curl_easy_setopt(result, CURLOPT_FAILONERROR, 1); + if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) { + curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT, + curl_low_speed_limit); + curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME, + curl_low_speed_time); + } + return result; } @@ -1177,6 +1197,8 @@ int main(int argc, char **argv) char *url; int arg = 1; struct active_request_slot *slot; + char *low_speed_limit; + char *low_speed_time; while (arg < argc && argv[arg][0] == '-') { if (argv[arg][1] == 't') { @@ -1232,6 +1254,13 @@ int main(int argc, char **argv) #endif ssl_cainfo = getenv("GIT_SSL_CAINFO"); + low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT"); + if (low_speed_limit != NULL) + curl_low_speed_limit = strtol(low_speed_limit, NULL, 10); + low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME"); + if (low_speed_time != NULL) + curl_low_speed_time = strtol(low_speed_time, NULL, 10); + git_config(http_options); if (curl_ssl_verify == -1) diff --git a/sha1_name.c b/sha1_name.c index 75c688ecf2..cc320d3d7f 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -323,6 +323,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) return -1; if (!type_string) { o = deref_tag(o); + if (!o || (!o->parsed && !parse_object(o->sha1))) + return -1; memcpy(sha1, o->sha1, 20); } else { @@ -332,7 +334,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) */ while (1) { - if (!o) + if (!o || (!o->parsed && !parse_object(o->sha1))) return -1; if (o->type == type_string) { memcpy(sha1, o->sha1, 20); diff --git a/upload-pack.c b/upload-pack.c index 21b4b8b757..8a41cafaaa 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -4,13 +4,19 @@ #include "tag.h" #include "object.h" -static const char upload_pack_usage[] = "git-upload-pack "; +static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] "; #define MAX_HAS (16) #define MAX_NEEDS (256) static int nr_has = 0, nr_needs = 0; static unsigned char has_sha1[MAX_HAS][20]; static unsigned char needs_sha1[MAX_NEEDS][20]; +static unsigned int timeout = 0; + +static void reset_timeout(void) +{ + alarm(timeout); +} static int strip(char *line, int len) { @@ -100,6 +106,7 @@ static int get_common_commits(void) for(;;) { len = packet_read_line(0, line, sizeof(line)); + reset_timeout(); if (!len) { packet_write(1, "NAK\n"); @@ -122,6 +129,7 @@ static int get_common_commits(void) for (;;) { len = packet_read_line(0, line, sizeof(line)); + reset_timeout(); if (!len) continue; len = strip(line, len); @@ -145,6 +153,7 @@ static int receive_needs(void) for (;;) { unsigned char dummy[20], *sha1_buf; len = packet_read_line(0, line, sizeof(line)); + reset_timeout(); if (!len) return needs; @@ -179,6 +188,7 @@ static int send_ref(const char *refname, const unsigned char *sha1) static int upload_pack(void) { + reset_timeout(); head_ref(send_ref); for_each_ref(send_ref); packet_flush(1); @@ -193,18 +203,43 @@ static int upload_pack(void) int main(int argc, char **argv) { const char *dir; - if (argc != 2) + int i; + int strict = 0; + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + + if (arg[0] != '-') + break; + if (!strcmp(arg, "--strict")) { + strict = 1; + continue; + } + if (!strncmp(arg, "--timeout=", 10)) { + timeout = atoi(arg+10); + continue; + } + if (!strcmp(arg, "--")) { + i++; + break; + } + } + + if (i != argc-1) usage(upload_pack_usage); - dir = argv[1]; + dir = argv[i]; /* chdir to the directory. If that fails, try appending ".git" */ if (chdir(dir) < 0) { - if (chdir(mkpath("%s.git", dir)) < 0) + if (strict || chdir(mkpath("%s.git", dir)) < 0) die("git-upload-pack unable to chdir to %s", dir); } - chdir(".git"); + if (!strict) + chdir(".git"); + if (access("objects", X_OK) || access("refs", X_OK)) die("git-upload-pack: %s doesn't seem to be a git archive", dir); + putenv("GIT_DIR=."); upload_pack(); return 0;