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]
|
[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]
|
||||||
|
|
||||||
|
4
Makefile
4
Makefile
@ -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
|
||||||
|
|
||||||
|
@ -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)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
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 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
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))
|
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;
|
||||||
|
@ -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;
|
||||||
|
26
sha1_file.c
26
sha1_file.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user