Merge 'jk/git-path' into kn/for-each-tag

* jk/git-path:
  memoize common git-path "constant" files
  get_repo_path: refactor path-allocation
  find_hook: keep our own static buffer
  refs.c: remove_empty_directories can take a strbuf
  refs.c: avoid git_path assignment in lock_ref_sha1_basic
  refs.c: avoid repeated git_path calls in rename_tmp_log
  refs.c: simplify strbufs in reflog setup and writing
  path.c: drop git_path_submodule
  refs.c: remove extra git_path calls from read_loose_refs
  remote.c: drop extraneous local variable from migrate_file
  prefer mkpathdup to mkpath in assignments
  prefer git_pathdup to git_path in some possibly-dangerous cases
  add_to_alternates_file: don't add duplicate entries
  t5700: modernize style
  cache.h: complete set of git_path_submodule helpers
  cache.h: clarify documentation for git_path, et al
maint
Junio C Hamano 2015-08-24 15:30:43 -07:00
commit 7b8419f094
30 changed files with 463 additions and 361 deletions

4
attr.c
View File

@ -490,6 +490,8 @@ static int git_attr_system(void)
return !git_env_bool("GIT_ATTR_NOSYSTEM", 0); return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
} }


static GIT_PATH_FUNC(git_path_info_attributes, INFOATTRIBUTES_FILE)

static void bootstrap_attr_stack(void) static void bootstrap_attr_stack(void)
{ {
struct attr_stack *elem; struct attr_stack *elem;
@ -531,7 +533,7 @@ static void bootstrap_attr_stack(void)
debug_push(elem); debug_push(elem);
} }


elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1); elem = read_attr_from_file(git_path_info_attributes(), 1);
if (!elem) if (!elem)
elem = xcalloc(1, sizeof(*elem)); elem = xcalloc(1, sizeof(*elem));
elem->origin = NULL; elem->origin = NULL;

View File

@ -420,10 +420,13 @@ static int read_bisect_refs(void)
return for_each_ref_in("refs/bisect/", register_ref, NULL); return for_each_ref_in("refs/bisect/", register_ref, NULL);
} }


static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")

static void read_bisect_paths(struct argv_array *array) static void read_bisect_paths(struct argv_array *array)
{ {
struct strbuf str = STRBUF_INIT; struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES"); const char *filename = git_path_bisect_names();
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename, "r");


if (!fp) if (!fp)
@ -644,7 +647,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,


static int is_expected_rev(const struct object_id *oid) static int is_expected_rev(const struct object_id *oid)
{ {
const char *filename = git_path("BISECT_EXPECTED_REV"); const char *filename = git_path_bisect_expected_rev();
struct stat st; struct stat st;
struct strbuf str = STRBUF_INIT; struct strbuf str = STRBUF_INIT;
FILE *fp; FILE *fp;

View File

@ -302,11 +302,11 @@ void create_branch(const char *head,


void remove_branch_state(void) void remove_branch_state(void)
{ {
unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path_cherry_pick_head());
unlink(git_path("REVERT_HEAD")); unlink(git_path_revert_head());
unlink(git_path("MERGE_HEAD")); unlink(git_path_merge_head());
unlink(git_path("MERGE_RR")); unlink(git_path_merge_rr());
unlink(git_path("MERGE_MSG")); unlink(git_path_merge_msg());
unlink(git_path("MERGE_MODE")); unlink(git_path_merge_mode());
unlink(git_path("SQUASH_MSG")); unlink(git_path_squash_msg());
} }

View File

@ -2227,20 +2227,19 @@ static struct commit_list **append_parent(struct commit_list **tail, const unsig
static void append_merge_parents(struct commit_list **tail) static void append_merge_parents(struct commit_list **tail)
{ {
int merge_head; int merge_head;
const char *merge_head_file = git_path("MERGE_HEAD");
struct strbuf line = STRBUF_INIT; struct strbuf line = STRBUF_INIT;


merge_head = open(merge_head_file, O_RDONLY); merge_head = open(git_path_merge_head(), O_RDONLY);
if (merge_head < 0) { if (merge_head < 0) {
if (errno == ENOENT) if (errno == ENOENT)
return; return;
die("cannot open '%s' for reading", merge_head_file); die("cannot open '%s' for reading", git_path_merge_head());
} }


while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
unsigned char sha1[20]; unsigned char sha1[20];
if (line.len < 40 || get_sha1_hex(line.buf, sha1)) if (line.len < 40 || get_sha1_hex(line.buf, sha1))
die("unknown line in '%s': %s", merge_head_file, line.buf); die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
tail = append_parent(tail, sha1); tail = append_parent(tail, sha1);
} }
close(merge_head); close(merge_head);

View File

@ -99,51 +99,66 @@ static const char *argv_submodule[] = {
"submodule", "update", "--init", "--recursive", NULL "submodule", "update", "--init", "--recursive", NULL
}; };


static char *get_repo_path(const char *repo, int *is_bundle) static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
{ {
static char *suffix[] = { "/.git", "", ".git/.git", ".git" }; static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
static char *bundle_suffix[] = { ".bundle", "" }; static char *bundle_suffix[] = { ".bundle", "" };
size_t baselen = path->len;
struct stat st; struct stat st;
int i; int i;


for (i = 0; i < ARRAY_SIZE(suffix); i++) { for (i = 0; i < ARRAY_SIZE(suffix); i++) {
const char *path; strbuf_setlen(path, baselen);
path = mkpath("%s%s", repo, suffix[i]); strbuf_addstr(path, suffix[i]);
if (stat(path, &st)) if (stat(path->buf, &st))
continue; continue;
if (S_ISDIR(st.st_mode) && is_git_directory(path)) { if (S_ISDIR(st.st_mode) && is_git_directory(path->buf)) {
*is_bundle = 0; *is_bundle = 0;
return xstrdup(absolute_path(path)); return path->buf;
} else if (S_ISREG(st.st_mode) && st.st_size > 8) { } else if (S_ISREG(st.st_mode) && st.st_size > 8) {
/* Is it a "gitfile"? */ /* Is it a "gitfile"? */
char signature[8]; char signature[8];
int len, fd = open(path, O_RDONLY); const char *dst;
int len, fd = open(path->buf, O_RDONLY);
if (fd < 0) if (fd < 0)
continue; continue;
len = read_in_full(fd, signature, 8); len = read_in_full(fd, signature, 8);
close(fd); close(fd);
if (len != 8 || strncmp(signature, "gitdir: ", 8)) if (len != 8 || strncmp(signature, "gitdir: ", 8))
continue; continue;
path = read_gitfile(path); dst = read_gitfile(path->buf);
if (path) { if (dst) {
*is_bundle = 0; *is_bundle = 0;
return xstrdup(absolute_path(path)); return dst;
} }
} }
} }


for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) { for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
const char *path; strbuf_setlen(path, baselen);
path = mkpath("%s%s", repo, bundle_suffix[i]); strbuf_addstr(path, bundle_suffix[i]);
if (!stat(path, &st) && S_ISREG(st.st_mode)) { if (!stat(path->buf, &st) && S_ISREG(st.st_mode)) {
*is_bundle = 1; *is_bundle = 1;
return xstrdup(absolute_path(path)); return path->buf;
} }
} }


return NULL; return NULL;
} }


static char *get_repo_path(const char *repo, int *is_bundle)
{
struct strbuf path = STRBUF_INIT;
const char *raw;
char *canon;

strbuf_addstr(&path, repo);
raw = get_repo_path_1(&path, is_bundle);
canon = raw ? xstrdup(absolute_path(raw)) : NULL;
strbuf_release(&path);
return canon;
}

static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{ {
const char *end = repo + strlen(repo), *start; const char *end = repo + strlen(repo), *start;

View File

@ -166,9 +166,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)


static void determine_whence(struct wt_status *s) static void determine_whence(struct wt_status *s)
{ {
if (file_exists(git_path("MERGE_HEAD"))) if (file_exists(git_path_merge_head()))
whence = FROM_MERGE; whence = FROM_MERGE;
else if (file_exists(git_path("CHERRY_PICK_HEAD"))) { else if (file_exists(git_path_cherry_pick_head())) {
whence = FROM_CHERRY_PICK; whence = FROM_CHERRY_PICK;
if (file_exists(git_path(SEQ_DIR))) if (file_exists(git_path(SEQ_DIR)))
sequencer_in_use = 1; sequencer_in_use = 1;
@ -725,12 +725,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
format_commit_message(commit, "fixup! %s\n\n", format_commit_message(commit, "fixup! %s\n\n",
&sb, &ctx); &sb, &ctx);
hook_arg1 = "message"; hook_arg1 = "message";
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) { } else if (!stat(git_path_merge_msg(), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
die_errno(_("could not read MERGE_MSG")); die_errno(_("could not read MERGE_MSG"));
hook_arg1 = "merge"; hook_arg1 = "merge";
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { } else if (!stat(git_path_squash_msg(), &statbuf)) {
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
die_errno(_("could not read SQUASH_MSG")); die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash"; hook_arg1 = "squash";
} else if (template_file) { } else if (template_file) {
@ -1684,10 +1684,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!reflog_msg) if (!reflog_msg)
reflog_msg = "commit (merge)"; reflog_msg = "commit (merge)";
pptr = &commit_list_insert(current_head, pptr)->next; pptr = &commit_list_insert(current_head, pptr)->next;
fp = fopen(git_path("MERGE_HEAD"), "r"); fp = fopen(git_path_merge_head(), "r");
if (fp == NULL) if (fp == NULL)
die_errno(_("could not open '%s' for reading"), die_errno(_("could not open '%s' for reading"),
git_path("MERGE_HEAD")); git_path_merge_head());
while (strbuf_getline(&m, fp, '\n') != EOF) { while (strbuf_getline(&m, fp, '\n') != EOF) {
struct commit *parent; struct commit *parent;


@ -1698,8 +1698,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
} }
fclose(fp); fclose(fp);
strbuf_release(&m); strbuf_release(&m);
if (!stat(git_path("MERGE_MODE"), &statbuf)) { if (!stat(git_path_merge_mode(), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0) if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
die_errno(_("could not read MERGE_MODE")); die_errno(_("could not read MERGE_MODE"));
if (!strcmp(sb.buf, "no-ff")) if (!strcmp(sb.buf, "no-ff"))
allow_fast_forward = 0; allow_fast_forward = 0;
@ -1775,12 +1775,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
} }
ref_transaction_free(transaction); ref_transaction_free(transaction);


unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path_cherry_pick_head());
unlink(git_path("REVERT_HEAD")); unlink(git_path_revert_head());
unlink(git_path("MERGE_HEAD")); unlink(git_path_merge_head());
unlink(git_path("MERGE_MSG")); unlink(git_path_merge_msg());
unlink(git_path("MERGE_MODE")); unlink(git_path_merge_mode());
unlink(git_path("SQUASH_MSG")); unlink(git_path_squash_msg());


if (commit_index_files()) if (commit_index_files())
die (_("Repository has been updated, but unable to write\n" die (_("Repository has been updated, but unable to write\n"

View File

@ -591,7 +591,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
const char *what, *kind; const char *what, *kind;
struct ref *rm; struct ref *rm;
char *url; char *url;
const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD"); const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
int want_status; int want_status;


fp = fopen(filename, "a"); fp = fopen(filename, "a");
@ -834,7 +834,7 @@ static void check_not_current_branch(struct ref *ref_map)


static int truncate_fetch_head(void) static int truncate_fetch_head(void)
{ {
const char *filename = git_path("FETCH_HEAD"); const char *filename = git_path_fetch_head();
FILE *fp = fopen(filename, "w"); FILE *fp = fopen(filename, "w");


if (!fp) if (!fp)

View File

@ -243,13 +243,14 @@ static void check_unreachable_object(struct object *obj)
printf("dangling %s %s\n", typename(obj->type), printf("dangling %s %s\n", typename(obj->type),
sha1_to_hex(obj->sha1)); sha1_to_hex(obj->sha1));
if (write_lost_and_found) { if (write_lost_and_found) {
const char *filename = git_path("lost-found/%s/%s", char *filename = git_pathdup("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other", obj->type == OBJ_COMMIT ? "commit" : "other",
sha1_to_hex(obj->sha1)); sha1_to_hex(obj->sha1));
FILE *f; FILE *f;


if (safe_create_leading_directories_const(filename)) { if (safe_create_leading_directories_const(filename)) {
error("Could not create lost-found"); error("Could not create lost-found");
free(filename);
return; return;
} }
if (!(f = fopen(filename, "w"))) if (!(f = fopen(filename, "w")))
@ -262,6 +263,7 @@ static void check_unreachable_object(struct object *obj)
if (fclose(f)) if (fclose(f))
die_errno("Could not finish '%s'", die_errno("Could not finish '%s'",
filename); filename);
free(filename);
} }
return; return;
} }

View File

@ -231,9 +231,9 @@ static struct option builtin_merge_options[] = {
/* Cleans up metadata that is uninteresting after a succeeded merge. */ /* Cleans up metadata that is uninteresting after a succeeded merge. */
static void drop_save(void) static void drop_save(void)
{ {
unlink(git_path("MERGE_HEAD")); unlink(git_path_merge_head());
unlink(git_path("MERGE_MSG")); unlink(git_path_merge_msg());
unlink(git_path("MERGE_MODE")); unlink(git_path_merge_mode());
} }


static int save_state(unsigned char *stash) static int save_state(unsigned char *stash)
@ -338,7 +338,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
struct pretty_print_context ctx = {0}; struct pretty_print_context ctx = {0};


printf(_("Squash commit -- not updating HEAD\n")); printf(_("Squash commit -- not updating HEAD\n"));
filename = git_path("SQUASH_MSG"); filename = git_path_squash_msg();
fd = open(filename, O_WRONLY | O_CREAT, 0666); fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0) if (fd < 0)
die_errno(_("Could not write to '%s'"), filename); die_errno(_("Could not write to '%s'"), filename);
@ -754,7 +754,7 @@ static void add_strategies(const char *string, unsigned attr)


static void write_merge_msg(struct strbuf *msg) static void write_merge_msg(struct strbuf *msg)
{ {
const char *filename = git_path("MERGE_MSG"); const char *filename = git_path_merge_msg();
int fd = open(filename, O_WRONLY | O_CREAT, 0666); int fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0) if (fd < 0)
die_errno(_("Could not open '%s' for writing"), die_errno(_("Could not open '%s' for writing"),
@ -766,7 +766,7 @@ static void write_merge_msg(struct strbuf *msg)


static void read_merge_msg(struct strbuf *msg) static void read_merge_msg(struct strbuf *msg)
{ {
const char *filename = git_path("MERGE_MSG"); const char *filename = git_path_merge_msg();
strbuf_reset(msg); strbuf_reset(msg);
if (strbuf_read_file(msg, filename, 0) < 0) if (strbuf_read_file(msg, filename, 0) < 0)
die_errno(_("Could not read from '%s'"), filename); die_errno(_("Could not read from '%s'"), filename);
@ -799,10 +799,10 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char); strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
write_merge_msg(&msg); write_merge_msg(&msg);
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg", if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
git_path("MERGE_MSG"), "merge", NULL)) git_path_merge_msg(), "merge", NULL))
abort_commit(remoteheads, NULL); abort_commit(remoteheads, NULL);
if (0 < option_edit) { if (0 < option_edit) {
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL)) if (launch_editor(git_path_merge_msg(), NULL, NULL))
abort_commit(remoteheads, NULL); abort_commit(remoteheads, NULL);
} }
read_merge_msg(&msg); read_merge_msg(&msg);
@ -865,7 +865,7 @@ static int suggest_conflicts(void)
FILE *fp; FILE *fp;
struct strbuf msgbuf = STRBUF_INIT; struct strbuf msgbuf = STRBUF_INIT;


filename = git_path("MERGE_MSG"); filename = git_path_merge_msg();
fp = fopen(filename, "a"); fp = fopen(filename, "a");
if (!fp) if (!fp)
die_errno(_("Could not open '%s' for writing"), filename); die_errno(_("Could not open '%s' for writing"), filename);
@ -967,7 +967,7 @@ static void write_merge_state(struct commit_list *remoteheads)
} }
strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1)); strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
} }
filename = git_path("MERGE_HEAD"); filename = git_path_merge_head();
fd = open(filename, O_WRONLY | O_CREAT, 0666); fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0) if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename); die_errno(_("Could not open '%s' for writing"), filename);
@ -977,7 +977,7 @@ static void write_merge_state(struct commit_list *remoteheads)
strbuf_addch(&merge_msg, '\n'); strbuf_addch(&merge_msg, '\n');
write_merge_msg(&merge_msg); write_merge_msg(&merge_msg);


filename = git_path("MERGE_MODE"); filename = git_path_merge_mode();
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename); die_errno(_("Could not open '%s' for writing"), filename);
@ -1070,7 +1070,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
if (!merge_names) if (!merge_names)
merge_names = &fetch_head_file; merge_names = &fetch_head_file;


filename = git_path("FETCH_HEAD"); filename = git_path_fetch_head();
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) if (fd < 0)
die_errno(_("could not open '%s' for reading"), filename); die_errno(_("could not open '%s' for reading"), filename);
@ -1204,7 +1204,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
int nargc = 2; int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL}; const char *nargv[] = {"reset", "--merge", NULL};


if (!file_exists(git_path("MERGE_HEAD"))) if (!file_exists(git_path_merge_head()))
die(_("There is no merge to abort (MERGE_HEAD missing).")); die(_("There is no merge to abort (MERGE_HEAD missing)."));


/* Invoke 'git reset --merge' */ /* Invoke 'git reset --merge' */
@ -1215,7 +1215,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged()) if (read_cache_unmerged())
die_resolve_conflict("merge"); die_resolve_conflict("merge");


if (file_exists(git_path("MERGE_HEAD"))) { if (file_exists(git_path_merge_head())) {
/* /*
* There is no unmerged entry, don't advise 'git * There is no unmerged entry, don't advise 'git
* add/rm <file>', just 'git commit'. * add/rm <file>', just 'git commit'.
@ -1226,7 +1226,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else else
die(_("You have not concluded your merge (MERGE_HEAD exists).")); die(_("You have not concluded your merge (MERGE_HEAD exists)."));
} }
if (file_exists(git_path("CHERRY_PICK_HEAD"))) { if (file_exists(git_path_cherry_pick_head())) {
if (advice_resolve_conflict) if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge.")); "Please, commit your changes before you merge."));

View File

@ -581,7 +581,6 @@ static int migrate_file(struct remote *remote)
{ {
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int i; int i;
const char *path = NULL;


strbuf_addf(&buf, "remote.%s.url", remote->name); strbuf_addf(&buf, "remote.%s.url", remote->name);
for (i = 0; i < remote->url_nr; i++) for (i = 0; i < remote->url_nr; i++)
@ -601,11 +600,9 @@ static int migrate_file(struct remote *remote)
return error(_("Could not append '%s' to '%s'"), return error(_("Could not append '%s' to '%s'"),
remote->fetch_refspec[i], buf.buf); remote->fetch_refspec[i], buf.buf);
if (remote->origin == REMOTE_REMOTES) if (remote->origin == REMOTE_REMOTES)
path = git_path("remotes/%s", remote->name); unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES) else if (remote->origin == REMOTE_BRANCHES)
path = git_path("branches/%s", remote->name); unlink_or_warn(git_path("branches/%s", remote->name));
if (path)
unlink_or_warn(path);
return 0; return 0;
} }



View File

@ -285,8 +285,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
failed = 0; failed = 0;
for_each_string_list_item(item, &names) { for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) { for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
const char *fname_old; char *fname, *fname_old;
char *fname;
fname = mkpathdup("%s/pack-%s%s", packdir, fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name); item->string, exts[ext].name);
if (!file_exists(fname)) { if (!file_exists(fname)) {
@ -294,7 +293,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
continue; continue;
} }


fname_old = mkpath("%s/old-%s%s", packdir, fname_old = mkpathdup("%s/old-%s%s", packdir,
item->string, exts[ext].name); item->string, exts[ext].name);
if (file_exists(fname_old)) if (file_exists(fname_old))
if (unlink(fname_old)) if (unlink(fname_old))
@ -302,10 +301,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)


if (!failed && rename(fname, fname_old)) { if (!failed && rename(fname, fname_old)) {
free(fname); free(fname);
free(fname_old);
failed = 1; failed = 1;
break; break;
} else { } else {
string_list_append(&rollback, fname); string_list_append(&rollback, fname);
free(fname_old);
} }
} }
if (failed) if (failed)
@ -314,13 +315,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (failed) { if (failed) {
struct string_list rollback_failure = STRING_LIST_INIT_DUP; struct string_list rollback_failure = STRING_LIST_INIT_DUP;
for_each_string_list_item(item, &rollback) { for_each_string_list_item(item, &rollback) {
const char *fname_old; char *fname, *fname_old;
char *fname;
fname = mkpathdup("%s/%s", packdir, item->string); fname = mkpathdup("%s/%s", packdir, item->string);
fname_old = mkpath("%s/old-%s", packdir, item->string); fname_old = mkpathdup("%s/old-%s", packdir, item->string);
if (rename(fname_old, fname)) if (rename(fname_old, fname))
string_list_append(&rollback_failure, fname); string_list_append(&rollback_failure, fname);
free(fname); free(fname);
free(fname_old);
} }


if (rollback_failure.nr) { if (rollback_failure.nr) {
@ -368,13 +369,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
/* Remove the "old-" files */ /* Remove the "old-" files */
for_each_string_list_item(item, &names) { for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) { for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
const char *fname; char *fname;
fname = mkpath("%s/old-%s%s", fname = mkpathdup("%s/old-%s%s",
packdir, packdir,
item->string, item->string,
exts[ext].name); exts[ext].name);
if (remove_path(fname)) if (remove_path(fname))
warning(_("removing '%s' failed"), fname); warning(_("removing '%s' failed"), fname);
free(fname);
} }
} }



View File

@ -36,7 +36,7 @@ static const char *reset_type_names[] = {


static inline int is_merge(void) static inline int is_merge(void)
{ {
return !access(git_path("MERGE_HEAD"), F_OK); return !access(git_path_merge_head(), F_OK);
} }


static int reset_index(const unsigned char *sha1, int reset_type, int quiet) static int reset_index(const unsigned char *sha1, int reset_type, int quiet)

47
cache.h
View File

@ -708,22 +708,59 @@ extern int check_repository_format(void);
#define DATA_CHANGED 0x0020 #define DATA_CHANGED 0x0020
#define TYPE_CHANGED 0x0040 #define TYPE_CHANGED 0x0040


/*
* Return a statically allocated filename, either generically (mkpath), in
* the repository directory (git_path), or in a submodule's repository
* directory (git_path_submodule). In all cases, note that the result
* may be overwritten by another call to _any_ of the functions. Consider
* using the safer "dup" or "strbuf" formats below (in some cases, the
* unsafe versions have already been removed).
*/
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));

extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
__attribute__((format (printf, 3, 4))); __attribute__((format (printf, 3, 4)));
extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
__attribute__((format (printf, 2, 3))); __attribute__((format (printf, 2, 3)));
extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
extern char *git_pathdup(const char *fmt, ...) extern char *git_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2))); __attribute__((format (printf, 1, 2)));
extern char *mkpathdup(const char *fmt, ...) extern char *mkpathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2))); __attribute__((format (printf, 1, 2)));

extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
/* Return a statically allocated filename matching the sha1 signature */
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3))); __attribute__((format (printf, 2, 3)));

extern void report_linked_checkout_garbage(void); extern void report_linked_checkout_garbage(void);


/*
* You can define a static memoized git path like:
*
* static GIT_PATH_FUNC(git_path_foo, "FOO");
*
* or use one of the global ones below.
*/
#define GIT_PATH_FUNC(func, filename) \
const char *func(void) \
{ \
static char *ret; \
if (!ret) \
ret = git_pathdup(filename); \
return ret; \
}

const char *git_path_cherry_pick_head(void);
const char *git_path_revert_head(void);
const char *git_path_squash_msg(void);
const char *git_path_merge_msg(void);
const char *git_path_merge_rr(void);
const char *git_path_merge_mode(void);
const char *git_path_merge_head(void);
const char *git_path_fetch_head(void);
const char *git_path_shallow(void);

/* /*
* Return the name of the file in the local object database that would * Return the name of the file in the local object database that would
* be used to store a loose object with the specified sha1. The * be used to store a loose object with the specified sha1. The

View File

@ -516,7 +516,7 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)


if (argc != 8) if (argc != 8)
return error("append-fetch-head takes 6 args"); return error("append-fetch-head takes 6 args");
filename = git_path("FETCH_HEAD"); filename = git_path_fetch_head();
fp = fopen(filename, "a"); fp = fopen(filename, "a");
if (!fp) if (!fp)
return error("cannot open %s: %s", filename, strerror(errno)); return error("cannot open %s: %s", filename, strerror(errno));
@ -534,7 +534,7 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)


if (argc != 5) if (argc != 5)
return error("fetch-native-store takes 3 args"); return error("fetch-native-store takes 3 args");
filename = git_path("FETCH_HEAD"); filename = git_path_fetch_head();
fp = fopen(filename, "a"); fp = fopen(filename, "a");
if (!fp) if (!fp)
return error("cannot open %s: %s", filename, strerror(errno)); return error("cannot open %s: %s", filename, strerror(errno));

4
dir.c
View File

@ -2185,6 +2185,8 @@ int remove_dir_recursively(struct strbuf *path, int flag)
return remove_dir_recurse(path, flag, NULL); return remove_dir_recurse(path, flag, NULL);
} }


static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")

void setup_standard_excludes(struct dir_struct *dir) void setup_standard_excludes(struct dir_struct *dir)
{ {
const char *path; const char *path;
@ -2199,7 +2201,7 @@ void setup_standard_excludes(struct dir_struct *dir)
dir->untracked ? &dir->ss_excludes_file : NULL); dir->untracked ? &dir->ss_excludes_file : NULL);


/* per repository user preference */ /* per repository user preference */
path = git_path("info/exclude"); path = git_path_info_exclude();
if (!access_or_warn(path, R_OK, 0)) if (!access_or_warn(path, R_OK, 0))
add_excludes_from_file_1(dir, path, add_excludes_from_file_1(dir, path,
dir->untracked ? &dir->ss_info_exclude : NULL); dir->untracked ? &dir->ss_info_exclude : NULL);

View File

@ -407,7 +407,7 @@ static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *);


static void write_crash_report(const char *err) static void write_crash_report(const char *err)
{ {
const char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid()); char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
FILE *rpt = fopen(loc, "w"); FILE *rpt = fopen(loc, "w");
struct branch *b; struct branch *b;
unsigned long lu; unsigned long lu;
@ -415,6 +415,7 @@ static void write_crash_report(const char *err)


if (!rpt) { if (!rpt) {
error("can't write crash report %s: %s", loc, strerror(errno)); error("can't write crash report %s: %s", loc, strerror(errno));
free(loc);
return; return;
} }


@ -488,6 +489,7 @@ static void write_crash_report(const char *err)
fputs("-------------------\n", rpt); fputs("-------------------\n", rpt);
fputs("END OF CRASH REPORT\n", rpt); fputs("END OF CRASH REPORT\n", rpt);
fclose(rpt); fclose(rpt);
free(loc);
} }


static void end_packfile(void); static void end_packfile(void);

View File

@ -948,7 +948,7 @@ static void update_shallow(struct fetch_pack_args *args,


if (args->depth > 0 && alternate_shallow_file) { if (args->depth > 0 && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */ if (*alternate_shallow_file == '\0') { /* --unshallow */
unlink_or_warn(git_path("shallow")); unlink_or_warn(git_path_shallow());
rollback_lock_file(&shallow_lock); rollback_lock_file(&shallow_lock);
} else } else
commit_lock_file(&shallow_lock); commit_lock_file(&shallow_lock);

View File

@ -164,7 +164,7 @@ static void send_strbuf(const char *type, struct strbuf *buf)


static void send_local_file(const char *the_type, const char *name) static void send_local_file(const char *the_type, const char *name)
{ {
const char *p = git_path("%s", name); char *p = git_pathdup("%s", name);
size_t buf_alloc = 8192; size_t buf_alloc = 8192;
char *buf = xmalloc(buf_alloc); char *buf = xmalloc(buf_alloc);
int fd; int fd;
@ -191,6 +191,7 @@ static void send_local_file(const char *the_type, const char *name)
} }
close(fd); close(fd);
free(buf); free(buf);
free(p);
} }


static void get_text_file(char *name) static void get_text_file(char *name)

View File

@ -295,7 +295,7 @@ static void write_buf_to_worktree(const unsigned char *obj,
const char *buf, unsigned long size) const char *buf, unsigned long size)
{ {
int fd; int fd;
const char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj)); char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj));
if (safe_create_leading_directories_const(path)) if (safe_create_leading_directories_const(path))
die_errno("unable to create directory for '%s'", path); die_errno("unable to create directory for '%s'", path);
if (file_exists(path)) if (file_exists(path))
@ -320,6 +320,7 @@ static void write_buf_to_worktree(const unsigned char *obj,
} }


close(fd); close(fd);
free(path);
} }


static void write_note_to_worktree(const unsigned char *obj, static void write_note_to_worktree(const unsigned char *obj,

37
path.c
View File

@ -224,11 +224,10 @@ const char *mkpath(const char *fmt, ...)
return cleanup_path(pathname->buf); return cleanup_path(pathname->buf);
} }


const char *git_path_submodule(const char *path, const char *fmt, ...) static void do_submodule_path(struct strbuf *buf, const char *path,
const char *fmt, va_list args)
{ {
struct strbuf *buf = get_pathname();
const char *git_dir; const char *git_dir;
va_list args;


strbuf_addstr(buf, path); strbuf_addstr(buf, path);
if (buf->len && buf->buf[buf->len - 1] != '/') if (buf->len && buf->buf[buf->len - 1] != '/')
@ -242,11 +241,27 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)
} }
strbuf_addch(buf, '/'); strbuf_addch(buf, '/');


va_start(args, fmt);
strbuf_vaddf(buf, fmt, args); strbuf_vaddf(buf, fmt, args);
va_end(args);
strbuf_cleanup_path(buf); strbuf_cleanup_path(buf);
return buf->buf; }

char *git_pathdup_submodule(const char *path, const char *fmt, ...)
{
va_list args;
struct strbuf buf = STRBUF_INIT;
va_start(args, fmt);
do_submodule_path(&buf, path, fmt, args);
va_end(args);
return strbuf_detach(&buf, NULL);
}

void strbuf_git_path_submodule(struct strbuf *buf, const char *path,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_submodule_path(buf, path, fmt, args);
va_end(args);
} }


int validate_headref(const char *path) int validate_headref(const char *path)
@ -918,3 +933,13 @@ char *xdg_config_home(const char *filename)
return mkpathdup("%s/.config/git/%s", home, filename); return mkpathdup("%s/.config/git/%s", home, filename);
return NULL; return NULL;
} }

GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD")
GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD")
GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG")
GIT_PATH_FUNC(git_path_merge_msg, "MERGE_MSG")
GIT_PATH_FUNC(git_path_merge_rr, "MERGE_RR")
GIT_PATH_FUNC(git_path_merge_mode, "MERGE_MODE")
GIT_PATH_FUNC(git_path_merge_head, "MERGE_HEAD")
GIT_PATH_FUNC(git_path_fetch_head, "FETCH_HEAD")
GIT_PATH_FUNC(git_path_shallow, "shallow")

160
refs.c
View File

@ -1288,12 +1288,12 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
*/ */
static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs) static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
{ {
const char *packed_refs_file; char *packed_refs_file;


if (*refs->name) if (*refs->name)
packed_refs_file = git_path_submodule(refs->name, "packed-refs"); packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
else else
packed_refs_file = git_path("packed-refs"); packed_refs_file = git_pathdup("packed-refs");


if (refs->packed && if (refs->packed &&
!stat_validity_check(&refs->packed->validity, packed_refs_file)) !stat_validity_check(&refs->packed->validity, packed_refs_file))
@ -1312,6 +1312,7 @@ static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
fclose(f); fclose(f);
} }
} }
free(packed_refs_file);
return refs->packed; return refs->packed;
} }


@ -1351,19 +1352,23 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
{ {
struct ref_cache *refs = dir->ref_cache; struct ref_cache *refs = dir->ref_cache;
DIR *d; DIR *d;
const char *path;
struct dirent *de; struct dirent *de;
int dirnamelen = strlen(dirname); int dirnamelen = strlen(dirname);
struct strbuf refname; struct strbuf refname;
struct strbuf path = STRBUF_INIT;
size_t path_baselen;


if (*refs->name) if (*refs->name)
path = git_path_submodule(refs->name, "%s", dirname); strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
else else
path = git_path("%s", dirname); strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len;


d = opendir(path); d = opendir(path.buf);
if (!d) if (!d) {
strbuf_release(&path);
return; return;
}


strbuf_init(&refname, dirnamelen + 257); strbuf_init(&refname, dirnamelen + 257);
strbuf_add(&refname, dirname, dirnamelen); strbuf_add(&refname, dirname, dirnamelen);
@ -1372,17 +1377,14 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
unsigned char sha1[20]; unsigned char sha1[20];
struct stat st; struct stat st;
int flag; int flag;
const char *refdir;


if (de->d_name[0] == '.') if (de->d_name[0] == '.')
continue; continue;
if (ends_with(de->d_name, ".lock")) if (ends_with(de->d_name, ".lock"))
continue; continue;
strbuf_addstr(&refname, de->d_name); strbuf_addstr(&refname, de->d_name);
refdir = *refs->name strbuf_addstr(&path, de->d_name);
? git_path_submodule(refs->name, "%s", refname.buf) if (stat(path.buf, &st) < 0) {
: git_path("%s", refname.buf);
if (stat(refdir, &st) < 0) {
; /* silently ignore */ ; /* silently ignore */
} else if (S_ISDIR(st.st_mode)) { } else if (S_ISDIR(st.st_mode)) {
strbuf_addch(&refname, '/'); strbuf_addch(&refname, '/');
@ -1429,8 +1431,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
create_ref_entry(refname.buf, sha1, flag, 0)); create_ref_entry(refname.buf, sha1, flag, 0));
} }
strbuf_setlen(&refname, dirnamelen); strbuf_setlen(&refname, dirnamelen);
strbuf_setlen(&path, path_baselen);
} }
strbuf_release(&refname); strbuf_release(&refname);
strbuf_release(&path);
closedir(d); closedir(d);
} }


@ -1481,14 +1485,15 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
{ {
int fd, len; int fd, len;
char buffer[128], *p; char buffer[128], *p;
const char *path; char *path;


if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN) if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
return -1; return -1;
path = *refs->name path = *refs->name
? git_path_submodule(refs->name, "%s", refname) ? git_pathdup_submodule(refs->name, "%s", refname)
: git_path("%s", refname); : git_pathdup("%s", refname);
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
free(path);
if (fd < 0) if (fd < 0)
return resolve_gitlink_packed_ref(refs, refname, sha1); return resolve_gitlink_packed_ref(refs, refname, sha1);


@ -2285,25 +2290,14 @@ static int verify_lock(struct ref_lock *lock,
return 0; return 0;
} }


static int remove_empty_directories(const char *file) static int remove_empty_directories(struct strbuf *path)
{ {
/* we want to create a file but there is a directory there; /*
* we want to create a file but there is a directory there;
* if that is an empty directory (or a directory that contains * if that is an empty directory (or a directory that contains
* only empty directories), remove them. * only empty directories), remove them.
*/ */
struct strbuf path; return remove_dir_recursively(path, REMOVE_DIR_EMPTY_ONLY);
int result, save_errno;

strbuf_init(&path, 20);
strbuf_addstr(&path, file);

result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
save_errno = errno;

strbuf_release(&path);
errno = save_errno;

return result;
} }


/* /*
@ -2403,7 +2397,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
unsigned int flags, int *type_p, unsigned int flags, int *type_p,
struct strbuf *err) struct strbuf *err)
{ {
const char *ref_file; struct strbuf ref_file = STRBUF_INIT;
struct strbuf orig_ref_file = STRBUF_INIT;
const char *orig_refname = refname; const char *orig_refname = refname;
struct ref_lock *lock; struct ref_lock *lock;
int last_errno = 0; int last_errno = 0;
@ -2427,20 +2422,19 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
refname = resolve_ref_unsafe(refname, resolve_flags, refname = resolve_ref_unsafe(refname, resolve_flags,
lock->old_oid.hash, &type); lock->old_oid.hash, &type);
if (!refname && errno == EISDIR) { if (!refname && errno == EISDIR) {
/* we are trying to lock foo but we used to /*
* we are trying to lock foo but we used to
* have foo/bar which now does not exist; * have foo/bar which now does not exist;
* it is normal for the empty directory 'foo' * it is normal for the empty directory 'foo'
* to remain. * to remain.
*/ */
ref_file = git_path("%s", orig_refname); strbuf_git_path(&orig_ref_file, "%s", orig_refname);
if (remove_empty_directories(ref_file)) { if (remove_empty_directories(&orig_ref_file)) {
last_errno = errno; last_errno = errno;

if (!verify_refname_available(orig_refname, extras, skip, if (!verify_refname_available(orig_refname, extras, skip,
get_loose_refs(&ref_cache), err)) get_loose_refs(&ref_cache), err))
strbuf_addf(err, "there are still refs under '%s'", strbuf_addf(err, "there are still refs under '%s'",
orig_refname); orig_refname);

goto error_return; goto error_return;
} }
refname = resolve_ref_unsafe(orig_refname, resolve_flags, refname = resolve_ref_unsafe(orig_refname, resolve_flags,
@ -2480,10 +2474,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
} }
lock->ref_name = xstrdup(refname); lock->ref_name = xstrdup(refname);
lock->orig_ref_name = xstrdup(orig_refname); lock->orig_ref_name = xstrdup(orig_refname);
ref_file = git_path("%s", refname); strbuf_git_path(&ref_file, "%s", refname);


retry: retry:
switch (safe_create_leading_directories_const(ref_file)) { switch (safe_create_leading_directories_const(ref_file.buf)) {
case SCLD_OK: case SCLD_OK:
break; /* success */ break; /* success */
case SCLD_VANISHED: case SCLD_VANISHED:
@ -2492,11 +2486,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
/* fall through */ /* fall through */
default: default:
last_errno = errno; last_errno = errno;
strbuf_addf(err, "unable to create directory for %s", ref_file); strbuf_addf(err, "unable to create directory for %s",
ref_file.buf);
goto error_return; goto error_return;
} }


if (hold_lock_file_for_update(lock->lk, ref_file, lflags) < 0) { if (hold_lock_file_for_update(lock->lk, ref_file.buf, lflags) < 0) {
last_errno = errno; last_errno = errno;
if (errno == ENOENT && --attempts_remaining > 0) if (errno == ENOENT && --attempts_remaining > 0)
/* /*
@ -2506,7 +2501,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
*/ */
goto retry; goto retry;
else { else {
unable_to_lock_message(ref_file, errno, err); unable_to_lock_message(ref_file.buf, errno, err);
goto error_return; goto error_return;
} }
} }
@ -2514,12 +2509,17 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
last_errno = errno; last_errno = errno;
goto error_return; goto error_return;
} }
return lock; goto out;


error_return: error_return:
unlock_ref(lock); unlock_ref(lock);
lock = NULL;

out:
strbuf_release(&ref_file);
strbuf_release(&orig_ref_file);
errno = last_errno; errno = last_errno;
return NULL; return lock;
} }


/* /*
@ -2925,9 +2925,13 @@ out:
static int rename_tmp_log(const char *newrefname) static int rename_tmp_log(const char *newrefname)
{ {
int attempts_remaining = 4; int attempts_remaining = 4;
struct strbuf path = STRBUF_INIT;
int ret = -1;


retry: retry:
switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) { strbuf_reset(&path);
strbuf_git_path(&path, "logs/%s", newrefname);
switch (safe_create_leading_directories_const(path.buf)) {
case SCLD_OK: case SCLD_OK:
break; /* success */ break; /* success */
case SCLD_VANISHED: case SCLD_VANISHED:
@ -2936,19 +2940,19 @@ static int rename_tmp_log(const char *newrefname)
/* fall through */ /* fall through */
default: default:
error("unable to create directory for %s", newrefname); error("unable to create directory for %s", newrefname);
return -1; goto out;
} }


if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) { if (rename(git_path(TMP_RENAMED_LOG), path.buf)) {
if ((errno==EISDIR || errno==ENOTDIR) && --attempts_remaining > 0) { if ((errno==EISDIR || errno==ENOTDIR) && --attempts_remaining > 0) {
/* /*
* rename(a, b) when b is an existing * rename(a, b) when b is an existing
* directory ought to result in ISDIR, but * directory ought to result in ISDIR, but
* Solaris 5.8 gives ENOTDIR. Sheesh. * Solaris 5.8 gives ENOTDIR. Sheesh.
*/ */
if (remove_empty_directories(git_path("logs/%s", newrefname))) { if (remove_empty_directories(&path)) {
error("Directory not empty: logs/%s", newrefname); error("Directory not empty: logs/%s", newrefname);
return -1; goto out;
} }
goto retry; goto retry;
} else if (errno == ENOENT && --attempts_remaining > 0) { } else if (errno == ENOENT && --attempts_remaining > 0) {
@ -2961,10 +2965,13 @@ static int rename_tmp_log(const char *newrefname)
} else { } else {
error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s", error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
newrefname, strerror(errno)); newrefname, strerror(errno));
return -1; goto out;
} }
} }
return 0; ret = 0;
out:
strbuf_release(&path);
return ret;
} }


static int rename_ref_available(const char *oldname, const char *newname) static int rename_ref_available(const char *oldname, const char *newname)
@ -3028,7 +3035,14 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) && if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
delete_ref(newrefname, sha1, REF_NODEREF)) { delete_ref(newrefname, sha1, REF_NODEREF)) {
if (errno==EISDIR) { if (errno==EISDIR) {
if (remove_empty_directories(git_path("%s", newrefname))) { struct strbuf path = STRBUF_INIT;
int result;

strbuf_git_path(&path, "%s", newrefname);
result = remove_empty_directories(&path);
strbuf_release(&path);

if (result) {
error("Directory not empty: %s", newrefname); error("Directory not empty: %s", newrefname);
goto rollback; goto rollback;
} }
@ -3145,25 +3159,21 @@ static int should_autocreate_reflog(const char *refname)
* should_autocreate_reflog returns non-zero. Otherwise, create it * should_autocreate_reflog returns non-zero. Otherwise, create it
* regardless of the ref name. Fill in *err and return -1 on failure. * regardless of the ref name. Fill in *err and return -1 on failure.
*/ */
static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err, int force_create) static int log_ref_setup(const char *refname, struct strbuf *logfile, struct strbuf *err, int force_create)
{ {
int logfd, oflags = O_APPEND | O_WRONLY; int logfd, oflags = O_APPEND | O_WRONLY;
char *logfile;


strbuf_git_path(sb_logfile, "logs/%s", refname); strbuf_git_path(logfile, "logs/%s", refname);
logfile = sb_logfile->buf;
/* make sure the rest of the function can't change "logfile" */
sb_logfile = NULL;
if (force_create || should_autocreate_reflog(refname)) { if (force_create || should_autocreate_reflog(refname)) {
if (safe_create_leading_directories(logfile) < 0) { if (safe_create_leading_directories(logfile->buf) < 0) {
strbuf_addf(err, "unable to create directory for %s: " strbuf_addf(err, "unable to create directory for %s: "
"%s", logfile, strerror(errno)); "%s", logfile->buf, strerror(errno));
return -1; return -1;
} }
oflags |= O_CREAT; oflags |= O_CREAT;
} }


logfd = open(logfile, oflags, 0666); logfd = open(logfile->buf, oflags, 0666);
if (logfd < 0) { if (logfd < 0) {
if (!(oflags & O_CREAT) && (errno == ENOENT || errno == EISDIR)) if (!(oflags & O_CREAT) && (errno == ENOENT || errno == EISDIR))
return 0; return 0;
@ -3171,20 +3181,20 @@ static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct
if (errno == EISDIR) { if (errno == EISDIR) {
if (remove_empty_directories(logfile)) { if (remove_empty_directories(logfile)) {
strbuf_addf(err, "There are still logs under " strbuf_addf(err, "There are still logs under "
"'%s'", logfile); "'%s'", logfile->buf);
return -1; return -1;
} }
logfd = open(logfile, oflags, 0666); logfd = open(logfile->buf, oflags, 0666);
} }


if (logfd < 0) { if (logfd < 0) {
strbuf_addf(err, "unable to append to %s: %s", strbuf_addf(err, "unable to append to %s: %s",
logfile, strerror(errno)); logfile->buf, strerror(errno));
return -1; return -1;
} }
} }


adjust_shared_perm(logfile); adjust_shared_perm(logfile->buf);
close(logfd); close(logfd);
return 0; return 0;
} }
@ -3228,36 +3238,32 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,


static int log_ref_write_1(const char *refname, const unsigned char *old_sha1, static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
const unsigned char *new_sha1, const char *msg, const unsigned char *new_sha1, const char *msg,
struct strbuf *sb_log_file, int flags, struct strbuf *logfile, int flags,
struct strbuf *err) struct strbuf *err)
{ {
int logfd, result, oflags = O_APPEND | O_WRONLY; int logfd, result, oflags = O_APPEND | O_WRONLY;
char *log_file;


if (log_all_ref_updates < 0) if (log_all_ref_updates < 0)
log_all_ref_updates = !is_bare_repository(); log_all_ref_updates = !is_bare_repository();


result = log_ref_setup(refname, sb_log_file, err, flags & REF_FORCE_CREATE_REFLOG); result = log_ref_setup(refname, logfile, err, flags & REF_FORCE_CREATE_REFLOG);


if (result) if (result)
return result; return result;
log_file = sb_log_file->buf;
/* make sure the rest of the function can't change "log_file" */
sb_log_file = NULL;


logfd = open(log_file, oflags); logfd = open(logfile->buf, oflags);
if (logfd < 0) if (logfd < 0)
return 0; return 0;
result = log_ref_write_fd(logfd, old_sha1, new_sha1, result = log_ref_write_fd(logfd, old_sha1, new_sha1,
git_committer_info(0), msg); git_committer_info(0), msg);
if (result) { if (result) {
strbuf_addf(err, "unable to append to %s: %s", log_file, strbuf_addf(err, "unable to append to %s: %s", logfile->buf,
strerror(errno)); strerror(errno));
close(logfd); close(logfd);
return -1; return -1;
} }
if (close(logfd)) { if (close(logfd)) {
strbuf_addf(err, "unable to append to %s: %s", log_file, strbuf_addf(err, "unable to append to %s: %s", logfile->buf,
strerror(errno)); strerror(errno));
return -1; return -1;
} }
@ -3378,7 +3384,7 @@ static int commit_ref_update(struct ref_lock *lock,
int create_symref(const char *ref_target, const char *refs_heads_master, int create_symref(const char *ref_target, const char *refs_heads_master,
const char *logmsg) const char *logmsg)
{ {
const char *lockpath; char *lockpath = NULL;
char ref[1000]; char ref[1000];
int fd, len, written; int fd, len, written;
char *git_HEAD = git_pathdup("%s", ref_target); char *git_HEAD = git_pathdup("%s", ref_target);
@ -3405,7 +3411,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
error("refname too long: %s", refs_heads_master); error("refname too long: %s", refs_heads_master);
goto error_free_return; goto error_free_return;
} }
lockpath = mkpath("%s.lock", git_HEAD); lockpath = mkpathdup("%s.lock", git_HEAD);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) { if (fd < 0) {
error("Unable to open %s for writing", lockpath); error("Unable to open %s for writing", lockpath);
@ -3425,9 +3431,11 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
error_unlink_return: error_unlink_return:
unlink_or_warn(lockpath); unlink_or_warn(lockpath);
error_free_return: error_free_return:
free(lockpath);
free(git_HEAD); free(git_HEAD);
return -1; return -1;
} }
free(lockpath);


#ifndef NO_SYMLINK_HEAD #ifndef NO_SYMLINK_HEAD
done: done:

View File

@ -20,8 +20,6 @@ static int rerere_enabled = -1;
/* automatically update cleanly resolved paths to the index */ /* automatically update cleanly resolved paths to the index */
static int rerere_autoupdate; static int rerere_autoupdate;


static char *merge_rr_path;

const char *rerere_path(const char *hex, const char *file) const char *rerere_path(const char *hex, const char *file)
{ {
return git_path("rr-cache/%s/%s", hex, file); return git_path("rr-cache/%s/%s", hex, file);
@ -37,7 +35,7 @@ static void read_rr(struct string_list *rr)
{ {
unsigned char sha1[20]; unsigned char sha1[20];
char buf[PATH_MAX]; char buf[PATH_MAX];
FILE *in = fopen(merge_rr_path, "r"); FILE *in = fopen(git_path_merge_rr(), "r");
if (!in) if (!in)
return; return;
while (fread(buf, 40, 1, in) == 1) { while (fread(buf, 40, 1, in) == 1) {
@ -577,21 +575,21 @@ static void git_rerere_config(void)
git_config(git_default_config, NULL); git_config(git_default_config, NULL);
} }


static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")

static int is_rerere_enabled(void) static int is_rerere_enabled(void)
{ {
const char *rr_cache;
int rr_cache_exists; int rr_cache_exists;


if (!rerere_enabled) if (!rerere_enabled)
return 0; return 0;


rr_cache = git_path("rr-cache"); rr_cache_exists = is_directory(git_path_rr_cache());
rr_cache_exists = is_directory(rr_cache);
if (rerere_enabled < 0) if (rerere_enabled < 0)
return rr_cache_exists; return rr_cache_exists;


if (!rr_cache_exists && mkdir_in_gitdir(rr_cache)) if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
die("Could not create directory %s", rr_cache); die("Could not create directory %s", git_path_rr_cache());
return 1; return 1;
} }


@ -605,8 +603,7 @@ int setup_rerere(struct string_list *merge_rr, int flags)


if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE)) if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE); rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
merge_rr_path = git_pathdup("MERGE_RR"); fd = hold_lock_file_for_update(&write_lock, git_path_merge_rr(),
fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
read_rr(merge_rr); read_rr(merge_rr);
return fd; return fd;
@ -741,5 +738,5 @@ void rerere_clear(struct string_list *merge_rr)
if (!has_rerere_resolution(name)) if (!has_rerere_resolution(name))
unlink_rr_item(name); unlink_rr_item(name);
} }
unlink_or_warn(git_path("MERGE_RR")); unlink_or_warn(git_path_merge_rr());
} }

View File

@ -797,11 +797,13 @@ int finish_async(struct async *async)


const char *find_hook(const char *name) const char *find_hook(const char *name)
{ {
const char *path = git_path("hooks/%s", name); static struct strbuf path = STRBUF_INIT;
if (access(path, X_OK) < 0)
path = NULL;


return path; strbuf_reset(&path);
strbuf_git_path(&path, "hooks/%s", name);
if (access(path.buf, X_OK) < 0)
return NULL;
return path.buf;
} }


int run_hook_ve(const char *const *env, const char *name, va_list args) int run_hook_ve(const char *const *env, const char *name, va_list args)

View File

@ -52,6 +52,11 @@ int start_command(struct child_process *);
int finish_command(struct child_process *); int finish_command(struct child_process *);
int run_command(struct child_process *); int run_command(struct child_process *);


/*
* Returns the path to the hook file, or NULL if the hook is missing
* or disabled. Note that this points to static storage that will be
* overwritten by further calls to find_hook and run_hook_*.
*/
extern const char *find_hook(const char *name); extern const char *find_hook(const char *name);
LAST_ARG_MUST_BE_NULL LAST_ARG_MUST_BE_NULL
extern int run_hook_le(const char *const *env, const char *name, ...); extern int run_hook_le(const char *const *env, const char *name, ...);

View File

@ -21,6 +21,11 @@
const char sign_off_header[] = "Signed-off-by: "; const char sign_off_header[] = "Signed-off-by: ";
static const char cherry_picked_prefix[] = "(cherry picked from commit "; static const char cherry_picked_prefix[] = "(cherry picked from commit ";


static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)
static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)
static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)
static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)

static int is_rfc2822_line(const char *buf, int len) static int is_rfc2822_line(const char *buf, int len)
{ {
int i; int i;
@ -186,7 +191,7 @@ static void print_advice(int show_hint, struct replay_opts *opts)
* (typically rebase --interactive) wants to take care * (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD * of the commit itself so remove CHERRY_PICK_HEAD
*/ */
unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path_cherry_pick_head());
return; return;
} }


@ -467,7 +472,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
struct commit *base, *next, *parent; struct commit *base, *next, *parent;
const char *base_label, *next_label; const char *base_label, *next_label;
struct commit_message msg = { NULL, NULL, NULL, NULL }; struct commit_message msg = { NULL, NULL, NULL, NULL };
char *defmsg = NULL;
struct strbuf msgbuf = STRBUF_INIT; struct strbuf msgbuf = STRBUF_INIT;
int res, unborn = 0, allow; int res, unborn = 0, allow;


@ -537,8 +541,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* reverse of it if we are revert. * reverse of it if we are revert.
*/ */


defmsg = git_pathdup("MERGE_MSG");

if (opts->action == REPLAY_REVERT) { if (opts->action == REPLAY_REVERT) {
base = commit; base = commit;
base_label = msg.label; base_label = msg.label;
@ -585,12 +587,12 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) { if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
res = do_recursive_merge(base, next, base_label, next_label, res = do_recursive_merge(base, next, base_label, next_label,
head, &msgbuf, opts); head, &msgbuf, opts);
write_message(&msgbuf, defmsg); write_message(&msgbuf, git_path_merge_msg());
} else { } else {
struct commit_list *common = NULL; struct commit_list *common = NULL;
struct commit_list *remotes = NULL; struct commit_list *remotes = NULL;


write_message(&msgbuf, defmsg); write_message(&msgbuf, git_path_merge_msg());


commit_list_insert(base, &common); commit_list_insert(base, &common);
commit_list_insert(next, &remotes); commit_list_insert(next, &remotes);
@ -628,11 +630,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
goto leave; goto leave;
} }
if (!opts->no_commit) if (!opts->no_commit)
res = run_git_commit(defmsg, opts, allow); res = run_git_commit(git_path_merge_msg(), opts, allow);


leave: leave:
free_message(commit, &msg); free_message(commit, &msg);
free(defmsg);


return res; return res;
} }
@ -756,24 +757,23 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
static void read_populate_todo(struct commit_list **todo_list, static void read_populate_todo(struct commit_list **todo_list,
struct replay_opts *opts) struct replay_opts *opts)
{ {
const char *todo_file = git_path(SEQ_TODO_FILE);
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int fd, res; int fd, res;


fd = open(todo_file, O_RDONLY); fd = open(git_path_todo_file(), O_RDONLY);
if (fd < 0) if (fd < 0)
die_errno(_("Could not open %s"), todo_file); die_errno(_("Could not open %s"), git_path_todo_file());
if (strbuf_read(&buf, fd, 0) < 0) { if (strbuf_read(&buf, fd, 0) < 0) {
close(fd); close(fd);
strbuf_release(&buf); strbuf_release(&buf);
die(_("Could not read %s."), todo_file); die(_("Could not read %s."), git_path_todo_file());
} }
close(fd); close(fd);


res = parse_insn_buffer(buf.buf, todo_list, opts); res = parse_insn_buffer(buf.buf, todo_list, opts);
strbuf_release(&buf); strbuf_release(&buf);
if (res) if (res)
die(_("Unusable instruction sheet: %s"), todo_file); die(_("Unusable instruction sheet: %s"), git_path_todo_file());
} }


static int populate_opts_cb(const char *key, const char *value, void *data) static int populate_opts_cb(const char *key, const char *value, void *data)
@ -813,12 +813,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)


static void read_populate_opts(struct replay_opts **opts_ptr) static void read_populate_opts(struct replay_opts **opts_ptr)
{ {
const char *opts_file = git_path(SEQ_OPTS_FILE); if (!file_exists(git_path_opts_file()))

if (!file_exists(opts_file))
return; return;
if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0) if (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts_ptr) < 0)
die(_("Malformed options sheet: %s"), opts_file); die(_("Malformed options sheet: %s"), git_path_opts_file());
} }


static void walk_revs_populate_todo(struct commit_list **todo_list, static void walk_revs_populate_todo(struct commit_list **todo_list,
@ -836,31 +834,29 @@ static void walk_revs_populate_todo(struct commit_list **todo_list,


static int create_seq_dir(void) static int create_seq_dir(void)
{ {
const char *seq_dir = git_path(SEQ_DIR); if (file_exists(git_path_seq_dir())) {

if (file_exists(seq_dir)) {
error(_("a cherry-pick or revert is already in progress")); error(_("a cherry-pick or revert is already in progress"));
advise(_("try \"git cherry-pick (--continue | --quit | --abort)\"")); advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
return -1; return -1;
} }
else if (mkdir(seq_dir, 0777) < 0) else if (mkdir(git_path_seq_dir(), 0777) < 0)
die_errno(_("Could not create sequencer directory %s"), seq_dir); die_errno(_("Could not create sequencer directory %s"),
git_path_seq_dir());
return 0; return 0;
} }


static void save_head(const char *head) static void save_head(const char *head)
{ {
const char *head_file = git_path(SEQ_HEAD_FILE);
static struct lock_file head_lock; static struct lock_file head_lock;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int fd; int fd;


fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR); fd = hold_lock_file_for_update(&head_lock, git_path_head_file(), LOCK_DIE_ON_ERROR);
strbuf_addf(&buf, "%s\n", head); strbuf_addf(&buf, "%s\n", head);
if (write_in_full(fd, buf.buf, buf.len) < 0) if (write_in_full(fd, buf.buf, buf.len) < 0)
die_errno(_("Could not write to %s"), head_file); die_errno(_("Could not write to %s"), git_path_head_file());
if (commit_lock_file(&head_lock) < 0) if (commit_lock_file(&head_lock) < 0)
die(_("Error wrapping up %s."), head_file); die(_("Error wrapping up %s."), git_path_head_file());
} }


static int reset_for_rollback(const unsigned char *sha1) static int reset_for_rollback(const unsigned char *sha1)
@ -877,8 +873,8 @@ static int rollback_single_pick(void)
{ {
unsigned char head_sha1[20]; unsigned char head_sha1[20];


if (!file_exists(git_path("CHERRY_PICK_HEAD")) && if (!file_exists(git_path_cherry_pick_head()) &&
!file_exists(git_path("REVERT_HEAD"))) !file_exists(git_path_revert_head()))
return error(_("no cherry-pick or revert in progress")); return error(_("no cherry-pick or revert in progress"));
if (read_ref_full("HEAD", 0, head_sha1, NULL)) if (read_ref_full("HEAD", 0, head_sha1, NULL))
return error(_("cannot resolve HEAD")); return error(_("cannot resolve HEAD"));
@ -889,13 +885,11 @@ static int rollback_single_pick(void)


static int sequencer_rollback(struct replay_opts *opts) static int sequencer_rollback(struct replay_opts *opts)
{ {
const char *filename;
FILE *f; FILE *f;
unsigned char sha1[20]; unsigned char sha1[20];
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;


filename = git_path(SEQ_HEAD_FILE); f = fopen(git_path_head_file(), "r");
f = fopen(filename, "r");
if (!f && errno == ENOENT) { if (!f && errno == ENOENT) {
/* /*
* There is no multiple-cherry-pick in progress. * There is no multiple-cherry-pick in progress.
@ -905,18 +899,18 @@ static int sequencer_rollback(struct replay_opts *opts)
return rollback_single_pick(); return rollback_single_pick();
} }
if (!f) if (!f)
return error(_("cannot open %s: %s"), filename, return error(_("cannot open %s: %s"), git_path_head_file(),
strerror(errno)); strerror(errno));
if (strbuf_getline(&buf, f, '\n')) { if (strbuf_getline(&buf, f, '\n')) {
error(_("cannot read %s: %s"), filename, ferror(f) ? error(_("cannot read %s: %s"), git_path_head_file(),
strerror(errno) : _("unexpected end of file")); ferror(f) ? strerror(errno) : _("unexpected end of file"));
fclose(f); fclose(f);
goto fail; goto fail;
} }
fclose(f); fclose(f);
if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') { if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"), error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
filename); git_path_head_file());
goto fail; goto fail;
} }
if (reset_for_rollback(sha1)) if (reset_for_rollback(sha1))
@ -931,28 +925,27 @@ fail:


static void save_todo(struct commit_list *todo_list, struct replay_opts *opts) static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
{ {
const char *todo_file = git_path(SEQ_TODO_FILE);
static struct lock_file todo_lock; static struct lock_file todo_lock;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int fd; int fd;


fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR); fd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), LOCK_DIE_ON_ERROR);
if (format_todo(&buf, todo_list, opts) < 0) if (format_todo(&buf, todo_list, opts) < 0)
die(_("Could not format %s."), todo_file); die(_("Could not format %s."), git_path_todo_file());
if (write_in_full(fd, buf.buf, buf.len) < 0) { if (write_in_full(fd, buf.buf, buf.len) < 0) {
strbuf_release(&buf); strbuf_release(&buf);
die_errno(_("Could not write to %s"), todo_file); die_errno(_("Could not write to %s"), git_path_todo_file());
} }
if (commit_lock_file(&todo_lock) < 0) { if (commit_lock_file(&todo_lock) < 0) {
strbuf_release(&buf); strbuf_release(&buf);
die(_("Error wrapping up %s."), todo_file); die(_("Error wrapping up %s."), git_path_todo_file());
} }
strbuf_release(&buf); strbuf_release(&buf);
} }


static void save_opts(struct replay_opts *opts) static void save_opts(struct replay_opts *opts)
{ {
const char *opts_file = git_path(SEQ_OPTS_FILE); const char *opts_file = git_path_opts_file();


if (opts->no_commit) if (opts->no_commit)
git_config_set_in_file(opts_file, "options.no-commit", "true"); git_config_set_in_file(opts_file, "options.no-commit", "true");
@ -1013,8 +1006,8 @@ static int continue_single_pick(void)
{ {
const char *argv[] = { "commit", NULL }; const char *argv[] = { "commit", NULL };


if (!file_exists(git_path("CHERRY_PICK_HEAD")) && if (!file_exists(git_path_cherry_pick_head()) &&
!file_exists(git_path("REVERT_HEAD"))) !file_exists(git_path_revert_head()))
return error(_("no cherry-pick or revert in progress")); return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD); return run_command_v_opt(argv, RUN_GIT_CMD);
} }
@ -1023,14 +1016,14 @@ static int sequencer_continue(struct replay_opts *opts)
{ {
struct commit_list *todo_list = NULL; struct commit_list *todo_list = NULL;


if (!file_exists(git_path(SEQ_TODO_FILE))) if (!file_exists(git_path_todo_file()))
return continue_single_pick(); return continue_single_pick();
read_populate_opts(&opts); read_populate_opts(&opts);
read_populate_todo(&todo_list, opts); read_populate_todo(&todo_list, opts);


/* Verify that the conflict has been resolved */ /* Verify that the conflict has been resolved */
if (file_exists(git_path("CHERRY_PICK_HEAD")) || if (file_exists(git_path_cherry_pick_head()) ||
file_exists(git_path("REVERT_HEAD"))) { file_exists(git_path_revert_head())) {
int ret = continue_single_pick(); int ret = continue_single_pick();
if (ret) if (ret)
return ret; return ret;

View File

@ -404,13 +404,46 @@ void read_info_alternates(const char * relative_base, int depth)
void add_to_alternates_file(const char *reference) void add_to_alternates_file(const char *reference)
{ {
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR); char *alts = git_pathdup("objects/info/alternates");
const char *alt = mkpath("%s\n", reference); FILE *in, *out;
write_or_die(fd, alt, strlen(alt));
if (commit_lock_file(lock)) hold_lock_file_for_update(lock, alts, LOCK_DIE_ON_ERROR);
die("could not close alternates file"); out = fdopen_lock_file(lock, "w");
if (alt_odb_tail) if (!out)
link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0); die_errno("unable to fdopen alternates lockfile");

in = fopen(alts, "r");
if (in) {
struct strbuf line = STRBUF_INIT;
int found = 0;

while (strbuf_getline(&line, in, '\n') != EOF) {
if (!strcmp(reference, line.buf)) {
found = 1;
break;
}
fprintf_or_die(out, "%s\n", line.buf);
}

strbuf_release(&line);
fclose(in);

if (found) {
rollback_lock_file(lock);
lock = NULL;
}
}
else if (errno != ENOENT)
die_errno("unable to read alternates file");

if (lock) {
fprintf_or_die(out, "%s\n", reference);
if (commit_lock_file(lock))
die_errno("unable to move new alternates file into place");
if (alt_odb_tail)
link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0);
}
free(alts);
} }


int foreach_alt_odb(alt_odb_fn fn, void *cb) int foreach_alt_odb(alt_odb_fn fn, void *cb)

View File

@ -48,7 +48,7 @@ int is_repository_shallow(void)
return is_shallow; return is_shallow;


if (!path) if (!path)
path = git_path("shallow"); path = git_path_shallow();
/* /*
* fetch-pack sets '--shallow-file ""' as an indicator that no * fetch-pack sets '--shallow-file ""' as an indicator that no
* shallow file should be used. We could just open it and it * shallow file should be used. We could just open it and it
@ -142,7 +142,7 @@ static void check_shallow_file_for_update(void)
if (is_shallow == -1) if (is_shallow == -1)
die("BUG: shallow must be initialized by now"); die("BUG: shallow must be initialized by now");


if (!stat_validity_check(&shallow_stat, git_path("shallow"))) if (!stat_validity_check(&shallow_stat, git_path_shallow()))
die("shallow file has changed since we read it"); die("shallow file has changed since we read it");
} }


@ -261,7 +261,7 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
int fd; int fd;


fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"), fd = hold_lock_file_for_update(shallow_lock, git_path_shallow(),
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(); check_shallow_file_for_update();
if (write_shallow_commits(&sb, 0, extra)) { if (write_shallow_commits(&sb, 0, extra)) {
@ -308,7 +308,7 @@ void prune_shallow(int show_only)
strbuf_release(&sb); strbuf_release(&sb);
return; return;
} }
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"), fd = hold_lock_file_for_update(&shallow_lock, git_path_shallow(),
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(); check_shallow_file_for_update();
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
@ -317,7 +317,7 @@ void prune_shallow(int show_only)
shallow_lock.filename.buf); shallow_lock.filename.buf);
commit_lock_file(&shallow_lock); commit_lock_file(&shallow_lock);
} else { } else {
unlink(git_path("shallow")); unlink(git_path_shallow());
rollback_lock_file(&shallow_lock); rollback_lock_file(&shallow_lock);
} }
strbuf_release(&sb); strbuf_release(&sb);

View File

@ -10,49 +10,51 @@ base_dir=`pwd`


U=$base_dir/UPLOAD_LOG U=$base_dir/UPLOAD_LOG


test_expect_success 'preparing first repository' \ # create a commit in repo $1 with name $2
'test_create_repo A && cd A && commit_in () {
echo first > file1 && (
git add file1 && cd "$1" &&
git commit -m initial' echo "$2" >"$2" &&
git add "$2" &&
git commit -m "$2"
)
}


cd "$base_dir" # check that there are $2 loose objects in repo $1
test_objcount () {
echo "$2" >expect &&
git -C "$1" count-objects >actual.raw &&
cut -d' ' -f1 <actual.raw >actual &&
test_cmp expect actual
}


test_expect_success 'preparing second repository' \ test_expect_success 'preparing first repository' '
'git clone A B && cd B && test_create_repo A &&
echo second > file2 && commit_in A file1
git add file2 && '
git commit -m addition &&
git repack -a -d &&
git prune'


cd "$base_dir" test_expect_success 'preparing second repository' '
git clone A B &&
commit_in B file2 &&
git -C B repack -ad &&
git -C B prune
'


test_expect_success 'cloning with reference (-l -s)' \ test_expect_success 'cloning with reference (-l -s)' '
'git clone -l -s --reference B A C' git clone -l -s --reference B A C
'


cd "$base_dir" test_expect_success 'existence of info/alternates' '
test_line_count = 2 C/.git/objects/info/alternates
'


test_expect_success 'existence of info/alternates' \ test_expect_success 'pulling from reference' '
'test_line_count = 2 C/.git/objects/info/alternates' git -C C pull ../B master
'


cd "$base_dir" test_expect_success 'that reference gets used' '

test_objcount C 0
test_expect_success 'pulling from reference' \ '
'cd C &&
git pull ../B master'

cd "$base_dir"

test_expect_success 'that reference gets used' \
'cd C &&
echo "0 objects, 0 kilobytes" > expected &&
git count-objects > current &&
test_cmp expected current'

cd "$base_dir"

rm -f "$U.D"


test_expect_success 'cloning with reference (no -l -s)' ' test_expect_success 'cloning with reference (no -l -s)' '
GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D
@ -63,95 +65,69 @@ test_expect_success 'fetched no objects' '
! grep " want" "$U.D" ! grep " want" "$U.D"
' '


cd "$base_dir" test_expect_success 'existence of info/alternates' '
test_line_count = 1 D/.git/objects/info/alternates
'


test_expect_success 'existence of info/alternates' \ test_expect_success 'pulling from reference' '
'test_line_count = 1 D/.git/objects/info/alternates' git -C D pull ../B master
'


cd "$base_dir" test_expect_success 'that reference gets used' '
test_objcount D 0
'


test_expect_success 'pulling from reference' \ test_expect_success 'updating origin' '
'cd D && git pull ../B master' commit_in A file3 &&
git -C A repack -ad &&
git -C A prune
'


cd "$base_dir" test_expect_success 'pulling changes from origin' '

git -C C pull origin
test_expect_success 'that reference gets used' \ '
'cd D && echo "0 objects, 0 kilobytes" > expected &&
git count-objects > current &&
test_cmp expected current'

cd "$base_dir"

test_expect_success 'updating origin' \
'cd A &&
echo third > file3 &&
git add file3 &&
git commit -m update &&
git repack -a -d &&
git prune'

cd "$base_dir"

test_expect_success 'pulling changes from origin' \
'cd C &&
git pull origin'

cd "$base_dir"


# the 2 local objects are commit and tree from the merge # the 2 local objects are commit and tree from the merge
test_expect_success 'that alternate to origin gets used' \ test_expect_success 'that alternate to origin gets used' '
'cd C && test_objcount C 2
echo "2 objects" > expected && '
git count-objects | cut -d, -f1 > current &&
test_cmp expected current'


cd "$base_dir" test_expect_success 'pulling changes from origin' '

git -C D pull origin
test_expect_success 'pulling changes from origin' \ '
'cd D &&
git pull origin'

cd "$base_dir"


# the 5 local objects are expected; file3 blob, commit in A to add it # the 5 local objects are expected; file3 blob, commit in A to add it
# and its tree, and 2 are our tree and the merge commit. # and its tree, and 2 are our tree and the merge commit.
test_expect_success 'check objects expected to exist locally' \ test_expect_success 'check objects expected to exist locally' '
'cd D && test_objcount D 5
echo "5 objects" > expected && '
git count-objects | cut -d, -f1 > current &&
test_cmp expected current'


cd "$base_dir" test_expect_success 'preparing alternate repository #1' '
test_create_repo F &&
commit_in F file1
'


test_expect_success 'preparing alternate repository #1' \ test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' '
'test_create_repo F && cd F && git clone F G &&
echo first > file1 && commit_in F file2
git add file1 && '
git commit -m initial'


cd "$base_dir" test_expect_success 'cloning alternate repo #1, using #2 as reference' '
git clone --reference G F H
'


test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' \ test_expect_success 'cloning with reference being subset of source (-l -s)' '
'git clone F G && cd F && git clone -l -s --reference A B E
echo second > file2 && '
git add file2 &&
git commit -m addition'


cd "$base_dir" test_expect_success 'cloning with multiple references drops duplicates' '

git clone -s --reference B --reference A --reference B A dups &&
test_expect_success 'cloning alternate repo #1, using #2 as reference' \ test_line_count = 2 dups/.git/objects/info/alternates
'git clone --reference G F H' '

cd "$base_dir"

test_expect_success 'cloning with reference being subset of source (-l -s)' \
'git clone -l -s --reference A B E'

cd "$base_dir"


test_expect_success 'clone with reference from a tagged repository' ' test_expect_success 'clone with reference from a tagged repository' '
( (
cd A && git tag -a -m 'tagged' HEAD cd A && git tag -a -m tagged HEAD
) && ) &&
git clone --reference=A A I git clone --reference=A A I
' '
@ -168,8 +144,6 @@ test_expect_success 'prepare branched repository' '
) )
' '


rm -f "$U.K"

test_expect_success 'fetch with incomplete alternates' ' test_expect_success 'fetch with incomplete alternates' '
git init K && git init K &&
echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates &&

View File

@ -1029,10 +1029,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (!core_apply_sparse_checkout || !o->update) if (!core_apply_sparse_checkout || !o->update)
o->skip_sparse_checkout = 1; o->skip_sparse_checkout = 1;
if (!o->skip_sparse_checkout) { if (!o->skip_sparse_checkout) {
if (add_excludes_from_file_to_list(git_path("info/sparse-checkout"), "", 0, &el, 0) < 0) char *sparse = git_pathdup("info/sparse-checkout");
if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0)
o->skip_sparse_checkout = 1; o->skip_sparse_checkout = 1;
else else
o->el = &el; o->el = &el;
free(sparse);
} }


memset(&o->result, 0, sizeof(o->result)); memset(&o->result, 0, sizeof(o->result));

View File

@ -1171,7 +1171,7 @@ static void show_rebase_in_progress(struct wt_status *s,
status_printf_ln(s, color, status_printf_ln(s, color,
_(" (use \"git rebase --abort\" to check out the original branch)")); _(" (use \"git rebase --abort\" to check out the original branch)"));
} }
} else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) { } else if (state->rebase_in_progress || !stat(git_path_merge_msg(), &st)) {
print_rebase_state(s, state, color); print_rebase_state(s, state, color);
if (s->hints) if (s->hints)
status_printf_ln(s, color, status_printf_ln(s, color,
@ -1368,7 +1368,7 @@ void wt_status_get_state(struct wt_status_state *state,
struct stat st; struct stat st;
unsigned char sha1[20]; unsigned char sha1[20];


if (!stat(git_path("MERGE_HEAD"), &st)) { if (!stat(git_path_merge_head(), &st)) {
state->merge_in_progress = 1; state->merge_in_progress = 1;
} else if (!stat(git_path("rebase-apply"), &st)) { } else if (!stat(git_path("rebase-apply"), &st)) {
if (!stat(git_path("rebase-apply/applying"), &st)) { if (!stat(git_path("rebase-apply/applying"), &st)) {
@ -1387,7 +1387,7 @@ void wt_status_get_state(struct wt_status_state *state,
state->rebase_in_progress = 1; state->rebase_in_progress = 1;
state->branch = read_and_strip_branch("rebase-merge/head-name"); state->branch = read_and_strip_branch("rebase-merge/head-name");
state->onto = read_and_strip_branch("rebase-merge/onto"); state->onto = read_and_strip_branch("rebase-merge/onto");
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st) && } else if (!stat(git_path_cherry_pick_head(), &st) &&
!get_sha1("CHERRY_PICK_HEAD", sha1)) { !get_sha1("CHERRY_PICK_HEAD", sha1)) {
state->cherry_pick_in_progress = 1; state->cherry_pick_in_progress = 1;
hashcpy(state->cherry_pick_head_sha1, sha1); hashcpy(state->cherry_pick_head_sha1, sha1);
@ -1396,7 +1396,7 @@ void wt_status_get_state(struct wt_status_state *state,
state->bisect_in_progress = 1; state->bisect_in_progress = 1;
state->branch = read_and_strip_branch("BISECT_START"); state->branch = read_and_strip_branch("BISECT_START");
} }
if (!stat(git_path("REVERT_HEAD"), &st) && if (!stat(git_path_revert_head(), &st) &&
!get_sha1("REVERT_HEAD", sha1)) { !get_sha1("REVERT_HEAD", sha1)) {
state->revert_in_progress = 1; state->revert_in_progress = 1;
hashcpy(state->revert_head_sha1, sha1); hashcpy(state->revert_head_sha1, sha1);