1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-06-10 13:26:12 +02:00

Merge branch 'jc/pack'

* jc/pack:
  pack-objects: document --revs, --unpacked and --all.
  pack-objects --unpacked=<existing pack> option.
  pack-objects: further work on internal rev-list logic.
  pack-objects: run rev-list equivalent internally.
  Separate object listing routines out of rev-list
This commit is contained in:
Junio C Hamano 2006-09-17 18:32:03 -07:00
commit 4405fb77f4
12 changed files with 435 additions and 228 deletions

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse] [verse]
'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty] 'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty]
[--local] [--incremental] [--window=N] [--depth=N] [--local] [--incremental] [--window=N] [--depth=N]
{--stdout | base-name} < object-list [--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
DESCRIPTION DESCRIPTION
@ -56,6 +56,24 @@ base-name::
Write the pack contents (what would have been written to Write the pack contents (what would have been written to
.pack file) out to the standard output. .pack file) out to the standard output.
--revs::
Read the revision arguments from the standard input, instead of
individual object names. The revision arguments are processed
the same way as gitlink:git-rev-list[1] with `--objects` flag
uses its `commit` arguments to build the list of objects it
outputs. The objects on the resulting list are packed.
--unpacked::
This implies `--revs`. When processing the list of
revision arguments read from the standard input, limit
the objects packed to those that are not already packed.
--all::
This implies `--revs`. In addition to the list of
revision arguments read from the standard input, pretend
as if all refs under `$GIT_DIR/refs` are specifed to be
included.
--window and --depth:: --window and --depth::
These two options affects how the objects contained in These two options affects how the objects contained in
the pack are stored using delta compression. The the pack are stored using delta compression. The
@ -103,6 +121,7 @@ Documentation by Junio C Hamano
See Also See Also
-------- --------
gitlink:git-rev-list[1]
gitlink:git-repack[1] gitlink:git-repack[1]
gitlink:git-prune-packed[1] gitlink:git-prune-packed[1]

View File

@ -235,7 +235,7 @@ XDIFF_LIB=xdiff/lib.a
LIB_H = \ LIB_H = \
archive.h blob.h cache.h commit.h csum-file.h delta.h \ archive.h blob.h cache.h commit.h csum-file.h delta.h \
diff.h object.h pack.h pkt-line.h quote.h refs.h sideband.h \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
@ -252,7 +252,7 @@ LIB_OBJS = \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
write_or_die.o trace.o \ write_or_die.o trace.o list-objects.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o color.o wt-status.o

View File

@ -62,7 +62,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
hex[40] = 0; hex[40] = 0;
if (get_sha1_hex(hex, sha1)) if (get_sha1_hex(hex, sha1))
die("internal error"); die("internal error");
if (has_sha1_pack(sha1)) if (has_sha1_pack(sha1, NULL))
(*packed_loose)++; (*packed_loose)++;
} }
} }

View File

@ -9,10 +9,13 @@
#include "pack.h" #include "pack.h"
#include "csum-file.h" #include "csum-file.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
#include <sys/time.h> #include <sys/time.h>
#include <signal.h> #include <signal.h>
static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list"; static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
struct object_entry { struct object_entry {
unsigned char sha1[20]; unsigned char sha1[20];
@ -66,6 +69,7 @@ static int progress = 1;
static volatile sig_atomic_t progress_update; static volatile sig_atomic_t progress_update;
static int window = 10; static int window = 10;
static int pack_to_stdout; static int pack_to_stdout;
static int num_preferred_base;
/* /*
* The object names in objects array are hashed with this hashtable, * The object names in objects array are hashed with this hashtable,
@ -838,7 +842,7 @@ static int check_pbase_path(unsigned hash)
return 0; return 0;
} }
static void add_preferred_base_object(char *name, unsigned hash) static void add_preferred_base_object(const char *name, unsigned hash)
{ {
struct pbase_tree *it; struct pbase_tree *it;
int cmplen = name_cmp_len(name); int cmplen = name_cmp_len(name);
@ -867,6 +871,9 @@ static void add_preferred_base(unsigned char *sha1)
unsigned long size; unsigned long size;
unsigned char tree_sha1[20]; unsigned char tree_sha1[20];
if (window <= num_preferred_base++)
return;
data = read_object_with_reference(sha1, tree_type, &size, tree_sha1); data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
if (!data) if (!data)
return; return;
@ -1326,89 +1333,13 @@ static int git_pack_config(const char *k, const char *v)
return git_default_config(k, v); return git_default_config(k, v);
} }
int cmd_pack_objects(int argc, const char **argv, const char *prefix) static void read_object_list_from_stdin(void)
{ {
SHA_CTX ctx;
char line[40 + 1 + PATH_MAX + 2]; char line[40 + 1 + PATH_MAX + 2];
int depth = 10; unsigned char sha1[20];
struct object_entry **list; unsigned hash;
int num_preferred_base = 0;
int i;
git_config(git_pack_config);
progress = isatty(2);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (*arg == '-') {
if (!strcmp("--non-empty", arg)) {
non_empty = 1;
continue;
}
if (!strcmp("--local", arg)) {
local = 1;
continue;
}
if (!strcmp("--progress", arg)) {
progress = 1;
continue;
}
if (!strcmp("--incremental", arg)) {
incremental = 1;
continue;
}
if (!strncmp("--window=", arg, 9)) {
char *end;
window = strtoul(arg+9, &end, 0);
if (!arg[9] || *end)
usage(pack_usage);
continue;
}
if (!strncmp("--depth=", arg, 8)) {
char *end;
depth = strtoul(arg+8, &end, 0);
if (!arg[8] || *end)
usage(pack_usage);
continue;
}
if (!strcmp("--progress", arg)) {
progress = 1;
continue;
}
if (!strcmp("-q", arg)) {
progress = 0;
continue;
}
if (!strcmp("--no-reuse-delta", arg)) {
no_reuse_delta = 1;
continue;
}
if (!strcmp("--stdout", arg)) {
pack_to_stdout = 1;
continue;
}
usage(pack_usage);
}
if (base_name)
usage(pack_usage);
base_name = arg;
}
if (pack_to_stdout != !base_name)
usage(pack_usage);
prepare_packed_git();
if (progress) {
fprintf(stderr, "Generating pack...\n");
setup_progress_signal();
}
for (;;) { for (;;) {
unsigned char sha1[20];
unsigned hash;
if (!fgets(line, sizeof(line), stdin)) { if (!fgets(line, sizeof(line), stdin)) {
if (feof(stdin)) if (feof(stdin))
break; break;
@ -1419,21 +1350,202 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
clearerr(stdin); clearerr(stdin);
continue; continue;
} }
if (line[0] == '-') { if (line[0] == '-') {
if (get_sha1_hex(line+1, sha1)) if (get_sha1_hex(line+1, sha1))
die("expected edge sha1, got garbage:\n %s", die("expected edge sha1, got garbage:\n %s",
line+1); line);
if (num_preferred_base++ < window) add_preferred_base(sha1);
add_preferred_base(sha1);
continue; continue;
} }
if (get_sha1_hex(line, sha1)) if (get_sha1_hex(line, sha1))
die("expected sha1, got garbage:\n %s", line); die("expected sha1, got garbage:\n %s", line);
hash = name_hash(line+41); hash = name_hash(line+41);
add_preferred_base_object(line+41, hash); add_preferred_base_object(line+41, hash);
add_object_entry(sha1, hash, 0); add_object_entry(sha1, hash, 0);
} }
}
static void show_commit(struct commit *commit)
{
unsigned hash = name_hash("");
add_preferred_base_object("", hash);
add_object_entry(commit->object.sha1, hash, 0);
}
static void show_object(struct object_array_entry *p)
{
unsigned hash = name_hash(p->name);
add_preferred_base_object(p->name, hash);
add_object_entry(p->item->sha1, hash, 0);
}
static void show_edge(struct commit *commit)
{
add_preferred_base(commit->object.sha1);
}
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
char line[1000];
int flags = 0;
init_revisions(&revs, NULL);
save_commit_buffer = 0;
track_object_refs = 0;
setup_revisions(ac, av, &revs, NULL);
while (fgets(line, sizeof(line), stdin) != NULL) {
int len = strlen(line);
if (line[len - 1] == '\n')
line[--len] = 0;
if (!len)
break;
if (*line == '-') {
if (!strcmp(line, "--not")) {
flags ^= UNINTERESTING;
continue;
}
die("not a rev '%s'", line);
}
if (handle_revision_arg(line, &revs, flags, 1))
die("bad revision '%s'", line);
}
prepare_revision_walk(&revs);
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
}
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
SHA_CTX ctx;
int depth = 10;
struct object_entry **list;
int use_internal_rev_list = 0;
int thin = 0;
int i;
const char *rp_av[64];
int rp_ac;
rp_av[0] = "pack-objects";
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
rp_ac = 2;
git_config(git_pack_config);
progress = isatty(2);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (*arg != '-')
break;
if (!strcmp("--non-empty", arg)) {
non_empty = 1;
continue;
}
if (!strcmp("--local", arg)) {
local = 1;
continue;
}
if (!strcmp("--progress", arg)) {
progress = 1;
continue;
}
if (!strcmp("--incremental", arg)) {
incremental = 1;
continue;
}
if (!strncmp("--window=", arg, 9)) {
char *end;
window = strtoul(arg+9, &end, 0);
if (!arg[9] || *end)
usage(pack_usage);
continue;
}
if (!strncmp("--depth=", arg, 8)) {
char *end;
depth = strtoul(arg+8, &end, 0);
if (!arg[8] || *end)
usage(pack_usage);
continue;
}
if (!strcmp("--progress", arg)) {
progress = 1;
continue;
}
if (!strcmp("-q", arg)) {
progress = 0;
continue;
}
if (!strcmp("--no-reuse-delta", arg)) {
no_reuse_delta = 1;
continue;
}
if (!strcmp("--stdout", arg)) {
pack_to_stdout = 1;
continue;
}
if (!strcmp("--revs", arg)) {
use_internal_rev_list = 1;
continue;
}
if (!strcmp("--unpacked", arg) ||
!strncmp("--unpacked=", arg, 11) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;
if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
die("too many internal rev-list options");
rp_av[rp_ac++] = arg;
continue;
}
if (!strcmp("--thin", arg)) {
use_internal_rev_list = 1;
thin = 1;
rp_av[1] = "--objects-edge";
continue;
}
usage(pack_usage);
}
/* Traditionally "pack-objects [options] base extra" failed;
* we would however want to take refs parameter that would
* have been given to upstream rev-list ourselves, which means
* we somehow want to say what the base name is. So the
* syntax would be:
*
* pack-objects [options] base <refs...>
*
* in other words, we would treat the first non-option as the
* base_name and send everything else to the internal revision
* walker.
*/
if (!pack_to_stdout)
base_name = argv[i++];
if (pack_to_stdout != !base_name)
usage(pack_usage);
if (!pack_to_stdout && thin)
die("--thin cannot be used to build an indexable pack.");
prepare_packed_git();
if (progress) {
fprintf(stderr, "Generating pack...\n");
setup_progress_signal();
}
if (!use_internal_rev_list)
read_object_list_from_stdin();
else {
rp_av[rp_ac] = NULL;
get_object_list(rp_ac, rp_av);
}
if (progress) if (progress)
fprintf(stderr, "Done counting %d objects.\n", nr_objects); fprintf(stderr, "Done counting %d objects.\n", nr_objects);
sorted_by_sha = create_final_object_list(); sorted_by_sha = create_final_object_list();

View File

@ -19,7 +19,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len)
memcpy(hex+2, de->d_name, 38); memcpy(hex+2, de->d_name, 38);
if (get_sha1_hex(hex, sha1)) if (get_sha1_hex(hex, sha1))
continue; continue;
if (!has_sha1_pack(sha1)) if (!has_sha1_pack(sha1, NULL))
continue; continue;
memcpy(pathname + len, de->d_name, 38); memcpy(pathname + len, de->d_name, 38);
if (dryrun) if (dryrun)

View File

@ -7,6 +7,7 @@
#include "tree-walk.h" #include "tree-walk.h"
#include "diff.h" #include "diff.h"
#include "revision.h" #include "revision.h"
#include "list-objects.h"
#include "builtin.h" #include "builtin.h"
/* bits #0-15 in revision.h */ /* bits #0-15 in revision.h */
@ -98,104 +99,24 @@ static void show_commit(struct commit *commit)
commit->buffer = NULL; commit->buffer = NULL;
} }
static void process_blob(struct blob *blob, static void show_object(struct object_array_entry *p)
struct object_array *p,
struct name_path *path,
const char *name)
{ {
struct object *obj = &blob->object; /* An object with name "foo\n0000000..." can be used to
* confuse downstream git-pack-objects very badly.
if (!revs.blob_objects) */
return; const char *ep = strchr(p->name, '\n');
if (obj->flags & (UNINTERESTING | SEEN)) if (ep) {
return; printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
obj->flags |= SEEN; (int) (ep - p->name),
name = xstrdup(name); p->name);
add_object(obj, p, path, name); }
else
printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
} }
static void process_tree(struct tree *tree, static void show_edge(struct commit *commit)
struct object_array *p,
struct name_path *path,
const char *name)
{ {
struct object *obj = &tree->object; printf("-%s\n", sha1_to_hex(commit->object.sha1));
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
if (!revs.tree_objects)
return;
if (obj->flags & (UNINTERESTING | SEEN))
return;
if (parse_tree(tree) < 0)
die("bad tree object %s", sha1_to_hex(obj->sha1));
obj->flags |= SEEN;
name = xstrdup(name);
add_object(obj, p, path, name);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry)) {
if (S_ISDIR(entry.mode))
process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
else
process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
}
free(tree->buffer);
tree->buffer = NULL;
}
static void show_commit_list(struct rev_info *revs)
{
int i;
struct commit *commit;
struct object_array objects = { 0, 0, NULL };
while ((commit = get_revision(revs)) != NULL) {
process_tree(commit->tree, &objects, NULL, "");
show_commit(commit);
}
for (i = 0; i < revs->pending.nr; i++) {
struct object_array_entry *pending = revs->pending.objects + i;
struct object *obj = pending->item;
const char *name = pending->name;
if (obj->flags & (UNINTERESTING | SEEN))
continue;
if (obj->type == OBJ_TAG) {
obj->flags |= SEEN;
add_object_array(obj, name, &objects);
continue;
}
if (obj->type == OBJ_TREE) {
process_tree((struct tree *)obj, &objects, NULL, name);
continue;
}
if (obj->type == OBJ_BLOB) {
process_blob((struct blob *)obj, &objects, NULL, name);
continue;
}
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
}
for (i = 0; i < objects.nr; i++) {
struct object_array_entry *p = objects.objects + i;
/* An object with name "foo\n0000000..." can be used to
* confuse downstream git-pack-objects very badly.
*/
const char *ep = strchr(p->name, '\n');
if (ep) {
printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
(int) (ep - p->name),
p->name);
}
else
printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
}
} }
/* /*
@ -276,35 +197,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
return best; return best;
} }
static void mark_edge_parents_uninteresting(struct commit *commit)
{
struct commit_list *parents;
for (parents = commit->parents; parents; parents = parents->next) {
struct commit *parent = parents->item;
if (!(parent->object.flags & UNINTERESTING))
continue;
mark_tree_uninteresting(parent->tree);
if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
parent->object.flags |= SHOWN;
printf("-%s\n", sha1_to_hex(parent->object.sha1));
}
}
}
static void mark_edges_uninteresting(struct commit_list *list)
{
for ( ; list; list = list->next) {
struct commit *commit = list->item;
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
continue;
}
mark_edge_parents_uninteresting(commit);
}
}
static void read_revisions_from_stdin(struct rev_info *revs) static void read_revisions_from_stdin(struct rev_info *revs)
{ {
char line[1000]; char line[1000];
@ -384,12 +276,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
prepare_revision_walk(&revs); prepare_revision_walk(&revs);
if (revs.tree_objects) if (revs.tree_objects)
mark_edges_uninteresting(revs.commits); mark_edges_uninteresting(revs.commits, &revs, show_edge);
if (bisect_list) if (bisect_list)
revs.commits = find_bisection(revs.commits); revs.commits = find_bisection(revs.commits);
show_commit_list(&revs); traverse_commit_list(&revs, show_commit, show_object);
return 0; return 0;
} }

View File

@ -259,7 +259,7 @@ extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
extern int write_sha1_to_fd(int fd, const unsigned char *sha1); extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int move_temp_to_file(const char *tmpfile, const char *filename);
extern int has_sha1_pack(const unsigned char *sha1); extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
extern int has_sha1_file(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1);
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *); extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
extern int legacy_loose_object(unsigned char *); extern int legacy_loose_object(unsigned char *);

140
list-objects.c Normal file
View File

@ -0,0 +1,140 @@
#include "cache.h"
#include "tag.h"
#include "commit.h"
#include "tree.h"
#include "blob.h"
#include "diff.h"
#include "tree-walk.h"
#include "revision.h"
#include "list-objects.h"
static void process_blob(struct rev_info *revs,
struct blob *blob,
struct object_array *p,
struct name_path *path,
const char *name)
{
struct object *obj = &blob->object;
if (!revs->blob_objects)
return;
if (obj->flags & (UNINTERESTING | SEEN))
return;
obj->flags |= SEEN;
name = xstrdup(name);
add_object(obj, p, path, name);
}
static void process_tree(struct rev_info *revs,
struct tree *tree,
struct object_array *p,
struct name_path *path,
const char *name)
{
struct object *obj = &tree->object;
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
if (!revs->tree_objects)
return;
if (obj->flags & (UNINTERESTING | SEEN))
return;
if (parse_tree(tree) < 0)
die("bad tree object %s", sha1_to_hex(obj->sha1));
obj->flags |= SEEN;
name = xstrdup(name);
add_object(obj, p, path, name);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry)) {
if (S_ISDIR(entry.mode))
process_tree(revs,
lookup_tree(entry.sha1),
p, &me, entry.path);
else
process_blob(revs,
lookup_blob(entry.sha1),
p, &me, entry.path);
}
free(tree->buffer);
tree->buffer = NULL;
}
static void mark_edge_parents_uninteresting(struct commit *commit,
struct rev_info *revs,
show_edge_fn show_edge)
{
struct commit_list *parents;
for (parents = commit->parents; parents; parents = parents->next) {
struct commit *parent = parents->item;
if (!(parent->object.flags & UNINTERESTING))
continue;
mark_tree_uninteresting(parent->tree);
if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
parent->object.flags |= SHOWN;
show_edge(parent);
}
}
}
void mark_edges_uninteresting(struct commit_list *list,
struct rev_info *revs,
show_edge_fn show_edge)
{
for ( ; list; list = list->next) {
struct commit *commit = list->item;
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
continue;
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
}
void traverse_commit_list(struct rev_info *revs,
void (*show_commit)(struct commit *),
void (*show_object)(struct object_array_entry *))
{
int i;
struct commit *commit;
struct object_array objects = { 0, 0, NULL };
while ((commit = get_revision(revs)) != NULL) {
process_tree(revs, commit->tree, &objects, NULL, "");
show_commit(commit);
}
for (i = 0; i < revs->pending.nr; i++) {
struct object_array_entry *pending = revs->pending.objects + i;
struct object *obj = pending->item;
const char *name = pending->name;
if (obj->flags & (UNINTERESTING | SEEN))
continue;
if (obj->type == OBJ_TAG) {
obj->flags |= SEEN;
add_object_array(obj, name, &objects);
continue;
}
if (obj->type == OBJ_TREE) {
process_tree(revs, (struct tree *)obj, &objects,
NULL, name);
continue;
}
if (obj->type == OBJ_BLOB) {
process_blob(revs, (struct blob *)obj, &objects,
NULL, name);
continue;
}
die("unknown pending object %s (%s)",
sha1_to_hex(obj->sha1), name);
}
for (i = 0; i < objects.nr; i++)
show_object(&objects.objects[i]);
}

12
list-objects.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef LIST_OBJECTS_H
#define LIST_OBJECTS_H
typedef void (*show_commit_fn)(struct commit *);
typedef void (*show_object_fn)(struct object_array_entry *);
typedef void (*show_edge_fn)(struct commit *);
void traverse_commit_list(struct rev_info *revs, show_commit_fn, show_object_fn);
void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
#endif

View File

@ -416,7 +416,8 @@ static void limit_list(struct rev_info *revs)
if (revs->max_age != -1 && (commit->date < revs->max_age)) if (revs->max_age != -1 && (commit->date < revs->max_age))
obj->flags |= UNINTERESTING; obj->flags |= UNINTERESTING;
if (revs->unpacked && has_sha1_pack(obj->sha1)) if (revs->unpacked &&
has_sha1_pack(obj->sha1, revs->ignore_packed))
obj->flags |= UNINTERESTING; obj->flags |= UNINTERESTING;
add_parents_to_list(revs, commit, &list); add_parents_to_list(revs, commit, &list);
if (obj->flags & UNINTERESTING) { if (obj->flags & UNINTERESTING) {
@ -671,6 +672,16 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
return 0; return 0;
} }
static void add_ignore_packed(struct rev_info *revs, const char *name)
{
int num = ++revs->num_ignore_packed;
revs->ignore_packed = xrealloc(revs->ignore_packed,
sizeof(const char **) * (num + 1));
revs->ignore_packed[num-1] = name;
revs->ignore_packed[num] = NULL;
}
/* /*
* Parse revision information, filling in the "rev_info" structure, * Parse revision information, filling in the "rev_info" structure,
* and removing the used arguments from the argument list. * and removing the used arguments from the argument list.
@ -811,6 +822,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
} }
if (!strcmp(arg, "--unpacked")) { if (!strcmp(arg, "--unpacked")) {
revs->unpacked = 1; revs->unpacked = 1;
free(revs->ignore_packed);
revs->ignore_packed = NULL;
revs->num_ignore_packed = 0;
continue;
}
if (!strncmp(arg, "--unpacked=", 11)) {
revs->unpacked = 1;
add_ignore_packed(revs, arg+11);
continue; continue;
} }
if (!strcmp(arg, "-r")) { if (!strcmp(arg, "-r")) {
@ -1057,7 +1076,8 @@ struct commit *get_revision(struct rev_info *revs)
*/ */
if (!revs->limited) { if (!revs->limited) {
if ((revs->unpacked && if ((revs->unpacked &&
has_sha1_pack(commit->object.sha1)) || has_sha1_pack(commit->object.sha1,
revs->ignore_packed)) ||
(revs->max_age != -1 && (revs->max_age != -1 &&
(commit->date < revs->max_age))) (commit->date < revs->max_age)))
continue; continue;

View File

@ -38,7 +38,7 @@ struct rev_info {
blob_objects:1, blob_objects:1,
edge_hint:1, edge_hint:1,
limited:1, limited:1,
unpacked:1, unpacked:1, /* see also ignore_packed below */
boundary:1, boundary:1,
parents:1; parents:1;
@ -57,6 +57,10 @@ struct rev_info {
unsigned int shown_one:1, unsigned int shown_one:1,
abbrev_commit:1, abbrev_commit:1,
relative_date:1; relative_date:1;
const char **ignore_packed; /* pretend objects in these are unpacked */
int num_ignore_packed;
unsigned int abbrev; unsigned int abbrev;
enum cmit_fmt commit_format; enum cmit_fmt commit_format;
struct log_info *loginfo; struct log_info *loginfo;

View File

@ -1217,12 +1217,20 @@ int find_pack_entry_one(const unsigned char *sha1,
return 0; return 0;
} }
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{ {
struct packed_git *p; struct packed_git *p;
prepare_packed_git(); prepare_packed_git();
for (p = packed_git; p; p = p->next) { for (p = packed_git; p; p = p->next) {
if (ignore_packed) {
const char **ig;
for (ig = ignore_packed; *ig; ig++)
if (!strcmp(p->pack_name, *ig))
break;
if (*ig)
continue;
}
if (find_pack_entry_one(sha1, e, p)) if (find_pack_entry_one(sha1, e, p))
return 1; return 1;
} }
@ -1255,10 +1263,10 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
if (!map) { if (!map) {
struct pack_entry e; struct pack_entry e;
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e, NULL))
return packed_object_info(&e, type, sizep); return packed_object_info(&e, type, sizep);
reprepare_packed_git(); reprepare_packed_git();
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e, NULL))
return packed_object_info(&e, type, sizep); return packed_object_info(&e, type, sizep);
return error("unable to find %s", sha1_to_hex(sha1)); return error("unable to find %s", sha1_to_hex(sha1));
} }
@ -1281,7 +1289,7 @@ static void *read_packed_sha1(const unsigned char *sha1, char *type, unsigned lo
{ {
struct pack_entry e; struct pack_entry e;
if (!find_pack_entry(sha1, &e)) { if (!find_pack_entry(sha1, &e, NULL)) {
error("cannot read sha1_file for %s", sha1_to_hex(sha1)); error("cannot read sha1_file for %s", sha1_to_hex(sha1));
return NULL; return NULL;
} }
@ -1294,7 +1302,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
void *map, *buf; void *map, *buf;
struct pack_entry e; struct pack_entry e;
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e, NULL))
return read_packed_sha1(sha1, type, size); return read_packed_sha1(sha1, type, size);
map = map_sha1_file(sha1, &mapsize); map = map_sha1_file(sha1, &mapsize);
if (map) { if (map) {
@ -1303,7 +1311,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
return buf; return buf;
} }
reprepare_packed_git(); reprepare_packed_git();
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e, NULL))
return read_packed_sha1(sha1, type, size); return read_packed_sha1(sha1, type, size);
return NULL; return NULL;
} }
@ -1735,10 +1743,10 @@ int has_pack_file(const unsigned char *sha1)
return 1; return 1;
} }
int has_sha1_pack(const unsigned char *sha1) int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed)
{ {
struct pack_entry e; struct pack_entry e;
return find_pack_entry(sha1, &e); return find_pack_entry(sha1, &e, ignore_packed);
} }
int has_sha1_file(const unsigned char *sha1) int has_sha1_file(const unsigned char *sha1)
@ -1746,7 +1754,7 @@ int has_sha1_file(const unsigned char *sha1)
struct stat st; struct stat st;
struct pack_entry e; struct pack_entry e;
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e, NULL))
return 1; return 1;
return find_sha1_file(sha1, &st) ? 1 : 0; return find_sha1_file(sha1, &st) ? 1 : 0;
} }