summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c3
-rw-r--r--builtin/apply.c143
-rw-r--r--builtin/blame.c5
-rw-r--r--builtin/branch.c4
-rw-r--r--builtin/checkout.c6
-rw-r--r--builtin/clean.c2
-rw-r--r--builtin/clone.c9
-rw-r--r--builtin/commit.c171
-rw-r--r--builtin/config.c31
-rw-r--r--builtin/fast-export.c300
-rw-r--r--builtin/fetch.c10
-rw-r--r--builtin/gc.c51
-rw-r--r--builtin/help.c3
-rw-r--r--builtin/index-pack.c33
-rw-r--r--builtin/init-db.c32
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/ls-files.c2
-rw-r--r--builtin/mailsplit.c17
-rw-r--r--builtin/merge-tree.c18
-rw-r--r--builtin/merge.c7
-rw-r--r--builtin/mv.c174
-rw-r--r--builtin/notes.c5
-rw-r--r--builtin/receive-pack.c37
-rw-r--r--builtin/remote-ext.c3
-rw-r--r--builtin/repack.c3
-rw-r--r--builtin/replace.c18
-rw-r--r--builtin/rev-parse.c6
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/send-pack.c27
-rw-r--r--builtin/tag.c16
-rw-r--r--builtin/update-ref.c52
-rw-r--r--builtin/verify-pack.c3
32 files changed, 808 insertions, 386 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 4baf3a5..352b85e 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -180,7 +180,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
char *file = git_pathdup("ADD_EDIT.patch");
const char *apply_argv[] = { "apply", "--recount", "--cached",
NULL, NULL };
- struct child_process child;
+ struct child_process child = CHILD_PROCESS_INIT;
struct rev_info rev;
int out;
struct stat st;
@@ -214,7 +214,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
if (!st.st_size)
die(_("Empty patch. Aborted."));
- memset(&child, 0, sizeof(child));
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
diff --git a/builtin/apply.c b/builtin/apply.c
index be2b4ce..f204cca 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1920,6 +1920,66 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
return used;
}
+static void prefix_one(char **name)
+{
+ char *old_name = *name;
+ if (!old_name)
+ return;
+ *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+ free(old_name);
+}
+
+static void prefix_patch(struct patch *p)
+{
+ if (!prefix || p->is_toplevel_relative)
+ return;
+ prefix_one(&p->new_name);
+ prefix_one(&p->old_name);
+}
+
+/*
+ * include/exclude
+ */
+
+static struct string_list limit_by_name;
+static int has_include;
+static void add_name_limit(const char *name, int exclude)
+{
+ struct string_list_item *it;
+
+ it = string_list_append(&limit_by_name, name);
+ it->util = exclude ? NULL : (void *) 1;
+}
+
+static int use_patch(struct patch *p)
+{
+ const char *pathname = p->new_name ? p->new_name : p->old_name;
+ int i;
+
+ /* Paths outside are not touched regardless of "--include" */
+ if (0 < prefix_length) {
+ int pathlen = strlen(pathname);
+ if (pathlen <= prefix_length ||
+ memcmp(prefix, pathname, prefix_length))
+ return 0;
+ }
+
+ /* See if it matches any of exclude/include rule */
+ for (i = 0; i < limit_by_name.nr; i++) {
+ struct string_list_item *it = &limit_by_name.items[i];
+ if (!wildmatch(it->string, pathname, 0, NULL))
+ return (it->util != NULL);
+ }
+
+ /*
+ * If we had any include, a path that does not match any rule is
+ * not used. Otherwise, we saw bunch of exclude rules (or none)
+ * and such a path is used.
+ */
+ return !has_include;
+}
+
+
/*
* Read the patch text in "buffer" that extends for "size" bytes; stop
* reading after seeing a single patch (i.e. changes to a single file).
@@ -1935,9 +1995,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
if (offset < 0)
return offset;
- patch->ws_rule = whitespace_rule(patch->new_name
- ? patch->new_name
- : patch->old_name);
+ prefix_patch(patch);
+
+ if (!use_patch(patch))
+ patch->ws_rule = 0;
+ else
+ patch->ws_rule = whitespace_rule(patch->new_name
+ ? patch->new_name
+ : patch->old_name);
patchsize = parse_single_patch(buffer + offset + hdrsize,
size - offset - hdrsize, patch);
@@ -4127,64 +4192,6 @@ static int write_out_results(struct patch *list)
static struct lock_file lock_file;
-static struct string_list limit_by_name;
-static int has_include;
-static void add_name_limit(const char *name, int exclude)
-{
- struct string_list_item *it;
-
- it = string_list_append(&limit_by_name, name);
- it->util = exclude ? NULL : (void *) 1;
-}
-
-static int use_patch(struct patch *p)
-{
- const char *pathname = p->new_name ? p->new_name : p->old_name;
- int i;
-
- /* Paths outside are not touched regardless of "--include" */
- if (0 < prefix_length) {
- int pathlen = strlen(pathname);
- if (pathlen <= prefix_length ||
- memcmp(prefix, pathname, prefix_length))
- return 0;
- }
-
- /* See if it matches any of exclude/include rule */
- for (i = 0; i < limit_by_name.nr; i++) {
- struct string_list_item *it = &limit_by_name.items[i];
- if (!wildmatch(it->string, pathname, 0, NULL))
- return (it->util != NULL);
- }
-
- /*
- * If we had any include, a path that does not match any rule is
- * not used. Otherwise, we saw bunch of exclude rules (or none)
- * and such a path is used.
- */
- return !has_include;
-}
-
-
-static void prefix_one(char **name)
-{
- char *old_name = *name;
- if (!old_name)
- return;
- *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
- free(old_name);
-}
-
-static void prefix_patches(struct patch *p)
-{
- if (!prefix || p->is_toplevel_relative)
- return;
- for ( ; p; p = p->next) {
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
- }
-}
-
#define INACCURATE_EOF (1<<0)
#define RECOUNT (1<<1)
@@ -4210,8 +4217,6 @@ static int apply_patch(int fd, const char *filename, int options)
break;
if (apply_in_reverse)
reverse_patches(patch);
- if (prefix)
- prefix_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
@@ -4269,13 +4274,11 @@ static int apply_patch(int fd, const char *filename, int options)
return 0;
}
-static int git_apply_config(const char *var, const char *value, void *cb)
+static void git_apply_config(void)
{
- if (!strcmp(var, "apply.whitespace"))
- return git_config_string(&apply_default_whitespace, var, value);
- else if (!strcmp(var, "apply.ignorewhitespace"))
- return git_config_string(&apply_default_ignorewhitespace, var, value);
- return git_default_config(var, value, cb);
+ git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
+ git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+ git_config(git_default_config, NULL);
}
static int option_parse_exclude(const struct option *opt,
@@ -4423,7 +4426,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
prefix = prefix_;
prefix_length = prefix ? strlen(prefix) : 0;
- git_config(git_apply_config, NULL);
+ git_apply_config();
if (apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace);
if (apply_default_ignorewhitespace)
diff --git a/builtin/blame.c b/builtin/blame.c
index 17d30d0..3838be2 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -2580,6 +2580,9 @@ parse_done:
case DATE_RFC2822:
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
break;
+ case DATE_ISO8601_STRICT:
+ blame_date_width = sizeof("2006-10-19T16:00:04-07:00");
+ break;
case DATE_ISO8601:
blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
break;
@@ -2700,7 +2703,7 @@ parse_done:
* uninteresting.
*/
if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
+ die(_("revision walk setup failed"));
if (is_null_sha1(sb.final->object.sha1)) {
o = sb.final->util;
diff --git a/builtin/branch.c b/builtin/branch.c
index 0591b22..ced422b 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -653,7 +653,9 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
add_pending_object(&ref_list.revs,
(struct object *) filter, "");
ref_list.revs.limited = 1;
- prepare_revision_walk(&ref_list.revs);
+
+ if (prepare_revision_walk(&ref_list.revs))
+ die(_("revision walk setup failed"));
if (verbose)
ref_list.maxwidth = calc_maxwidth(&ref_list);
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f71e745..8afdf2b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -552,6 +552,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
}
+ if (!active_cache_tree)
+ active_cache_tree = cache_tree();
+
+ if (!cache_tree_fully_valid(active_cache_tree))
+ cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
diff --git a/builtin/clean.c b/builtin/clean.c
index 1032563..3beeea6 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -67,7 +67,7 @@ struct menu_item {
char hotkey;
const char *title;
int selected;
- int (*fn)();
+ int (*fn)(void);
};
enum menu_stuff_type {
diff --git a/builtin/clone.c b/builtin/clone.c
index bbd169c..3927edf 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -685,9 +685,10 @@ static void write_config(struct string_list *config)
}
}
-static void write_refspec_config(const char* src_ref_prefix,
- const struct ref* our_head_points_at,
- const struct ref* remote_head_points_at, struct strbuf* branch_top)
+static void write_refspec_config(const char *src_ref_prefix,
+ const struct ref *our_head_points_at,
+ const struct ref *remote_head_points_at,
+ struct strbuf *branch_top)
{
struct strbuf key = STRBUF_INIT;
struct strbuf value = STRBUF_INIT;
@@ -1004,5 +1005,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&key);
strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL;
+
+ free(refspec);
return err;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 5ed6036..b0fe784 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -42,7 +42,20 @@ static const char * const builtin_status_usage[] = {
NULL
};
-static const char implicit_ident_advice[] =
+static const char implicit_ident_advice_noconfig[] =
+N_("Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly. Run the\n"
+"following command and follow the instructions in your editor to edit\n"
+"your configuration file:\n"
+"\n"
+" git config --global --edit\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+" git commit --amend --reset-author\n");
+
+static const char implicit_ident_advice_config[] =
N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly:\n"
@@ -340,6 +353,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
discard_cache();
read_cache_from(index_lock.filename);
+ if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+ if (reopen_lock_file(&index_lock) < 0)
+ die(_("unable to write index file"));
+ if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ die(_("unable to update temporary index"));
+ } else
+ warning(_("Failed to update main cache tree"));
commit_style = COMMIT_NORMAL;
return index_lock.filename;
@@ -380,8 +400,12 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
if (!only && !pathspec.nr) {
hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
- if (active_cache_changed) {
+ if (active_cache_changed
+ || !cache_tree_fully_valid(active_cache_tree)) {
update_main_cache_tree(WRITE_TREE_SILENT);
+ active_cache_changed = 1;
+ }
+ if (active_cache_changed) {
if (write_locked_index(&the_index, &index_lock,
COMMIT_LOCK))
die(_("unable to write new_index file"));
@@ -431,6 +455,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
hold_locked_index(&index_lock, 1);
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
+ update_main_cache_tree(WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
die(_("unable to write new_index file"));
@@ -520,77 +545,80 @@ static int sane_ident_split(struct ident_split *person)
return 1;
}
-static int parse_force_date(const char *in, char *out, int len)
+static int parse_force_date(const char *in, struct strbuf *out)
{
- if (len < 1)
- return -1;
- *out++ = '@';
- len--;
+ strbuf_addch(out, '@');
- if (parse_date(in, out, len) < 0) {
+ if (parse_date(in, out) < 0) {
int errors = 0;
unsigned long t = approxidate_careful(in, &errors);
if (errors)
return -1;
- snprintf(out, len, "%lu", t);
+ strbuf_addf(out, "%lu", t);
}
return 0;
}
+static void set_ident_var(char **buf, char *val)
+{
+ free(*buf);
+ *buf = val;
+}
+
+static char *envdup(const char *var)
+{
+ const char *val = getenv(var);
+ return val ? xstrdup(val) : NULL;
+}
+
static void determine_author_info(struct strbuf *author_ident)
{
char *name, *email, *date;
struct ident_split author;
- char date_buf[64];
- name = getenv("GIT_AUTHOR_NAME");
- email = getenv("GIT_AUTHOR_EMAIL");
- date = getenv("GIT_AUTHOR_DATE");
+ name = envdup("GIT_AUTHOR_NAME");
+ email = envdup("GIT_AUTHOR_EMAIL");
+ date = envdup("GIT_AUTHOR_DATE");
if (author_message) {
- const char *a, *lb, *rb, *eol;
+ struct ident_split ident;
size_t len;
+ const char *a;
- a = strstr(author_message_buffer, "\nauthor ");
+ a = find_commit_header(author_message_buffer, "author", &len);
if (!a)
- die(_("invalid commit: %s"), author_message);
-
- lb = strchrnul(a + strlen("\nauthor "), '<');
- rb = strchrnul(lb, '>');
- eol = strchrnul(rb, '\n');
- if (!*lb || !*rb || !*eol)
- die(_("invalid commit: %s"), author_message);
-
- if (lb == a + strlen("\nauthor "))
- /* \nauthor <foo@example.com> */
- name = xcalloc(1, 1);
- else
- name = xmemdupz(a + strlen("\nauthor "),
- (lb - strlen(" ") -
- (a + strlen("\nauthor "))));
- email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
- len = eol - (rb + strlen("> "));
- date = xmalloc(len + 2);
- *date = '@';
- memcpy(date + 1, rb + strlen("> "), len);
- date[len + 1] = '\0';
+ die(_("commit '%s' lacks author header"), author_message);
+ if (split_ident_line(&ident, a, len) < 0)
+ die(_("commit '%s' has malformed author line"), author_message);
+
+ set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+ set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
+
+ if (ident.date_begin) {
+ struct strbuf date_buf = STRBUF_INIT;
+ strbuf_addch(&date_buf, '@');
+ strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin);
+ strbuf_addch(&date_buf, ' ');
+ strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin);
+ set_ident_var(&date, strbuf_detach(&date_buf, NULL));
+ }
}
if (force_author) {
- const char *lb = strstr(force_author, " <");
- const char *rb = strchr(force_author, '>');
+ struct ident_split ident;
- if (!lb || !rb)
+ if (split_ident_line(&ident, force_author, strlen(force_author)) < 0)
die(_("malformed --author parameter"));
- name = xstrndup(force_author, lb - force_author);
- email = xstrndup(lb + 2, rb - (lb + 2));
+ set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+ set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
}
if (force_date) {
- if (parse_force_date(force_date, date_buf, sizeof(date_buf)))
+ struct strbuf date_buf = STRBUF_INIT;
+ if (parse_force_date(force_date, &date_buf))
die(_("invalid date format: %s"), force_date);
- date = date_buf;
+ set_ident_var(&date, strbuf_detach(&date_buf, NULL));
}
strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
@@ -600,6 +628,10 @@ static void determine_author_info(struct strbuf *author_ident)
export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
}
+
+ free(name);
+ free(email);
+ free(date);
}
static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
@@ -1048,7 +1080,8 @@ static const char *find_author_by_nickname(const char *name)
revs.mailmap = &mailmap;
read_mailmap(revs.mailmap, NULL);
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die(_("revision walk setup failed"));
commit = get_revision(&revs);
if (commit) {
struct pretty_print_context ctx = {0};
@@ -1402,6 +1435,24 @@ int cmd_status(int argc, const char **argv, const char *prefix)
return 0;
}
+static const char *implicit_ident_advice(void)
+{
+ char *user_config = NULL;
+ char *xdg_config = NULL;
+ int config_exists;
+
+ home_config_paths(&user_config, &xdg_config, "config");
+ config_exists = file_exists(user_config) || file_exists(xdg_config);
+ free(user_config);
+ free(xdg_config);
+
+ if (config_exists)
+ return _(implicit_ident_advice_config);
+ else
+ return _(implicit_ident_advice_noconfig);
+
+}
+
static void print_summary(const char *prefix, const unsigned char *sha1,
int initial_commit)
{
@@ -1440,7 +1491,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
strbuf_addbuf_percentquote(&format, &committer_ident);
if (advice_implicit_identity) {
strbuf_addch(&format, '\n');
- strbuf_addstr(&format, _(implicit_ident_advice));
+ strbuf_addstr(&format, implicit_ident_advice());
}
}
strbuf_release(&author_ident);
@@ -1508,7 +1559,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
{
/* oldsha1 SP newsha1 LF NUL */
static char buf[2*40 + 3];
- struct child_process proc;
+ struct child_process proc = CHILD_PROCESS_INIT;
const char *argv[3];
int code;
size_t n;
@@ -1520,7 +1571,6 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
argv[1] = "amend";
argv[2] = NULL;
- memset(&proc, 0, sizeof(proc));
proc.argv = argv;
proc.in = -1;
proc.stdout_to_stderr = 1;
@@ -1620,11 +1670,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
const char *index_file, *reflog_msg;
char *nl;
unsigned char sha1[20];
- struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1746,16 +1797,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_release(&author_ident);
free_commit_extra_headers(extra);
- ref_lock = lock_any_ref_for_update("HEAD",
- !current_head
- ? NULL
- : current_head->object.sha1,
- 0, NULL);
- if (!ref_lock) {
- rollback_index_files();
- die(_("cannot lock HEAD ref"));
- }
-
nl = strchr(sb.buf, '\n');
if (nl)
strbuf_setlen(&sb, nl + 1 - sb.buf);
@@ -1764,10 +1805,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
- if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
+ transaction = ref_transaction_begin(&err);
+ if (!transaction ||
+ ref_transaction_update(transaction, "HEAD", sha1,
+ current_head
+ ? current_head->object.sha1 : NULL,
+ 0, !!current_head, &err) ||
+ ref_transaction_commit(transaction, sb.buf, &err)) {
rollback_index_files();
- die(_("cannot update HEAD ref"));
+ die("%s", err.buf);
}
+ ref_transaction_free(transaction);
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
@@ -1778,7 +1826,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (commit_index_files())
die (_("Repository has been updated, but unable to write\n"
- "new_index file. Check that disk is not full or quota is\n"
+ "new_index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git reset HEAD\" to recover."));
rerere(0);
@@ -1796,5 +1844,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!quiet)
print_summary(prefix, sha1, !current_head);
+ strbuf_release(&err);
return 0;
}
diff --git a/builtin/config.c b/builtin/config.c
index fcd8474..aba7135 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -445,6 +445,20 @@ static int get_urlmatch(const char *var, const char *url)
return 0;
}
+static char *default_user_config(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf,
+ _("# This is Git's per-user configuration file.\n"
+ "[core]\n"
+ "# Please adapt and uncomment the following lines:\n"
+ "# user = %s\n"
+ "# email = %s\n"),
+ ident_default_name(),
+ ident_default_email());
+ return strbuf_detach(&buf, NULL);
+}
+
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
@@ -551,6 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
}
else if (actions == ACTION_EDIT) {
+ const char *config_file = given_config_source.file ?
+ given_config_source.file : git_path("config");
check_argc(argc, 0, 0);
if (!given_config_source.file && nongit)
die("not in a git directory");
@@ -559,9 +575,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (given_config_source.blob)
die("editing blobs is not supported");
git_config(git_default_config, NULL);
- launch_editor(given_config_source.file ?
- given_config_source.file : git_path("config"),
- NULL, NULL);
+ if (use_global_config) {
+ int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd) {
+ char *content = default_user_config();
+ write_str_in_full(fd, content);
+ free(content);
+ close(fd);
+ }
+ else if (errno != EEXIST)
+ die_errno(_("cannot create configuration file %s"), config_file);
+ }
+ launch_editor(config_file, NULL, NULL);
}
else if (actions == ACTION_SET) {
int ret;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 92b4624..b8182c2 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -18,6 +18,7 @@
#include "parse-options.h"
#include "quote.h"
#include "remote.h"
+#include "blob.h"
static const char *fast_export_usage[] = {
N_("git fast-export [rev-list-opts]"),
@@ -34,6 +35,7 @@ static int full_tree;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct refspec *refspecs;
static int refspecs_nr;
+static int anonymize;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
@@ -81,6 +83,76 @@ static int has_unshown_parent(struct commit *commit)
return 0;
}
+struct anonymized_entry {
+ struct hashmap_entry hash;
+ const char *orig;
+ size_t orig_len;
+ const char *anon;
+ size_t anon_len;
+};
+
+static int anonymized_entry_cmp(const void *va, const void *vb,
+ const void *data)
+{
+ const struct anonymized_entry *a = va, *b = vb;
+ return a->orig_len != b->orig_len ||
+ memcmp(a->orig, b->orig, a->orig_len);
+}
+
+/*
+ * Basically keep a cache of X->Y so that we can repeatedly replace
+ * the same anonymized string with another. The actual generation
+ * is farmed out to the generate function.
+ */
+static const void *anonymize_mem(struct hashmap *map,
+ void *(*generate)(const void *, size_t *),
+ const void *orig, size_t *len)
+{
+ struct anonymized_entry key, *ret;
+
+ if (!map->cmpfn)
+ hashmap_init(map, anonymized_entry_cmp, 0);
+
+ hashmap_entry_init(&key, memhash(orig, *len));
+ key.orig = orig;
+ key.orig_len = *len;
+ ret = hashmap_get(map, &key, NULL);
+
+ if (!ret) {
+ ret = xmalloc(sizeof(*ret));
+ hashmap_entry_init(&ret->hash, key.hash.hash);
+ ret->orig = xstrdup(orig);
+ ret->orig_len = *len;
+ ret->anon = generate(orig, len);
+ ret->anon_len = *len;
+ hashmap_put(map, ret);
+ }
+
+ *len = ret->anon_len;
+ return ret->anon;
+}
+
+/*
+ * We anonymize each component of a path individually,
+ * so that paths a/b and a/c will share a common root.
+ * The paths are cached via anonymize_mem so that repeated
+ * lookups for "a" will yield the same value.
+ */
+static void anonymize_path(struct strbuf *out, const char *path,
+ struct hashmap *map,
+ void *(*generate)(const void *, size_t *))
+{
+ while (*path) {
+ const char *end_of_component = strchrnul(path, '/');
+ size_t len = end_of_component - path;
+ const char *c = anonymize_mem(map, generate, path, &len);
+ strbuf_add(out, c, len);
+ path = end_of_component;
+ if (*path)
+ strbuf_addch(out, *path++);
+ }
+}
+
/* Since intptr_t is C99, we do not use it here */
static inline uint32_t *mark_to_ptr(uint32_t mark)
{
@@ -119,6 +191,26 @@ static void show_progress(void)
printf("progress %d objects\n", counter);
}
+/*
+ * Ideally we would want some transformation of the blob data here
+ * that is unreversible, but would still be the same size and have
+ * the same data relationship to other blobs (so that we get the same
+ * delta and packing behavior as the original). But the first and last
+ * requirements there are probably mutually exclusive, so let's take
+ * the easy way out for now, and just generate arbitrary content.
+ *
+ * There's no need to cache this result with anonymize_mem, since
+ * we already handle blob content caching with marks.
+ */
+static char *anonymize_blob(unsigned long *size)
+{
+ static int counter;
+ struct strbuf out = STRBUF_INIT;
+ strbuf_addf(&out, "anonymous blob %d", counter++);
+ *size = out.len;
+ return strbuf_detach(&out, NULL);
+}
+
static void export_blob(const unsigned char *sha1)
{
unsigned long size;
@@ -137,12 +229,19 @@ static void export_blob(const unsigned char *sha1)
if (object && object->flags & SHOWN)
return;
- buf = read_sha1_file(sha1, &type, &size);
- if (!buf)
- die ("Could not read blob %s", sha1_to_hex(sha1));
- if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
- die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
- object = parse_object_buffer(sha1, type, size, buf, &eaten);
+ if (anonymize) {
+ buf = anonymize_blob(&size);
+ object = (struct object *)lookup_blob(sha1);
+ eaten = 0;
+ } else {
+ buf = read_sha1_file(sha1, &type, &size);
+ if (!buf)
+ die ("Could not read blob %s", sha1_to_hex(sha1));
+ if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
+ die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
+ object = parse_object_buffer(sha1, type, size, buf, &eaten);
+ }
+
if (!object)
die("Could not read blob %s", sha1_to_hex(sha1));
@@ -190,7 +289,7 @@ static int depth_first(const void *a_, const void *b_)
return (a->status == 'R') - (b->status == 'R');
}
-static void print_path(const char *path)
+static void print_path_1(const char *path)
{
int need_quote = quote_c_style(path, NULL, NULL, 0);
if (need_quote)
@@ -201,6 +300,43 @@ static void print_path(const char *path)
printf("%s", path);
}
+static void *anonymize_path_component(const void *path, size_t *len)
+{
+ static int counter;
+ struct strbuf out = STRBUF_INIT;
+ strbuf_addf(&out, "path%d", counter++);
+ return strbuf_detach(&out, len);
+}
+
+static void print_path(const char *path)
+{
+ if (!anonymize)
+ print_path_1(path);
+ else {
+ static struct hashmap paths;
+ static struct strbuf anon = STRBUF_INIT;
+
+ anonymize_path(&anon, path, &paths, anonymize_path_component);
+ print_path_1(anon.buf);
+ strbuf_reset(&anon);
+ }
+}
+
+static void *generate_fake_sha1(const void *old, size_t *len)
+{
+ static uint32_t counter = 1; /* avoid null sha1 */
+ unsigned char *out = xcalloc(20, 1);
+ put_be32(out + 16, counter++);
+ return out;
+}
+
+static const unsigned char *anonymize_sha1(const unsigned char *sha1)
+{
+ static struct hashmap sha1s;
+ size_t len = 20;
+ return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len);
+}
+
static void show_filemodify(struct diff_queue_struct *q,
struct diff_options *options, void *data)
{
@@ -245,7 +381,9 @@ static void show_filemodify(struct diff_queue_struct *q,
*/
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s ", spec->mode,
- sha1_to_hex(spec->sha1));
+ sha1_to_hex(anonymize ?
+ anonymize_sha1(spec->sha1) :
+ spec->sha1));
else {
struct object *object = lookup_object(spec->sha1);
printf("M %06o :%d ", spec->mode,
@@ -279,6 +417,114 @@ static const char *find_encoding(const char *begin, const char *end)
return bol;
}
+static void *anonymize_ref_component(const void *old, size_t *len)
+{
+ static int counter;
+ struct strbuf out = STRBUF_INIT;
+ strbuf_addf(&out, "ref%d", counter++);
+ return strbuf_detach(&out, len);
+}
+
+static const char *anonymize_refname(const char *refname)
+{
+ /*
+ * If any of these prefixes is found, we will leave it intact
+ * so that tags remain tags and so forth.
+ */
+ static const char *prefixes[] = {
+ "refs/heads/",
+ "refs/tags/",
+ "refs/remotes/",
+ "refs/"
+ };
+ static struct hashmap refs;
+ static struct strbuf anon = STRBUF_INIT;
+ int i;
+
+ /*
+ * We also leave "master" as a special case, since it does not reveal
+ * anything interesting.
+ */
+ if (!strcmp(refname, "refs/heads/master"))
+ return refname;
+
+ strbuf_reset(&anon);
+ for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
+ if (skip_prefix(refname, prefixes[i], &refname)) {
+ strbuf_addstr(&anon, prefixes[i]);
+ break;
+ }
+ }
+
+ anonymize_path(&anon, refname, &refs, anonymize_ref_component);
+ return anon.buf;
+}
+
+/*
+ * We do not even bother to cache commit messages, as they are unlikely
+ * to be repeated verbatim, and it is not that interesting when they are.
+ */
+static char *anonymize_commit_message(const char *old)
+{
+ static int counter;
+ return xstrfmt("subject %d\n\nbody\n", counter++);
+}
+
+static struct hashmap idents;
+static void *anonymize_ident(const void *old, size_t *len)
+{
+ static int counter;
+ struct strbuf out = STRBUF_INIT;
+ strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
+ counter++;
+ return strbuf_detach(&out, len);
+}
+
+/*
+ * Our strategy here is to anonymize the names and email addresses,
+ * but keep timestamps intact, as they influence things like traversal
+ * order (and by themselves should not be too revealing).
+ */
+static void anonymize_ident_line(const char **beg, const char **end)
+{
+ static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
+ static unsigned which_buffer;
+
+ struct strbuf *out;
+ struct ident_split split;
+ const char *end_of_header;
+
+ out = &buffers[which_buffer++];
+ which_buffer %= ARRAY_SIZE(buffers);
+ strbuf_reset(out);
+
+ /* skip "committer", "author", "tagger", etc */
+ end_of_header = strchr(*beg, ' ');
+ if (!end_of_header)
+ die("BUG: malformed line fed to anonymize_ident_line: %.*s",
+ (int)(*end - *beg), *beg);
+ end_of_header++;
+ strbuf_add(out, *beg, end_of_header - *beg);
+
+ if (!split_ident_line(&split, end_of_header, *end - end_of_header) &&
+ split.date_begin) {
+ const char *ident;
+ size_t len;
+
+ len = split.mail_end - split.name_begin;
+ ident = anonymize_mem(&idents, anonymize_ident,
+ split.name_begin, &len);
+ strbuf_add(out, ident, len);
+ strbuf_addch(out, ' ');
+ strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
+ } else {
+ strbuf_addstr(out, "Malformed Ident <malformed@example.com> 0 -0000");
+ }
+
+ *beg = out->buf;
+ *end = out->buf + out->len;
+}
+
static void handle_commit(struct commit *commit, struct rev_info *rev)
{
int saved_output_format = rev->diffopt.output_format;
@@ -287,6 +533,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
const char *encoding, *message;
char *reencoded = NULL;
struct commit_list *p;
+ const char *refname;
int i;
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
@@ -326,13 +573,22 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
export_blob(diff_queued_diff.queue[i]->two->sha1);
+ refname = commit->util;
+ if (anonymize) {
+ refname = anonymize_refname(refname);
+ anonymize_ident_line(&committer, &committer_end);
+ anonymize_ident_line(&author, &author_end);
+ }
+
mark_next_object(&commit->object);
- if (!is_encoding_utf8(encoding))
+ if (anonymize)
+ reencoded = anonymize_commit_message(message);
+ else if (!is_encoding_utf8(encoding))
reencoded = reencode_string(message, "UTF-8", encoding);
if (!commit->parents)
- printf("reset %s\n", (const char*)commit->util);
+ printf("reset %s\n", refname);
printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
- (const char *)commit->util, last_idnum,
+ refname, last_idnum,
(int)(author_end - author), author,
(int)(committer_end - committer), committer,
(unsigned)(reencoded
@@ -363,6 +619,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
show_progress();
}
+static void *anonymize_tag(const void *old, size_t *len)
+{
+ static int counter;
+ struct strbuf out = STRBUF_INIT;
+ strbuf_addf(&out, "tag message %d", counter++);
+ return strbuf_detach(&out, len);
+}
+
static void handle_tail(struct object_array *commits, struct rev_info *revs)
{
struct commit *commit;
@@ -419,6 +683,17 @@ static void handle_tag(const char *name, struct tag *tag)
} else {
tagger++;
tagger_end = strchrnul(tagger, '\n');
+ if (anonymize)
+ anonymize_ident_line(&tagger, &tagger_end);
+ }
+
+ if (anonymize) {
+ name = anonymize_refname(name);
+ if (message) {
+ static struct hashmap tags;
+ message = anonymize_mem(&tags, anonymize_tag,
+ message, &message_size);
+ }
}
/* handle signed tags */
@@ -584,6 +859,8 @@ static void handle_tags_and_duplicates(void)
handle_tag(name, (struct tag *)object);
break;
case OBJ_COMMIT:
+ if (anonymize)
+ name = anonymize_refname(name);
/* create refs pointing to already seen commits */
commit = (struct commit *)object;
printf("reset %s\nfrom :%d\n\n", name,
@@ -719,6 +996,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
N_("Apply refspec to exported refs")),
+ OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
OPT_END()
};
diff --git a/builtin/fetch.c b/builtin/fetch.c
index e8d0cca..159fb7e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1110,9 +1110,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct string_list list = STRING_LIST_INIT_NODUP;
struct remote *remote;
int result = 0;
- static const char *argv_gc_auto[] = {
- "gc", "--auto", NULL,
- };
+ struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
packet_trace_identity("fetch");
@@ -1198,7 +1196,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
list.strdup_strings = 1;
string_list_clear(&list, 0);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
+ if (verbosity < 0)
+ argv_array_push(&argv_gc_auto, "--quiet");
+ run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);
+ argv_array_clear(&argv_gc_auto);
return result;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index 8d219d8..ced1456 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -55,44 +55,33 @@ static void remove_pidfile_on_signal(int signo)
raise(signo);
}
-static int gc_config(const char *var, const char *value, void *cb)
+static void gc_config(void)
{
- if (!strcmp(var, "gc.packrefs")) {
+ const char *value;
+
+ if (!git_config_get_value("gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
pack_refs = -1;
else
- pack_refs = git_config_bool(var, value);
- return 0;
- }
- if (!strcmp(var, "gc.aggressivewindow")) {
- aggressive_window = git_config_int(var, value);
- return 0;
- }
- if (!strcmp(var, "gc.aggressivedepth")) {
- aggressive_depth = git_config_int(var, value);
- return 0;
- }
- if (!strcmp(var, "gc.auto")) {
- gc_auto_threshold = git_config_int(var, value);
- return 0;
- }
- if (!strcmp(var, "gc.autopacklimit")) {
- gc_auto_pack_limit = git_config_int(var, value);
- return 0;
+ pack_refs = git_config_bool("gc.packrefs", value);
}
- if (!strcmp(var, "gc.autodetach")) {
- detach_auto = git_config_bool(var, value);
- return 0;
- }
- if (!strcmp(var, "gc.pruneexpire")) {
- if (value && strcmp(value, "now")) {
+
+ git_config_get_int("gc.aggressivewindow", &aggressive_window);
+ git_config_get_int("gc.aggressivedepth", &aggressive_depth);
+ git_config_get_int("gc.auto", &gc_auto_threshold);
+ git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
+ git_config_get_bool("gc.autodetach", &detach_auto);
+
+ if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) {
+ if (strcmp(prune_expire, "now")) {
unsigned long now = approxidate("now");
- if (approxidate(value) >= now)
- return error(_("Invalid %s: '%s'"), var, value);
+ if (approxidate(prune_expire) >= now) {
+ git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"),
+ prune_expire);
+ }
}
- return git_config_string(&prune_expire, var, value);
}
- return git_default_config(var, value, cb);
+ git_config(git_default_config, NULL);
}
static int too_many_loose_objects(void)
@@ -301,7 +290,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
argv_array_pushl(&prune, "prune", "--expire", NULL );
argv_array_pushl(&rerere, "rerere", "gc", NULL);
- git_config(gc_config, NULL);
+ gc_config();
if (pack_refs < 0)
pack_refs = !is_bare_repository();
diff --git a/builtin/help.c b/builtin/help.c
index 1fdefeb..8343b40 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -79,12 +79,11 @@ static const char *get_man_viewer_info(const char *name)
static int check_emacsclient_version(void)
{
struct strbuf buffer = STRBUF_INIT;
- struct child_process ec_process;
+ struct child_process ec_process = CHILD_PROCESS_INIT;
const char *argv_ec[] = { "emacsclient", "--version", NULL };
int version;
/* emacsclient prints its version number on stderr */
- memset(&ec_process, 0, sizeof(ec_process));
ec_process.argv = argv_ec;
ec_process.err = -1;
ec_process.stdout_to_stderr = 1;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 5568a5b..eebf1a8 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -112,6 +112,10 @@ static pthread_mutex_t deepest_delta_mutex;
#define deepest_delta_lock() lock_mutex(&deepest_delta_mutex)
#define deepest_delta_unlock() unlock_mutex(&deepest_delta_mutex)
+static pthread_mutex_t type_cas_mutex;
+#define type_cas_lock() lock_mutex(&type_cas_mutex)
+#define type_cas_unlock() unlock_mutex(&type_cas_mutex)
+
static pthread_key_t key;
static inline void lock_mutex(pthread_mutex_t *mutex)
@@ -135,6 +139,7 @@ static void init_thread(void)
init_recursive_mutex(&read_mutex);
pthread_mutex_init(&counter_mutex, NULL);
pthread_mutex_init(&work_mutex, NULL);
+ pthread_mutex_init(&type_cas_mutex, NULL);
if (show_stat)
pthread_mutex_init(&deepest_delta_mutex, NULL);
pthread_key_create(&key, NULL);
@@ -157,6 +162,7 @@ static void cleanup_thread(void)
pthread_mutex_destroy(&read_mutex);
pthread_mutex_destroy(&counter_mutex);
pthread_mutex_destroy(&work_mutex);
+ pthread_mutex_destroy(&type_cas_mutex);
if (show_stat)
pthread_mutex_destroy(&deepest_delta_mutex);
for (i = 0; i < nr_threads; i++)
@@ -862,7 +868,6 @@ static void resolve_delta(struct object_entry *delta_obj,
{
void *base_data, *delta_data;
- delta_obj->real_type = base->obj->real_type;
if (show_stat) {
delta_obj->delta_depth = base->obj->delta_depth + 1;
deepest_delta_lock();
@@ -888,6 +893,26 @@ static void resolve_delta(struct object_entry *delta_obj,
counter_unlock();
}
+/*
+ * Standard boolean compare-and-swap: atomically check whether "*type" is
+ * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched
+ * and return false.
+ */
+static int compare_and_swap_type(enum object_type *type,
+ enum object_type want,
+ enum object_type set)
+{
+ enum object_type old;
+
+ type_cas_lock();
+ old = *type;
+ if (old == want)
+ *type = set;
+ type_cas_unlock();
+
+ return old == want;
+}
+
static struct base_data *find_unresolved_deltas_1(struct base_data *base,
struct base_data *prev_base)
{
@@ -915,7 +940,10 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
struct object_entry *child = objects + deltas[base->ref_first].obj_no;
struct base_data *result = alloc_base_data();
- assert(child->real_type == OBJ_REF_DELTA);
+ if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
+ base->obj->real_type))
+ die("BUG: child->real_type != OBJ_REF_DELTA");
+
resolve_delta(child, base, result);
if (base->ref_first == base->ref_last && base->ofs_last == -1)
free_base_data(base);
@@ -929,6 +957,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
struct base_data *result = alloc_base_data();
assert(child->real_type == OBJ_OFS_DELTA);
+ child->real_type = base->obj->real_type;
resolve_delta(child, base, result);
if (base->ofs_first == base->ofs_last)
free_base_data(base);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 56f85e2..587a505 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -330,12 +330,12 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir,
* moving the target repo later on in separate_git_dir()
*/
git_link = xstrdup(real_path(git_dir));
+ set_git_dir(real_path(real_git_dir));
}
else {
- real_git_dir = real_path(git_dir);
+ set_git_dir(real_path(git_dir));
git_link = NULL;
}
- set_git_dir(real_path(real_git_dir));
return 0;
}
@@ -426,8 +426,9 @@ int init_db(const char *template_dir, unsigned int flags)
static int guess_repository_type(const char *git_dir)
{
- char cwd[PATH_MAX];
const char *slash;
+ char *cwd;
+ int cwd_is_git_dir;
/*
* "GIT_DIR=. git init" is always bare.
@@ -435,9 +436,10 @@ static int guess_repository_type(const char *git_dir)
*/
if (!strcmp(".", git_dir))
return 1;
- if (!getcwd(cwd, sizeof(cwd)))
- die_errno(_("cannot tell cwd"));
- if (!strcmp(git_dir, cwd))
+ cwd = xgetcwd();
+ cwd_is_git_dir = !strcmp(git_dir, cwd);
+ free(cwd);
+ if (cwd_is_git_dir)
return 1;
/*
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
@@ -535,10 +537,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
usage(init_db_usage[0]);
}
if (is_bare_repository_cfg == 1) {
- static char git_dir[PATH_MAX+1];
-
- setenv(GIT_DIR_ENVIRONMENT,
- getcwd(git_dir, sizeof(git_dir)), argc > 0);
+ char *cwd = xgetcwd();
+ setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
+ free(cwd);
}
if (init_shared_repository != -1)
@@ -572,13 +573,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
git_work_tree_cfg = xstrdup(real_path(rel));
free(rel);
}
- if (!git_work_tree_cfg) {
- git_work_tree_cfg = xcalloc(PATH_MAX, 1);
- if (!getcwd(git_work_tree_cfg, PATH_MAX))
- die_errno (_("Cannot access current working directory"));
- }
+ if (!git_work_tree_cfg)
+ git_work_tree_cfg = xgetcwd();
if (work_tree)
- set_git_work_tree(real_path(work_tree));
+ set_git_work_tree(work_tree);
else
set_git_work_tree(git_work_tree_cfg);
if (access(get_git_work_tree(), X_OK))
@@ -587,7 +585,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
}
else {
if (work_tree)
- set_git_work_tree(real_path(work_tree));
+ set_git_work_tree(work_tree);
}
set_git_dir_init(git_dir, real_git_dir, 1);
diff --git a/builtin/log.c b/builtin/log.c
index 4389722..e4d8122 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -864,6 +864,7 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name)
strbuf_addbuf(buf, &desc);
strbuf_addch(buf, '\n');
}
+ strbuf_release(&desc);
}
static char *find_branch_name(struct rev_info *rev)
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 47c3880..99cee20 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -474,7 +474,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
OPT_BOOL('k', "killed", &show_killed,
N_("show files on the filesystem that need to be removed")),
OPT_BIT(0, "directory", &dir.flags,
- N_("show 'other' directories' name only"),
+ N_("show 'other' directories' names only"),
DIR_SHOW_OTHER_DIRECTORIES),
OPT_NEGBIT(0, "empty-directory", &dir.flags,
N_("don't show empty directories"),
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 06296d4..763cda0 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -53,14 +53,16 @@ static int keep_cr;
*/
static int split_one(FILE *mbox, const char *name, int allow_bare)
{
- FILE *output = NULL;
+ FILE *output;
int fd;
int status = 0;
int is_bare = !is_from_line(buf.buf, buf.len);
- if (is_bare && !allow_bare)
- goto corrupt;
-
+ if (is_bare && !allow_bare) {
+ unlink(name);
+ fprintf(stderr, "corrupt mailbox\n");
+ exit(1);
+ }
fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0)
die_errno("cannot open output file '%s'", name);
@@ -91,13 +93,6 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
}
fclose(output);
return status;
-
- corrupt:
- if (output)
- fclose(output);
- unlink(name);
- fprintf(stderr, "corrupt mailbox\n");
- exit(1);
}
static int populate_maildir_list(struct string_list *list, const char *path)
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 61cbde4..f9ab485 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -25,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
merge_result_end = &entry->next;
}
-static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
+static void merge_trees(struct tree_desc t[3], const char *base);
static const char *explanation(struct merge_list *entry)
{
@@ -195,8 +195,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
add_merge_entry(final);
}
-static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
- int df_conflict)
+static void unresolved_directory(const struct traverse_info *info,
+ struct name_entry n[3])
{
char *newbase;
struct name_entry *p;
@@ -218,7 +218,7 @@ static void unresolved_directory(const struct traverse_info *info, struct name_e
buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
#undef ENTRY_SHA1
- merge_trees_recursive(t, newbase, df_conflict);
+ merge_trees(t, newbase);
free(buf0);
free(buf1);
@@ -259,7 +259,7 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
dirmask |= (1 << i);
}
- unresolved_directory(info, n, dirmask && (dirmask != mask));
+ unresolved_directory(info, n);
if (dirmask == mask)
return;
@@ -335,21 +335,15 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
return mask;
}
-static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
+static void merge_trees(struct tree_desc t[3], const char *base)
{
struct traverse_info info;
setup_traverse_info(&info, base);
- info.data = &df_conflict;
info.fn = threeway_callback;
traverse_trees(3, t, &info);
}
-static void merge_trees(struct tree_desc t[3], const char *base)
-{
- merge_trees_recursive(t, base, 0);
-}
-
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
{
unsigned char sha1[20];
diff --git a/builtin/merge.c b/builtin/merge.c
index ce82eb2..ec6fa93 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -237,11 +237,10 @@ static void drop_save(void)
static int save_state(unsigned char *stash)
{
int len;
- struct child_process cp;
+ struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf buffer = STRBUF_INIT;
const char *argv[] = {"stash", "create", NULL};
- memset(&cp, 0, sizeof(cp));
cp.argv = argv;
cp.out = -1;
cp.git_cmd = 1;
@@ -1144,14 +1143,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
*/
if (advice_resolve_conflict)
die(_("You have not concluded your merge (MERGE_HEAD exists).\n"
- "Please, commit your changes before you can merge."));
+ "Please, commit your changes before you merge."));
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
- "Please, commit your changes before you can merge."));
+ "Please, commit your changes before you merge."));
else
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
}
diff --git a/builtin/mv.c b/builtin/mv.c
index 6ffe540..bf784cb 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -61,6 +61,46 @@ static const char *add_slash(const char *path)
static struct lock_file lock_file;
#define SUBMODULE_WITH_GITDIR ((const char *)1)
+static void prepare_move_submodule(const char *src, int first,
+ const char **submodule_gitfile)
+{
+ struct strbuf submodule_dotgit = STRBUF_INIT;
+ if (!S_ISGITLINK(active_cache[first]->ce_mode))
+ die(_("Directory %s is in index and no submodule?"), src);
+ if (!is_staging_gitmodules_ok())
+ die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+ strbuf_addf(&submodule_dotgit, "%s/.git", src);
+ *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
+ if (*submodule_gitfile)
+ *submodule_gitfile = xstrdup(*submodule_gitfile);
+ else
+ *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+ strbuf_release(&submodule_dotgit);
+}
+
+static int index_range_of_same_dir(const char *src, int length,
+ int *first_p, int *last_p)
+{
+ const char *src_w_slash = add_slash(src);
+ int first, last, len_w_slash = length + 1;
+
+ first = cache_name_pos(src_w_slash, len_w_slash);
+ if (first >= 0)
+ die(_("%.*s is in index"), len_w_slash, src_w_slash);
+
+ first = -1 - first;
+ for (last = first; last < active_nr; last++) {
+ const char *path = active_cache[last]->name;
+ if (strncmp(path, src_w_slash, len_w_slash))
+ break;
+ }
+ if (src_w_slash != src)
+ free((char *)src_w_slash);
+ *first_p = first;
+ *last_p = last;
+ return last - first;
+}
+
int cmd_mv(int argc, const char **argv, const char *prefix)
{
int i, gitmodules_modified = 0;
@@ -108,7 +148,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
} else {
if (argc != 1)
- die("destination '%s' is not a directory", dest_path[0]);
+ die(_("destination '%s' is not a directory"), dest_path[0]);
destination = dest_path;
}
@@ -131,75 +171,36 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
&& lstat(dst, &st) == 0)
bad = _("cannot move directory over file");
else if (src_is_dir) {
- int first = cache_name_pos(src, length);
- if (first >= 0) {
- struct strbuf submodule_dotgit = STRBUF_INIT;
- if (!S_ISGITLINK(active_cache[first]->ce_mode))
- die (_("Huh? Directory %s is in index and no submodule?"), src);
- if (!is_staging_gitmodules_ok())
- die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
- strbuf_addf(&submodule_dotgit, "%s/.git", src);
- submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
- if (submodule_gitfile[i])
- submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
- else
- submodule_gitfile[i] = SUBMODULE_WITH_GITDIR;
- strbuf_release(&submodule_dotgit);
- } else {
- const char *src_w_slash = add_slash(src);
- int last, len_w_slash = length + 1;
+ int first = cache_name_pos(src, length), last;
- modes[i] = WORKING_DIRECTORY;
+ if (first >= 0)
+ prepare_move_submodule(src, first,
+ submodule_gitfile + i);
+ else if (index_range_of_same_dir(src, length,
+ &first, &last) < 1)
+ bad = _("source directory is empty");
+ else { /* last - first >= 1 */
+ int j, dst_len, n;
- first = cache_name_pos(src_w_slash, len_w_slash);
- if (first >= 0)
- die (_("Huh? %.*s is in index?"),
- len_w_slash, src_w_slash);
-
- first = -1 - first;
- for (last = first; last < active_nr; last++) {
- const char *path = active_cache[last]->name;
- if (strncmp(path, src_w_slash, len_w_slash))
- break;
- }
- if (src_w_slash != src)
- free((char *)src_w_slash);
-
- if (last - first < 1)
- bad = _("source directory is empty");
- else {
- int j, dst_len;
-
- if (last - first > 0) {
- source = xrealloc(source,
- (argc + last - first)
- * sizeof(char *));
- destination = xrealloc(destination,
- (argc + last - first)
- * sizeof(char *));
- modes = xrealloc(modes,
- (argc + last - first)
- * sizeof(enum update_mode));
- submodule_gitfile = xrealloc(submodule_gitfile,
- (argc + last - first)
- * sizeof(char *));
- }
+ modes[i] = WORKING_DIRECTORY;
+ n = argc + last - first;
+ source = xrealloc(source, n * sizeof(char *));
+ destination = xrealloc(destination, n * sizeof(char *));
+ modes = xrealloc(modes, n * sizeof(enum update_mode));
+ submodule_gitfile = xrealloc(submodule_gitfile, n * sizeof(char *));
- dst = add_slash(dst);
- dst_len = strlen(dst);
+ dst = add_slash(dst);
+ dst_len = strlen(dst);
- for (j = 0; j < last - first; j++) {
- const char *path =
- active_cache[first + j]->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len,
- path + length + 1);
- modes[argc + j] = INDEX;
- submodule_gitfile[argc + j] = NULL;
- }
- argc += last - first;
+ for (j = 0; j < last - first; j++) {
+ const char *path = active_cache[first + j]->name;
+ source[argc + j] = path;
+ destination[argc + j] =
+ prefix_path(dst, dst_len, path + length + 1);
+ modes[argc + j] = INDEX;
+ submodule_gitfile[argc + j] = NULL;
}
+ argc += last - first;
}
} else if (cache_name_pos(src, length) < 0)
bad = _("not under version control");
@@ -225,24 +226,22 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
else
string_list_insert(&src_for_dst, dst);
- if (bad) {
- if (ignore_errors) {
- if (--argc > 0) {
- memmove(source + i, source + i + 1,
- (argc - i) * sizeof(char *));
- memmove(destination + i,
- destination + i + 1,
- (argc - i) * sizeof(char *));
- memmove(modes + i, modes + i + 1,
- (argc - i) * sizeof(enum update_mode));
- memmove(submodule_gitfile + i,
- submodule_gitfile + i + 1,
- (argc - i) * sizeof(char *));
- i--;
- }
- } else
- die (_("%s, source=%s, destination=%s"),
- bad, src, dst);
+ if (!bad)
+ continue;
+ if (!ignore_errors)
+ die(_("%s, source=%s, destination=%s"),
+ bad, src, dst);
+ if (--argc > 0) {
+ int n = argc - i;
+ memmove(source + i, source + i + 1,
+ n * sizeof(char *));
+ memmove(destination + i, destination + i + 1,
+ n * sizeof(char *));
+ memmove(modes + i, modes + i + 1,
+ n * sizeof(enum update_mode));
+ memmove(submodule_gitfile + i, submodule_gitfile + i + 1,
+ n * sizeof(char *));
+ i--;
}
}
@@ -254,7 +253,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
printf(_("Renaming %s to %s\n"), src, dst);
if (!show_only && mode != INDEX) {
if (rename(src, dst) < 0 && !ignore_errors)
- die_errno (_("renaming '%s' failed"), src);
+ die_errno(_("renaming '%s' failed"), src);
if (submodule_gitfile[i]) {
if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
@@ -275,10 +274,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (gitmodules_modified)
stage_updated_gitmodules();
- if (active_cache_changed) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("Unable to write new index file"));
- }
+ if (active_cache_changed &&
+ write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ die(_("Unable to write new index file"));
return 0;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 820c341..67d0bb1 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -122,12 +122,11 @@ static void write_commented_object(int fd, const unsigned char *object)
{
const char *show_args[5] =
{"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
- struct child_process show;
+ struct child_process show = CHILD_PROCESS_INIT;
struct strbuf buf = STRBUF_INIT;
struct strbuf cbuf = STRBUF_INIT;
/* Invoke "git show --stat --no-notes $object" */
- memset(&show, 0, sizeof(show));
show.argv = show_args;
show.no_stdin = 1;
show.out = -1;
@@ -211,7 +210,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
error(_("unable to write note object"));
if (path)
- error(_("The note contents has been left in %s"),
+ error(_("The note contents have been left in %s"),
path);
exit(128);
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f93ac45..afb8d99 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -255,7 +255,7 @@ static int copy_to_sideband(int in, int out, void *arg)
typedef int (*feed_fn)(void *, const char **, size_t *);
static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
{
- struct child_process proc;
+ struct child_process proc = CHILD_PROCESS_INIT;
struct async muxer;
const char *argv[2];
int code;
@@ -266,7 +266,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
argv[1] = NULL;
- memset(&proc, 0, sizeof(proc));
proc.argv = argv;
proc.in = -1;
proc.stdout_to_stderr = 1;
@@ -350,7 +349,7 @@ static int run_receive_hook(struct command *commands, const char *hook_name,
static int run_update_hook(struct command *cmd)
{
const char *argv[5];
- struct child_process proc;
+ struct child_process proc = CHILD_PROCESS_INIT;
int code;
argv[0] = find_hook("update");
@@ -362,7 +361,6 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;
- memset(&proc, 0, sizeof(proc));
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
@@ -475,7 +473,6 @@ static const char *update(struct command *cmd, struct shallow_info *si)
const char *namespaced_name;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
- struct ref_lock *lock;
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -576,19 +573,27 @@ static const char *update(struct command *cmd, struct shallow_info *si)
return NULL; /* good */
}
else {
+ struct strbuf err = STRBUF_INIT;
+ struct ref_transaction *transaction;
+
if (shallow_update && si->shallow_ref[cmd->index] &&
update_shallow_ref(cmd, si))
return "shallow error";
- lock = lock_any_ref_for_update(namespaced_name, old_sha1,
- 0, NULL);
- if (!lock) {
- rp_error("failed to lock %s", name);
- return "failed to lock";
- }
- if (write_ref_sha1(lock, new_sha1, "push")) {
- return "failed to write"; /* error() already called */
+ transaction = ref_transaction_begin(&err);
+ if (!transaction ||
+ ref_transaction_update(transaction, namespaced_name,
+ new_sha1, old_sha1, 0, 1, &err) ||
+ ref_transaction_commit(transaction, "push", &err)) {
+ ref_transaction_free(transaction);
+
+ rp_error("%s", err.buf);
+ strbuf_release(&err);
+ return "failed to update ref";
}
+
+ ref_transaction_free(transaction);
+ strbuf_release(&err);
return NULL; /* good */
}
}
@@ -598,7 +603,7 @@ static void run_update_post_hook(struct command *commands)
struct command *cmd;
int argc;
const char **argv;
- struct child_process proc;
+ struct child_process proc = CHILD_PROCESS_INIT;
char *hook;
hook = find_hook("post-update");
@@ -621,7 +626,6 @@ static void run_update_post_hook(struct command *commands)
}
argv[argc] = NULL;
- memset(&proc, 0, sizeof(proc));
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
@@ -911,7 +915,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
const char *hdr_err;
int status;
char hdr_arg[38];
- struct child_process child;
+ struct child_process child = CHILD_PROCESS_INIT;
int fsck_objects = (receive_fsck_objects >= 0
? receive_fsck_objects
: transfer_fsck_objects >= 0
@@ -933,7 +937,6 @@ static const char *unpack(int err_fd, struct shallow_info *si)
argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL);
}
- memset(&child, 0, sizeof(child));
if (ntohl(hdr.hdr_entries) < unpack_limit) {
argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL);
if (quiet)
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 692c834..d699d28 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -179,9 +179,8 @@ static void send_git_request(int stdin_fd, const char *serv, const char *repo,
static int run_child(const char *arg, const char *service)
{
int r;
- struct child_process child;
+ struct child_process child = CHILD_PROCESS_INIT;
- memset(&child, 0, sizeof(child));
child.in = -1;
child.out = -1;
child.err = 0;
diff --git a/builtin/repack.c b/builtin/repack.c
index a77e743..fc088db 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -133,7 +133,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
{".idx"},
{".bitmap", 1},
};
- struct child_process cmd;
+ struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
struct argv_array cmd_args = ARGV_ARRAY_INIT;
struct string_list names = STRING_LIST_INIT_DUP;
@@ -250,7 +250,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd_args, packtmp);
- memset(&cmd, 0, sizeof(cmd));
cmd.argv = cmd_args.argv;
cmd.git_cmd = 1;
cmd.out = -1;
diff --git a/builtin/replace.c b/builtin/replace.c
index 294b61b..8020db8 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -155,7 +155,8 @@ static int replace_object_sha1(const char *object_ref,
unsigned char prev[20];
enum object_type obj_type, repl_type;
char ref[PATH_MAX];
- struct ref_lock *lock;
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
obj_type = sha1_object_info(object, NULL);
repl_type = sha1_object_info(repl, NULL);
@@ -168,12 +169,13 @@ static int replace_object_sha1(const char *object_ref,
check_ref_valid(object, prev, ref, sizeof(ref), force);
- lock = lock_any_ref_for_update(ref, prev, 0, NULL);
- if (!lock)
- die("%s: cannot lock the ref", ref);
- if (write_ref_sha1(lock, repl, NULL) < 0)
- die("%s: cannot update the ref", ref);
+ transaction = ref_transaction_begin(&err);
+ if (!transaction ||
+ ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) ||
+ ref_transaction_commit(transaction, NULL, &err))
+ die("%s", err.buf);
+ ref_transaction_free(transaction);
return 0;
}
@@ -197,7 +199,7 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
static void export_object(const unsigned char *sha1, enum object_type type,
int raw, const char *filename)
{
- struct child_process cmd = { NULL };
+ struct child_process cmd = CHILD_PROCESS_INIT;
int fd;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -234,7 +236,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
if (!raw && type == OBJ_TREE) {
const char *argv[] = { "mktree", NULL };
- struct child_process cmd = { argv };
+ struct child_process cmd = CHILD_PROCESS_INIT;
struct strbuf result = STRBUF_INIT;
cmd.argv = argv;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index d85e08c..c911b45 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -736,7 +736,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--git-dir")) {
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
- static char cwd[PATH_MAX];
+ char *cwd;
int len;
if (gitdir) {
puts(gitdir);
@@ -746,10 +746,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(".git");
continue;
}
- if (!getcwd(cwd, PATH_MAX))
- die_errno("unable to get current working directory");
+ cwd = xgetcwd();
len = strlen(cwd);
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
+ free(cwd);
continue;
}
if (!strcmp(arg, "--resolve-git-dir")) {
diff --git a/builtin/rm.c b/builtin/rm.c
index bc6490b..2b61d3b 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -65,7 +65,7 @@ static void error_removing_concrete_submodules(struct string_list *files, int *e
Q_("the following submodule (or one of its nested "
"submodules)\n"
"uses a .git directory:",
- "the following submodules (or one of its nested "
+ "the following submodules (or one of their nested "
"submodules)\n"
"use a .git directory:", files->nr),
_("\n(use 'rm -rf' if you really want to remove "
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index f420b74..4b1bc0f 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -110,6 +110,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int flags;
unsigned int reject_reasons;
int progress = -1;
+ int from_stdin = 0;
struct push_cas_option cas = {0};
argv++;
@@ -169,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.stateless_rpc = 1;
continue;
}
+ if (!strcmp(arg, "--stdin")) {
+ from_stdin = 1;
+ continue;
+ }
if (!strcmp(arg, "--helper-status")) {
helper_status = 1;
continue;
@@ -201,6 +206,28 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
}
if (!dest)
usage(send_pack_usage);
+
+ 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);
+ } else {
+ struct strbuf line = STRBUF_INIT;
+ while (strbuf_getline(&line, stdin, '\n') != EOF)
+ argv_array_push(&all_refspecs, 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.
diff --git a/builtin/tag.c b/builtin/tag.c
index 19eb747..a81b9e4 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -576,7 +576,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct strbuf ref = STRBUF_INIT;
unsigned char object[20], prev[20];
const char *object_ref, *tag;
- struct ref_lock *lock;
struct create_tag_options opt;
char *cleanup_arg = NULL;
int annotate = 0, force = 0, lines = -1;
@@ -584,6 +583,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
@@ -729,14 +730,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (annotate)
create_tag(object, tag, &buf, &opt, prev, object);
- lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
- if (!lock)
- die(_("%s: cannot lock the ref"), ref.buf);
- if (write_ref_sha1(lock, object, NULL) < 0)
- die(_("%s: cannot update the ref"), ref.buf);
+ transaction = ref_transaction_begin(&err);
+ if (!transaction ||
+ ref_transaction_update(transaction, ref.buf, object, prev,
+ 0, 1, &err) ||
+ ref_transaction_commit(transaction, NULL, &err))
+ die("%s", err.buf);
+ ref_transaction_free(transaction);
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
+ strbuf_release(&err);
strbuf_release(&buf);
strbuf_release(&ref);
return 0;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 3067b11..54a48c0 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -12,11 +12,8 @@ static const char * const git_update_ref_usage[] = {
NULL
};
-static struct ref_transaction *transaction;
-
static char line_termination = '\n';
static int update_flags;
-static struct strbuf err = STRBUF_INIT;
/*
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
@@ -177,8 +174,10 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
* depending on how line_termination is set.
*/
-static const char *parse_cmd_update(struct strbuf *input, const char *next)
+static const char *parse_cmd_update(struct ref_transaction *transaction,
+ struct strbuf *input, const char *next)
{
+ struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
@@ -204,12 +203,15 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
update_flags = 0;
free(refname);
+ strbuf_release(&err);
return next;
}
-static const char *parse_cmd_create(struct strbuf *input, const char *next)
+static const char *parse_cmd_create(struct ref_transaction *transaction,
+ struct strbuf *input, const char *next)
{
+ struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
@@ -226,16 +228,21 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- ref_transaction_create(transaction, refname, new_sha1, update_flags);
+ if (ref_transaction_create(transaction, refname, new_sha1,
+ update_flags, &err))
+ die("%s", err.buf);
update_flags = 0;
free(refname);
+ strbuf_release(&err);
return next;
}
-static const char *parse_cmd_delete(struct strbuf *input, const char *next)
+static const char *parse_cmd_delete(struct ref_transaction *transaction,
+ struct strbuf *input, const char *next)
{
+ struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char old_sha1[20];
int have_old;
@@ -256,17 +263,21 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
if (*next != line_termination)
die("delete %s: extra input: %s", refname, next);
- ref_transaction_delete(transaction, refname, old_sha1,
- update_flags, have_old);
+ if (ref_transaction_delete(transaction, refname, old_sha1,
+ update_flags, have_old, &err))
+ die("%s", err.buf);
update_flags = 0;
free(refname);
+ strbuf_release(&err);
return next;
}
-static const char *parse_cmd_verify(struct strbuf *input, const char *next)
+static const char *parse_cmd_verify(struct ref_transaction *transaction,
+ struct strbuf *input, const char *next)
{
+ struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
@@ -294,6 +305,7 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
update_flags = 0;
free(refname);
+ strbuf_release(&err);
return next;
}
@@ -307,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next)
return next + 8;
}
-static void update_refs_stdin(void)
+static void update_refs_stdin(struct ref_transaction *transaction)
{
struct strbuf input = STRBUF_INIT;
const char *next;
@@ -322,13 +334,13 @@ static void update_refs_stdin(void)
else if (isspace(*next))
die("whitespace before command: %s", next);
else if (starts_with(next, "update "))
- next = parse_cmd_update(&input, next + 7);
+ next = parse_cmd_update(transaction, &input, next + 7);
else if (starts_with(next, "create "))
- next = parse_cmd_create(&input, next + 7);
+ next = parse_cmd_create(transaction, &input, next + 7);
else if (starts_with(next, "delete "))
- next = parse_cmd_delete(&input, next + 7);
+ next = parse_cmd_delete(transaction, &input, next + 7);
else if (starts_with(next, "verify "))
- next = parse_cmd_verify(&input, next + 7);
+ next = parse_cmd_verify(transaction, &input, next + 7);
else if (starts_with(next, "option "))
next = parse_cmd_option(&input, next + 7);
else
@@ -362,15 +374,21 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
die("Refusing to perform update with empty message.");
if (read_stdin) {
- transaction = ref_transaction_begin();
+ struct strbuf err = STRBUF_INIT;
+ struct ref_transaction *transaction;
+
+ transaction = ref_transaction_begin(&err);
+ if (!transaction)
+ die("%s", err.buf);
if (delete || no_deref || argc > 0)
usage_with_options(git_update_ref_usage, options);
if (end_null)
line_termination = '\0';
- update_refs_stdin();
+ update_refs_stdin(transaction);
if (ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
+ strbuf_release(&err);
return 0;
}
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 972579f..7747537 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -8,7 +8,7 @@
static int verify_one_pack(const char *path, unsigned int flags)
{
- struct child_process index_pack;
+ struct child_process index_pack = CHILD_PROCESS_INIT;
const char *argv[] = {"index-pack", NULL, NULL, NULL };
struct strbuf arg = STRBUF_INIT;
int verbose = flags & VERIFY_PACK_VERBOSE;
@@ -32,7 +32,6 @@ static int verify_one_pack(const char *path, unsigned int flags)
strbuf_addstr(&arg, ".pack");
argv[2] = arg.buf;
- memset(&index_pack, 0, sizeof(index_pack));
index_pack.argv = argv;
index_pack.git_cmd = 1;