summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/checkout.c7
-rw-r--r--builtin/clone.c10
-rw-r--r--builtin/fast-export.c9
-rw-r--r--builtin/pack-objects.c138
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/tag.c46
6 files changed, 204 insertions, 8 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f152adf9ab..d647a31303 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -716,10 +716,12 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
unsigned char rev[20];
int flag;
memset(&old, 0, sizeof(old));
- old.path = resolve_ref("HEAD", rev, 0, &flag);
+ old.path = xstrdup(resolve_ref("HEAD", rev, 0, &flag));
old.commit = lookup_commit_reference_gently(rev, 1);
- if (!(flag & REF_ISSYMREF))
+ if (!(flag & REF_ISSYMREF)) {
+ free((char *)old.path);
old.path = NULL;
+ }
if (old.path && !prefixcmp(old.path, "refs/heads/"))
old.name = old.path + strlen("refs/heads/");
@@ -742,6 +744,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
update_refs_for_switch(opts, &old, new);
ret = post_checkout_hook(old.commit, new->commit, 1);
+ free((char *)old.path);
return ret || opts->writeout_error;
}
diff --git a/builtin/clone.c b/builtin/clone.c
index a15784a7b8..7663bc22c9 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -345,8 +345,9 @@ static void remove_junk_on_signal(int signo)
static struct ref *wanted_peer_refs(const struct ref *refs,
struct refspec *refspec)
{
- struct ref *local_refs = NULL;
- struct ref **tail = &local_refs;
+ struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
+ struct ref *local_refs = head;
+ struct ref **tail = head ? &head->next : &local_refs;
get_fetch_map(refs, refspec, &tail, 0);
if (!option_mirror)
@@ -359,8 +360,11 @@ static void write_remote_refs(const struct ref *local_refs)
{
const struct ref *r;
- for (r = local_refs; r; r = r->next)
+ for (r = local_refs; r; r = r->next) {
+ if (!r->peer_ref)
+ continue;
add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
+ }
pack_refs(PACK_REFS_ALL);
clear_extra_refs();
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index daf19451ba..becef85782 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -26,6 +26,7 @@ static int progress;
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
static int fake_missing_tagger;
+static int use_done_feature;
static int no_data;
static int full_tree;
@@ -627,6 +628,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Fake a tagger when tags lack one"),
OPT_BOOLEAN(0, "full-tree", &full_tree,
"Output full tree for each commit"),
+ OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
+ "Use the done feature to terminate the stream"),
{ OPTION_NEGBIT, 0, "data", &no_data, NULL,
"Skip output of blob data",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
@@ -648,6 +651,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (argc > 1)
usage_with_options (fast_export_usage, options);
+ if (use_done_feature)
+ printf("feature done\n");
+
if (import_filename)
import_marks(import_filename);
@@ -675,5 +681,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (export_filename)
export_marks(export_filename);
+ if (use_done_feature)
+ printf("done\n");
+
return 0;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 84e6dafb12..27f24d3aaf 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -51,6 +51,8 @@ struct object_entry {
* objects against.
*/
unsigned char no_try_delta;
+ unsigned char tagged; /* near the very tip of refs */
+ unsigned char filled; /* assigned write-order */
};
/*
@@ -96,6 +98,7 @@ static unsigned long window_memory_limit = 0;
*/
static int *object_ix;
static int object_ix_hashsz;
+static struct object_entry *locate_object_entry(const unsigned char *sha1);
/*
* stats
@@ -200,6 +203,7 @@ static void copy_pack_data(struct sha1file *f,
}
}
+/* Return 0 if we will bust the pack-size limit */
static unsigned long write_object(struct sha1file *f,
struct object_entry *entry,
off_t write_offset)
@@ -434,6 +438,134 @@ static int write_one(struct sha1file *f,
return 1;
}
+static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
+ void *cb_data)
+{
+ unsigned char peeled[20];
+ struct object_entry *entry = locate_object_entry(sha1);
+
+ if (entry)
+ entry->tagged = 1;
+ if (!peel_ref(path, peeled)) {
+ entry = locate_object_entry(peeled);
+ if (entry)
+ entry->tagged = 1;
+ }
+ return 0;
+}
+
+static void add_to_write_order(struct object_entry **wo,
+ int *endp,
+ struct object_entry *e)
+{
+ if (e->filled)
+ return;
+ wo[(*endp)++] = e;
+ e->filled = 1;
+}
+
+static void add_descendants_to_write_order(struct object_entry **wo,
+ int *endp,
+ struct object_entry *e)
+{
+ struct object_entry *child;
+
+ for (child = e->delta_child; child; child = child->delta_sibling)
+ add_to_write_order(wo, endp, child);
+ for (child = e->delta_child; child; child = child->delta_sibling)
+ add_descendants_to_write_order(wo, endp, child);
+}
+
+static void add_family_to_write_order(struct object_entry **wo,
+ int *endp,
+ struct object_entry *e)
+{
+ struct object_entry *root;
+
+ for (root = e; root->delta; root = root->delta)
+ ; /* nothing */
+ add_to_write_order(wo, endp, root);
+ add_descendants_to_write_order(wo, endp, root);
+}
+
+static struct object_entry **compute_write_order(void)
+{
+ int i, wo_end;
+
+ struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
+
+ for (i = 0; i < nr_objects; i++) {
+ objects[i].tagged = 0;
+ objects[i].filled = 0;
+ objects[i].delta_child = NULL;
+ objects[i].delta_sibling = NULL;
+ }
+
+ /*
+ * Fully connect delta_child/delta_sibling network.
+ * Make sure delta_sibling is sorted in the original
+ * recency order.
+ */
+ for (i = nr_objects - 1; 0 <= i; i--) {
+ struct object_entry *e = &objects[i];
+ if (!e->delta)
+ continue;
+ /* Mark me as the first child */
+ e->delta_sibling = e->delta->delta_child;
+ e->delta->delta_child = e;
+ }
+
+ /*
+ * Mark objects that are at the tip of tags.
+ */
+ for_each_tag_ref(mark_tagged, NULL);
+
+ /*
+ * Give the commits in the original recency order until
+ * we see a tagged tip.
+ */
+ for (i = wo_end = 0; i < nr_objects; i++) {
+ if (objects[i].tagged)
+ break;
+ add_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ /*
+ * Then fill all the tagged tips.
+ */
+ for (; i < nr_objects; i++) {
+ if (objects[i].tagged)
+ add_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ /*
+ * And then all remaining commits and tags.
+ */
+ for (i = 0; i < nr_objects; i++) {
+ if (objects[i].type != OBJ_COMMIT &&
+ objects[i].type != OBJ_TAG)
+ continue;
+ add_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ /*
+ * And then all the trees.
+ */
+ for (i = 0; i < nr_objects; i++) {
+ if (objects[i].type != OBJ_TREE)
+ continue;
+ add_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ /*
+ * Finally all the rest in really tight order
+ */
+ for (i = 0; i < nr_objects; i++)
+ add_family_to_write_order(wo, &wo_end, &objects[i]);
+
+ return wo;
+}
+
static void write_pack_file(void)
{
uint32_t i = 0, j;
@@ -442,10 +574,12 @@ static void write_pack_file(void)
struct pack_header hdr;
uint32_t nr_remaining = nr_result;
time_t last_mtime = 0;
+ struct object_entry **write_order;
if (progress > pack_to_stdout)
progress_state = start_progress("Writing objects", nr_result);
written_list = xmalloc(nr_objects * sizeof(*written_list));
+ write_order = compute_write_order();
do {
unsigned char sha1[20];
@@ -469,7 +603,8 @@ static void write_pack_file(void)
offset = sizeof(hdr);
nr_written = 0;
for (; i < nr_objects; i++) {
- if (!write_one(f, objects + i, &offset))
+ struct object_entry *e = write_order[i];
+ if (!write_one(f, e, &offset))
break;
display_progress(progress_state, written);
}
@@ -546,6 +681,7 @@ static void write_pack_file(void)
} while (nr_remaining && i < nr_objects);
free(written_list);
+ free(write_order);
stop_progress(&progress_state);
if (written != nr_result)
die("wrote %"PRIu32" objects while expecting %"PRIu32,
diff --git a/builtin/reset.c b/builtin/reset.c
index 98bca044c1..777e7c6129 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -162,7 +162,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
for (i = 0; i < q->nr; i++) {
struct diff_filespec *one = q->queue[i]->one;
- if (one->mode) {
+ if (one->mode && !is_null_sha1(one->sha1)) {
struct cache_entry *ce;
ce = make_cache_entry(one->mode, one->sha1, one->path,
0, 0);
diff --git a/builtin/tag.c b/builtin/tag.c
index cef27263bc..667515e527 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -12,6 +12,8 @@
#include "tag.h"
#include "run-command.h"
#include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
static const char * const git_tag_usage[] = {
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
@@ -40,6 +42,48 @@ static int match_pattern(const char **patterns, const char *ref)
return 0;
}
+static int in_commit_list(const struct commit_list *want, struct commit *c)
+{
+ for (; want; want = want->next)
+ if (!hashcmp(want->item->object.sha1, c->object.sha1))
+ return 1;
+ return 0;
+}
+
+static int contains_recurse(struct commit *candidate,
+ const struct commit_list *want)
+{
+ struct commit_list *p;
+
+ /* was it previously marked as containing a want commit? */
+ if (candidate->object.flags & TMP_MARK)
+ return 1;
+ /* or marked as not possibly containing a want commit? */
+ if (candidate->object.flags & UNINTERESTING)
+ return 0;
+ /* or are we it? */
+ if (in_commit_list(want, candidate))
+ return 1;
+
+ if (parse_commit(candidate) < 0)
+ return 0;
+
+ /* Otherwise recurse and mark ourselves for future traversals. */
+ for (p = candidate->parents; p; p = p->next) {
+ if (contains_recurse(p->item, want)) {
+ candidate->object.flags |= TMP_MARK;
+ return 1;
+ }
+ }
+ candidate->object.flags |= UNINTERESTING;
+ return 0;
+}
+
+static int contains(struct commit *candidate, const struct commit_list *want)
+{
+ return contains_recurse(candidate, want);
+}
+
static int show_reference(const char *refname, const unsigned char *sha1,
int flag, void *cb_data)
{
@@ -58,7 +102,7 @@ static int show_reference(const char *refname, const unsigned char *sha1,
commit = lookup_commit_reference_gently(sha1, 1);
if (!commit)
return 0;
- if (!is_descendant_of(commit, filter->with_commit))
+ if (!contains(commit, filter->with_commit))
return 0;
}