aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2007-11-14 14:26:04 -0800
committerJunio C Hamano <gitster@pobox.com>2007-11-14 14:26:04 -0800
commitf5f6cb87defc4b7e8ba6cc6e82f616bef47ea6b0 (patch)
treecfa0daa0b019e83aba1d15ae5d8a4359da578a0e
parentb2e163272c01aca4aee4684f5c683ba341c1953d (diff)
parent4191c35671f6392173221bea3994f8b305f4f3a8 (diff)
downloadgit-f5f6cb87defc4b7e8ba6cc6e82f616bef47ea6b0.tar.gz
git-f5f6cb87defc4b7e8ba6cc6e82f616bef47ea6b0.tar.xz
Merge branch 'sp/fetch-fix'
* sp/fetch-fix: git-fetch: avoid local fetching from alternate (again) rev-list: Introduce --quiet to avoid /dev/null redirects run-command: Support sending stderr to /dev/null git-fetch: Always fetch tags if the object they reference exists
-rw-r--r--Documentation/git-rev-list.txt9
-rw-r--r--builtin-fetch.c71
-rw-r--r--builtin-rev-list.c26
-rw-r--r--run-command.c6
-rw-r--r--run-command.h1
-rwxr-xr-xt/t5502-quickfetch.sh33
6 files changed, 137 insertions, 9 deletions
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 485280423..989fbf356 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -20,6 +20,7 @@ SYNOPSIS
[ \--not ]
[ \--all ]
[ \--stdin ]
+ [ \--quiet ]
[ \--topo-order ]
[ \--parents ]
[ \--timestamp ]
@@ -270,6 +271,14 @@ limiting may be applied.
In addition to the '<commit>' listed on the command
line, read them from the standard input.
+--quiet::
+
+ Don't print anything to standard output. This form of
+ git-rev-list is primarly meant to allow the caller to
+ test the exit status to see if a range of objects is fully
+ connected (or not). It is faster than redirecting stdout
+ to /dev/null as the output does not have to be formatted.
+
--cherry-pick::
Omit any commit that introduces the same change as
diff --git a/builtin-fetch.c b/builtin-fetch.c
index e65690f25..be9e3ea2b 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -8,10 +8,12 @@
#include "path-list.h"
#include "remote.h"
#include "transport.h"
+#include "run-command.h"
static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack <upload-pack>] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth <depth>] [-v | --verbose] [<repository> <refspec>...]";
static int append, force, tags, no_tags, update_head_ok, verbose, quiet;
+static const char *depth;
static char *default_rla = NULL;
static struct transport *transport;
@@ -335,9 +337,72 @@ static void store_updated_refs(const char *url, struct ref *ref_map)
fclose(fp);
}
+/*
+ * We would want to bypass the object transfer altogether if
+ * everything we are going to fetch already exists and connected
+ * locally.
+ *
+ * The refs we are going to fetch are in to_fetch (nr_heads in
+ * total). If running
+ *
+ * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
+ *
+ * does not error out, that means everything reachable from the
+ * refs we are going to fetch exists and is connected to some of
+ * our existing refs.
+ */
+static int quickfetch(struct ref *ref_map)
+{
+ struct child_process revlist;
+ struct ref *ref;
+ char **argv;
+ int i, err;
+
+ /*
+ * If we are deepening a shallow clone we already have these
+ * objects reachable. Running rev-list here will return with
+ * a good (0) exit status and we'll bypass the fetch that we
+ * really need to perform. Claiming failure now will ensure
+ * we perform the network exchange to deepen our history.
+ */
+ if (depth)
+ return -1;
+
+ for (i = 0, ref = ref_map; ref; ref = ref->next)
+ i++;
+ if (!i)
+ return 0;
+
+ argv = xmalloc(sizeof(*argv) * (i + 6));
+ i = 0;
+ argv[i++] = xstrdup("rev-list");
+ argv[i++] = xstrdup("--quiet");
+ argv[i++] = xstrdup("--objects");
+ for (ref = ref_map; ref; ref = ref->next)
+ argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1));
+ argv[i++] = xstrdup("--not");
+ argv[i++] = xstrdup("--all");
+ argv[i++] = NULL;
+
+ memset(&revlist, 0, sizeof(revlist));
+ revlist.argv = (const char**)argv;
+ revlist.git_cmd = 1;
+ revlist.no_stdin = 1;
+ revlist.no_stdout = 1;
+ revlist.no_stderr = 1;
+ err = run_command(&revlist);
+
+ for (i = 0; argv[i]; i++)
+ free(argv[i]);
+ free(argv);
+ return err;
+}
+
static int fetch_refs(struct transport *transport, struct ref *ref_map)
{
- int ret = transport_fetch_refs(transport, ref_map);
+ int ret = quickfetch(ref_map);
+ if (ret)
+ ret = transport_fetch_refs(transport, ref_map);
if (!ret)
store_updated_refs(transport->url, ref_map);
transport_unlock_pack(transport);
@@ -389,7 +454,7 @@ static struct ref *find_non_local_tags(struct transport *transport,
if (!path_list_has_path(&existing_refs, ref_name) &&
!path_list_has_path(&new_refs, ref_name) &&
- lookup_object(ref->old_sha1)) {
+ has_sha1_file(ref->old_sha1)) {
path_list_insert(ref_name, &new_refs);
rm = alloc_ref(strlen(ref_name) + 1);
@@ -473,7 +538,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
static const char **refs = NULL;
int ref_nr = 0;
int cmd_len = 0;
- const char *depth = NULL, *upload_pack = NULL;
+ const char *upload_pack = NULL;
int keep = 0;
for (i = 1; i < argc; i++) {
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 697046723..f5149e59b 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -26,6 +26,7 @@ static const char rev_list_usage[] =
" --remove-empty\n"
" --all\n"
" --stdin\n"
+" --quiet\n"
" ordering output:\n"
" --topo-order\n"
" --date-order\n"
@@ -50,6 +51,7 @@ static int show_timestamp;
static int hdr_termination;
static const char *header_prefix;
+static void finish_commit(struct commit *commit);
static void show_commit(struct commit *commit)
{
if (show_timestamp)
@@ -93,6 +95,11 @@ static void show_commit(struct commit *commit)
strbuf_release(&buf);
}
maybe_flush_or_die(stdout, "stdout");
+ finish_commit(commit);
+}
+
+static void finish_commit(struct commit *commit)
+{
if (commit->parents) {
free_commit_list(commit->parents);
commit->parents = NULL;
@@ -101,6 +108,12 @@ static void show_commit(struct commit *commit)
commit->buffer = NULL;
}
+static void finish_object(struct object_array_entry *p)
+{
+ if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
+ die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
+}
+
static void show_object(struct object_array_entry *p)
{
/* An object with name "foo\n0000000..." can be used to
@@ -108,9 +121,7 @@ static void show_object(struct object_array_entry *p)
*/
const char *ep = strchr(p->name, '\n');
- if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
- die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
-
+ finish_object(p);
if (ep) {
printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
(int) (ep - p->name),
@@ -527,6 +538,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int read_from_stdin = 0;
int bisect_show_vars = 0;
int bisect_find_all = 0;
+ int quiet = 0;
git_config(git_default_config);
init_revisions(&revs, prefix);
@@ -565,6 +577,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
read_revisions_from_stdin(&revs);
continue;
}
+ if (!strcmp(arg, "--quiet")) {
+ quiet = 1;
+ continue;
+ }
usage(rev_list_usage);
}
@@ -640,7 +656,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
}
}
- traverse_commit_list(&revs, show_commit, show_object);
+ traverse_commit_list(&revs,
+ quiet ? finish_commit : show_commit,
+ quiet ? finish_object : show_object);
return 0;
}
diff --git a/run-command.c b/run-command.c
index d99a6c4ea..476d00c21 100644
--- a/run-command.c
+++ b/run-command.c
@@ -41,7 +41,7 @@ int start_command(struct child_process *cmd)
cmd->close_out = 1;
}
- need_err = cmd->err < 0;
+ need_err = !cmd->no_stderr && cmd->err < 0;
if (need_err) {
if (pipe(fderr) < 0) {
if (need_in)
@@ -87,7 +87,9 @@ int start_command(struct child_process *cmd)
close(cmd->out);
}
- if (need_err) {
+ if (cmd->no_stderr)
+ dup_devnull(2);
+ else if (need_err) {
dup2(fderr[1], 2);
close_pair(fderr);
}
diff --git a/run-command.h b/run-command.h
index 94e1e9d51..1fc781d76 100644
--- a/run-command.h
+++ b/run-command.h
@@ -23,6 +23,7 @@ struct child_process {
unsigned close_out:1;
unsigned no_stdin:1;
unsigned no_stdout:1;
+ unsigned no_stderr:1;
unsigned git_cmd:1; /* if this is to be git sub-command */
unsigned stdout_to_stderr:1;
};
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
index b4760f2dc..16eadd6b6 100755
--- a/t/t5502-quickfetch.sh
+++ b/t/t5502-quickfetch.sh
@@ -86,4 +86,37 @@ test_expect_success 'quickfetch should not leave a corrupted repository' '
'
+test_expect_success 'quickfetch should not copy from alternate' '
+
+ (
+ mkdir quickclone &&
+ cd quickclone &&
+ git init-db &&
+ (cd ../.git/objects && pwd) >.git/objects/info/alternates &&
+ git remote add origin .. &&
+ git fetch -k -k
+ ) &&
+ obj_cnt=$( (
+ cd quickclone &&
+ git count-objects | sed -e "s/ *objects,.*//"
+ ) ) &&
+ pck_cnt=$( (
+ cd quickclone &&
+ git count-objects -v | sed -n -e "/packs:/{
+ s/packs://
+ p
+ q
+ }"
+ ) ) &&
+ origin_master=$( (
+ cd quickclone &&
+ git rev-parse origin/master
+ ) ) &&
+ echo "loose objects: $obj_cnt, packfiles: $pck_cnt" &&
+ test $obj_cnt -eq 0 &&
+ test $pck_cnt -eq 0 &&
+ test z$origin_master = z$(git rev-parse master)
+
+'
+
test_done