#include "commit.h"
#include "tag.h"
#include "exec_cmd.h"
+#include "pack.h"
#include "sideband.h"
-#include <sys/wait.h>
static int keep_pack;
+static int transfer_unpack_limit = -1;
+static int fetch_unpack_limit = -1;
+static int unpack_limit = 100;
static int quiet;
static int verbose;
static int fetch_all;
static int depth;
+static int no_progress;
static const char fetch_pack_usage[] =
-"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [--depth=<n>] [host:]directory <refs>...";
-static const char *exec = "git-upload-pack";
+"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+static const char *uploadpack = "git-upload-pack";
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
}
if (!fetching)
- packet_write(fd[1], "want %s%s%s%s%s%s\n",
+ packet_write(fd[1], "want %s%s%s%s%s%s%s\n",
sha1_to_hex(remote),
(multi_ack ? " multi_ack" : ""),
(use_sideband == 2 ? " side-band-64k" : ""),
(use_sideband == 1 ? " side-band" : ""),
(use_thin_pack ? " thin-pack" : ""),
+ (no_progress ? " no-progress" : ""),
" ofs-delta");
else
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
int len;
while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
- if (!strncmp("shallow ", line, 8)) {
+ if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
- /* no need making it shallow if we have it already */
- if (lookup_object(sha1))
- continue;
register_shallow(sha1);
continue;
}
- if (!strncmp("unshallow ", line, 10)) {
+ if (!prefixcmp(line, "unshallow ")) {
if (get_sha1_hex(line + 10, sha1))
die("invalid unshallow line: %s", line);
if (!lookup_object(sha1))
if (!memcmp(ref->name, "refs/", 5) &&
check_ref_format(ref->name + 5))
; /* trash */
- else if (fetch_all) {
+ else if (fetch_all &&
+ (!depth || prefixcmp(ref->name, "refs/tags/") )) {
*newtail = ref;
ref->next = NULL;
newtail = &ref->next;
return side_pid;
}
-static int get_pack(int xd[2], const char **argv)
+static int get_pack(int xd[2])
{
int status;
pid_t pid, side_pid;
int fd[2];
+ const char *argv[20];
+ char keep_arg[256];
+ char hdr_arg[256];
+ const char **av;
+ int do_keep = keep_pack;
side_pid = setup_sideband(fd, xd);
+
+ av = argv;
+ *hdr_arg = 0;
+ if (unpack_limit) {
+ struct pack_header header;
+
+ if (read_pack_header(fd[0], &header))
+ die("protocol error: bad pack header");
+ snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u",
+ ntohl(header.hdr_version), ntohl(header.hdr_entries));
+ if (ntohl(header.hdr_entries) < unpack_limit)
+ do_keep = 0;
+ else
+ do_keep = 1;
+ }
+
+ if (do_keep) {
+ *av++ = "index-pack";
+ *av++ = "--stdin";
+ if (!quiet && !no_progress)
+ *av++ = "-v";
+ if (use_thin_pack)
+ *av++ = "--fix-thin";
+ if (keep_pack > 1 || unpack_limit) {
+ int s = sprintf(keep_arg,
+ "--keep=fetch-pack %d on ", getpid());
+ if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
+ strcpy(keep_arg + s, "localhost");
+ *av++ = keep_arg;
+ }
+ }
+ else {
+ *av++ = "unpack-objects";
+ if (quiet)
+ *av++ = "-q";
+ }
+ if (*hdr_arg)
+ *av++ = hdr_arg;
+ *av++ = NULL;
+
pid = fork();
if (pid < 0)
die("fetch-pack: unable to fork off %s", argv[0]);
die("%s died of unnatural causes %d", argv[0], status);
}
-static int explode_rx_pack(int xd[2])
-{
- const char *argv[3] = { "unpack-objects", quiet ? "-q" : NULL, NULL };
- return get_pack(xd, argv);
-}
-
-static int keep_rx_pack(int xd[2])
-{
- const char *argv[6];
- char keep_arg[256];
- int n = 0;
-
- argv[n++] = "index-pack";
- argv[n++] = "--stdin";
- if (!quiet)
- argv[n++] = "-v";
- if (use_thin_pack)
- argv[n++] = "--fix-thin";
- if (keep_pack > 1) {
- int s = sprintf(keep_arg, "--keep=fetch-pack %i on ", getpid());
- if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
- strcpy(keep_arg + s, "localhost");
- argv[n++] = keep_arg;
- }
- argv[n] = NULL;
- return get_pack(xd, argv);
-}
-
static int fetch_pack(int fd[2], int nr_match, char **match)
{
struct ref *ref;
unsigned char sha1[20];
- int status;
get_remote_heads(fd[0], &ref, 0, NULL, 0);
if (is_repository_shallow() && !server_supports("shallow"))
*/
fprintf(stderr, "warning: no common commits\n");
- status = (keep_pack) ? keep_rx_pack(fd) : explode_rx_pack(fd);
- if (status)
+ if (get_pack(fd))
die("git-fetch-pack: fetch failed.");
all_done:
return 0;
}
+static int remove_duplicates(int nr_heads, char **heads)
+{
+ int src, dst;
+
+ for (src = dst = 0; src < nr_heads; src++) {
+ /* If heads[src] is different from any of
+ * heads[0..dst], push it in.
+ */
+ int i;
+ for (i = 0; i < dst; i++) {
+ if (!strcmp(heads[i], heads[src]))
+ break;
+ }
+ if (i < dst)
+ continue;
+ if (src != dst)
+ heads[dst] = heads[src];
+ dst++;
+ }
+ heads[dst] = 0;
+ return dst;
+}
+
+static int fetch_pack_config(const char *var, const char *value)
+{
+ if (strcmp(var, "fetch.unpacklimit") == 0) {
+ fetch_unpack_limit = git_config_int(var, value);
+ return 0;
+ }
+
+ if (strcmp(var, "transfer.unpacklimit") == 0) {
+ transfer_unpack_limit = git_config_int(var, value);
+ return 0;
+ }
+
+ return git_default_config(var, value);
+}
+
+static struct lock_file lock;
+
int main(int argc, char **argv)
{
int i, ret, nr_heads;
int fd[2];
pid_t pid;
struct stat st;
- struct lock_file lock;
setup_git_directory();
+ git_config(fetch_pack_config);
+
+ if (0 <= transfer_unpack_limit)
+ unpack_limit = transfer_unpack_limit;
+ else if (0 <= fetch_unpack_limit)
+ unpack_limit = fetch_unpack_limit;
nr_heads = 0;
heads = NULL;
char *arg = argv[i];
if (*arg == '-') {
- if (!strncmp("--exec=", arg, 7)) {
- exec = arg + 7;
+ if (!prefixcmp(arg, "--upload-pack=")) {
+ uploadpack = arg + 14;
+ continue;
+ }
+ if (!prefixcmp(arg, "--exec=")) {
+ uploadpack = arg + 7;
continue;
}
if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
}
if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
keep_pack++;
+ unpack_limit = 0;
continue;
}
if (!strcmp("--thin", arg)) {
verbose = 1;
continue;
}
- if (!strncmp("--depth=", arg, 8)) {
+ if (!prefixcmp(arg, "--depth=")) {
depth = strtol(arg + 8, NULL, 0);
if (stat(git_path("shallow"), &st))
st.st_mtime = 0;
continue;
}
+ if (!strcmp("--no-progress", arg)) {
+ no_progress = 1;
+ continue;
+ }
usage(fetch_pack_usage);
}
dest = arg;
}
if (!dest)
usage(fetch_pack_usage);
- pid = git_connect(fd, dest, exec);
+ pid = git_connect(fd, dest, uploadpack, verbose ? CONNECT_VERBOSE : 0);
if (pid < 0)
return 1;
+ if (heads && nr_heads)
+ nr_heads = remove_duplicates(nr_heads, heads);
ret = fetch_pack(fd, nr_heads, heads);
close(fd[0]);
close(fd[1]);
fd = hold_lock_file_for_update(&lock, shallow, 1);
if (!write_shallow_commits(fd, 0)) {
- unlink(lock.filename);
+ unlink(shallow);
rollback_lock_file(&lock);
} else {
close(fd);