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:
commit
4405fb77f4
@ -11,7 +11,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty]
|
||||
[--local] [--incremental] [--window=N] [--depth=N]
|
||||
{--stdout | base-name} < object-list
|
||||
[--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -56,6 +56,24 @@ base-name::
|
||||
Write the pack contents (what would have been written to
|
||||
.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::
|
||||
These two options affects how the objects contained in
|
||||
the pack are stored using delta compression. The
|
||||
@ -103,6 +121,7 @@ Documentation by Junio C Hamano
|
||||
|
||||
See Also
|
||||
--------
|
||||
gitlink:git-rev-list[1]
|
||||
gitlink:git-repack[1]
|
||||
gitlink:git-prune-packed[1]
|
||||
|
||||
|
4
Makefile
4
Makefile
@ -235,7 +235,7 @@ XDIFF_LIB=xdiff/lib.a
|
||||
|
||||
LIB_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 \
|
||||
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 \
|
||||
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 \
|
||||
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) \
|
||||
color.o wt-status.o
|
||||
|
||||
|
@ -62,7 +62,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||
hex[40] = 0;
|
||||
if (get_sha1_hex(hex, sha1))
|
||||
die("internal error");
|
||||
if (has_sha1_pack(sha1))
|
||||
if (has_sha1_pack(sha1, NULL))
|
||||
(*packed_loose)++;
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,13 @@
|
||||
#include "pack.h"
|
||||
#include "csum-file.h"
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include <sys/time.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 {
|
||||
unsigned char sha1[20];
|
||||
@ -66,6 +69,7 @@ static int progress = 1;
|
||||
static volatile sig_atomic_t progress_update;
|
||||
static int window = 10;
|
||||
static int pack_to_stdout;
|
||||
static int num_preferred_base;
|
||||
|
||||
/*
|
||||
* The object names in objects array are hashed with this hashtable,
|
||||
@ -838,7 +842,7 @@ static int check_pbase_path(unsigned hash)
|
||||
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;
|
||||
int cmplen = name_cmp_len(name);
|
||||
@ -867,6 +871,9 @@ static void add_preferred_base(unsigned char *sha1)
|
||||
unsigned long size;
|
||||
unsigned char tree_sha1[20];
|
||||
|
||||
if (window <= num_preferred_base++)
|
||||
return;
|
||||
|
||||
data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
|
||||
if (!data)
|
||||
return;
|
||||
@ -1326,89 +1333,13 @@ static int git_pack_config(const char *k, const char *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];
|
||||
int depth = 10;
|
||||
struct object_entry **list;
|
||||
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();
|
||||
}
|
||||
unsigned char sha1[20];
|
||||
unsigned hash;
|
||||
|
||||
for (;;) {
|
||||
unsigned char sha1[20];
|
||||
unsigned hash;
|
||||
|
||||
if (!fgets(line, sizeof(line), stdin)) {
|
||||
if (feof(stdin))
|
||||
break;
|
||||
@ -1419,21 +1350,202 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
clearerr(stdin);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] == '-') {
|
||||
if (get_sha1_hex(line+1, sha1))
|
||||
die("expected edge sha1, got garbage:\n %s",
|
||||
line+1);
|
||||
if (num_preferred_base++ < window)
|
||||
add_preferred_base(sha1);
|
||||
line);
|
||||
add_preferred_base(sha1);
|
||||
continue;
|
||||
}
|
||||
if (get_sha1_hex(line, sha1))
|
||||
die("expected sha1, got garbage:\n %s", line);
|
||||
|
||||
hash = name_hash(line+41);
|
||||
add_preferred_base_object(line+41, hash);
|
||||
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)
|
||||
fprintf(stderr, "Done counting %d objects.\n", nr_objects);
|
||||
sorted_by_sha = create_final_object_list();
|
||||
|
@ -19,7 +19,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len)
|
||||
memcpy(hex+2, de->d_name, 38);
|
||||
if (get_sha1_hex(hex, sha1))
|
||||
continue;
|
||||
if (!has_sha1_pack(sha1))
|
||||
if (!has_sha1_pack(sha1, NULL))
|
||||
continue;
|
||||
memcpy(pathname + len, de->d_name, 38);
|
||||
if (dryrun)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include "builtin.h"
|
||||
|
||||
/* bits #0-15 in revision.h */
|
||||
@ -98,104 +99,24 @@ static void show_commit(struct commit *commit)
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
|
||||
static void process_blob(struct blob *blob,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
static void show_object(struct object_array_entry *p)
|
||||
{
|
||||
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);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static void process_tree(struct tree *tree,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
static void show_edge(struct commit *commit)
|
||||
{
|
||||
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(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);
|
||||
}
|
||||
printf("-%s\n", sha1_to_hex(commit->object.sha1));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -276,35 +197,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
|
||||
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)
|
||||
{
|
||||
char line[1000];
|
||||
@ -384,12 +276,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (revs.tree_objects)
|
||||
mark_edges_uninteresting(revs.commits);
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
|
||||
if (bisect_list)
|
||||
revs.commits = find_bisection(revs.commits);
|
||||
|
||||
show_commit_list(&revs);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
2
cache.h
2
cache.h
@ -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 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 void *map_sha1_file(const unsigned char *sha1, unsigned long *);
|
||||
extern int legacy_loose_object(unsigned char *);
|
||||
|
140
list-objects.c
Normal file
140
list-objects.c
Normal 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
12
list-objects.h
Normal 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
|
24
revision.c
24
revision.c
@ -416,7 +416,8 @@ static void limit_list(struct rev_info *revs)
|
||||
|
||||
if (revs->max_age != -1 && (commit->date < revs->max_age))
|
||||
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;
|
||||
add_parents_to_list(revs, commit, &list);
|
||||
if (obj->flags & UNINTERESTING) {
|
||||
@ -671,6 +672,16 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
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,
|
||||
* 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")) {
|
||||
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;
|
||||
}
|
||||
if (!strcmp(arg, "-r")) {
|
||||
@ -1057,7 +1076,8 @@ struct commit *get_revision(struct rev_info *revs)
|
||||
*/
|
||||
if (!revs->limited) {
|
||||
if ((revs->unpacked &&
|
||||
has_sha1_pack(commit->object.sha1)) ||
|
||||
has_sha1_pack(commit->object.sha1,
|
||||
revs->ignore_packed)) ||
|
||||
(revs->max_age != -1 &&
|
||||
(commit->date < revs->max_age)))
|
||||
continue;
|
||||
|
@ -38,7 +38,7 @@ struct rev_info {
|
||||
blob_objects:1,
|
||||
edge_hint:1,
|
||||
limited:1,
|
||||
unpacked:1,
|
||||
unpacked:1, /* see also ignore_packed below */
|
||||
boundary:1,
|
||||
parents:1;
|
||||
|
||||
@ -57,6 +57,10 @@ struct rev_info {
|
||||
unsigned int shown_one:1,
|
||||
abbrev_commit:1,
|
||||
relative_date:1;
|
||||
|
||||
const char **ignore_packed; /* pretend objects in these are unpacked */
|
||||
int num_ignore_packed;
|
||||
|
||||
unsigned int abbrev;
|
||||
enum cmit_fmt commit_format;
|
||||
struct log_info *loginfo;
|
||||
|
26
sha1_file.c
26
sha1_file.c
@ -1217,12 +1217,20 @@ int find_pack_entry_one(const unsigned char *sha1,
|
||||
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;
|
||||
prepare_packed_git();
|
||||
|
||||
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))
|
||||
return 1;
|
||||
}
|
||||
@ -1255,10 +1263,10 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
|
||||
if (!map) {
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return packed_object_info(&e, type, sizep);
|
||||
reprepare_packed_git();
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return packed_object_info(&e, type, sizep);
|
||||
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;
|
||||
|
||||
if (!find_pack_entry(sha1, &e)) {
|
||||
if (!find_pack_entry(sha1, &e, NULL)) {
|
||||
error("cannot read sha1_file for %s", sha1_to_hex(sha1));
|
||||
return NULL;
|
||||
}
|
||||
@ -1294,7 +1302,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
|
||||
void *map, *buf;
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return read_packed_sha1(sha1, type, size);
|
||||
map = map_sha1_file(sha1, &mapsize);
|
||||
if (map) {
|
||||
@ -1303,7 +1311,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
|
||||
return buf;
|
||||
}
|
||||
reprepare_packed_git();
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return read_packed_sha1(sha1, type, size);
|
||||
return NULL;
|
||||
}
|
||||
@ -1735,10 +1743,10 @@ int has_pack_file(const unsigned char *sha1)
|
||||
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;
|
||||
return find_pack_entry(sha1, &e);
|
||||
return find_pack_entry(sha1, &e, ignore_packed);
|
||||
}
|
||||
|
||||
int has_sha1_file(const unsigned char *sha1)
|
||||
@ -1746,7 +1754,7 @@ int has_sha1_file(const unsigned char *sha1)
|
||||
struct stat st;
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return 1;
|
||||
return find_sha1_file(sha1, &st) ? 1 : 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user