summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c3
-rw-r--r--builtin/am.c40
-rw-r--r--builtin/blame.c131
-rw-r--r--builtin/branch.c6
-rw-r--r--builtin/cat-file.c16
-rw-r--r--builtin/checkout.c19
-rw-r--r--builtin/clone.c15
-rw-r--r--builtin/column.c1
-rw-r--r--builtin/commit.c46
-rw-r--r--builtin/config.c5
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c4
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/difftool.c11
-rw-r--r--builtin/fast-export.c39
-rw-r--r--builtin/fetch.c150
-rw-r--r--builtin/fsck.c50
-rw-r--r--builtin/gc.c167
-rw-r--r--builtin/grep.c9
-rw-r--r--builtin/help.c40
-rw-r--r--builtin/index-pack.c23
-rw-r--r--builtin/init-db.c4
-rw-r--r--builtin/log.c12
-rw-r--r--builtin/ls-files.c8
-rw-r--r--builtin/ls-remote.c4
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/merge.c26
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/notes.c20
-rw-r--r--builtin/pack-objects.c509
-rw-r--r--builtin/pack-redundant.c62
-rw-r--r--builtin/prune-packed.c2
-rw-r--r--builtin/prune.c3
-rw-r--r--builtin/pull.c25
-rw-r--r--builtin/push.c80
-rw-r--r--builtin/read-tree.c3
-rw-r--r--builtin/rebase--helper.c13
-rw-r--r--builtin/receive-pack.c12
-rw-r--r--builtin/reflog.c2
-rw-r--r--builtin/remote.c55
-rw-r--r--builtin/repack.c21
-rw-r--r--builtin/replace.c245
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-parse.c12
-rw-r--r--builtin/rm.c3
-rw-r--r--builtin/send-pack.c24
-rw-r--r--builtin/submodule--helper.c54
-rw-r--r--builtin/tag.c4
-rw-r--r--builtin/unpack-objects.c9
-rw-r--r--builtin/update-index.c34
-rw-r--r--builtin/worktree.c101
52 files changed, 1409 insertions, 725 deletions
diff --git a/builtin/add.c b/builtin/add.c
index c9e2619a9a..8a155dd41e 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -265,8 +265,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
return 0;
}
-static struct lock_file lock_file;
-
static const char ignore_error[] =
N_("The following paths are ignored by one of your .gitignore files:\n");
@@ -393,6 +391,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int add_new_files;
int require_pathspec;
char *seen = NULL;
+ struct lock_file lock_file = LOCK_INIT;
git_config(add_config, NULL);
diff --git a/builtin/am.c b/builtin/am.c
index d834f9e62b..2fc2d1e82c 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -403,11 +403,11 @@ static void am_load(struct am_state *state)
struct strbuf sb = STRBUF_INIT;
if (read_state_file(&sb, state, "next", 1) < 0)
- die("BUG: state file 'next' does not exist");
+ BUG("state file 'next' does not exist");
state->cur = strtol(sb.buf, NULL, 10);
if (read_state_file(&sb, state, "last", 1) < 0)
- die("BUG: state file 'last' does not exist");
+ BUG("state file 'last' does not exist");
state->last = strtol(sb.buf, NULL, 10);
if (read_author_script(state) < 0)
@@ -986,7 +986,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
case PATCH_FORMAT_MBOXRD:
return split_mail_mbox(state, paths, keep_cr, 1);
default:
- die("BUG: invalid patch_format");
+ BUG("invalid patch_format");
}
return -1;
}
@@ -1041,7 +1041,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
str = "b";
break;
default:
- die("BUG: invalid value for state->keep");
+ BUG("invalid value for state->keep");
}
write_state_text(state, "keep", str);
@@ -1058,7 +1058,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
str = "t";
break;
default:
- die("BUG: invalid value for state->scissors");
+ BUG("invalid value for state->scissors");
}
write_state_text(state, "scissors", str);
@@ -1216,7 +1216,7 @@ static int parse_mail(struct am_state *state, const char *mail)
mi.keep_non_patch_brackets_in_subject = 1;
break;
default:
- die("BUG: invalid value for state->keep");
+ BUG("invalid value for state->keep");
}
if (state->message_id)
@@ -1232,7 +1232,7 @@ static int parse_mail(struct am_state *state, const char *mail)
mi.use_scissors = 1;
break;
default:
- die("BUG: invalid value for state->scissors");
+ BUG("invalid value for state->scissors");
}
mi.input = xfopen(mail, "r");
@@ -1463,7 +1463,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
int options = 0;
if (init_apply_state(&apply_state, NULL))
- die("BUG: init_apply_state() failed");
+ BUG("init_apply_state() failed");
argv_array_push(&apply_opts, "apply");
argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
@@ -1489,7 +1489,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
apply_state.apply_verbosity = verbosity_silent;
if (check_apply_state(&apply_state, force_apply))
- die("BUG: check_apply_state() failed");
+ BUG("check_apply_state() failed");
argv_array_push(&apply_paths, am_path(state, "patch"));
@@ -1542,7 +1542,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
char *their_tree_name;
if (get_oid("HEAD", &our_tree) < 0)
- hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
+ oidcpy(&our_tree, the_hash_algo->empty_tree);
if (build_fake_ancestor(state, index_path))
return error("could not build fake ancestor");
@@ -2042,7 +2042,7 @@ static void am_skip(struct am_state *state)
am_rerere_clear();
if (get_oid("HEAD", &head))
- hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
+ oidcpy(&head, the_hash_algo->empty_tree);
if (clean_index(&head, &head))
die(_("failed to clean index"));
@@ -2105,11 +2105,11 @@ static void am_abort(struct am_state *state)
curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
- hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
+ oidcpy(&curr_head, the_hash_algo->empty_tree);
has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
if (!has_orig_head)
- hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
+ oidcpy(&orig_head, the_hash_algo->empty_tree);
clean_index(&curr_head, &orig_head);
@@ -2231,12 +2231,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
OPT_BOOL('m', "message-id", &state.message_id,
N_("pass -m flag to git-mailinfo")),
- { OPTION_SET_INT, 0, "keep-cr", &keep_cr, NULL,
- N_("pass --keep-cr flag to git-mailsplit for mbox format"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
- { OPTION_SET_INT, 0, "no-keep-cr", &keep_cr, NULL,
- N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
+ OPT_SET_INT_F(0, "keep-cr", &keep_cr,
+ N_("pass --keep-cr flag to git-mailsplit for mbox format"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "no-keep-cr", &keep_cr,
+ N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
+ 0, PARSE_OPT_NONEG),
OPT_BOOL('c', "scissors", &state.scissors,
N_("strip everything before a scissors line")),
OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),
@@ -2407,7 +2407,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
ret = show_patch(&state);
break;
default:
- die("BUG: invalid resume value");
+ BUG("invalid resume value");
}
am_state_release(&state);
diff --git a/builtin/blame.c b/builtin/blame.c
index db38c0b307..4202584f97 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
+#include "color.h"
#include "builtin.h"
#include "commit.h"
#include "diff.h"
@@ -23,6 +24,7 @@
#include "dir.h"
#include "progress.h"
#include "blame.h"
+#include "string-list.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
@@ -46,6 +48,8 @@ static int xdl_opts;
static int abbrev = -1;
static int no_whole_file_rename;
static int show_progress;
+static char repeated_meta_color[COLOR_MAXLEN];
+static int coloring_mode;
static struct date_mode blame_date_mode = { DATE_ISO8601 };
static size_t blame_date_width;
@@ -316,10 +320,12 @@ static const char *format_time(timestamp_t time, const char *tz_str,
#define OUTPUT_PORCELAIN 010
#define OUTPUT_SHOW_NAME 020
#define OUTPUT_SHOW_NUMBER 040
-#define OUTPUT_SHOW_SCORE 0100
-#define OUTPUT_NO_AUTHOR 0200
+#define OUTPUT_SHOW_SCORE 0100
+#define OUTPUT_NO_AUTHOR 0200
#define OUTPUT_SHOW_EMAIL 0400
-#define OUTPUT_LINE_PORCELAIN 01000
+#define OUTPUT_LINE_PORCELAIN 01000
+#define OUTPUT_COLOR_LINE 02000
+#define OUTPUT_SHOW_AGE_WITH_COLOR 04000
static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
{
@@ -367,6 +373,63 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
putchar('\n');
}
+static struct color_field {
+ timestamp_t hop;
+ char col[COLOR_MAXLEN];
+} *colorfield;
+static int colorfield_nr, colorfield_alloc;
+
+static void parse_color_fields(const char *s)
+{
+ struct string_list l = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+ enum { EXPECT_DATE, EXPECT_COLOR } next = EXPECT_COLOR;
+
+ colorfield_nr = 0;
+
+ /* Ideally this would be stripped and split at the same time? */
+ string_list_split(&l, s, ',', -1);
+ ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+
+ for_each_string_list_item(item, &l) {
+ switch (next) {
+ case EXPECT_DATE:
+ colorfield[colorfield_nr].hop = approxidate(item->string);
+ next = EXPECT_COLOR;
+ colorfield_nr++;
+ ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+ break;
+ case EXPECT_COLOR:
+ if (color_parse(item->string, colorfield[colorfield_nr].col))
+ die(_("expecting a color: %s"), item->string);
+ next = EXPECT_DATE;
+ break;
+ }
+ }
+
+ if (next == EXPECT_COLOR)
+ die (_("must end with a color"));
+
+ colorfield[colorfield_nr].hop = TIME_MAX;
+}
+
+static void setup_default_color_by_age(void)
+{
+ parse_color_fields("blue,12 month ago,white,1 month ago,red");
+}
+
+static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
+{
+ int i = 0;
+ struct commit_info ci;
+ get_commit_info(ent->suspect->commit, &ci, 1);
+
+ while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
+ i++;
+
+ *dest_color = colorfield[i].col;
+}
+
static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
{
int cnt;
@@ -375,15 +438,35 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
struct commit_info ci;
char hex[GIT_MAX_HEXSZ + 1];
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
+ const char *default_color = NULL, *color = NULL, *reset = NULL;
get_commit_info(suspect->commit, &ci, 1);
oid_to_hex_r(hex, &suspect->commit->object.oid);
cp = blame_nth_line(sb, ent->lno);
+
+ if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
+ determine_line_heat(ent, &default_color);
+ color = default_color;
+ reset = GIT_COLOR_RESET;
+ }
+
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
+ if (opt & OUTPUT_COLOR_LINE) {
+ if (cnt > 0) {
+ color = repeated_meta_color;
+ reset = GIT_COLOR_RESET;
+ } else {
+ color = default_color ? default_color : NULL;
+ reset = default_color ? GIT_COLOR_RESET : NULL;
+ }
+ }
+ if (color)
+ fputs(color, stdout);
+
if (suspect->commit->object.flags & UNINTERESTING) {
if (blank_boundary)
memset(hex, ' ', length);
@@ -433,6 +516,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
printf(" %*d) ",
max_digits, ent->lno + 1 + cnt);
}
+ if (reset)
+ fputs(reset, stdout);
do {
ch = *cp++;
putchar(ch);
@@ -607,6 +692,30 @@ static int git_blame_config(const char *var, const char *value, void *cb)
parse_date_format(value, &blame_date_mode);
return 0;
}
+ if (!strcmp(var, "color.blame.repeatedlines")) {
+ if (color_parse_mem(value, strlen(value), repeated_meta_color))
+ warning(_("invalid color '%s' in color.blame.repeatedLines"),
+ value);
+ return 0;
+ }
+ if (!strcmp(var, "color.blame.highlightrecent")) {
+ parse_color_fields(value);
+ return 0;
+ }
+
+ if (!strcmp(var, "blame.coloring")) {
+ if (!strcmp(value, "repeatedLines")) {
+ coloring_mode |= OUTPUT_COLOR_LINE;
+ } else if (!strcmp(value, "highlightRecent")) {
+ coloring_mode |= OUTPUT_SHOW_AGE_WITH_COLOR;
+ } else if (!strcmp(value, "none")) {
+ coloring_mode &= ~(OUTPUT_COLOR_LINE |
+ OUTPUT_SHOW_AGE_WITH_COLOR);
+ } else {
+ warning(_("invalid value for blame.coloring"));
+ return 0;
+ }
+ }
if (git_diff_heuristic_config(var, value, cb) < 0)
return -1;
@@ -655,7 +764,7 @@ static int is_a_rev(const char *name)
if (get_oid(name, &oid))
return 0;
- return OBJ_NONE < oid_object_info(&oid, NULL);
+ return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
}
int cmd_blame(int argc, const char **argv, const char *prefix)
@@ -690,6 +799,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+ OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
+ OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
/*
* The following two options are parsed by parse_revision_opt()
@@ -714,6 +825,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
+ setup_default_color_by_age();
git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
@@ -949,8 +1061,17 @@ parse_done:
blame_coalesce(&sb);
- if (!(output_option & OUTPUT_PORCELAIN))
+ if (!(output_option & (OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR)))
+ output_option |= coloring_mode;
+
+ if (!(output_option & OUTPUT_PORCELAIN)) {
find_alignment(&sb, &output_option);
+ if (!*repeated_meta_color &&
+ (output_option & OUTPUT_COLOR_LINE))
+ strcpy(repeated_meta_color, GIT_COLOR_CYAN);
+ }
+ if (output_option & OUTPUT_ANNOTATE_COMPAT)
+ output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
output(&sb, output_option);
free((void *)sb.final_buf);
diff --git a/builtin/branch.c b/builtin/branch.c
index efc9ac1922..d53f6e2ad4 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -500,7 +500,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
- die("BUG: expected prefix missing for refs");
+ BUG("expected prefix missing for refs");
}
if (copy)
@@ -592,8 +592,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("suppress informational messages")),
OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"),
BRANCH_TRACK_EXPLICIT),
- { OPTION_SET_INT, 0, "set-upstream", &track, NULL, N_("do not use"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, BRANCH_TRACK_OVERRIDE },
+ OPT_SET_INT_F(0, "set-upstream", &track, N_("do not use"),
+ BRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),
OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("Unset the upstream info")),
OPT__COLOR(&branch_use_color, N_("use colored output")),
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 2c46d257cd..665b581949 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -77,7 +77,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
switch (opt) {
case 't':
oi.type_name = &sb;
- if (oid_object_info_extended(&oid, &oi, flags) < 0)
+ if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
if (sb.len) {
printf("%s\n", sb.buf);
@@ -88,7 +88,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 's':
oi.sizep = &size;
- if (oid_object_info_extended(&oid, &oi, flags) < 0)
+ if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
printf("%lu\n", size);
return 0;
@@ -116,7 +116,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
/* else fallthrough */
case 'p':
- type = oid_object_info(&oid, NULL);
+ type = oid_object_info(the_repository, &oid, NULL);
if (type < 0)
die("Not a valid object name %s", obj_name);
@@ -140,7 +140,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 0:
if (type_from_string(exp_type) == OBJ_BLOB) {
struct object_id blob_oid;
- if (oid_object_info(&oid, NULL) == OBJ_TAG) {
+ if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
char *buffer = read_object_file(&oid, &type,
&size);
const char *target;
@@ -151,7 +151,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
} else
oidcpy(&blob_oid, &oid);
- if (oid_object_info(&blob_oid, NULL) == OBJ_BLOB)
+ if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
return stream_blob_to_fd(1, &blob_oid, NULL, 0);
/*
* we attempted to dereference a tag to a blob
@@ -312,7 +312,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
} else
- die("BUG: invalid cmdmode: %c", opt->cmdmode);
+ BUG("invalid cmdmode: %c", opt->cmdmode);
batch_write(opt, contents, size);
free(contents);
} else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
@@ -342,7 +342,7 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
struct strbuf buf = STRBUF_INIT;
if (!data->skip_object_info &&
- oid_object_info_extended(&data->oid, &data->info,
+ oid_object_info_extended(the_repository, &data->oid, &data->info,
OBJECT_INFO_LOOKUP_REPLACE) < 0) {
printf("%s missing\n",
obj_name ? obj_name : oid_to_hex(&data->oid));
@@ -387,7 +387,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
(uintmax_t)strlen(obj_name), obj_name);
break;
default:
- die("BUG: unknown get_sha1_with_context result %d\n",
+ BUG("unknown get_sha1_with_context result %d\n",
result);
break;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index b49b582071..2e1d2376d2 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -484,7 +484,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
resolve_undo_clear();
if (opts->force) {
- ret = reset_tree(new_branch_info->commit->tree, opts, 1, writeout_error);
+ ret = reset_tree(get_commit_tree(new_branch_info->commit),
+ opts, 1, writeout_error);
if (ret)
return ret;
} else {
@@ -526,6 +527,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
init_tree_desc(&trees[1], tree->buffer, tree->size);
ret = unpack_trees(2, trees, &topts);
+ clear_unpack_trees_porcelain(&topts);
if (ret == -1) {
/*
* Unpack couldn't do a trivial merge; either
@@ -570,18 +572,23 @@ static int merge_working_tree(const struct checkout_opts *opts,
o.verbosity = 0;
work = write_tree_from_memory(&o);
- ret = reset_tree(new_branch_info->commit->tree, opts, 1,
+ ret = reset_tree(get_commit_tree(new_branch_info->commit),
+ opts, 1,
writeout_error);
if (ret)
return ret;
o.ancestor = old_branch_info->name;
o.branch1 = new_branch_info->name;
o.branch2 = "local";
- ret = merge_trees(&o, new_branch_info->commit->tree, work,
- old_branch_info->commit->tree, &result);
+ ret = merge_trees(&o,
+ get_commit_tree(new_branch_info->commit),
+ work,
+ get_commit_tree(old_branch_info->commit),
+ &result);
if (ret < 0)
exit(128);
- ret = reset_tree(new_branch_info->commit->tree, opts, 0,
+ ret = reset_tree(get_commit_tree(new_branch_info->commit),
+ opts, 0,
writeout_error);
strbuf_release(&o.obuf);
if (ret)
@@ -1002,7 +1009,7 @@ static int parse_branchname_arg(int argc, const char **argv,
*source_tree = parse_tree_indirect(rev);
} else {
parse_commit_or_die(new_branch_info->commit);
- *source_tree = new_branch_info->commit->tree;
+ *source_tree = get_commit_tree(new_branch_info->commit);
}
if (!*source_tree) /* case (1): want a tree */
diff --git a/builtin/clone.c b/builtin/clone.c
index 84f1473d19..99e73dae85 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -14,6 +14,7 @@
#include "parse-options.h"
#include "fetch-pack.h"
#include "refs.h"
+#include "refspec.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -546,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
}
static struct ref *wanted_peer_refs(const struct ref *refs,
- struct refspec *refspec)
+ struct refspec_item *refspec)
{
struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
struct ref *local_refs = head;
@@ -823,7 +824,7 @@ static void write_refspec_config(const char *src_ref_prefix,
} else if (remote_head_points_at) {
const char *head = remote_head_points_at->name;
if (!skip_prefix(head, "refs/heads/", &head))
- die("BUG: remote HEAD points at non-head?");
+ BUG("remote HEAD points at non-head?");
strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
branch_top->buf, head);
@@ -894,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
- struct refspec *refspec;
- const char *fetch_pattern;
+ struct refspec_item refspec;
fetch_if_missing = 0;
@@ -1077,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- fetch_pattern = value.buf;
- refspec = parse_fetch_refspec(1, &fetch_pattern);
+ refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
strbuf_reset(&value);
@@ -1138,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
refs = transport_get_remote_refs(transport, NULL);
if (refs) {
- mapped_refs = wanted_peer_refs(refs, refspec);
+ mapped_refs = wanted_peer_refs(refs, &refspec);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
@@ -1232,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL;
- free(refspec);
+ refspec_item_clear(&refspec);
return err;
}
diff --git a/builtin/column.c b/builtin/column.c
index 0c3223d64b..5228ccf37a 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -42,7 +42,6 @@ int cmd_column(int argc, const char **argv, const char *prefix)
git_config(column_config, NULL);
memset(&copts, 0, sizeof(copts));
- copts.width = term_columns();
copts.padding = 1;
argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
if (argc)
diff --git a/builtin/commit.c b/builtin/commit.c
index 5571d4a3e2..a842fea666 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -143,6 +143,16 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
+{
+ const char **value = opt->value;
+ if (arg != NULL && *arg == '=')
+ arg = arg + 1;
+
+ *value = arg;
+ return 0;
+}
+
static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path_merge_head()))
@@ -161,9 +171,9 @@ static void determine_whence(struct wt_status *s)
static void status_init_config(struct wt_status *s, config_fn_t fn)
{
wt_status_prepare(s);
+ init_diff_ui_defaults();
git_config(fn, s);
determine_whence(s);
- init_diff_ui_defaults();
s->hints = advice_status_hints; /* must come after git_config() */
}
@@ -495,7 +505,7 @@ static int is_a_merge(const struct commit *current_head)
static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
{
if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
- die("BUG: unable to parse our own ident: %s", buf->buf);
+ BUG("unable to parse our own ident: %s", buf->buf);
}
static void export_one(const char *var, const char *s, const char *e, int hack)
@@ -1259,11 +1269,31 @@ static int git_status_config(const char *k, const char *v, void *cb)
return error(_("Invalid untracked files mode '%s'"), v);
return 0;
}
+ if (!strcmp(k, "diff.renamelimit")) {
+ if (s->rename_limit == -1)
+ s->rename_limit = git_config_int(k, v);
+ return 0;
+ }
+ if (!strcmp(k, "status.renamelimit")) {
+ s->rename_limit = git_config_int(k, v);
+ return 0;
+ }
+ if (!strcmp(k, "diff.renames")) {
+ if (s->detect_rename == -1)
+ s->detect_rename = git_config_rename(k, v);
+ return 0;
+ }
+ if (!strcmp(k, "status.renames")) {
+ s->detect_rename = git_config_rename(k, v);
+ return 0;
+ }
return git_diff_ui_config(k, v, NULL);
}
int cmd_status(int argc, const char **argv, const char *prefix)
{
+ static int no_renames = -1;
+ static const char *rename_score_arg = (const char *)-1;
static struct wt_status s;
int fd;
struct object_id oid;
@@ -1297,6 +1327,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
+ OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
+ { OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
+ N_("n"), N_("detect renames, optionally set similarity index"),
+ PARSE_OPT_OPTARG, opt_parse_rename_score },
OPT_END(),
};
@@ -1336,6 +1370,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
s.ignore_submodule_arg = ignore_submodule_arg;
s.status_format = status_format;
s.verbose = verbose;
+ if (no_renames != -1)
+ s.detect_rename = !no_renames;
+ if ((intptr_t)rename_score_arg != -1) {
+ if (s.detect_rename < DIFF_DETECT_RENAME)
+ s.detect_rename = DIFF_DETECT_RENAME;
+ if (rename_score_arg)
+ s.rename_score = parse_rename_score(&rename_score_arg);
+ }
wt_status_collect(&s);
diff --git a/builtin/config.c b/builtin/config.c
index 69e7270356..b29d26dede 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -398,7 +398,7 @@ static char *normalize_value(const char *key, const char *value)
return xstrdup(value);
}
- die("BUG: cannot normalize type %d", type);
+ BUG("cannot normalize type %d", type);
}
static int get_color_found;
@@ -602,6 +602,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (use_local_config && nongit)
die(_("--local can only be used inside a git repository"));
+ if (given_config_source.blob && nongit)
+ die(_("--blob can only be used inside a git repository"));
+
if (given_config_source.file &&
!strcmp(given_config_source.file, "-")) {
given_config_source.file = NULL;
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index b054713e1a..d51e2ce1ec 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -66,7 +66,7 @@ static int count_loose(const struct object_id *oid, const char *path, void *data
else {
loose_size += on_disk_bytes(st);
loose++;
- if (verbose && has_sha1_pack(oid->hash))
+ if (verbose && has_object_pack(oid))
packed_loose++;
}
return 0;
diff --git a/builtin/describe.c b/builtin/describe.c
index b5afc45846..cf1ae77d7c 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -502,7 +502,7 @@ static void describe(const char *arg, int last_one)
if (cmit)
describe_commit(&oid, &sb);
- else if (oid_object_info(&oid, NULL) == OBJ_BLOB)
+ else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB)
describe_blob(oid, &sb);
else
die(_("%s is neither a commit nor blob"), arg);
@@ -612,7 +612,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
suffix = broken;
}
} else if (dirty) {
- static struct lock_file index_lock;
+ struct lock_file index_lock = LOCK_INIT;
struct rev_info revs;
struct argv_array args = ARGV_ARRAY_INIT;
int fd, result;
diff --git a/builtin/diff.c b/builtin/diff.c
index 16bfb22f73..bfefff3a84 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -398,7 +398,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
- obj = &((struct commit *)obj)->tree->object;
+ obj = &get_commit_tree(((struct commit *)obj))->object;
if (obj->type == OBJ_TREE) {
obj->flags |= flags;
diff --git a/builtin/difftool.c b/builtin/difftool.c
index aad0e073ee..bc97d4aef2 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -610,7 +610,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
continue;
if (!indices_loaded) {
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/wtindex", tmpdir);
if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
@@ -695,12 +695,11 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
N_("use `diff.guitool` instead of `diff.tool`")),
OPT_BOOL('d', "dir-diff", &dir_diff,
N_("perform a full-directory diff")),
- { OPTION_SET_INT, 'y', "no-prompt", &prompt, NULL,
+ OPT_SET_INT_F('y', "no-prompt", &prompt,
N_("do not prompt before launching a diff tool"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
- { OPTION_SET_INT, 0, "prompt", &prompt, NULL, NULL,
- PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN,
- NULL, 1 },
+ 0, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "prompt", &prompt, NULL,
+ 1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
OPT_BOOL(0, "symlinks", &symlinks,
N_("use symlinks in dir-diff mode")),
OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"),
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 530df12f05..6c9768742f 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "refspec.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -35,8 +36,7 @@ static int use_done_feature;
static int no_data;
static int full_tree;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec *refspecs;
-static int refspecs_nr;
+static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -156,15 +156,14 @@ static void anonymize_path(struct strbuf *out, const char *path,
}
}
-/* Since intptr_t is C99, we do not use it here */
-static inline uint32_t *mark_to_ptr(uint32_t mark)
+static inline void *mark_to_ptr(uint32_t mark)
{
- return ((uint32_t *)NULL) + mark;
+ return (void *)(uintptr_t)mark;
}
static inline uint32_t ptr_to_mark(void * mark)
{
- return (uint32_t *)mark - (uint32_t *)NULL;
+ return (uint32_t)(uintptr_t)mark;
}
static inline void mark_object(struct object *object, uint32_t mark)
@@ -517,7 +516,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
/* skip "committer", "author", "tagger", etc */
end_of_header = strchr(*beg, ' ');
if (!end_of_header)
- die("BUG: malformed line fed to anonymize_ident_line: %.*s",
+ BUG("malformed line fed to anonymize_ident_line: %.*s",
(int)(*end - *beg), *beg);
end_of_header++;
strbuf_add(out, *beg, end_of_header - *beg);
@@ -578,11 +577,11 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
get_object_mark(&commit->parents->item->object) != 0 &&
!full_tree) {
parse_commit_or_die(commit->parents->item);
- diff_tree_oid(&commit->parents->item->tree->object.oid,
- &commit->tree->object.oid, "", &rev->diffopt);
+ diff_tree_oid(get_commit_tree_oid(commit->parents->item),
+ get_commit_tree_oid(commit), "", &rev->diffopt);
}
else
- diff_root_tree_oid(&commit->tree->object.oid,
+ diff_root_tree_oid(get_commit_tree_oid(commit),
"", &rev->diffopt);
/* Export the referenced blobs, and remember the marks. */
@@ -829,9 +828,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
continue;
- if (refspecs) {
+ if (refspecs.nr) {
char *private;
- private = apply_refspecs(refspecs, refspecs_nr, full_name);
+ private = apply_refspecs(&refspecs, full_name);
if (private) {
free(full_name);
full_name = private;
@@ -950,7 +949,7 @@ static void import_marks(char *input_file)
if (last_idnum < mark)
last_idnum = mark;
- type = oid_object_info(&oid, NULL);
+ type = oid_object_info(the_repository, &oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(&oid));
@@ -977,8 +976,8 @@ static void import_marks(char *input_file)
static void handle_deletes(void)
{
int i;
- for (i = 0; i < refspecs_nr; i++) {
- struct refspec *refspec = &refspecs[i];
+ for (i = 0; i < refspecs.nr; i++) {
+ struct refspec_item *refspec = &refspecs.items[i];
if (*refspec->src)
continue;
@@ -1039,18 +1038,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
usage_with_options (fast_export_usage, options);
if (refspecs_list.nr) {
- const char **refspecs_str;
int i;
- ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
for (i = 0; i < refspecs_list.nr; i++)
- refspecs_str[i] = refspecs_list.items[i].string;
-
- refspecs_nr = refspecs_list.nr;
- refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
+ refspec_append(&refspecs, refspecs_list.items[i].string);
string_list_clear(&refspecs_list, 1);
- free(refspecs_str);
}
if (use_done_feature)
@@ -1089,7 +1082,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (use_done_feature)
printf("done\n");
- free_refspec(refspecs_nr, refspecs);
+ refspec_clear(&refspecs);
return 0;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7ee83ac0f8..ea5b9669ad 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -5,6 +5,7 @@
#include "config.h"
#include "repository.h"
#include "refs.h"
+#include "refspec.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
@@ -59,9 +60,9 @@ static const char *submodule_prefix = "";
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
static int shown_url = 0;
-static int refmap_alloc, refmap_nr;
-static const char **refmap_array;
+static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
+static struct string_list server_options = STRING_LIST_INIT_DUP;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -107,14 +108,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
- ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
-
/*
* "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere
*/
- if (*arg)
- refmap_array[refmap_nr++] = arg;
+ refspec_append(&refmap, arg);
+
return 0;
}
@@ -156,9 +155,9 @@ static struct option builtin_fetch_options[] = {
N_("deepen history of shallow clone, excluding rev")),
OPT_INTEGER(0, "deepen", &deepen_relative,
N_("deepen history of shallow clone")),
- { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
- N_("convert to a complete repository"),
- PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
+ OPT_SET_INT_F(0, "unshallow", &unshallow,
+ N_("convert to a complete repository"),
+ 1, PARSE_OPT_NONEG),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
{ OPTION_CALLBACK, 0, "recurse-submodules-default",
@@ -170,6 +169,7 @@ static struct option builtin_fetch_options[] = {
N_("accept refs that update .git/shallow")),
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
+ OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@@ -202,7 +202,7 @@ static void add_merge_config(struct ref **head,
for (i = 0; i < branch->merge_nr; i++) {
struct ref *rm, **old_tail = *tail;
- struct refspec refspec;
+ struct refspec_item refspec;
for (rm = *head; rm; rm = rm->next) {
if (branch_merge_matches(branch, i, rm->name)) {
@@ -339,7 +339,7 @@ static void find_non_local_tags(struct transport *transport,
}
static struct ref *get_ref_map(struct transport *transport,
- struct refspec *refspecs, int refspec_count,
+ struct refspec *rs,
int tags, int *autotags)
{
int i;
@@ -353,29 +353,26 @@ static struct ref *get_ref_map(struct transport *transport,
const struct ref *remote_refs;
- for (i = 0; i < refspec_count; i++) {
- if (!refspecs[i].exact_sha1) {
- const char *glob = strchr(refspecs[i].src, '*');
- if (glob)
- argv_array_pushf(&ref_prefixes, "%.*s",
- (int)(glob - refspecs[i].src),
- refspecs[i].src);
- else
- expand_ref_prefix(&ref_prefixes, refspecs[i].src);
- }
+ if (rs->nr)
+ refspec_ref_prefixes(rs, &ref_prefixes);
+ else if (transport->remote && transport->remote->fetch.nr)
+ refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
+
+ if (ref_prefixes.argc &&
+ (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+ argv_array_push(&ref_prefixes, "refs/tags/");
}
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
argv_array_clear(&ref_prefixes);
- if (refspec_count) {
+ if (rs->nr) {
struct refspec *fetch_refspec;
- int fetch_refspec_nr;
- for (i = 0; i < refspec_count; i++) {
- get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
- if (refspecs[i].dst && refspecs[i].dst[0])
+ for (i = 0; i < rs->nr; i++) {
+ get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
+ if (rs->items[i].dst && rs->items[i].dst[0])
*autotags = 1;
}
/* Merge everything on the command line (but not --tags) */
@@ -402,17 +399,14 @@ static struct ref *get_ref_map(struct transport *transport,
* by ref_remove_duplicates() in favor of one of these
* opportunistic entries with FETCH_HEAD_IGNORE.
*/
- if (refmap_array) {
- fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
- fetch_refspec_nr = refmap_nr;
- } else {
- fetch_refspec = transport->remote->fetch;
- fetch_refspec_nr = transport->remote->fetch_refspec_nr;
- }
+ if (refmap.nr)
+ fetch_refspec = &refmap;
+ else
+ fetch_refspec = &transport->remote->fetch;
- for (i = 0; i < fetch_refspec_nr; i++)
- get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
- } else if (refmap_array) {
+ for (i = 0; i < fetch_refspec->nr; i++)
+ get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
+ } else if (refmap.nr) {
die("--refmap option is only meaningful with command-line refspec(s).");
} else {
/* Use the defaults */
@@ -420,16 +414,16 @@ static struct ref *get_ref_map(struct transport *transport,
struct branch *branch = branch_get(NULL);
int has_merge = branch_has_merge_config(branch);
if (remote &&
- (remote->fetch_refspec_nr ||
+ (remote->fetch.nr ||
/* Note: has_merge implies non-NULL branch->remote_name */
(has_merge && !strcmp(branch->remote_name, remote->name)))) {
- for (i = 0; i < remote->fetch_refspec_nr; i++) {
- get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0);
- if (remote->fetch[i].dst &&
- remote->fetch[i].dst[0])
+ for (i = 0; i < remote->fetch.nr; i++) {
+ get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
+ if (remote->fetch.items[i].dst &&
+ remote->fetch.items[i].dst[0])
*autotags = 1;
if (!i && !has_merge && ref_map &&
- !remote->fetch[0].pattern)
+ !remote->fetch.items[0].pattern)
ref_map->fetch_head_status = FETCH_HEAD_MERGE;
}
/*
@@ -654,7 +648,7 @@ static int update_local_ref(struct ref *ref,
struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = prettify_refname(ref->name);
- type = oid_object_info(&ref->new_oid, NULL);
+ type = oid_object_info(the_repository, &ref->new_oid, NULL);
if (type < 0)
die(_("object %s not found"), oid_to_hex(&ref->new_oid));
@@ -964,11 +958,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
- const char *raw_url)
+static int prune_refs(struct refspec *rs, struct ref *ref_map,
+ const char *raw_url)
{
int url_len, i, result = 0;
- struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+ struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
char *url;
int summary_width = transport_summary_width(stale_refs);
const char *dangling_msg = dry_run
@@ -1114,7 +1108,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
}
static int do_fetch(struct transport *transport,
- struct refspec *refs, int ref_count)
+ struct refspec *rs)
{
struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct ref *ref_map;
@@ -1138,7 +1132,7 @@ static int do_fetch(struct transport *transport,
goto cleanup;
}
- ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
+ ref_map = get_ref_map(transport, rs, tags, &autotags);
if (!update_head_ok)
check_not_current_branch(ref_map);
@@ -1162,11 +1156,10 @@ static int do_fetch(struct transport *transport,
* explicitly (via command line or configuration); we
* don't care whether --tags was specified.
*/
- if (ref_count) {
- prune_refs(refs, ref_count, ref_map, transport->url);
+ if (rs->nr) {
+ prune_refs(rs, ref_map, transport->url);
} else {
- prune_refs(transport->remote->fetch,
- transport->remote->fetch_refspec_nr,
+ prune_refs(&transport->remote->fetch,
ref_map,
transport->url);
}
@@ -1355,10 +1348,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
{
- static const char **refs = NULL;
- struct refspec *refspec;
- int ref_nr = 0;
- int j = 0;
+ struct refspec rs = REFSPEC_INIT_FETCH;
+ int i;
int exit_code;
int maybe_prune_tags;
int remote_via_config = remote_is_configured(remote, 0);
@@ -1391,37 +1382,34 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
maybe_prune_tags = prune_tags_ok && prune_tags;
if (maybe_prune_tags && remote_via_config)
- add_prune_tags_to_fetch_refspec(remote);
-
- if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
- size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
- refs = xcalloc(nr_alloc, sizeof(const char *));
- if (maybe_prune_tags) {
- refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
- ref_nr++;
+ refspec_append(&remote->fetch, TAG_REFSPEC);
+
+ if (maybe_prune_tags && (argc || !remote_via_config))
+ refspec_append(&rs, TAG_REFSPEC);
+
+ for (i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "tag")) {
+ char *tag;
+ i++;
+ if (i >= argc)
+ die(_("You need to specify a tag name."));
+
+ tag = xstrfmt("refs/tags/%s:refs/tags/%s",
+ argv[i], argv[i]);
+ refspec_append(&rs, tag);
+ free(tag);
+ } else {
+ refspec_append(&rs, argv[i]);
}
}
- if (argc > 0) {
- int i;
- for (i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "tag")) {
- i++;
- if (i >= argc)
- die(_("You need to specify a tag name."));
- refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s",
- argv[i], argv[i]);
- } else
- refs[j++] = argv[i];
- ref_nr++;
- }
- }
+ if (server_options.nr)
+ gtransport->server_options = &server_options;
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
- refspec = parse_fetch_refspec(ref_nr, refs);
- exit_code = do_fetch(gtransport, refspec, ref_nr);
- free_refspec(ref_nr, refspec);
+ exit_code = do_fetch(gtransport, &rs);
+ refspec_clear(&rs);
transport_disconnect(gtransport);
gtransport = NULL;
return exit_code;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 087360a675..3ad4f160f9 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -67,7 +67,8 @@ static const char *printable_type(struct object *obj)
const char *ret;
if (obj->type == OBJ_NONE) {
- enum object_type type = oid_object_info(&obj->oid, NULL);
+ enum object_type type = oid_object_info(the_repository,
+ &obj->oid, NULL);
if (type > 0)
object_as_type(obj, type, 0);
}
@@ -227,7 +228,7 @@ static void check_reachable_object(struct object *obj)
if (!(obj->flags & HAS_OBJ)) {
if (is_promisor_object(&obj->oid))
return;
- if (has_sha1_pack(obj->oid.hash))
+ if (has_object_pack(&obj->oid))
return; /* it is in pack - forget about it */
printf("missing %s %s\n", printable_type(obj),
describe_object(obj));
@@ -339,7 +340,7 @@ static void check_connectivity(void)
}
}
-static int fsck_obj(struct object *obj)
+static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
{
int err;
@@ -353,7 +354,7 @@ static int fsck_obj(struct object *obj)
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, "broken links");
- err = fsck_object(obj, NULL, 0, &fsck_obj_options);
+ err = fsck_object(obj, buffer, size, &fsck_obj_options);
if (err)
goto out;
@@ -398,7 +399,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
- return fsck_obj(obj);
+ return fsck_obj(obj, buffer, size);
}
static int default_refs;
@@ -506,44 +507,42 @@ static void get_default_heads(void)
}
}
-static struct object *parse_loose_object(const struct object_id *oid,
- const char *path)
+static int fsck_loose(const struct object_id *oid, const char *path, void *data)
{
struct object *obj;
- void *contents;
enum object_type type;
unsigned long size;
+ void *contents;
int eaten;
- if (read_loose_object(path, oid, &type, &size, &contents) < 0)
- return NULL;
+ if (read_loose_object(path, oid, &type, &size, &contents) < 0) {
+ errors_found |= ERROR_OBJECT;
+ error("%s: object corrupt or missing: %s",
+ oid_to_hex(oid), path);
+ return 0; /* keep checking other objects */
+ }
if (!contents && type != OBJ_BLOB)
- die("BUG: read_loose_object streamed a non-blob");
+ BUG("read_loose_object streamed a non-blob");
obj = parse_object_buffer(oid, type, size, contents, &eaten);
-
- if (!eaten)
- free(contents);
- return obj;
-}
-
-static int fsck_loose(const struct object_id *oid, const char *path, void *data)
-{
- struct object *obj = parse_loose_object(oid, path);
-
if (!obj) {
errors_found |= ERROR_OBJECT;
- error("%s: object corrupt or missing: %s",
+ error("%s: object could not be parsed: %s",
oid_to_hex(oid), path);
+ if (!eaten)
+ free(contents);
return 0; /* keep checking other objects */
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
- if (fsck_obj(obj))
+ if (fsck_obj(obj, contents, size))
errors_found |= ERROR_OBJECT;
- return 0;
+
+ if (!eaten)
+ free(contents);
+ return 0; /* keep checking other objects, even if we saw an error */
}
static int fsck_cruft(const char *basename, const char *path, void *data)
@@ -755,6 +754,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
stop_progress(&progress);
}
+
+ if (fsck_finish(&fsck_obj_options))
+ errors_found |= ERROR_OBJECT;
}
for (i = 0; i < argc; i++) {
diff --git a/builtin/gc.c b/builtin/gc.c
index d604940bb6..ccfb1ceaeb 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -22,6 +22,10 @@
#include "commit.h"
#include "packfile.h"
#include "object-store.h"
+#include "pack.h"
+#include "pack-objects.h"
+#include "blob.h"
+#include "tree.h"
#define FAILED_RUN "failed to run %s"
@@ -41,6 +45,8 @@ static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
static const char *prune_expire = "2.weeks.ago";
static const char *prune_worktrees_expire = "3.months.ago";
+static unsigned long big_pack_threshold;
+static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
static struct argv_array reflog = ARGV_ARRAY_INIT;
@@ -128,6 +134,9 @@ static void gc_config(void)
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_get_expiry("gc.logexpiry", &gc_log_expire);
+ git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
+ git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+
git_config(git_default_config, NULL);
}
@@ -166,6 +175,28 @@ static int too_many_loose_objects(void)
return needed;
}
+static struct packed_git *find_base_packs(struct string_list *packs,
+ unsigned long limit)
+{
+ struct packed_git *p, *base = NULL;
+
+ for (p = get_packed_git(the_repository); p; p = p->next) {
+ if (!p->pack_local)
+ continue;
+ if (limit) {
+ if (p->pack_size >= limit)
+ string_list_append(packs, p->pack_name);
+ } else if (!base || base->pack_size < p->pack_size) {
+ base = p;
+ }
+ }
+
+ if (base)
+ string_list_append(packs, base->pack_name);
+
+ return base;
+}
+
static int too_many_packs(void)
{
struct packed_git *p;
@@ -188,7 +219,86 @@ static int too_many_packs(void)
return gc_auto_pack_limit < cnt;
}
-static void add_repack_all_option(void)
+static uint64_t total_ram(void)
+{
+#if defined(HAVE_SYSINFO)
+ struct sysinfo si;
+
+ if (!sysinfo(&si))
+ return si.totalram;
+#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
+ int64_t physical_memory;
+ int mib[2];
+ size_t length;
+
+ mib[0] = CTL_HW;
+# if defined(HW_MEMSIZE)
+ mib[1] = HW_MEMSIZE;
+# else
+ mib[1] = HW_PHYSMEM;
+# endif
+ length = sizeof(int64_t);
+ if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
+ return physical_memory;
+#elif defined(GIT_WINDOWS_NATIVE)
+ MEMORYSTATUSEX memInfo;
+
+ memInfo.dwLength = sizeof(MEMORYSTATUSEX);
+ if (GlobalMemoryStatusEx(&memInfo))
+ return memInfo.ullTotalPhys;
+#endif
+ return 0;
+}
+
+static uint64_t estimate_repack_memory(struct packed_git *pack)
+{
+ unsigned long nr_objects = approximate_object_count();
+ size_t os_cache, heap;
+
+ if (!pack || !nr_objects)
+ return 0;
+
+ /*
+ * First we have to scan through at least one pack.
+ * Assume enough room in OS file cache to keep the entire pack
+ * or we may accidentally evict data of other processes from
+ * the cache.
+ */
+ os_cache = pack->pack_size + pack->index_size;
+ /* then pack-objects needs lots more for book keeping */
+ heap = sizeof(struct object_entry) * nr_objects;
+ /*
+ * internal rev-list --all --objects takes up some memory too,
+ * let's say half of it is for blobs
+ */
+ heap += sizeof(struct blob) * nr_objects / 2;
+ /*
+ * and the other half is for trees (commits and tags are
+ * usually insignificant)
+ */
+ heap += sizeof(struct tree) * nr_objects / 2;
+ /* and then obj_hash[], underestimated in fact */
+ heap += sizeof(struct object *) * nr_objects;
+ /* revindex is used also */
+ heap += sizeof(struct revindex_entry) * nr_objects;
+ /*
+ * read_sha1_file() (either at delta calculation phase, or
+ * writing phase) also fills up the delta base cache
+ */
+ heap += delta_base_cache_limit;
+ /* and of course pack-objects has its own delta cache */
+ heap += max_delta_cache_size;
+
+ return os_cache + heap;
+}
+
+static int keep_one_pack(struct string_list_item *item, void *data)
+{
+ argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
+ return 0;
+}
+
+static void add_repack_all_option(struct string_list *keep_pack)
{
if (prune_expire && !strcmp(prune_expire, "now"))
argv_array_push(&repack, "-a");
@@ -197,6 +307,9 @@ static void add_repack_all_option(void)
if (prune_expire)
argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
}
+
+ if (keep_pack)
+ for_each_string_list(keep_pack, keep_one_pack, NULL);
}
static void add_repack_incremental_option(void)
@@ -219,9 +332,35 @@ static int need_to_gc(void)
* we run "repack -A -d -l". Otherwise we tell the caller
* there is no need.
*/
- if (too_many_packs())
- add_repack_all_option();
- else if (too_many_loose_objects())
+ if (too_many_packs()) {
+ struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+ if (big_pack_threshold) {
+ find_base_packs(&keep_pack, big_pack_threshold);
+ if (keep_pack.nr >= gc_auto_pack_limit) {
+ big_pack_threshold = 0;
+ string_list_clear(&keep_pack, 0);
+ find_base_packs(&keep_pack, 0);
+ }
+ } else {
+ struct packed_git *p = find_base_packs(&keep_pack, 0);
+ uint64_t mem_have, mem_want;
+
+ mem_have = total_ram();
+ mem_want = estimate_repack_memory(p);
+
+ /*
+ * Only allow 1/2 of memory for pack-objects, leave
+ * the rest for the OS and other processes in the
+ * system.
+ */
+ if (!mem_have || mem_want < mem_have / 2)
+ string_list_clear(&keep_pack, 0);
+ }
+
+ add_repack_all_option(&keep_pack);
+ string_list_clear(&keep_pack, 0);
+ } else if (too_many_loose_objects())
add_repack_incremental_option();
else
return 0;
@@ -234,7 +373,7 @@ static int need_to_gc(void)
/* return NULL on success, else hostname running the gc */
static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
{
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
char my_host[HOST_NAME_MAX + 1];
struct strbuf sb = STRBUF_INIT;
struct stat st;
@@ -354,6 +493,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
const char *name;
pid_t pid;
int daemonized = 0;
+ int keep_base_pack = -1;
timestamp_t dummy;
struct option builtin_gc_options[] = {
@@ -367,6 +507,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
OPT_BOOL_F(0, "force", &force,
N_("force running gc even if there may be another gc running"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
+ N_("repack all other packs except the largest pack")),
OPT_END()
};
@@ -435,8 +577,19 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
*/
daemonized = !daemonize();
}
- } else
- add_repack_all_option();
+ } else {
+ struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+ if (keep_base_pack != -1) {
+ if (keep_base_pack)
+ find_base_packs(&keep_pack, 0);
+ } else if (big_pack_threshold) {
+ find_base_packs(&keep_pack, big_pack_threshold);
+ }
+
+ add_repack_all_option(&keep_pack);
+ string_list_clear(&keep_pack, 0);
+ }
name = lock_repo_for_gc(force, &pid);
if (name) {
diff --git a/builtin/grep.c b/builtin/grep.c
index 6e7bc76785..ee753a403e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -488,7 +488,8 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
strbuf_addstr(&name, repo->submodule_prefix);
}
- repo_read_index(repo);
+ if (repo_read_index(repo) < 0)
+ die("index file corrupt");
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
@@ -885,9 +886,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("indicate hit with exit status without output")),
OPT_BOOL(0, "all-match", &opt.all_match,
N_("show only matches from files that match all patterns")),
- { OPTION_SET_INT, 0, "debug", &opt.debug, NULL,
- N_("show parse tree for grep expression"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 },
+ OPT_SET_INT_F(0, "debug", &opt.debug,
+ N_("show parse tree for grep expression"),
+ 1, PARSE_OPT_HIDDEN),
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
N_("pager"), N_("show matching files in the pager"),
diff --git a/builtin/help.c b/builtin/help.c
index 2d51071429..58e0a5507f 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -9,6 +9,7 @@
#include "run-command.h"
#include "column.h"
#include "help.h"
+#include "alias.h"
#ifndef DEFAULT_HELP_FORMAT
#define DEFAULT_HELP_FORMAT "man"
@@ -36,6 +37,7 @@ static const char *html_path;
static int show_all = 0;
static int show_guides = 0;
+static int verbose;
static unsigned int colopts;
static enum help_format help_format = HELP_FORMAT_NONE;
static int exclude_guides;
@@ -48,6 +50,7 @@ static struct option builtin_help_options[] = {
HELP_FORMAT_WEB),
OPT_SET_INT('i', "info", &help_format, N_("show info page"),
HELP_FORMAT_INFO),
+ OPT__VERBOSE(&verbose, N_("print command description")),
OPT_END(),
};
@@ -400,38 +403,6 @@ static void show_html_page(const char *git_cmd)
open_html(page_path.buf);
}
-static struct {
- const char *name;
- const char *help;
-} common_guides[] = {
- { "attributes", N_("Defining attributes per path") },
- { "everyday", N_("Everyday Git With 20 Commands Or So") },
- { "glossary", N_("A Git glossary") },
- { "ignore", N_("Specifies intentionally untracked files to ignore") },
- { "modules", N_("Defining submodule properties") },
- { "revisions", N_("Specifying revisions and ranges for Git") },
- { "tutorial", N_("A tutorial introduction to Git (for version 1.5.1 or newer)") },
- { "workflows", N_("An overview of recommended workflows with Git") },
-};
-
-static void list_common_guides_help(void)
-{
- int i, longest = 0;
-
- for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
- if (longest < strlen(common_guides[i].name))
- longest = strlen(common_guides[i].name);
- }
-
- puts(_("The common Git guides are:\n"));
- for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
- printf(" %s ", common_guides[i].name);
- mput_char(' ', longest - strlen(common_guides[i].name));
- puts(_(common_guides[i].help));
- }
- putchar('\n');
-}
-
static const char *check_git_cmd(const char* cmd)
{
char *alias;
@@ -463,6 +434,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (show_all) {
git_config(git_help_config, NULL);
+ if (verbose) {
+ setup_pager();
+ list_all_cmds_help();
+ return 0;
+ }
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
load_command_list("git-", &main_cmds, &other_cmds);
list_commands(colopts, &main_cmds, &other_cmds);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index a2cd29d8f4..4ab31ed388 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -223,7 +223,7 @@ static unsigned check_object(struct object *obj)
if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size;
- int type = oid_object_info(&obj->oid, &size);
+ int type = oid_object_info(the_repository, &obj->oid, &size);
if (type <= 0)
die(_("did not receive expected object %s"),
oid_to_hex(&obj->oid));
@@ -812,7 +812,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
enum object_type has_type;
unsigned long has_size;
read_lock();
- has_type = oid_object_info(oid, &has_size);
+ has_type = oid_object_info(the_repository, oid, &has_size);
if (has_type < 0)
die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size)
@@ -837,6 +837,9 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
blob->object.flags |= FLAG_CHECKED;
else
die(_("invalid blob object %s"), oid_to_hex(oid));
+ if (do_fsck_object &&
+ fsck_object(&blob->object, (void *)data, size, &fsck_options))
+ die(_("fsck error in packed object"));
} else {
struct object *obj;
int eaten;
@@ -854,7 +857,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("invalid %s"), type_name(type));
if (do_fsck_object &&
fsck_object(obj, buf, size, &fsck_options))
- die(_("Error in object"));
+ die(_("fsck error in packed object"));
if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
@@ -866,7 +869,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
if (detach_commit_buffer(commit, NULL) != data)
- die("BUG: parse_object_buffer transmogrified our buffer");
+ BUG("parse_object_buffer transmogrified our buffer");
}
obj->flags |= FLAG_CHECKED;
}
@@ -1015,7 +1018,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
base->obj->real_type))
- die("BUG: child->real_type != OBJ_REF_DELTA");
+ BUG("child->real_type != OBJ_REF_DELTA");
resolve_delta(child, base, result);
if (base->ref_first == base->ref_last && base->ofs_last == -1)
@@ -1479,6 +1482,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
} else
chmod(final_index_name, 0444);
+ if (do_fsck_object)
+ add_packed_git(final_index_name, strlen(final_index_name), 0);
+
if (!from_stdin) {
printf("%s\n", sha1_to_hex(hash));
} else {
@@ -1543,12 +1549,13 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
{
const uint32_t *idx1, *idx2;
uint32_t i;
+ const uint32_t hashwords = the_hash_algo->rawsz / sizeof(uint32_t);
/* The address of the 4-byte offset table */
idx1 = (((const uint32_t *)p->index_data)
+ 2 /* 8-byte header */
+ 256 /* fan out */
- + 5 * p->num_objects /* 20-byte SHA-1 table */
+ + hashwords * p->num_objects /* object ID table */
+ p->num_objects /* CRC32 table */
);
@@ -1820,6 +1827,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
pack_hash);
else
close(input_fd);
+
+ if (do_fsck_object && fsck_finish(&fsck_options))
+ die(_("fsck error in pack objects"));
+
free(objects);
strbuf_release(&index_name_buf);
if (pack_name == NULL)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 2542c5244e..4ecf909368 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -117,7 +117,7 @@ static void copy_templates(const char *template_dir)
dir = opendir(template_path.buf);
if (!dir) {
- warning(_("templates not found %s"), template_dir);
+ warning(_("templates not found in %s"), template_dir);
goto free_return;
}
@@ -391,7 +391,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
else if (get_shared_repository() == PERM_EVERYBODY)
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
else
- die("BUG: invalid value for shared_repository");
+ BUG("invalid value for shared_repository");
git_config_set("core.sharedrepository", buf);
git_config_set("receive.denyNonFastforwards", "true");
}
diff --git a/builtin/log.c b/builtin/log.c
index 71f68a3e4f..4686f68594 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1019,7 +1019,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
return;
- log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte);
+ log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
for (i = 0; !need_8bit_cte && i < nr; i++) {
const char *buf = get_commit_buffer(list[i], NULL);
@@ -1067,8 +1067,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
diff_setup_done(&opts);
- diff_tree_oid(&origin->tree->object.oid,
- &head->tree->object.oid,
+ diff_tree_oid(get_commit_tree_oid(origin),
+ get_commit_tree_oid(head),
"", &opts);
diffcore_std(&opts);
diff_flush(&opts);
@@ -1474,9 +1474,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("output all-zero hash in From header")),
OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
N_("don't include a patch matching a commit upstream")),
- { OPTION_SET_INT, 'p', "no-stat", &use_patch_format, NULL,
- N_("show patch format instead of default (patch + stat)"),
- PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1},
+ OPT_SET_INT_F('p', "no-stat", &use_patch_format,
+ N_("show patch format instead of default (patch + stat)"),
+ 1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
{ OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
N_("add email header"), 0, header_callback },
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a71f6bd088..88bb2019ad 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -166,7 +166,7 @@ static void show_killed_files(const struct index_state *istate,
*/
pos = index_name_pos(istate, ent->name, ent->len);
if (0 <= pos)
- die("BUG: killed-file %.*s not found",
+ BUG("killed-file %.*s not found",
ent->len, ent->name);
pos = -pos - 1;
while (pos < istate->cache_nr &&
@@ -556,9 +556,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
N_("add the standard git exclusions"),
PARSE_OPT_NOARG, option_parse_exclude_standard },
- { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
- N_("make the output relative to the project top directory"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
+ OPT_SET_INT_F(0, "full-name", &prefix_len,
+ N_("make the output relative to the project top directory"),
+ 0, PARSE_OPT_NONEG),
OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
N_("recurse through submodules")),
OPT_BOOL(0, "error-unmatch", &error_unmatch,
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index ca3f04a839..1a25df7ee1 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -47,6 +47,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
const char **pattern = NULL;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
int i;
+ struct string_list server_options = STRING_LIST_INIT_DUP;
struct remote *remote;
struct transport *transport;
@@ -73,6 +74,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
2, PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "symref", &show_symref_target,
N_("show underlying ref in addition to the object pointed by it")),
+ OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_END()
};
@@ -116,6 +118,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
transport = transport_get(remote, NULL);
if (uploadpack != NULL)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+ if (server_options.nr)
+ transport->server_options = &server_options;
ref = transport_get_remote_refs(transport, &ref_prefixes);
if (transport_disconnect(transport)) {
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index d44b4f9c27..409da4e835 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -94,7 +94,7 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
char size_text[24];
if (!strcmp(type, blob_type)) {
unsigned long size;
- if (oid_object_info(oid, &size) == OBJ_BAD)
+ if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text),
"BAD");
else
diff --git a/builtin/merge.c b/builtin/merge.c
index 9db5a2cf16..b00d6f4821 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
#include "run-command.h"
#include "diff.h"
#include "refs.h"
+#include "refspec.h"
#include "commit.h"
#include "diffcore.h"
#include "revision.h"
@@ -34,6 +35,7 @@
#include "string-list.h"
#include "packfile.h"
#include "tag.h"
+#include "alias.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -213,9 +215,9 @@ static struct option builtin_merge_options[] = {
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
- { OPTION_SET_INT, 0, "ff-only", &fast_forward, NULL,
- N_("abort if fast-forward is not possible"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
+ OPT_SET_INT_F(0, "ff-only", &fast_forward,
+ N_("abort if fast-forward is not possible"),
+ FF_ONLY, PARSE_OPT_NONEG),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),
@@ -280,7 +282,7 @@ out:
return rc;
}
-static void read_empty(unsigned const char *sha1, int verbose)
+static void read_empty(const struct object_id *oid, int verbose)
{
int i = 0;
const char *args[7];
@@ -290,15 +292,15 @@ static void read_empty(unsigned const char *sha1, int verbose)
args[i++] = "-v";
args[i++] = "-m";
args[i++] = "-u";
- args[i++] = EMPTY_TREE_SHA1_HEX;
- args[i++] = sha1_to_hex(sha1);
+ args[i++] = empty_tree_oid_hex();
+ args[i++] = oid_to_hex(oid);
args[i] = NULL;
if (run_command_v_opt(args, RUN_GIT_CMD))
die(_("read-tree failed"));
}
-static void reset_hard(unsigned const char *sha1, int verbose)
+static void reset_hard(const struct object_id *oid, int verbose)
{
int i = 0;
const char *args[6];
@@ -308,7 +310,7 @@ static void reset_hard(unsigned const char *sha1, int verbose)
args[i++] = "-v";
args[i++] = "--reset";
args[i++] = "-u";
- args[i++] = sha1_to_hex(sha1);
+ args[i++] = oid_to_hex(oid);
args[i] = NULL;
if (run_command_v_opt(args, RUN_GIT_CMD))
@@ -324,7 +326,7 @@ static void restore_state(const struct object_id *head,
if (is_null_oid(stash))
return;
- reset_hard(head->hash, 1);
+ reset_hard(head, 1);
args[2] = oid_to_hex(stash);
@@ -647,7 +649,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
struct commit_list *remoteheads,
struct commit *head)
{
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
const char *head_arg = "HEAD";
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
@@ -805,7 +807,7 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
@@ -1297,7 +1299,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (remoteheads->next)
die(_("Can merge only exactly one commit into empty head"));
remote_head_oid = &remoteheads->item->object.oid;
- read_empty(remote_head_oid->hash, 0);
+ read_empty(remote_head_oid, 0);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
goto done;
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 263c530315..bb76b469fd 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -116,7 +116,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
}
/* Check the type of object identified by sha1 */
- obj_type = oid_object_info(&oid, NULL);
+ obj_type = oid_object_info(the_repository, &oid, NULL);
if (obj_type < 0) {
if (allow_missing) {
; /* no problem - missing objects are presumed to be of the right type */
diff --git a/builtin/mv.c b/builtin/mv.c
index 7a63667d64..80bb967a63 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -72,7 +72,6 @@ static const char *add_slash(const char *path)
return path;
}
-static struct lock_file lock_file;
#define SUBMODULE_WITH_GITDIR ((const char *)1)
static void prepare_move_submodule(const char *src, int first,
@@ -131,6 +130,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ struct lock_file lock_file = LOCK_INIT;
git_config(git_default_config, NULL);
diff --git a/builtin/notes.c b/builtin/notes.c
index e5bf80eef1..6981e2d906 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -461,7 +461,7 @@ static int add(int argc, const char **argv, const char *prefix)
if (d.buf.len || allow_empty) {
write_note_data(&d, &new_note);
if (add_note(t, &object, &new_note, combine_notes_overwrite))
- die("BUG: combine_notes_overwrite failed");
+ BUG("combine_notes_overwrite failed");
commit_notes(t, "Notes added by 'git notes add'");
} else {
fprintf(stderr, _("Removing note for object %s\n"),
@@ -544,7 +544,7 @@ static int copy(int argc, const char **argv, const char *prefix)
}
if (add_note(t, &object, from_note, combine_notes_overwrite))
- die("BUG: combine_notes_overwrite failed");
+ BUG("combine_notes_overwrite failed");
commit_notes(t, "Notes added by 'git notes copy'");
out:
free_notes(t);
@@ -621,7 +621,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
if (d.buf.len || allow_empty) {
write_note_data(&d, &new_note);
if (add_note(t, &object, &new_note, combine_notes_overwrite))
- die("BUG: combine_notes_overwrite failed");
+ BUG("combine_notes_overwrite failed");
logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
} else {
fprintf(stderr, _("Removing note for object %s\n"),
@@ -778,13 +778,13 @@ static int merge(int argc, const char **argv, const char *prefix)
N_("resolve notes conflicts using the given strategy "
"(manual/ours/theirs/union/cat_sort_uniq)")),
OPT_GROUP(N_("Committing unmerged notes")),
- { OPTION_SET_INT, 0, "commit", &do_commit, NULL,
- N_("finalize notes merge by committing unmerged notes"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
+ OPT_SET_INT_F(0, "commit", &do_commit,
+ N_("finalize notes merge by committing unmerged notes"),
+ 1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Aborting notes merge resolution")),
- { OPTION_SET_INT, 0, "abort", &do_abort, NULL,
- N_("abort notes merge"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
+ OPT_SET_INT_F(0, "abort", &do_abort,
+ N_("abort notes merge"),
+ 1, PARSE_OPT_NONEG),
OPT_END()
};
@@ -831,7 +831,7 @@ static int merge(int argc, const char **argv, const char *prefix)
const char *short_ref = NULL;
if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
- die("BUG: local ref %s is outside of refs/notes/",
+ BUG("local ref %s is outside of refs/notes/",
o.local_ref);
strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 24b1c6c5dd..71056d8294 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -30,6 +30,19 @@
#include "list.h"
#include "packfile.h"
#include "object-store.h"
+#include "dir.h"
+
+#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
+#define SIZE(obj) oe_size(&to_pack, obj)
+#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
+#define DELTA_SIZE(obj) oe_delta_size(&to_pack, obj)
+#define DELTA(obj) oe_delta(&to_pack, obj)
+#define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
+#define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
+#define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
+#define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
+#define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
+#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
static const char *pack_usage[] = {
N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
@@ -45,7 +58,7 @@ static const char *pack_usage[] = {
static struct packing_data to_pack;
static struct pack_idx_entry **written_list;
-static uint32_t nr_result, nr_written;
+static uint32_t nr_result, nr_written, nr_seen;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
@@ -55,7 +68,8 @@ static int pack_loose_unreachable;
static int local;
static int have_non_local_packs;
static int incremental;
-static int ignore_packed_keep;
+static int ignore_packed_keep_on_disk;
+static int ignore_packed_keep_in_core;
static int allow_ofs_delta;
static struct pack_idx_option pack_idx_opts;
static const char *base_name;
@@ -80,7 +94,7 @@ static uint16_t write_bitmap_options;
static int exclude_promisor_objects;
static unsigned long delta_cache_size = 0;
-static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
+static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_limit = 0;
@@ -127,13 +141,14 @@ static void *get_delta(struct object_entry *entry)
buf = read_object_file(&entry->idx.oid, &type, &size);
if (!buf)
die("unable to read %s", oid_to_hex(&entry->idx.oid));
- base_buf = read_object_file(&entry->delta->idx.oid, &type, &base_size);
+ base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
+ &base_size);
if (!base_buf)
die("unable to read %s",
- oid_to_hex(&entry->delta->idx.oid));
+ oid_to_hex(&DELTA(entry)->idx.oid));
delta_buf = diff_delta(base_buf, base_size,
buf, size, &delta_size, 0);
- if (!delta_buf || delta_size != entry->delta_size)
+ if (!delta_buf || delta_size != DELTA_SIZE(entry))
die("delta size changed");
free(buf);
free(base_buf);
@@ -264,10 +279,11 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
enum object_type type;
void *buf;
struct git_istream *st = NULL;
+ const unsigned hashsz = the_hash_algo->rawsz;
if (!usable_delta) {
- if (entry->type == OBJ_BLOB &&
- entry->size > big_file_threshold &&
+ if (oe_type(entry) == OBJ_BLOB &&
+ oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
(st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL)
buf = NULL;
else {
@@ -283,15 +299,15 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
FREE_AND_NULL(entry->delta_data);
entry->z_delta_size = 0;
} else if (entry->delta_data) {
- size = entry->delta_size;
+ size = DELTA_SIZE(entry);
buf = entry->delta_data;
entry->delta_data = NULL;
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
+ type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
} else {
buf = get_delta(entry);
- size = entry->delta_size;
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
+ size = DELTA_SIZE(entry);
+ type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
}
@@ -315,12 +331,12 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
* encoding of the relative offset for the delta
* base from this object's position in the pack.
*/
- off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+ off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
dheader[--pos] = 128 | (--ofs & 127);
- if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+ if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
if (st)
close_istream(st);
free(buf);
@@ -332,19 +348,19 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
} else if (type == OBJ_REF_DELTA) {
/*
* Deltas with a base reference contain
- * an additional 20 bytes for the base sha1.
+ * additional bytes for the base object ID.
*/
- if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+ if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
if (st)
close_istream(st);
free(buf);
return 0;
}
hashwrite(f, header, hdrlen);
- hashwrite(f, entry->delta->idx.oid.hash, 20);
- hdrlen += 20;
+ hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+ hdrlen += hashsz;
} else {
- if (limit && hdrlen + datalen + 20 >= limit) {
+ if (limit && hdrlen + datalen + hashsz >= limit) {
if (st)
close_istream(st);
free(buf);
@@ -367,21 +383,23 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
unsigned long limit, int usable_delta)
{
- struct packed_git *p = entry->in_pack;
+ struct packed_git *p = IN_PACK(entry);
struct pack_window *w_curs = NULL;
struct revindex_entry *revidx;
off_t offset;
- enum object_type type = entry->type;
+ enum object_type type = oe_type(entry);
off_t datalen;
unsigned char header[MAX_PACK_OBJECT_HEADER],
dheader[MAX_PACK_OBJECT_HEADER];
unsigned hdrlen;
+ const unsigned hashsz = the_hash_algo->rawsz;
+ unsigned long entry_size = SIZE(entry);
- if (entry->delta)
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
+ if (DELTA(entry))
+ type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
hdrlen = encode_in_pack_object_header(header, sizeof(header),
- type, entry->size);
+ type, entry_size);
offset = entry->in_pack_offset;
revidx = find_pack_revindex(p, offset);
@@ -398,7 +416,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
datalen -= entry->in_pack_header_size;
if (!pack_to_stdout && p->index_version == 1 &&
- check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
+ check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
error("corrupt packed object for %s",
oid_to_hex(&entry->idx.oid));
unuse_pack(&w_curs);
@@ -406,12 +424,12 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
}
if (type == OBJ_OFS_DELTA) {
- off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+ off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
dheader[--pos] = 128 | (--ofs & 127);
- if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+ if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
unuse_pack(&w_curs);
return 0;
}
@@ -420,16 +438,16 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
hdrlen += sizeof(dheader) - pos;
reused_delta++;
} else if (type == OBJ_REF_DELTA) {
- if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+ if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
unuse_pack(&w_curs);
return 0;
}
hashwrite(f, header, hdrlen);
- hashwrite(f, entry->delta->idx.oid.hash, 20);
- hdrlen += 20;
+ hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+ hdrlen += hashsz;
reused_delta++;
} else {
- if (limit && hdrlen + datalen + 20 >= limit) {
+ if (limit && hdrlen + datalen + hashsz >= limit) {
unuse_pack(&w_curs);
return 0;
}
@@ -465,28 +483,29 @@ static off_t write_object(struct hashfile *f,
else
limit = pack_size_limit - write_offset;
- if (!entry->delta)
+ if (!DELTA(entry))
usable_delta = 0; /* no delta */
else if (!pack_size_limit)
usable_delta = 1; /* unlimited packfile */
- else if (entry->delta->idx.offset == (off_t)-1)
+ else if (DELTA(entry)->idx.offset == (off_t)-1)
usable_delta = 0; /* base was written to another pack */
- else if (entry->delta->idx.offset)
+ else if (DELTA(entry)->idx.offset)
usable_delta = 1; /* base already exists in this pack */
else
usable_delta = 0; /* base could end up in another pack */
if (!reuse_object)
to_reuse = 0; /* explicit */
- else if (!entry->in_pack)
+ else if (!IN_PACK(entry))
to_reuse = 0; /* can't reuse what we don't have */
- else if (entry->type == OBJ_REF_DELTA || entry->type == OBJ_OFS_DELTA)
+ else if (oe_type(entry) == OBJ_REF_DELTA ||
+ oe_type(entry) == OBJ_OFS_DELTA)
/* check_object() decided it for us ... */
to_reuse = usable_delta;
/* ... but pack split may override that */
- else if (entry->type != entry->in_pack_type)
+ else if (oe_type(entry) != entry->in_pack_type)
to_reuse = 0; /* pack has delta which is unusable */
- else if (entry->delta)
+ else if (DELTA(entry))
to_reuse = 0; /* we want to pack afresh */
else
to_reuse = 1; /* we have it in-pack undeltified,
@@ -538,12 +557,12 @@ static enum write_one_status write_one(struct hashfile *f,
}
/* if we are deltified, write out base object first. */
- if (e->delta) {
+ if (DELTA(e)) {
e->idx.offset = 1; /* now recurse */
- switch (write_one(f, e->delta, offset)) {
+ switch (write_one(f, DELTA(e), offset)) {
case WRITE_ONE_RECURSIVE:
/* we cannot depend on this one */
- e->delta = NULL;
+ SET_DELTA(e, NULL);
break;
default:
break;
@@ -605,34 +624,34 @@ static void add_descendants_to_write_order(struct object_entry **wo,
/* add this node... */
add_to_write_order(wo, endp, e);
/* all its siblings... */
- for (s = e->delta_sibling; s; s = s->delta_sibling) {
+ for (s = DELTA_SIBLING(e); s; s = DELTA_SIBLING(s)) {
add_to_write_order(wo, endp, s);
}
}
/* drop down a level to add left subtree nodes if possible */
- if (e->delta_child) {
+ if (DELTA_CHILD(e)) {
add_to_order = 1;
- e = e->delta_child;
+ e = DELTA_CHILD(e);
} else {
add_to_order = 0;
/* our sibling might have some children, it is next */
- if (e->delta_sibling) {
- e = e->delta_sibling;
+ if (DELTA_SIBLING(e)) {
+ e = DELTA_SIBLING(e);
continue;
}
/* go back to our parent node */
- e = e->delta;
- while (e && !e->delta_sibling) {
+ e = DELTA(e);
+ while (e && !DELTA_SIBLING(e)) {
/* we're on the right side of a subtree, keep
* going up until we can go right again */
- e = e->delta;
+ e = DELTA(e);
}
if (!e) {
/* done- we hit our original root node */
return;
}
/* pass it off to sibling at this level */
- e = e->delta_sibling;
+ e = DELTA_SIBLING(e);
}
};
}
@@ -643,7 +662,7 @@ static void add_family_to_write_order(struct object_entry **wo,
{
struct object_entry *root;
- for (root = e; root->delta; root = root->delta)
+ for (root = e; DELTA(root); root = DELTA(root))
; /* nothing */
add_descendants_to_write_order(wo, endp, root);
}
@@ -658,8 +677,8 @@ static struct object_entry **compute_write_order(void)
for (i = 0; i < to_pack.nr_objects; i++) {
objects[i].tagged = 0;
objects[i].filled = 0;
- objects[i].delta_child = NULL;
- objects[i].delta_sibling = NULL;
+ SET_DELTA_CHILD(&objects[i], NULL);
+ SET_DELTA_SIBLING(&objects[i], NULL);
}
/*
@@ -669,11 +688,11 @@ static struct object_entry **compute_write_order(void)
*/
for (i = to_pack.nr_objects; i > 0;) {
struct object_entry *e = &objects[--i];
- if (!e->delta)
+ if (!DELTA(e))
continue;
/* Mark me as the first child */
- e->delta_sibling = e->delta->delta_child;
- e->delta->delta_child = e;
+ e->delta_sibling_idx = DELTA(e)->delta_child_idx;
+ SET_DELTA_CHILD(DELTA(e), e);
}
/*
@@ -705,8 +724,8 @@ static struct object_entry **compute_write_order(void)
* And then all remaining commits and tags.
*/
for (i = last_untagged; i < to_pack.nr_objects; i++) {
- if (objects[i].type != OBJ_COMMIT &&
- objects[i].type != OBJ_TAG)
+ if (oe_type(&objects[i]) != OBJ_COMMIT &&
+ oe_type(&objects[i]) != OBJ_TAG)
continue;
add_to_write_order(wo, &wo_end, &objects[i]);
}
@@ -715,7 +734,7 @@ static struct object_entry **compute_write_order(void)
* And then all the trees.
*/
for (i = last_untagged; i < to_pack.nr_objects; i++) {
- if (objects[i].type != OBJ_TREE)
+ if (oe_type(&objects[i]) != OBJ_TREE)
continue;
add_to_write_order(wo, &wo_end, &objects[i]);
}
@@ -752,7 +771,7 @@ static off_t write_reused_pack(struct hashfile *f)
die_errno("unable to seek in reused packfile");
if (reuse_packfile_offset < 0)
- reuse_packfile_offset = reuse_packfile->pack_size - 20;
+ reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
total = to_write = reuse_packfile_offset - sizeof(struct pack_header);
@@ -878,7 +897,8 @@ static void write_pack_file(void)
if (write_bitmap_index) {
bitmap_writer_set_checksum(oid.hash);
- bitmap_writer_build_type_index(written_list, nr_written);
+ bitmap_writer_build_type_index(
+ &to_pack, written_list, nr_written);
}
finish_tmp_packfile(&tmpname, pack_tmp_name,
@@ -982,13 +1002,16 @@ static int want_found_object(int exclude, struct packed_git *p)
* Otherwise, we signal "-1" at the end to tell the caller that we do
* not know either way, and it needs to check more packs.
*/
- if (!ignore_packed_keep &&
+ if (!ignore_packed_keep_on_disk &&
+ !ignore_packed_keep_in_core &&
(!local || !have_non_local_packs))
return 1;
if (local && !p->pack_local)
return 0;
- if (ignore_packed_keep && p->pack_local && p->pack_keep)
+ if (p->pack_local &&
+ ((ignore_packed_keep_on_disk && p->pack_keep) ||
+ (ignore_packed_keep_in_core && p->pack_keep_in_core)))
return 0;
/* we don't know yet; keep looking for more packs */
@@ -1012,7 +1035,7 @@ static int want_object_in_pack(const struct object_id *oid,
int want;
struct list_head *pos;
- if (!exclude && local && has_loose_object_nonlocal(oid->hash))
+ if (!exclude && local && has_loose_object_nonlocal(oid))
return 0;
/*
@@ -1066,14 +1089,13 @@ static void create_object_entry(const struct object_id *oid,
entry = packlist_alloc(&to_pack, oid->hash, index_pos);
entry->hash = hash;
- if (type)
- entry->type = type;
+ oe_set_type(entry, type);
if (exclude)
entry->preferred_base = 1;
else
nr_result++;
if (found_pack) {
- entry->in_pack = found_pack;
+ oe_set_in_pack(&to_pack, entry, found_pack);
entry->in_pack_offset = found_offset;
}
@@ -1091,6 +1113,8 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
off_t found_offset = 0;
uint32_t index_pos;
+ display_progress(progress_state, ++nr_seen);
+
if (have_duplicate_entry(oid, exclude, &index_pos))
return 0;
@@ -1106,8 +1130,6 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
create_object_entry(oid, type, pack_name_hash(name),
exclude, name && no_try_delta(name),
index_pos, found_pack, found_offset);
-
- display_progress(progress_state, nr_result);
return 1;
}
@@ -1118,6 +1140,8 @@ static int add_object_entry_from_bitmap(const struct object_id *oid,
{
uint32_t index_pos;
+ display_progress(progress_state, ++nr_seen);
+
if (have_duplicate_entry(oid, 0, &index_pos))
return 0;
@@ -1125,8 +1149,6 @@ static int add_object_entry_from_bitmap(const struct object_id *oid,
return 0;
create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
-
- display_progress(progress_state, nr_result);
return 1;
}
@@ -1398,8 +1420,10 @@ static void cleanup_preferred_base(void)
static void check_object(struct object_entry *entry)
{
- if (entry->in_pack) {
- struct packed_git *p = entry->in_pack;
+ unsigned long canonical_size;
+
+ if (IN_PACK(entry)) {
+ struct packed_git *p = IN_PACK(entry);
struct pack_window *w_curs = NULL;
const unsigned char *base_ref = NULL;
struct object_entry *base_entry;
@@ -1407,6 +1431,8 @@ static void check_object(struct object_entry *entry)
unsigned long avail;
off_t ofs;
unsigned char *buf, c;
+ enum object_type type;
+ unsigned long in_pack_size;
buf = use_pack(p, &w_curs, entry->in_pack_offset, &avail);
@@ -1415,11 +1441,15 @@ static void check_object(struct object_entry *entry)
* since non-delta representations could still be reused.
*/
used = unpack_object_header_buffer(buf, avail,
- &entry->in_pack_type,
- &entry->size);
+ &type,
+ &in_pack_size);
if (used == 0)
goto give_up;
+ if (type < 0)
+ BUG("invalid type %d", type);
+ entry->in_pack_type = type;
+
/*
* Determine if this is a delta and if so whether we can
* reuse it or not. Otherwise let's find out as cheaply as
@@ -1428,9 +1458,10 @@ static void check_object(struct object_entry *entry)
switch (entry->in_pack_type) {
default:
/* Not a delta hence we've already got all we need. */
- entry->type = entry->in_pack_type;
+ oe_set_type(entry, entry->in_pack_type);
+ SET_SIZE(entry, in_pack_size);
entry->in_pack_header_size = used;
- if (entry->type < OBJ_COMMIT || entry->type > OBJ_BLOB)
+ if (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)
goto give_up;
unuse_pack(&w_curs);
return;
@@ -1438,7 +1469,7 @@ static void check_object(struct object_entry *entry)
if (reuse_delta && !entry->preferred_base)
base_ref = use_pack(p, &w_curs,
entry->in_pack_offset + used, NULL);
- entry->in_pack_header_size = used + 20;
+ entry->in_pack_header_size = used + the_hash_algo->rawsz;
break;
case OBJ_OFS_DELTA:
buf = use_pack(p, &w_curs,
@@ -1484,25 +1515,29 @@ static void check_object(struct object_entry *entry)
* deltify other objects against, in order to avoid
* circular deltas.
*/
- entry->type = entry->in_pack_type;
- entry->delta = base_entry;
- entry->delta_size = entry->size;
- entry->delta_sibling = base_entry->delta_child;
- base_entry->delta_child = entry;
+ oe_set_type(entry, entry->in_pack_type);
+ SET_SIZE(entry, in_pack_size); /* delta size */
+ SET_DELTA(entry, base_entry);
+ SET_DELTA_SIZE(entry, in_pack_size);
+ entry->delta_sibling_idx = base_entry->delta_child_idx;
+ SET_DELTA_CHILD(base_entry, entry);
unuse_pack(&w_curs);
return;
}
- if (entry->type) {
+ if (oe_type(entry)) {
+ off_t delta_pos;
+
/*
* This must be a delta and we already know what the
* final object type is. Let's extract the actual
* object size from the delta header.
*/
- entry->size = get_size_from_delta(p, &w_curs,
- entry->in_pack_offset + entry->in_pack_header_size);
- if (entry->size == 0)
+ delta_pos = entry->in_pack_offset + entry->in_pack_header_size;
+ canonical_size = get_size_from_delta(p, &w_curs, delta_pos);
+ if (canonical_size == 0)
goto give_up;
+ SET_SIZE(entry, canonical_size);
unuse_pack(&w_curs);
return;
}
@@ -1516,27 +1551,34 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
}
- entry->type = oid_object_info(&entry->idx.oid, &entry->size);
- /*
- * The error condition is checked in prepare_pack(). This is
- * to permit a missing preferred base object to be ignored
- * as a preferred base. Doing so can result in a larger
- * pack file, but the transfer will still take place.
- */
+ oe_set_type(entry,
+ oid_object_info(the_repository, &entry->idx.oid, &canonical_size));
+ if (entry->type_valid) {
+ SET_SIZE(entry, canonical_size);
+ } else {
+ /*
+ * Bad object type is checked in prepare_pack(). This is
+ * to permit a missing preferred base object to be ignored
+ * as a preferred base. Doing so can result in a larger
+ * pack file, but the transfer will still take place.
+ */
+ }
}
static int pack_offset_sort(const void *_a, const void *_b)
{
const struct object_entry *a = *(struct object_entry **)_a;
const struct object_entry *b = *(struct object_entry **)_b;
+ const struct packed_git *a_in_pack = IN_PACK(a);
+ const struct packed_git *b_in_pack = IN_PACK(b);
/* avoid filesystem trashing with loose objects */
- if (!a->in_pack && !b->in_pack)
+ if (!a_in_pack && !b_in_pack)
return oidcmp(&a->idx.oid, &b->idx.oid);
- if (a->in_pack < b->in_pack)
+ if (a_in_pack < b_in_pack)
return -1;
- if (a->in_pack > b->in_pack)
+ if (a_in_pack > b_in_pack)
return 1;
return a->in_pack_offset < b->in_pack_offset ? -1 :
(a->in_pack_offset > b->in_pack_offset);
@@ -1557,29 +1599,37 @@ static int pack_offset_sort(const void *_a, const void *_b)
*/
static void drop_reused_delta(struct object_entry *entry)
{
- struct object_entry **p = &entry->delta->delta_child;
+ unsigned *idx = &to_pack.objects[entry->delta_idx - 1].delta_child_idx;
struct object_info oi = OBJECT_INFO_INIT;
+ enum object_type type;
+ unsigned long size;
+
+ while (*idx) {
+ struct object_entry *oe = &to_pack.objects[*idx - 1];
- while (*p) {
- if (*p == entry)
- *p = (*p)->delta_sibling;
+ if (oe == entry)
+ *idx = oe->delta_sibling_idx;
else
- p = &(*p)->delta_sibling;
+ idx = &oe->delta_sibling_idx;
}
- entry->delta = NULL;
+ SET_DELTA(entry, NULL);
entry->depth = 0;
- oi.sizep = &entry->size;
- oi.typep = &entry->type;
- if (packed_object_info(entry->in_pack, entry->in_pack_offset, &oi) < 0) {
+ oi.sizep = &size;
+ oi.typep = &type;
+ if (packed_object_info(the_repository, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
/*
* We failed to get the info from this pack for some reason;
* fall back to sha1_object_info, which may find another copy.
- * And if that fails, the error will be recorded in entry->type
+ * And if that fails, the error will be recorded in oe_type(entry)
* and dealt with in prepare_pack().
*/
- entry->type = oid_object_info(&entry->idx.oid, &entry->size);
+ oe_set_type(entry,
+ oid_object_info(the_repository, &entry->idx.oid, &size));
+ } else {
+ oe_set_type(entry, type);
}
+ SET_SIZE(entry, size);
}
/*
@@ -1603,7 +1653,7 @@ static void break_delta_chains(struct object_entry *entry)
for (cur = entry, total_depth = 0;
cur;
- cur = cur->delta, total_depth++) {
+ cur = DELTA(cur), total_depth++) {
if (cur->dfs_state == DFS_DONE) {
/*
* We've already seen this object and know it isn't
@@ -1620,7 +1670,7 @@ static void break_delta_chains(struct object_entry *entry)
* is a bug.
*/
if (cur->dfs_state != DFS_NONE)
- die("BUG: confusing delta dfs state in first pass: %d",
+ BUG("confusing delta dfs state in first pass: %d",
cur->dfs_state);
/*
@@ -1628,7 +1678,7 @@ static void break_delta_chains(struct object_entry *entry)
* it's not a delta, we're done traversing, but we'll mark it
* done to save time on future traversals.
*/
- if (!cur->delta) {
+ if (!DELTA(cur)) {
cur->dfs_state = DFS_DONE;
break;
}
@@ -1651,7 +1701,7 @@ static void break_delta_chains(struct object_entry *entry)
* We keep all commits in the chain that we examined.
*/
cur->dfs_state = DFS_ACTIVE;
- if (cur->delta->dfs_state == DFS_ACTIVE) {
+ if (DELTA(cur)->dfs_state == DFS_ACTIVE) {
drop_reused_delta(cur);
cur->dfs_state = DFS_DONE;
break;
@@ -1666,7 +1716,7 @@ static void break_delta_chains(struct object_entry *entry)
* an extra "next" pointer to keep going after we reset cur->delta.
*/
for (cur = entry; cur; cur = next) {
- next = cur->delta;
+ next = DELTA(cur);
/*
* We should have a chain of zero or more ACTIVE states down to
@@ -1677,7 +1727,7 @@ static void break_delta_chains(struct object_entry *entry)
if (cur->dfs_state == DFS_DONE)
break;
else if (cur->dfs_state != DFS_ACTIVE)
- die("BUG: confusing delta dfs state in second pass: %d",
+ BUG("confusing delta dfs state in second pass: %d",
cur->dfs_state);
/*
@@ -1711,6 +1761,10 @@ static void get_object_details(void)
uint32_t i;
struct object_entry **sorted_by_offset;
+ if (progress)
+ progress_state = start_progress(_("Counting objects"),
+ to_pack.nr_objects);
+
sorted_by_offset = xcalloc(to_pack.nr_objects, sizeof(struct object_entry *));
for (i = 0; i < to_pack.nr_objects; i++)
sorted_by_offset[i] = to_pack.objects + i;
@@ -1719,9 +1773,12 @@ static void get_object_details(void)
for (i = 0; i < to_pack.nr_objects; i++) {
struct object_entry *entry = sorted_by_offset[i];
check_object(entry);
- if (big_file_threshold < entry->size)
+ if (entry->type_valid &&
+ oe_size_greater_than(&to_pack, entry, big_file_threshold))
entry->no_try_delta = 1;
+ display_progress(progress_state, i + 1);
}
+ stop_progress(&progress_state);
/*
* This must happen in a second pass, since we rely on the delta
@@ -1746,10 +1803,14 @@ static int type_size_sort(const void *_a, const void *_b)
{
const struct object_entry *a = *(struct object_entry **)_a;
const struct object_entry *b = *(struct object_entry **)_b;
+ enum object_type a_type = oe_type(a);
+ enum object_type b_type = oe_type(b);
+ unsigned long a_size = SIZE(a);
+ unsigned long b_size = SIZE(b);
- if (a->type > b->type)
+ if (a_type > b_type)
return -1;
- if (a->type < b->type)
+ if (a_type < b_type)
return 1;
if (a->hash > b->hash)
return -1;
@@ -1759,9 +1820,9 @@ static int type_size_sort(const void *_a, const void *_b)
return -1;
if (a->preferred_base < b->preferred_base)
return 1;
- if (a->size > b->size)
+ if (a_size > b_size)
return -1;
- if (a->size < b->size)
+ if (a_size < b_size)
return 1;
return a < b ? -1 : (a > b); /* newest first */
}
@@ -1814,6 +1875,46 @@ static pthread_mutex_t progress_mutex;
#endif
+/*
+ * Return the size of the object without doing any delta
+ * reconstruction (so non-deltas are true object sizes, but deltas
+ * return the size of the delta data).
+ */
+unsigned long oe_get_size_slow(struct packing_data *pack,
+ const struct object_entry *e)
+{
+ struct packed_git *p;
+ struct pack_window *w_curs;
+ unsigned char *buf;
+ enum object_type type;
+ unsigned long used, avail, size;
+
+ if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
+ read_lock();
+ if (oid_object_info(the_repository, &e->idx.oid, &size) < 0)
+ die(_("unable to get size of %s"),
+ oid_to_hex(&e->idx.oid));
+ read_unlock();
+ return size;
+ }
+
+ p = oe_in_pack(pack, e);
+ if (!p)
+ BUG("when e->type is a delta, it must belong to a pack");
+
+ read_lock();
+ w_curs = NULL;
+ buf = use_pack(p, &w_curs, e->in_pack_offset, &avail);
+ used = unpack_object_header_buffer(buf, avail, &type, &size);
+ if (used == 0)
+ die(_("unable to parse object header of %s"),
+ oid_to_hex(&e->idx.oid));
+
+ unuse_pack(&w_curs);
+ read_unlock();
+ return size;
+}
+
static int try_delta(struct unpacked *trg, struct unpacked *src,
unsigned max_depth, unsigned long *mem_usage)
{
@@ -1825,7 +1926,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
void *delta_buf;
/* Don't bother doing diffs between different types */
- if (trg_entry->type != src_entry->type)
+ if (oe_type(trg_entry) != oe_type(src_entry))
return -1;
/*
@@ -1836,8 +1937,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
* it, we will still save the transfer cost, as we already know
* the other side has it and we won't send src_entry at all.
*/
- if (reuse_delta && trg_entry->in_pack &&
- trg_entry->in_pack == src_entry->in_pack &&
+ if (reuse_delta && IN_PACK(trg_entry) &&
+ IN_PACK(trg_entry) == IN_PACK(src_entry) &&
!src_entry->preferred_base &&
trg_entry->in_pack_type != OBJ_REF_DELTA &&
trg_entry->in_pack_type != OBJ_OFS_DELTA)
@@ -1848,19 +1949,19 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
return 0;
/* Now some size filtering heuristics. */
- trg_size = trg_entry->size;
- if (!trg_entry->delta) {
- max_size = trg_size/2 - 20;
+ trg_size = SIZE(trg_entry);
+ if (!DELTA(trg_entry)) {
+ max_size = trg_size/2 - the_hash_algo->rawsz;
ref_depth = 1;
} else {
- max_size = trg_entry->delta_size;
+ max_size = DELTA_SIZE(trg_entry);
ref_depth = trg->depth;
}
max_size = (uint64_t)max_size * (max_depth - src->depth) /
(max_depth - ref_depth + 1);
if (max_size == 0)
return 0;
- src_size = src_entry->size;
+ src_size = SIZE(src_entry);
sizediff = src_size < trg_size ? trg_size - src_size : 0;
if (sizediff >= max_size)
return 0;
@@ -1922,10 +2023,14 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
if (!delta_buf)
return 0;
+ if (delta_size >= (1U << OE_DELTA_SIZE_BITS)) {
+ free(delta_buf);
+ return 0;
+ }
- if (trg_entry->delta) {
+ if (DELTA(trg_entry)) {
/* Prefer only shallower same-sized deltas. */
- if (delta_size == trg_entry->delta_size &&
+ if (delta_size == DELTA_SIZE(trg_entry) &&
src->depth + 1 >= trg->depth) {
free(delta_buf);
return 0;
@@ -1940,7 +2045,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
free(trg_entry->delta_data);
cache_lock();
if (trg_entry->delta_data) {
- delta_cache_size -= trg_entry->delta_size;
+ delta_cache_size -= DELTA_SIZE(trg_entry);
trg_entry->delta_data = NULL;
}
if (delta_cacheable(src_size, trg_size, delta_size)) {
@@ -1952,8 +2057,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
free(delta_buf);
}
- trg_entry->delta = src_entry;
- trg_entry->delta_size = delta_size;
+ SET_DELTA(trg_entry, src_entry);
+ SET_DELTA_SIZE(trg_entry, delta_size);
trg->depth = src->depth + 1;
return 1;
@@ -1961,13 +2066,13 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
{
- struct object_entry *child = me->delta_child;
+ struct object_entry *child = DELTA_CHILD(me);
unsigned int m = n;
while (child) {
unsigned int c = check_delta_limit(child, n + 1);
if (m < c)
m = c;
- child = child->delta_sibling;
+ child = DELTA_SIBLING(child);
}
return m;
}
@@ -1978,7 +2083,7 @@ static unsigned long free_unpacked(struct unpacked *n)
free_delta_index(n->index);
n->index = NULL;
if (n->data) {
- freed_mem += n->entry->size;
+ freed_mem += SIZE(n->entry);
FREE_AND_NULL(n->data);
}
n->entry = NULL;
@@ -2036,7 +2141,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
* otherwise they would become too deep.
*/
max_depth = depth;
- if (entry->delta_child) {
+ if (DELTA_CHILD(entry)) {
max_depth -= check_delta_limit(entry, 0);
if (max_depth <= 0)
goto next;
@@ -2074,19 +2179,26 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
* between writes at that moment.
*/
if (entry->delta_data && !pack_to_stdout) {
- entry->z_delta_size = do_compress(&entry->delta_data,
- entry->delta_size);
- cache_lock();
- delta_cache_size -= entry->delta_size;
- delta_cache_size += entry->z_delta_size;
- cache_unlock();
+ unsigned long size;
+
+ size = do_compress(&entry->delta_data, DELTA_SIZE(entry));
+ if (size < (1U << OE_Z_DELTA_BITS)) {
+ entry->z_delta_size = size;
+ cache_lock();
+ delta_cache_size -= DELTA_SIZE(entry);
+ delta_cache_size += entry->z_delta_size;
+ cache_unlock();
+ } else {
+ FREE_AND_NULL(entry->delta_data);
+ entry->z_delta_size = 0;
+ }
}
/* if we made n a delta, and if n is already at max
* depth, leaving it in the window is pointless. we
* should evict it first.
*/
- if (entry->delta && max_depth <= n->depth)
+ if (DELTA(entry) && max_depth <= n->depth)
continue;
/*
@@ -2094,7 +2206,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
* currently deltified object, to keep it longer. It will
* be the first base object to be attempted next.
*/
- if (entry->delta) {
+ if (DELTA(entry)) {
struct unpacked swap = array[best_base];
int dist = (window + idx - best_base) % window;
int dst = best_base;
@@ -2415,13 +2527,14 @@ static void prepare_pack(int window, int depth)
for (i = 0; i < to_pack.nr_objects; i++) {
struct object_entry *entry = to_pack.objects + i;
- if (entry->delta)
+ if (DELTA(entry))
/* This happens if we decided to reuse existing
* delta from a pack. "reuse_delta &&" is implied.
*/
continue;
- if (entry->size < 50)
+ if (!entry->type_valid ||
+ oe_size_less_than(&to_pack, entry, 50))
continue;
if (entry->no_try_delta)
@@ -2429,11 +2542,11 @@ static void prepare_pack(int window, int depth)
if (!entry->preferred_base) {
nr_deltas++;
- if (entry->type < 0)
+ if (oe_type(entry) < 0)
die("unable to get type of object %s",
oid_to_hex(&entry->idx.oid));
} else {
- if (entry->type < 0) {
+ if (oe_type(entry) < 0) {
/*
* This object is not found, but we
* don't have to include it anyway.
@@ -2542,7 +2655,7 @@ static void read_object_list_from_stdin(void)
die("expected object ID, got garbage:\n %s", line);
add_preferred_base_object(p + 1);
- add_object_entry(&oid, 0, p + 1, 0);
+ add_object_entry(&oid, OBJ_NONE, p + 1, 0);
}
}
@@ -2675,7 +2788,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
struct object_id oid;
struct object *o;
- if (!p->pack_local || p->pack_keep)
+ if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
continue;
if (open_pack_index(p))
die("cannot open pack index");
@@ -2706,7 +2819,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
static int add_loose_object(const struct object_id *oid, const char *path,
void *data)
{
- enum object_type type = oid_object_info(oid, NULL);
+ enum object_type type = oid_object_info(the_repository, oid, NULL);
if (type < 0) {
warning("loose object at %s could not be examined", path);
@@ -2738,7 +2851,8 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
get_packed_git(the_repository);
while (p) {
- if ((!p->pack_local || p->pack_keep) &&
+ if ((!p->pack_local || p->pack_keep ||
+ p->pack_keep_in_core) &&
find_pack_entry_one(oid->hash, p)) {
last_found = p;
return 1;
@@ -2781,7 +2895,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
struct object_id oid;
for (p = get_packed_git(the_repository); p; p = p->next) {
- if (!p->pack_local || p->pack_keep)
+ if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
continue;
if (open_pack_index(p))
@@ -2807,7 +2921,8 @@ static int pack_options_allow_reuse(void)
{
return pack_to_stdout &&
allow_ofs_delta &&
- !ignore_packed_keep &&
+ !ignore_packed_keep_on_disk &&
+ !ignore_packed_keep_in_core &&
(!local || !have_non_local_packs) &&
!incremental;
}
@@ -2916,6 +3031,32 @@ static void get_object_list(int ac, const char **av)
oid_array_clear(&recent_objects);
}
+static void add_extra_kept_packs(const struct string_list *names)
+{
+ struct packed_git *p;
+
+ if (!names->nr)
+ return;
+
+ for (p = get_packed_git(the_repository); p; p = p->next) {
+ const char *name = basename(p->pack_name);
+ int i;
+
+ if (!p->pack_local)
+ continue;
+
+ for (i = 0; i < names->nr; i++)
+ if (!fspathcmp(name, names->items[i].string))
+ break;
+
+ if (i < names->nr) {
+ p->pack_keep_in_core = 1;
+ ignore_packed_keep_in_core = 1;
+ continue;
+ }
+ }
+}
+
static int option_parse_index_version(const struct option *opt,
const char *arg, int unset)
{
@@ -2955,6 +3096,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
struct argv_array rp = ARGV_ARRAY_INIT;
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
int rev_list_index = 0;
+ struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
@@ -2992,18 +3134,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("do not create an empty pack output")),
OPT_BOOL(0, "revs", &use_internal_rev_list,
N_("read revision arguments from standard input")),
- { OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
- N_("limit the objects to those that are not yet packed"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
- { OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
- N_("include objects reachable from any reference"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
- { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
- N_("include objects referred by reflog entries"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
- { OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
- N_("include objects referred to by the index"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+ OPT_SET_INT_F(0, "unpacked", &rev_list_unpacked,
+ N_("limit the objects to those that are not yet packed"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "all", &rev_list_all,
+ N_("include objects reachable from any reference"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "reflog", &rev_list_reflog,
+ N_("include objects referred by reflog entries"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "indexed-objects", &rev_list_index,
+ N_("include objects referred to by the index"),
+ 1, PARSE_OPT_NONEG),
OPT_BOOL(0, "stdout", &pack_to_stdout,
N_("output pack to stdout")),
OPT_BOOL(0, "include-tag", &include_tag,
@@ -3019,8 +3161,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("create thin packs")),
OPT_BOOL(0, "shallow", &shallow,
N_("create packs suitable for shallow fetches")),
- OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
+ OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep_on_disk,
N_("ignore packs that have companion .keep file")),
+ OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
+ N_("ignore this pack")),
OPT_INTEGER(0, "compression", &pack_compression_level,
N_("pack compression level")),
OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
@@ -3038,6 +3182,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
+ BUG("too many dfs states, increase OE_DFS_STATE_BITS");
+
check_replace_refs = 0;
reset_pack_idx_option(&pack_idx_opts);
@@ -3054,6 +3201,17 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (pack_to_stdout != !base_name || argc)
usage_with_options(pack_usage, pack_objects_options);
+ if (depth >= (1 << OE_DEPTH_BITS)) {
+ warning(_("delta chain depth %d is too deep, forcing %d"),
+ depth, (1 << OE_DEPTH_BITS) - 1);
+ depth = (1 << OE_DEPTH_BITS) - 1;
+ }
+ if (cache_max_small_delta_size >= (1U << OE_Z_DELTA_BITS)) {
+ warning(_("pack.deltaCacheLimit is too high, forcing %d"),
+ (1U << OE_Z_DELTA_BITS) - 1);
+ cache_max_small_delta_size = (1U << OE_Z_DELTA_BITS) - 1;
+ }
+
argv_array_push(&rp, "pack-objects");
if (thin) {
use_internal_rev_list = 1;
@@ -3085,6 +3243,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
fetch_if_missing = 0;
argv_array_push(&rp, "--exclude-promisor-objects");
}
+ if (unpack_unreachable || keep_unreachable || pack_loose_unreachable)
+ use_internal_rev_list = 1;
if (!reuse_object)
reuse_delta = 0;
@@ -3148,19 +3308,20 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (progress && all_progress_implied)
progress = 2;
- if (ignore_packed_keep) {
+ add_extra_kept_packs(&keep_pack_list);
+ if (ignore_packed_keep_on_disk) {
struct packed_git *p;
for (p = get_packed_git(the_repository); p; p = p->next)
if (p->pack_local && p->pack_keep)
break;
if (!p) /* no keep-able packs found */
- ignore_packed_keep = 0;
+ ignore_packed_keep_on_disk = 0;
}
if (local) {
/*
- * unlike ignore_packed_keep above, we do not want to
- * unset "local" based on looking at packs, as it
- * also covers non-local objects
+ * unlike ignore_packed_keep_on_disk above, we do not
+ * want to unset "local" based on looking at packs, as
+ * it also covers non-local objects
*/
struct packed_git *p;
for (p = get_packed_git(the_repository); p; p = p->next) {
@@ -3171,8 +3332,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
}
+ prepare_packing_data(&to_pack);
+
if (progress)
- progress_state = start_progress(_("Counting objects"), 0);
+ progress_state = start_progress(_("Enumerating objects"), 0);
if (!use_internal_rev_list)
read_object_list_from_stdin();
else {
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 354478a127..0494dceff7 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -20,7 +20,7 @@ static int load_all_packs, verbose, alt_odb;
struct llist_item {
struct llist_item *next;
- const unsigned char *sha1;
+ const struct object_id *oid;
};
static struct llist {
struct llist_item *front;
@@ -90,14 +90,14 @@ static struct llist * llist_copy(struct llist *list)
return ret;
new_item = ret->front = llist_item_get();
- new_item->sha1 = list->front->sha1;
+ new_item->oid = list->front->oid;
old_item = list->front->next;
while (old_item) {
prev = new_item;
new_item = llist_item_get();
prev->next = new_item;
- new_item->sha1 = old_item->sha1;
+ new_item->oid = old_item->oid;
old_item = old_item->next;
}
new_item->next = NULL;
@@ -108,10 +108,10 @@ static struct llist * llist_copy(struct llist *list)
static inline struct llist_item *llist_insert(struct llist *list,
struct llist_item *after,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
struct llist_item *new_item = llist_item_get();
- new_item->sha1 = sha1;
+ new_item->oid = oid;
new_item->next = NULL;
if (after != NULL) {
@@ -131,21 +131,21 @@ static inline struct llist_item *llist_insert(struct llist *list,
}
static inline struct llist_item *llist_insert_back(struct llist *list,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
- return llist_insert(list, list->back, sha1);
+ return llist_insert(list, list->back, oid);
}
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
- const unsigned char *sha1, struct llist_item *hint)
+ const struct object_id *oid, struct llist_item *hint)
{
struct llist_item *prev = NULL, *l;
l = (hint == NULL) ? list->front : hint;
while (l) {
- int cmp = hashcmp(l->sha1, sha1);
+ int cmp = oidcmp(l->oid, oid);
if (cmp > 0) { /* we insert before this entry */
- return llist_insert(list, prev, sha1);
+ return llist_insert(list, prev, oid);
}
if (!cmp) { /* already exists */
return l;
@@ -154,11 +154,11 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
l = l->next;
}
/* insert at the end */
- return llist_insert_back(list, sha1);
+ return llist_insert_back(list, oid);
}
/* returns a pointer to an item in front of sha1 */
-static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *sha1, struct llist_item *hint)
+static inline struct llist_item * llist_sorted_remove(struct llist *list, const struct object_id *oid, struct llist_item *hint)
{
struct llist_item *prev, *l;
@@ -166,7 +166,7 @@ redo_from_start:
l = (hint == NULL) ? list->front : hint;
prev = NULL;
while (l) {
- int cmp = hashcmp(l->sha1, sha1);
+ int cmp = oidcmp(l->oid, oid);
if (cmp > 0) /* not in list, since sorted */
return prev;
if (!cmp) { /* found */
@@ -201,7 +201,7 @@ static void llist_sorted_difference_inplace(struct llist *A,
b = B->front;
while (b) {
- hint = llist_sorted_remove(A, b->sha1, hint);
+ hint = llist_sorted_remove(A, b->oid, hint);
b = b->next;
}
}
@@ -252,13 +252,14 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
unsigned long p1_off = 0, p2_off = 0, p1_step, p2_step;
const unsigned char *p1_base, *p2_base;
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
+ const unsigned int hashsz = the_hash_algo->rawsz;
p1_base = p1->pack->index_data;
p2_base = p2->pack->index_data;
p1_base += 256 * 4 + ((p1->pack->index_version < 2) ? 4 : 8);
p2_base += 256 * 4 + ((p2->pack->index_version < 2) ? 4 : 8);
- p1_step = (p1->pack->index_version < 2) ? 24 : 20;
- p2_step = (p2->pack->index_version < 2) ? 24 : 20;
+ p1_step = hashsz + ((p1->pack->index_version < 2) ? 4 : 0);
+ p2_step = hashsz + ((p2->pack->index_version < 2) ? 4 : 0);
while (p1_off < p1->pack->num_objects * p1_step &&
p2_off < p2->pack->num_objects * p2_step)
@@ -267,9 +268,11 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
/* cmp ~ p1 - p2 */
if (cmp == 0) {
p1_hint = llist_sorted_remove(p1->unique_objects,
- p1_base + p1_off, p1_hint);
+ (const struct object_id *)(p1_base + p1_off),
+ p1_hint);
p2_hint = llist_sorted_remove(p2->unique_objects,
- p1_base + p1_off, p2_hint);
+ (const struct object_id *)(p1_base + p1_off),
+ p2_hint);
p1_off += p1_step;
p2_off += p2_step;
continue;
@@ -359,13 +362,14 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
size_t ret = 0;
unsigned long p1_off = 0, p2_off = 0, p1_step, p2_step;
const unsigned char *p1_base, *p2_base;
+ const unsigned int hashsz = the_hash_algo->rawsz;
p1_base = p1->index_data;
p2_base = p2->index_data;
p1_base += 256 * 4 + ((p1->index_version < 2) ? 4 : 8);
p2_base += 256 * 4 + ((p2->index_version < 2) ? 4 : 8);
- p1_step = (p1->index_version < 2) ? 24 : 20;
- p2_step = (p2->index_version < 2) ? 24 : 20;
+ p1_step = hashsz + ((p1->index_version < 2) ? 4 : 0);
+ p2_step = hashsz + ((p2->index_version < 2) ? 4 : 0);
while (p1_off < p1->num_objects * p1_step &&
p2_off < p2->num_objects * p2_step)
@@ -499,7 +503,7 @@ static void load_all_objects(void)
l = pl->all_objects->front;
while (l) {
hint = llist_insert_sorted_unique(all_objects,
- l->sha1, hint);
+ l->oid, hint);
l = l->next;
}
pl = pl->next;
@@ -558,9 +562,9 @@ static struct pack_list * add_pack(struct packed_git *p)
base = p->index_data;
base += 256 * 4 + ((p->index_version < 2) ? 4 : 8);
- step = (p->index_version < 2) ? 24 : 20;
+ step = the_hash_algo->rawsz + ((p->index_version < 2) ? 4 : 0);
while (off < p->num_objects * step) {
- llist_insert_back(l.all_objects, base + off);
+ llist_insert_back(l.all_objects, (const struct object_id *)(base + off));
off += step;
}
/* this list will be pruned in cmp_two_packs later */
@@ -601,8 +605,8 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
int i;
struct pack_list *min, *red, *pl;
struct llist *ignore;
- unsigned char *sha1;
- char buf[42]; /* 40 byte sha1 + \n + \0 */
+ struct object_id *oid;
+ char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(pack_redundant_usage);
@@ -650,10 +654,10 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
llist_init(&ignore);
if (!isatty(0)) {
while (fgets(buf, sizeof(buf), stdin)) {
- sha1 = xmalloc(20);
- if (get_sha1_hex(buf, sha1))
- die("Bad sha1 on stdin: %s", buf);
- llist_insert_sorted_unique(ignore, sha1, NULL);
+ oid = xmalloc(sizeof(*oid));
+ if (get_oid_hex(buf, oid))
+ die("Bad object ID on stdin: %s", buf);
+ llist_insert_sorted_unique(ignore, oid, NULL);
}
}
llist_sorted_difference_inplace(all_objects, ignore);
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index 419238171d..4ff525e50f 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -25,7 +25,7 @@ static int prune_object(const struct object_id *oid, const char *path,
{
int *opts = data;
- if (!has_sha1_pack(oid->hash))
+ if (!has_object_pack(oid))
return 0;
if (*opts & PRUNE_PACKED_DRY_RUN)
diff --git a/builtin/prune.c b/builtin/prune.c
index 38ced18dad..518ffbea13 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -50,7 +50,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
if (st.st_mtime > expire)
return 0;
if (show_only || verbose) {
- enum object_type type = oid_object_info(oid, NULL);
+ enum object_type type = oid_object_info(the_repository, oid,
+ NULL);
printf("%s %s\n", oid_to_hex(oid),
(type > 0) ? type_name(type) : "unknown");
}
diff --git a/builtin/pull.c b/builtin/pull.c
index 71aac5005e..1f2ecf3a88 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -15,6 +15,7 @@
#include "remote.h"
#include "dir.h"
#include "refs.h"
+#include "refspec.h"
#include "revision.h"
#include "submodule.h"
#include "submodule-config.h"
@@ -27,14 +28,16 @@ enum rebase_type {
REBASE_FALSE = 0,
REBASE_TRUE,
REBASE_PRESERVE,
+ REBASE_MERGES,
REBASE_INTERACTIVE
};
/**
* Parses the value of --rebase. If value is a false value, returns
* REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
- * "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with
- * a fatal error if fatal is true, otherwise returns REBASE_INVALID.
+ * "merges", returns REBASE_MERGES. If value is "preserve", returns
+ * REBASE_PRESERVE. If value is a invalid value, dies with a fatal error if
+ * fatal is true, otherwise returns REBASE_INVALID.
*/
static enum rebase_type parse_config_rebase(const char *key, const char *value,
int fatal)
@@ -47,6 +50,8 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
return REBASE_TRUE;
else if (!strcmp(value, "preserve"))
return REBASE_PRESERVE;
+ else if (!strcmp(value, "merges"))
+ return REBASE_MERGES;
else if (!strcmp(value, "interactive"))
return REBASE_INTERACTIVE;
@@ -130,7 +135,7 @@ static struct option pull_options[] = {
/* Options passed to git-merge or git-rebase */
OPT_GROUP(N_("Options related to merging")),
{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
- "false|true|preserve|interactive",
+ "false|true|merges|preserve|interactive",
N_("incorporate changes by rebasing rather than merging"),
PARSE_OPT_OPTARG, parse_opt_rebase },
OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
@@ -539,7 +544,7 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, repo);
argv_array_pushv(&args, refspecs);
} else if (*refspecs)
- die("BUG: refspecs without repo?");
+ BUG("refspecs without repo?");
ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
return ret;
@@ -675,12 +680,12 @@ static const char *get_upstream_branch(const char *remote)
*/
static const char *get_tracking_branch(const char *remote, const char *refspec)
{
- struct refspec *spec;
+ struct refspec_item spec;
const char *spec_src;
const char *merge_branch;
- spec = parse_fetch_refspec(1, &refspec);
- spec_src = spec->src;
+ refspec_item_init(&spec, refspec, REFSPEC_FETCH);
+ spec_src = spec.src;
if (!*spec_src || !strcmp(spec_src, "HEAD"))
spec_src = "HEAD";
else if (skip_prefix(spec_src, "heads/", &spec_src))
@@ -700,7 +705,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
} else
merge_branch = NULL;
- free_refspec(1, spec);
+ refspec_item_clear(&spec);
return merge_branch;
}
@@ -800,7 +805,9 @@ static int run_rebase(const struct object_id *curr_head,
argv_push_verbosity(&args);
/* Options passed to git-rebase */
- if (opt_rebase == REBASE_PRESERVE)
+ if (opt_rebase == REBASE_MERGES)
+ argv_array_push(&args, "--rebase-merges");
+ else if (opt_rebase == REBASE_PRESERVE)
argv_array_push(&args, "--preserve-merges");
else if (opt_rebase == REBASE_INTERACTIVE)
argv_array_push(&args, "--interactive");
diff --git a/builtin/push.c b/builtin/push.c
index ac3705370e..9cd8e8cd56 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "refspec.h"
#include "run-command.h"
#include "builtin.h"
#include "remote.h"
@@ -56,19 +57,10 @@ static enum transport_family family;
static struct push_cas_option cas;
-static const char **refspec;
-static int refspec_nr;
-static int refspec_alloc;
+static struct refspec rs = REFSPEC_INIT_PUSH;
static struct string_list push_options_config = STRING_LIST_INIT_DUP;
-static void add_refspec(const char *ref)
-{
- refspec_nr++;
- ALLOC_GROW(refspec, refspec_nr, refspec_alloc);
- refspec[refspec_nr-1] = ref;
-}
-
static const char *map_refspec(const char *ref,
struct remote *remote, struct ref *local_refs)
{
@@ -78,12 +70,11 @@ static const char *map_refspec(const char *ref,
if (count_refspec_match(ref, local_refs, &matched) != 1)
return ref;
- if (remote->push) {
- struct refspec query;
- memset(&query, 0, sizeof(struct refspec));
+ if (remote->push.nr) {
+ struct refspec_item query;
+ memset(&query, 0, sizeof(struct refspec_item));
query.src = matched->name;
- if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
- query.dst) {
+ if (!query_refspecs(&remote->push, &query) && query.dst) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s%s:%s",
query.force ? "+" : "",
@@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
}
ref = map_refspec(ref, remote, local_refs);
}
- add_refspec(ref);
+ refspec_append(&rs, ref);
}
}
@@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch,
}
strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src);
- add_refspec(refspec.buf);
+ refspec_append(&rs, refspec.buf);
}
static void setup_push_current(struct remote *remote, struct branch *branch)
@@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch)
if (!branch)
die(_(message_detached_head_die), remote->name);
strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname);
- add_refspec(refspec.buf);
+ refspec_append(&rs, refspec.buf);
}
static int is_workflow_triangular(struct remote *remote)
@@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)
switch (push_default) {
default:
case PUSH_DEFAULT_MATCHING:
- add_refspec(":");
+ refspec_append(&rs, ":");
break;
case PUSH_DEFAULT_UNSPECIFIED:
@@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)
advise(_(message_advice_ref_needs_force));
}
-static int push_with_options(struct transport *transport, int flags)
+static int push_with_options(struct transport *transport, struct refspec *rs,
+ int flags)
{
int err;
unsigned int reject_reasons;
@@ -363,8 +355,7 @@ static int push_with_options(struct transport *transport, int flags)
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
- err = transport_push(transport, refspec_nr, refspec, flags,
- &reject_reasons);
+ err = transport_push(transport, rs, flags, &reject_reasons);
if (err != 0) {
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
error(_("failed to push some refs to '%s'"), transport->url);
@@ -397,6 +388,7 @@ static int do_push(const char *repo, int flags,
struct remote *remote = pushremote_get(repo);
const char **url;
int url_nr;
+ struct refspec *push_refspec = &rs;
if (!remote) {
if (repo)
@@ -417,27 +409,9 @@ static int do_push(const char *repo, int flags,
if (push_options->nr)
flags |= TRANSPORT_PUSH_OPTIONS;
- if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
- if (!strcmp(*refspec, "refs/tags/*"))
- return error(_("--all and --tags are incompatible"));
- return error(_("--all can't be combined with refspecs"));
- }
-
- if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
- if (!strcmp(*refspec, "refs/tags/*"))
- return error(_("--mirror and --tags are incompatible"));
- return error(_("--mirror can't be combined with refspecs"));
- }
-
- if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
- (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
- return error(_("--all and --mirror are incompatible"));
- }
-
- if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
- if (remote->push_refspec_nr) {
- refspec = remote->push_refspec;
- refspec_nr = remote->push_refspec_nr;
+ if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) {
+ if (remote->push.nr) {
+ push_refspec = &remote->push;
} else if (!(flags & TRANSPORT_PUSH_MIRROR))
setup_default_push_refspecs(remote);
}
@@ -449,7 +423,7 @@ static int do_push(const char *repo, int flags,
transport_get(remote, url[i]);
if (flags & TRANSPORT_PUSH_OPTIONS)
transport->push_options = push_options;
- if (push_with_options(transport, flags))
+ if (push_with_options(transport, push_refspec, flags))
errs++;
}
} else {
@@ -457,7 +431,7 @@ static int do_push(const char *repo, int flags,
transport_get(remote, NULL);
if (flags & TRANSPORT_PUSH_OPTIONS)
transport->push_options = push_options;
- if (push_with_options(transport, flags))
+ if (push_with_options(transport, push_refspec, flags))
errs++;
}
return !!errs;
@@ -625,6 +599,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)
die(_("--delete is incompatible with --all, --mirror and --tags"));
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
+ if (flags & TRANSPORT_PUSH_ALL) {
+ if (tags)
+ die(_("--all and --tags are incompatible"));
+ if (argc >= 2)
+ die(_("--all can't be combined with refspecs"));
+ }
+ if (flags & TRANSPORT_PUSH_MIRROR) {
+ if (tags)
+ die(_("--mirror and --tags are incompatible"));
+ if (argc >= 2)
+ die(_("--mirror can't be combined with refspecs"));
+ }
+ if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
+ die(_("--all and --mirror are incompatible"));
if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
@@ -634,7 +622,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
if (tags)
- add_refspec("refs/tags/*");
+ refspec_append(&rs, "refs/tags/*");
if (argc > 0) {
repo = argv[0];
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index bf87a2710b..ebc43eb805 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -107,8 +107,6 @@ static int git_read_tree_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static struct lock_file lock_file;
-
int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
{
int i, stage = 0;
@@ -116,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
struct tree_desc t[MAX_UNPACK_TREES];
struct unpack_trees_options opts;
int prefix_set = 0;
+ struct lock_file lock_file = LOCK_INIT;
const struct option read_tree_options[] = {
{ OPTION_CALLBACK, 0, "index-output", NULL, N_("file"),
N_("write resulting index to <file>"),
diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c
index ad074705bb..f7c2a5fdc8 100644
--- a/builtin/rebase--helper.c
+++ b/builtin/rebase--helper.c
@@ -12,8 +12,8 @@ static const char * const builtin_rebase_helper_usage[] = {
int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
- unsigned flags = 0, keep_empty = 0;
- int abbreviate_commands = 0;
+ unsigned flags = 0, keep_empty = 0, rebase_merges = 0;
+ int abbreviate_commands = 0, rebase_cousins = -1;
enum {
CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,
CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,
@@ -24,6 +24,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
N_("allow commits with empty messages")),
+ OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")),
+ OPT_BOOL(0, "rebase-cousins", &rebase_cousins,
+ N_("keep original branch points of cousins")),
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
CONTINUE),
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
@@ -57,8 +60,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
+ flags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
+ flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
+ if (rebase_cousins >= 0 && !rebase_merges)
+ warning(_("--[no-]rebase-cousins has no effect without "
+ "--rebase-merges"));
+
if (command == CONTINUE && argc == 1)
return !!sequencer_continue(&opts);
if (command == ABORT && argc == 1)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0dd163280d..68d36e0a56 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -454,21 +454,21 @@ static void hmac_sha1(unsigned char *out,
/* RFC 2104 2. (6) & (7) */
git_SHA1_Init(&ctx);
git_SHA1_Update(&ctx, k_opad, sizeof(k_opad));
- git_SHA1_Update(&ctx, out, 20);
+ git_SHA1_Update(&ctx, out, GIT_SHA1_RAWSZ);
git_SHA1_Final(out, &ctx);
}
static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
{
struct strbuf buf = STRBUF_INIT;
- unsigned char sha1[20];
+ unsigned char sha1[GIT_SHA1_RAWSZ];
strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
strbuf_release(&buf);
/* RFC 2104 5. HMAC-SHA1-80 */
- strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1));
+ strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, GIT_SHA1_HEXSZ, sha1_to_hex(sha1));
return strbuf_detach(&buf, NULL);
}
@@ -876,7 +876,7 @@ static void refuse_unconfigured_deny_delete_current(void)
static int command_singleton_iterator(void *cb_data, struct object_id *oid);
static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
{
- static struct lock_file shallow_lock;
+ struct lock_file shallow_lock = LOCK_INIT;
struct oid_array extra = OID_ARRAY_INIT;
struct check_connected_options opt = CHECK_CONNECTED_INIT;
uint32_t mask = 1 << (cmd->index % 32);
@@ -968,7 +968,7 @@ static const char *push_to_deploy(unsigned char *sha1,
return "Working directory has unstaged changes";
/* diff-index with either HEAD or an empty tree */
- diff_index[4] = head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX;
+ diff_index[4] = head_has_history() ? "HEAD" : empty_tree_oid_hex();
child_process_init(&child);
child.argv = diff_index;
@@ -1378,7 +1378,7 @@ static void warn_if_skipped_connectivity_check(struct command *commands,
}
}
if (!checked_connectivity)
- die("BUG: connectivity check skipped???");
+ BUG("connectivity check skipped???");
}
static void execute_commands_non_atomic(struct command *commands,
diff --git a/builtin/reflog.c b/builtin/reflog.c
index a89bd1dd25..a48984d37e 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -154,7 +154,7 @@ static int commit_is_complete(struct commit *commit)
for (i = 0; i < found.nr; i++) {
struct commit *c =
(struct commit *)found.objects[i].item;
- if (!tree_is_complete(&c->tree->object.oid)) {
+ if (!tree_is_complete(get_commit_tree_oid(c))) {
is_incomplete = 1;
c->object.flags |= INCOMPLETE;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index 8708e584e9..1a82d850a2 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -7,6 +7,7 @@
#include "strbuf.h"
#include "run-command.h"
#include "refs.h"
+#include "refspec.h"
#include "argv-array.h"
static const char * const builtin_remote_usage[] = {
@@ -245,7 +246,9 @@ static int add(int argc, const char **argv)
struct branch_info {
char *remote_name;
struct string_list merge;
- enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
+ enum {
+ NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES
+ } rebase;
};
static struct string_list branch_list = STRING_LIST_INIT_NODUP;
@@ -306,6 +309,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
info->rebase = v;
else if (!strcmp(value, "preserve"))
info->rebase = NORMAL_REBASE;
+ else if (!strcmp(value, "merges"))
+ info->rebase = REBASE_MERGES;
else if (!strcmp(value, "interactive"))
info->rebase = INTERACTIVE_REBASE;
}
@@ -332,10 +337,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
struct ref *ref, *stale_refs;
int i;
- for (i = 0; i < states->remote->fetch_refspec_nr; i++)
- if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
+ for (i = 0; i < states->remote->fetch.nr; i++)
+ if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
die(_("Could not get fetch map for refspec %s"),
- states->remote->fetch_refspec[i]);
+ states->remote->fetch.raw[i]);
states->new_refs.strdup_strings = 1;
states->tracked.strdup_strings = 1;
@@ -346,8 +351,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
}
- stale_refs = get_stale_heads(states->remote->fetch,
- states->remote->fetch_refspec_nr, fetch_map);
+ stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
for (ref = stale_refs; ref; ref = ref->next) {
struct string_list_item *item =
string_list_append(&states->stale, abbrev_branch(ref->name));
@@ -387,8 +391,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
local_refs = get_local_heads();
push_map = copy_ref_list(remote_refs);
- match_push_refs(local_refs, &push_map, remote->push_refspec_nr,
- remote->push_refspec, MATCH_REFS_NONE);
+ match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
states->push.strdup_strings = 1;
for (ref = push_map; ref; ref = ref->next) {
@@ -434,14 +437,14 @@ static int get_push_ref_states_noquery(struct ref_states *states)
return 0;
states->push.strdup_strings = 1;
- if (!remote->push_refspec_nr) {
+ if (!remote->push.nr) {
item = string_list_append(&states->push, _("(matching)"));
info = item->util = xcalloc(1, sizeof(struct push_info));
info->status = PUSH_STATUS_NOTQUERIED;
info->dest = xstrdup(item->string);
}
- for (i = 0; i < remote->push_refspec_nr; i++) {
- struct refspec *spec = remote->push + i;
+ for (i = 0; i < remote->push.nr; i++) {
+ const struct refspec_item *spec = &remote->push.items[i];
if (spec->matching)
item = string_list_append(&states->push, _("(matching)"));
else if (strlen(spec->src))
@@ -461,7 +464,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
{
struct ref *ref, *matches;
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
- struct refspec refspec;
+ struct refspec_item refspec;
refspec.force = 0;
refspec.pattern = 1;
@@ -514,7 +517,7 @@ static int add_branch_for_removal(const char *refname,
const struct object_id *oid, int flags, void *cb_data)
{
struct branches_for_remote *branches = cb_data;
- struct refspec refspec;
+ struct refspec_item refspec;
struct known_remote *kr;
memset(&refspec, 0, sizeof(refspec));
@@ -585,12 +588,12 @@ static int migrate_file(struct remote *remote)
git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name);
- for (i = 0; i < remote->push_refspec_nr; i++)
- git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
+ for (i = 0; i < remote->push.raw_nr; i++)
+ git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
- for (i = 0; i < remote->fetch_refspec_nr; i++)
- git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
+ for (i = 0; i < remote->fetch.raw_nr; i++)
+ git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES)
@@ -645,11 +648,11 @@ static int mv(int argc, const char **argv)
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
git_config_set_multivar(buf.buf, NULL, NULL, 1);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
- for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
+ for (i = 0; i < oldremote->fetch.raw_nr; i++) {
char *ptr;
strbuf_reset(&buf2);
- strbuf_addstr(&buf2, oldremote->fetch_refspec[i]);
+ strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) {
refspec_updated = 1;
@@ -833,7 +836,7 @@ static int append_ref_to_tracked_list(const char *refname,
const struct object_id *oid, int flags, void *cb_data)
{
struct ref_states *states = cb_data;
- struct refspec refspec;
+ struct refspec_item refspec;
if (flags & REF_ISSYMREF)
return 0;
@@ -963,9 +966,15 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
printf(" %-*s ", show_info->width, item->string);
if (branch_info->rebase) {
- printf_ln(branch_info->rebase == INTERACTIVE_REBASE
- ? _("rebases interactively onto remote %s")
- : _("rebases onto remote %s"), merge->items[0].string);
+ const char *msg;
+ if (branch_info->rebase == INTERACTIVE_REBASE)
+ msg = _("rebases interactively onto remote %s");
+ else if (branch_info->rebase == REBASE_MERGES)
+ msg = _("rebases interactively (with merges) onto "
+ "remote %s");
+ else
+ msg = _("rebases onto remote %s");
+ printf_ln(msg, merge->items[0].string);
return 0;
} else if (show_info->any_rebase) {
printf_ln(_(" merges with remote %s"), merge->items[0].string);
diff --git a/builtin/repack.c b/builtin/repack.c
index 7bdb40142f..6c636e159e 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -86,7 +86,8 @@ static void remove_pack_on_signal(int signo)
* have a corresponding .keep or .promisor file. These packs are not to
* be kept if we are going to pack everything into one file.
*/
-static void get_non_kept_pack_filenames(struct string_list *fname_list)
+static void get_non_kept_pack_filenames(struct string_list *fname_list,
+ const struct string_list *extra_keep)
{
DIR *dir;
struct dirent *e;
@@ -97,6 +98,14 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
while ((e = readdir(dir)) != NULL) {
size_t len;
+ int i;
+
+ for (i = 0; i < extra_keep->nr; i++)
+ if (!fspathcmp(e->d_name, extra_keep->items[i].string))
+ break;
+ if (extra_keep->nr > 0 && i < extra_keep->nr)
+ continue;
+
if (!strip_suffix(e->d_name, ".pack", &len))
continue;
@@ -148,7 +157,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct string_list rollback = STRING_LIST_INIT_NODUP;
struct string_list existing_packs = STRING_LIST_INIT_DUP;
struct strbuf line = STRBUF_INIT;
- int ext, ret, failed;
+ int i, ext, ret, failed;
FILE *out;
/* variables to be filled by option parsing */
@@ -160,6 +169,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
const char *depth = NULL;
const char *threads = NULL;
const char *max_pack_size = NULL;
+ struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
int no_reuse_delta = 0, no_reuse_object = 0;
int no_update_server_info = 0;
int quiet = 0;
@@ -200,6 +210,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("maximum size of each packfile")),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
+ OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
+ N_("do not repack this pack")),
OPT_END()
};
@@ -230,6 +242,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd.args, "--keep-true-parents");
if (!pack_kept_objects)
argv_array_push(&cmd.args, "--honor-pack-keep");
+ for (i = 0; i < keep_pack_list.nr; i++)
+ argv_array_pushf(&cmd.args, "--keep-pack=%s",
+ keep_pack_list.items[i].string);
argv_array_push(&cmd.args, "--non-empty");
argv_array_push(&cmd.args, "--all");
argv_array_push(&cmd.args, "--reflog");
@@ -254,7 +269,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd.args, "--write-bitmap-index");
if (pack_everything & ALL_INTO_ONE) {
- get_non_kept_pack_filenames(&existing_packs);
+ get_non_kept_pack_filenames(&existing_packs, &keep_pack_list);
if (existing_packs.nr && delete_redundant) {
if (unpack_unreachable) {
diff --git a/builtin/replace.c b/builtin/replace.c
index 237ea656cf..6da2411e14 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -22,6 +22,7 @@ static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
N_("git replace [-f] --edit <object>"),
N_("git replace [-f] --graft <commit> [<parent>...]"),
+ N_("git replace [-f] --convert-graft-file"),
N_("git replace -d <object>..."),
N_("git replace [--format=<format>] [-l [<pattern>]]"),
NULL
@@ -55,8 +56,9 @@ static int show_reference(const char *refname, const struct object_id *oid,
if (get_oid(refname, &object))
return error("Failed to resolve '%s' as a valid ref.", refname);
- obj_type = oid_object_info(&object, NULL);
- repl_type = oid_object_info(oid, NULL);
+ obj_type = oid_object_info(the_repository, &object,
+ NULL);
+ repl_type = oid_object_info(the_repository, oid, NULL);
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
oid_to_hex(oid), type_name(repl_type));
@@ -81,9 +83,9 @@ static int list_replace_refs(const char *pattern, const char *format)
else if (!strcmp(format, "long"))
data.format = REPLACE_FORMAT_LONG;
else
- die("invalid replace format '%s'\n"
- "valid formats are 'short', 'medium' and 'long'\n",
- format);
+ return error("invalid replace format '%s'\n"
+ "valid formats are 'short', 'medium' and 'long'\n",
+ format);
for_each_replace_ref(the_repository, show_reference, (void *)&data);
@@ -136,7 +138,7 @@ static int delete_replace_ref(const char *name, const char *ref,
return 0;
}
-static void check_ref_valid(struct object_id *object,
+static int check_ref_valid(struct object_id *object,
struct object_id *prev,
struct strbuf *ref,
int force)
@@ -144,12 +146,13 @@ static void check_ref_valid(struct object_id *object,
strbuf_reset(ref);
strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
if (check_refname_format(ref->buf, 0))
- die("'%s' is not a valid ref name.", ref->buf);
+ return error("'%s' is not a valid ref name.", ref->buf);
if (read_ref(ref->buf, prev))
oidclr(prev);
else if (!force)
- die("replace ref '%s' already exists", ref->buf);
+ return error("replace ref '%s' already exists", ref->buf);
+ return 0;
}
static int replace_object_oid(const char *object_ref,
@@ -163,28 +166,33 @@ static int replace_object_oid(const char *object_ref,
struct strbuf ref = STRBUF_INIT;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
+ int res = 0;
- obj_type = oid_object_info(object, NULL);
- repl_type = oid_object_info(repl, NULL);
+ obj_type = oid_object_info(the_repository, object, NULL);
+ repl_type = oid_object_info(the_repository, repl, NULL);
if (!force && obj_type != repl_type)
- die("Objects must be of the same type.\n"
- "'%s' points to a replaced object of type '%s'\n"
- "while '%s' points to a replacement object of type '%s'.",
- object_ref, type_name(obj_type),
- replace_ref, type_name(repl_type));
-
- check_ref_valid(object, &prev, &ref, force);
+ return error("Objects must be of the same type.\n"
+ "'%s' points to a replaced object of type '%s'\n"
+ "while '%s' points to a replacement object of "
+ "type '%s'.",
+ object_ref, type_name(obj_type),
+ replace_ref, type_name(repl_type));
+
+ if (check_ref_valid(object, &prev, &ref, force)) {
+ strbuf_release(&ref);
+ return -1;
+ }
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, repl, &prev,
0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
- die("%s", err.buf);
+ res = error("%s", err.buf);
ref_transaction_free(transaction);
strbuf_release(&ref);
- return 0;
+ return res;
}
static int replace_object(const char *object_ref, const char *replace_ref, int force)
@@ -192,9 +200,11 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
struct object_id object, repl;
if (get_oid(object_ref, &object))
- die("Failed to resolve '%s' as a valid ref.", object_ref);
+ return error("Failed to resolve '%s' as a valid ref.",
+ object_ref);
if (get_oid(replace_ref, &repl))
- die("Failed to resolve '%s' as a valid ref.", replace_ref);
+ return error("Failed to resolve '%s' as a valid ref.",
+ replace_ref);
return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
}
@@ -204,7 +214,7 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
* If "raw" is true, then the object's raw contents are printed according to
* "type". Otherwise, we pretty-print the contents for human editing.
*/
-static void export_object(const struct object_id *oid, enum object_type type,
+static int export_object(const struct object_id *oid, enum object_type type,
int raw, const char *filename)
{
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -212,7 +222,7 @@ static void export_object(const struct object_id *oid, enum object_type type,
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
- die_errno("unable to open %s for writing", filename);
+ return error_errno("unable to open %s for writing", filename);
argv_array_push(&cmd.args, "--no-replace-objects");
argv_array_push(&cmd.args, "cat-file");
@@ -225,7 +235,8 @@ static void export_object(const struct object_id *oid, enum object_type type,
cmd.out = fd;
if (run_command(&cmd))
- die("cat-file reported failure");
+ return error("cat-file reported failure");
+ return 0;
}
/*
@@ -233,14 +244,14 @@ static void export_object(const struct object_id *oid, enum object_type type,
* interpreting it as "type", and writing the result to the object database.
* The sha1 of the written object is returned via sha1.
*/
-static void import_object(struct object_id *oid, enum object_type type,
+static int import_object(struct object_id *oid, enum object_type type,
int raw, const char *filename)
{
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
- die_errno("unable to open %s for reading", filename);
+ return error_errno("unable to open %s for reading", filename);
if (!raw && type == OBJ_TREE) {
const char *argv[] = { "mktree", NULL };
@@ -252,27 +263,40 @@ static void import_object(struct object_id *oid, enum object_type type,
cmd.in = fd;
cmd.out = -1;
- if (start_command(&cmd))
- die("unable to spawn mktree");
+ if (start_command(&cmd)) {
+ close(fd);
+ return error("unable to spawn mktree");
+ }
- if (strbuf_read(&result, cmd.out, 41) < 0)
- die_errno("unable to read from mktree");
+ if (strbuf_read(&result, cmd.out, 41) < 0) {
+ error_errno("unable to read from mktree");
+ close(fd);
+ close(cmd.out);
+ return -1;
+ }
close(cmd.out);
- if (finish_command(&cmd))
- die("mktree reported failure");
- if (get_oid_hex(result.buf, oid) < 0)
- die("mktree did not return an object name");
+ if (finish_command(&cmd)) {
+ strbuf_release(&result);
+ return error("mktree reported failure");
+ }
+ if (get_oid_hex(result.buf, oid) < 0) {
+ strbuf_release(&result);
+ return error("mktree did not return an object name");
+ }
strbuf_release(&result);
} else {
struct stat st;
int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
- if (fstat(fd, &st) < 0)
- die_errno("unable to fstat %s", filename);
+ if (fstat(fd, &st) < 0) {
+ error_errno("unable to fstat %s", filename);
+ close(fd);
+ return -1;
+ }
if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
- die("unable to write object to database");
+ return error("unable to write object to database");
/* index_fd close()s fd for us */
}
@@ -280,30 +304,43 @@ static void import_object(struct object_id *oid, enum object_type type,
* No need to close(fd) here; both run-command and index-fd
* will have done it for us.
*/
+ return 0;
}
static int edit_and_replace(const char *object_ref, int force, int raw)
{
- char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
+ char *tmpfile;
enum object_type type;
struct object_id old_oid, new_oid, prev;
struct strbuf ref = STRBUF_INIT;
if (get_oid(object_ref, &old_oid) < 0)
- die("Not a valid object name: '%s'", object_ref);
+ return error("Not a valid object name: '%s'", object_ref);
- type = oid_object_info(&old_oid, NULL);
+ type = oid_object_info(the_repository, &old_oid, NULL);
if (type < 0)
- die("unable to get object type for %s", oid_to_hex(&old_oid));
+ return error("unable to get object type for %s",
+ oid_to_hex(&old_oid));
- check_ref_valid(&old_oid, &prev, &ref, force);
+ if (check_ref_valid(&old_oid, &prev, &ref, force)) {
+ strbuf_release(&ref);
+ return -1;
+ }
strbuf_release(&ref);
- export_object(&old_oid, type, raw, tmpfile);
- if (launch_editor(tmpfile, NULL, NULL) < 0)
- die("editing object file failed");
- import_object(&new_oid, type, raw, tmpfile);
-
+ tmpfile = git_pathdup("REPLACE_EDITOBJ");
+ if (export_object(&old_oid, type, raw, tmpfile)) {
+ free(tmpfile);
+ return -1;
+ }
+ if (launch_editor(tmpfile, NULL, NULL) < 0) {
+ free(tmpfile);
+ return error("editing object file failed");
+ }
+ if (import_object(&new_oid, type, raw, tmpfile)) {
+ free(tmpfile);
+ return -1;
+ }
free(tmpfile);
if (!oidcmp(&old_oid, &new_oid))
@@ -312,7 +349,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
}
-static void replace_parents(struct strbuf *buf, int argc, const char **argv)
+static int replace_parents(struct strbuf *buf, int argc, const char **argv)
{
struct strbuf new_parents = STRBUF_INIT;
const char *parent_start, *parent_end;
@@ -329,9 +366,15 @@ static void replace_parents(struct strbuf *buf, int argc, const char **argv)
/* prepare new parents */
for (i = 0; i < argc; i++) {
struct object_id oid;
- if (get_oid(argv[i], &oid) < 0)
- die(_("Not a valid object name: '%s'"), argv[i]);
- lookup_commit_or_die(&oid, argv[i]);
+ if (get_oid(argv[i], &oid) < 0) {
+ strbuf_release(&new_parents);
+ return error(_("Not a valid object name: '%s'"),
+ argv[i]);
+ }
+ if (!lookup_commit_reference(&oid)) {
+ strbuf_release(&new_parents);
+ return error(_("could not parse %s"), argv[i]);
+ }
strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid));
}
@@ -340,6 +383,7 @@ static void replace_parents(struct strbuf *buf, int argc, const char **argv)
new_parents.buf, new_parents.len);
strbuf_release(&new_parents);
+ return 0;
}
struct check_mergetag_data {
@@ -347,7 +391,7 @@ struct check_mergetag_data {
const char **argv;
};
-static void check_one_mergetag(struct commit *commit,
+static int check_one_mergetag(struct commit *commit,
struct commit_extra_header *extra,
void *data)
{
@@ -360,33 +404,35 @@ static void check_one_mergetag(struct commit *commit,
hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
tag = lookup_tag(&tag_oid);
if (!tag)
- die(_("bad mergetag in commit '%s'"), ref);
+ return error(_("bad mergetag in commit '%s'"), ref);
if (parse_tag_buffer(tag, extra->value, extra->len))
- die(_("malformed mergetag in commit '%s'"), ref);
+ return error(_("malformed mergetag in commit '%s'"), ref);
/* iterate over new parents */
for (i = 1; i < mergetag_data->argc; i++) {
struct object_id oid;
if (get_oid(mergetag_data->argv[i], &oid) < 0)
- die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]);
+ return error(_("Not a valid object name: '%s'"),
+ mergetag_data->argv[i]);
if (!oidcmp(&tag->tagged->oid, &oid))
- return; /* found */
+ return 0; /* found */
}
- die(_("original commit '%s' contains mergetag '%s' that is discarded; "
- "use --edit instead of --graft"), ref, oid_to_hex(&tag_oid));
+ return error(_("original commit '%s' contains mergetag '%s' that is "
+ "discarded; use --edit instead of --graft"), ref,
+ oid_to_hex(&tag_oid));
}
-static void check_mergetags(struct commit *commit, int argc, const char **argv)
+static int check_mergetags(struct commit *commit, int argc, const char **argv)
{
struct check_mergetag_data mergetag_data;
mergetag_data.argc = argc;
mergetag_data.argv = argv;
- for_each_mergetag(check_one_mergetag, commit, &mergetag_data);
+ return for_each_mergetag(check_one_mergetag, commit, &mergetag_data);
}
-static int create_graft(int argc, const char **argv, int force)
+static int create_graft(int argc, const char **argv, int force, int gentle)
{
struct object_id old_oid, new_oid;
const char *old_ref = argv[0];
@@ -396,33 +442,81 @@ static int create_graft(int argc, const char **argv, int force)
unsigned long size;
if (get_oid(old_ref, &old_oid) < 0)
- die(_("Not a valid object name: '%s'"), old_ref);
- commit = lookup_commit_or_die(&old_oid, old_ref);
+ return error(_("Not a valid object name: '%s'"), old_ref);
+ commit = lookup_commit_reference(&old_oid);
+ if (!commit)
+ return error(_("could not parse %s"), old_ref);
buffer = get_commit_buffer(commit, &size);
strbuf_add(&buf, buffer, size);
unuse_commit_buffer(commit, buffer);
- replace_parents(&buf, argc - 1, &argv[1]);
+ if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
+ strbuf_release(&buf);
+ return -1;
+ }
if (remove_signature(&buf)) {
warning(_("the original commit '%s' has a gpg signature."), old_ref);
warning(_("the signature will be removed in the replacement commit!"));
}
- check_mergetags(commit, argc, argv);
+ if (check_mergetags(commit, argc, argv)) {
+ strbuf_release(&buf);
+ return -1;
+ }
- if (write_object_file(buf.buf, buf.len, commit_type, &new_oid))
- die(_("could not write replacement commit for: '%s'"), old_ref);
+ if (write_object_file(buf.buf, buf.len, commit_type, &new_oid)) {
+ strbuf_release(&buf);
+ return error(_("could not write replacement commit for: '%s'"),
+ old_ref);
+ }
strbuf_release(&buf);
- if (!oidcmp(&old_oid, &new_oid))
+ if (!oidcmp(&old_oid, &new_oid)) {
+ if (gentle) {
+ warning("graft for '%s' unnecessary", oid_to_hex(&old_oid));
+ return 0;
+ }
return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
+ }
return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
}
+static int convert_graft_file(int force)
+{
+ const char *graft_file = get_graft_file();
+ FILE *fp = fopen_or_warn(graft_file, "r");
+ struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
+ struct argv_array args = ARGV_ARRAY_INIT;
+
+ if (!fp)
+ return -1;
+
+ while (strbuf_getline(&buf, fp) != EOF) {
+ if (*buf.buf == '#')
+ continue;
+
+ argv_array_split(&args, buf.buf);
+ if (args.argc && create_graft(args.argc, args.argv, force, 1))
+ strbuf_addf(&err, "\n\t%s", buf.buf);
+ argv_array_clear(&args);
+ }
+ fclose(fp);
+
+ strbuf_release(&buf);
+
+ if (!err.len)
+ return unlink_or_warn(graft_file);
+
+ warning(_("could not convert the following graft(s):\n%s"), err.buf);
+ strbuf_release(&err);
+
+ return -1;
+}
+
int cmd_replace(int argc, const char **argv, const char *prefix)
{
int force = 0;
@@ -434,6 +528,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
MODE_DELETE,
MODE_EDIT,
MODE_GRAFT,
+ MODE_CONVERT_GRAFT_FILE,
MODE_REPLACE
} cmdmode = MODE_UNSPECIFIED;
struct option options[] = {
@@ -441,6 +536,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE),
OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT),
OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT),
+ OPT_CMDMODE(0, "convert-graft-file", &cmdmode, N_("convert existing graft file"), MODE_CONVERT_GRAFT_FILE),
OPT_BOOL_F('f', "force", &force, N_("replace the ref if it exists"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")),
@@ -463,7 +559,8 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
if (force &&
cmdmode != MODE_REPLACE &&
cmdmode != MODE_EDIT &&
- cmdmode != MODE_GRAFT)
+ cmdmode != MODE_GRAFT &&
+ cmdmode != MODE_CONVERT_GRAFT_FILE)
usage_msg_opt("-f only makes sense when writing a replacement",
git_replace_usage, options);
@@ -494,7 +591,13 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
if (argc < 1)
usage_msg_opt("-g needs at least one argument",
git_replace_usage, options);
- return create_graft(argc, argv, force);
+ return create_graft(argc, argv, force, 0);
+
+ case MODE_CONVERT_GRAFT_FILE:
+ if (argc != 0)
+ usage_msg_opt("--convert-graft-file takes no argument",
+ git_replace_usage, options);
+ return !!convert_graft_file(force);
case MODE_LIST:
if (argc > 1)
@@ -503,6 +606,6 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
return list_replace_refs(argv[0], format);
default:
- die("BUG: invalid cmdmode %d", (int)cmdmode);
+ BUG("invalid cmdmode %d", (int)cmdmode);
}
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 7f1c3f02a3..a862c70fab 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -314,7 +314,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
- hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
+ oidcpy(&oid, the_hash_algo->empty_tree);
} else if (!pathspec.nr) {
struct commit *commit;
if (get_oid_committish(rev, &oid))
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 36b2087782..4f49e96bfd 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -282,6 +282,10 @@ static int try_difference(const char *arg)
struct commit *a, *b;
a = lookup_commit_reference(&start_oid);
b = lookup_commit_reference(&end_oid);
+ if (!a || !b) {
+ *dotdot = '.';
+ return 0;
+ }
exclude = get_merge_bases(a, b);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
@@ -328,12 +332,12 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_oid_committish(arg, &oid)) {
+ if (get_oid_committish(arg, &oid) ||
+ !(commit = lookup_commit_reference(&oid))) {
*dotdot = '^';
return 0;
}
- commit = lookup_commit_reference(&oid);
if (exclude_parent &&
exclude_parent > commit_list_count(commit->parents)) {
*dotdot = '^';
@@ -887,8 +891,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die(_("Could not read the index"));
if (the_index.split_index) {
- const unsigned char *sha1 = the_index.split_index->base_sha1;
- const char *path = git_path("sharedindex.%s", sha1_to_hex(sha1));
+ const struct object_id *oid = &the_index.split_index->base_oid;
+ const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
strbuf_reset(&buf);
puts(relative_path(path, prefix, &buf));
}
diff --git a/builtin/rm.c b/builtin/rm.c
index 5b6fc7ee81..65b448ef8e 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -233,8 +233,6 @@ static int check_local_mod(struct object_id *head, int index_only)
return errs;
}
-static struct lock_file lock_file;
-
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
static int ignore_unmatch = 0;
@@ -251,6 +249,7 @@ static struct option builtin_rm_options[] = {
int cmd_rm(int argc, const char **argv, const char *prefix)
{
+ struct lock_file lock_file = LOCK_INIT;
int i;
struct pathspec pathspec;
char *seen;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index b5427f75e3..4923b1058c 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
- int i, nr_refspecs = 0;
- const char **refspecs = NULL;
+ struct refspec rs = REFSPEC_INIT_PUSH;
const char *remote_name = NULL;
struct remote *remote = NULL;
const char *dest = NULL;
@@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
if (argc > 0) {
dest = argv[0];
- refspecs = (const char **)(argv + 1);
- nr_refspecs = argc - 1;
+ refspec_appendn(&rs, argv + 1, argc - 1);
}
if (!dest)
@@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.push_options = push_options.nr ? &push_options : NULL;
if (from_stdin) {
- struct argv_array all_refspecs = ARGV_ARRAY_INIT;
-
- for (i = 0; i < nr_refspecs; i++)
- argv_array_push(&all_refspecs, refspecs[i]);
-
if (args.stateless_rpc) {
const char *buf;
while ((buf = packet_read_line(0, NULL)))
- argv_array_push(&all_refspecs, buf);
+ refspec_append(&rs, buf);
} else {
struct strbuf line = STRBUF_INIT;
while (strbuf_getline(&line, stdin) != EOF)
- argv_array_push(&all_refspecs, line.buf);
+ refspec_append(&rs, line.buf);
strbuf_release(&line);
}
-
- refspecs = all_refspecs.argv;
- nr_refspecs = all_refspecs.argc;
}
/*
* --all and --mirror are incompatible; neither makes sense
* with any refspecs.
*/
- if ((nr_refspecs > 0 && (send_all || args.send_mirror)) ||
+ if ((rs.nr > 0 && (send_all || args.send_mirror)) ||
(send_all && args.send_mirror))
usage_with_options(send_pack_usage, options);
@@ -275,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
BUG("unknown protocol version");
}
- transport_verify_remote_names(nr_refspecs, refspecs);
-
local_refs = get_local_heads();
flags = MATCH_REFS_NONE;
@@ -287,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
flags |= MATCH_REFS_MIRROR;
/* match them up */
- if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
+ if (match_push_refs(local_refs, &remote_refs, &rs, flags))
return -1;
if (!is_empty_cas(&cas))
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2403a915f..bd250ca216 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -12,6 +12,7 @@
#include "run-command.h"
#include "remote.h"
#include "refs.h"
+#include "refspec.h"
#include "connect.h"
#include "revision.h"
#include "diffcore.h"
@@ -1065,7 +1066,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
}
static int clone_submodule(const char *path, const char *gitdir, const char *url,
- const char *depth, struct string_list *reference,
+ const char *depth, struct string_list *reference, int dissociate,
int quiet, int progress)
{
struct child_process cp = CHILD_PROCESS_INIT;
@@ -1084,6 +1085,8 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
argv_array_pushl(&cp.args, "--reference",
item->string, NULL);
}
+ if (dissociate)
+ argv_array_push(&cp.args, "--dissociate");
if (gitdir && *gitdir)
argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
@@ -1199,6 +1202,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
char *p, *path = NULL, *sm_gitdir;
struct strbuf sb = STRBUF_INIT;
struct string_list reference = STRING_LIST_INIT_NODUP;
+ int dissociate = 0;
char *sm_alternate = NULL, *error_strategy = NULL;
struct option module_clone_options[] = {
@@ -1217,6 +1221,8 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "reference", &reference,
N_("repo"),
N_("reference repository")),
+ OPT_BOOL(0, "dissociate", &dissociate,
+ N_("use --reference only while cloning")),
OPT_STRING(0, "depth", &depth,
N_("string"),
N_("depth for shallow clones")),
@@ -1256,7 +1262,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
prepare_possible_alternates(name, &reference);
- if (clone_submodule(path, sm_gitdir, url, depth, &reference,
+ if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
quiet, progress))
die(_("clone of '%s' into submodule path '%s' failed"),
url, path);
@@ -1308,6 +1314,7 @@ struct submodule_update_clone {
int quiet;
int recommend_shallow;
struct string_list references;
+ int dissociate;
const char *depth;
const char *recursive_prefix;
const char *prefix;
@@ -1323,7 +1330,7 @@ struct submodule_update_clone {
int failed_clones_nr, failed_clones_alloc;
};
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
- SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \
+ SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
NULL, NULL, NULL, \
STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
@@ -1450,6 +1457,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
for_each_string_list_item(item, &suc->references)
argv_array_pushl(&child->args, "--reference", item->string, NULL);
}
+ if (suc->dissociate)
+ argv_array_push(&child->args, "--dissociate");
if (suc->depth)
argv_array_push(&child->args, suc->depth);
@@ -1583,6 +1592,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
N_("rebase, merge, checkout or none")),
OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
N_("reference repository")),
+ OPT_BOOL(0, "dissociate", &suc.dissociate,
+ N_("use --reference only while cloning")),
OPT_STRING(0, "depth", &suc.depth, "<depth>",
N_("Create a shallow clone truncated to the "
"specified number of revisions")),
@@ -1743,13 +1754,14 @@ static int push_check(int argc, const char **argv, const char *prefix)
/* Check the refspec */
if (argc > 2) {
- int i, refspec_nr = argc - 2;
+ int i;
struct ref *local_refs = get_local_heads();
- struct refspec *refspec = parse_push_refspec(refspec_nr,
- argv + 2);
+ struct refspec refspec = REFSPEC_INIT_PUSH;
- for (i = 0; i < refspec_nr; i++) {
- struct refspec *rs = refspec + i;
+ refspec_appendn(&refspec, argv + 2, argc - 2);
+
+ for (i = 0; i < refspec.nr; i++) {
+ const struct refspec_item *rs = &refspec.items[i];
if (rs->pattern || rs->matching)
continue;
@@ -1776,7 +1788,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
rs->src);
}
}
- free_refspec(refspec_nr, refspec);
+ refspec_clear(&refspec);
}
free(head);
@@ -1825,6 +1837,29 @@ static int is_active(int argc, const char **argv, const char *prefix)
return !is_submodule_active(the_repository, argv[1]);
}
+/*
+ * Exit non-zero if any of the submodule names given on the command line is
+ * invalid. If no names are given, filter stdin to print only valid names
+ * (which is primarily intended for testing).
+ */
+static int check_name(int argc, const char **argv, const char *prefix)
+{
+ if (argc > 1) {
+ while (*++argv) {
+ if (check_submodule_name(*argv) < 0)
+ return 1;
+ }
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ while (strbuf_getline(&buf, stdin) != EOF) {
+ if (!check_submodule_name(buf.buf))
+ printf("%s\n", buf.buf);
+ }
+ strbuf_release(&buf);
+ }
+ return 0;
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -1850,6 +1885,7 @@ static struct cmd_struct commands[] = {
{"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
{"is-active", is_active, 0},
+ {"check-name", check_name, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/builtin/tag.c b/builtin/tag.c
index 46a5c6a1da..5d0dd11240 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -212,7 +212,7 @@ static void create_tag(const struct object_id *object, const char *tag,
struct strbuf header = STRBUF_INIT;
char *path = NULL;
- type = oid_object_info(object, NULL);
+ type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
die(_("bad object type."));
@@ -298,7 +298,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
}
strbuf_addstr(sb, " (");
- type = oid_object_info(oid, NULL);
+ type = oid_object_info(the_repository, oid, NULL);
switch (type) {
default:
strbuf_addstr(sb, "object of unknown type");
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index b7755c6cc5..6e81ca8ca2 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -199,7 +199,7 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op
if (!(obj->flags & FLAG_OPEN)) {
unsigned long size;
- int type = oid_object_info(&obj->oid, &size);
+ int type = oid_object_info(the_repository, &obj->oid, &size);
if (type != obj->type || type <= 0)
die("object of unexpected type");
obj->flags |= FLAG_WRITTEN;
@@ -210,7 +210,7 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op
if (!obj_buf)
die("Whoops! Cannot find object '%s'", oid_to_hex(&obj->oid));
if (fsck_object(obj, obj_buf->buffer, obj_buf->size, &fsck_options))
- die("Error in object");
+ die("fsck error in packed object");
fsck_options.walk = check_object;
if (fsck_walk(obj, NULL, &fsck_options))
die("Error on reachable objects of %s", oid_to_hex(&obj->oid));
@@ -572,8 +572,11 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
unpack_all();
the_hash_algo->update_fn(&ctx, buffer, offset);
the_hash_algo->final_fn(oid.hash, &ctx);
- if (strict)
+ if (strict) {
write_rest();
+ if (fsck_finish(&fsck_options))
+ die(_("fsck error in pack objects"));
+ }
if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
die("final sha1 did not match");
use(the_hash_algo->rawsz);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 10d070a76f..a8709a26ec 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -364,10 +364,9 @@ static int process_directory(const char *path, int len, struct stat *st)
return error("%s: is a directory - add files inside instead", path);
}
-static int process_path(const char *path)
+static int process_path(const char *path, struct stat *st, int stat_errno)
{
int pos, len;
- struct stat st;
const struct cache_entry *ce;
len = strlen(path);
@@ -391,13 +390,13 @@ static int process_path(const char *path)
* First things first: get the stat information, to decide
* what to do about the pathname!
*/
- if (lstat(path, &st) < 0)
- return process_lstat_error(path, errno);
+ if (stat_errno)
+ return process_lstat_error(path, stat_errno);
- if (S_ISDIR(st.st_mode))
- return process_directory(path, len, &st);
+ if (S_ISDIR(st->st_mode))
+ return process_directory(path, len, st);
- return add_one_path(ce, path, len, &st);
+ return add_one_path(ce, path, len, st);
}
static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
@@ -406,7 +405,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
int size, len, option;
struct cache_entry *ce;
- if (!verify_path(path))
+ if (!verify_path(path, mode))
return error("Invalid path '%s'", path);
len = strlen(path);
@@ -449,7 +448,18 @@ static void chmod_path(char flip, const char *path)
static void update_one(const char *path)
{
- if (!verify_path(path)) {
+ int stat_errno = 0;
+ struct stat st;
+
+ if (mark_valid_only || mark_skip_worktree_only || force_remove ||
+ mark_fsmonitor_only)
+ st.st_mode = 0;
+ else if (lstat(path, &st) < 0) {
+ st.st_mode = 0;
+ stat_errno = errno;
+ } /* else stat is valid */
+
+ if (!verify_path(path, st.st_mode)) {
fprintf(stderr, "Ignoring path %s\n", path);
return;
}
@@ -475,7 +485,7 @@ static void update_one(const char *path)
report("remove '%s'", path);
return;
}
- if (process_path(path))
+ if (process_path(path, &st, stat_errno))
die("Unable to process path %s", path);
report("add '%s'", path);
}
@@ -545,7 +555,7 @@ static void read_index_info(int nul_term_line)
path_name = uq.buf;
}
- if (!verify_path(path_name)) {
+ if (!verify_path(path_name, mode)) {
fprintf(stderr, "Ignoring path %s\n", path_name);
continue;
}
@@ -1164,7 +1174,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
break;
default:
- die("BUG: bad untracked_cache value: %d", untracked_cache);
+ BUG("bad untracked_cache value: %d", untracked_cache);
}
if (fsmonitor > 0) {
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 30647b30c5..5c7d2bb180 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -29,8 +29,6 @@ struct add_opts {
int detach;
int checkout;
int keep_locked;
- const char *new_branch;
- int force_new_branch;
};
static int show_only;
@@ -298,8 +296,6 @@ static int add_worktree(const char *path, const char *refname,
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
- fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name);
-
argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
@@ -366,18 +362,75 @@ done:
return ret;
}
+static void print_preparing_worktree_line(int detach,
+ const char *branch,
+ const char *new_branch,
+ int force_new_branch)
+{
+ if (force_new_branch) {
+ struct commit *commit = lookup_commit_reference_by_name(new_branch);
+ if (!commit)
+ printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+ else
+ printf_ln(_("Preparing worktree (resetting branch '%s'; was at %s)"),
+ new_branch,
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ } else if (new_branch) {
+ printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+ } else {
+ struct strbuf s = STRBUF_INIT;
+ if (!detach && !strbuf_check_branch_ref(&s, branch) &&
+ ref_exists(s.buf))
+ printf_ln(_("Preparing worktree (checking out '%s')"),
+ branch);
+ else {
+ struct commit *commit = lookup_commit_reference_by_name(branch);
+ if (!commit)
+ die(_("invalid reference: %s"), branch);
+ printf_ln(_("Preparing worktree (detached HEAD %s)"),
+ find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ }
+ strbuf_release(&s);
+ }
+}
+
+static const char *dwim_branch(const char *path, const char **new_branch)
+{
+ int n;
+ const char *s = worktree_basename(path, &n);
+ const char *branchname = xstrndup(s, n);
+ struct strbuf ref = STRBUF_INIT;
+
+ UNLEAK(branchname);
+ if (!strbuf_check_branch_ref(&ref, branchname) &&
+ ref_exists(ref.buf)) {
+ strbuf_release(&ref);
+ return branchname;
+ }
+
+ *new_branch = branchname;
+ if (guess_remote) {
+ struct object_id oid;
+ const char *remote =
+ unique_tracking_name(*new_branch, &oid);
+ return remote;
+ }
+ return NULL;
+}
+
static int add(int ac, const char **av, const char *prefix)
{
struct add_opts opts;
const char *new_branch_force = NULL;
char *path;
const char *branch;
+ const char *new_branch = NULL;
const char *opt_track = NULL;
struct option options[] = {
OPT__FORCE(&opts.force,
N_("checkout <branch> even if already checked out in other worktree"),
PARSE_OPT_NOCOMPLETE),
- OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+ OPT_STRING('b', NULL, &new_branch, N_("branch"),
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
N_("create or reset a branch")),
@@ -395,7 +448,7 @@ static int add(int ac, const char **av, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
- if (!!opts.detach + !!opts.new_branch + !!new_branch_force > 1)
+ if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("-b, -B, and --detach are mutually exclusive"));
if (ac < 1 || ac > 2)
usage_with_options(worktree_usage, options);
@@ -406,33 +459,25 @@ static int add(int ac, const char **av, const char *prefix)
if (!strcmp(branch, "-"))
branch = "@{-1}";
- opts.force_new_branch = !!new_branch_force;
- if (opts.force_new_branch) {
+ if (new_branch_force) {
struct strbuf symref = STRBUF_INIT;
- opts.new_branch = new_branch_force;
+ new_branch = new_branch_force;
if (!opts.force &&
- !strbuf_check_branch_ref(&symref, opts.new_branch) &&
+ !strbuf_check_branch_ref(&symref, new_branch) &&
ref_exists(symref.buf))
die_if_checked_out(symref.buf, 0);
strbuf_release(&symref);
}
- if (ac < 2 && !opts.new_branch && !opts.detach) {
- int n;
- const char *s = worktree_basename(path, &n);
- opts.new_branch = xstrndup(s, n);
- if (guess_remote) {
- struct object_id oid;
- const char *remote =
- unique_tracking_name(opts.new_branch, &oid);
- if (remote)
- branch = remote;
- }
+ if (ac < 2 && !new_branch && !opts.detach) {
+ const char *s = dwim_branch(path, &new_branch);
+ if (s)
+ branch = s;
}
- if (ac == 2 && !opts.new_branch && !opts.detach) {
+ if (ac == 2 && !new_branch && !opts.detach) {
struct object_id oid;
struct commit *commit;
const char *remote;
@@ -441,25 +486,27 @@ static int add(int ac, const char **av, const char *prefix)
if (!commit) {
remote = unique_tracking_name(branch, &oid);
if (remote) {
- opts.new_branch = branch;
+ new_branch = branch;
branch = remote;
}
}
}
- if (opts.new_branch) {
+ print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
+
+ if (new_branch) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
argv_array_push(&cp.args, "branch");
- if (opts.force_new_branch)
+ if (new_branch_force)
argv_array_push(&cp.args, "--force");
- argv_array_push(&cp.args, opts.new_branch);
+ argv_array_push(&cp.args, new_branch);
argv_array_push(&cp.args, branch);
if (opt_track)
argv_array_push(&cp.args, opt_track);
if (run_command(&cp))
return -1;
- branch = opts.new_branch;
+ branch = new_branch;
} else if (opt_track) {
die(_("--[no-]track can only be used if a new branch is created"));
}