git_path() and mkpath() are handy helper functions but it is easy
to misuse, as the callers need to be careful to keep the number of
active results below 4.  Their uses have been reduced.

* 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
This commit is contained in:
Junio C Hamano 2015-08-19 14:48:56 -07:00
Родитель 51a22ce147 f932729cc7
Коммит 8c9155e031
30 изменённых файлов: 463 добавлений и 361 удалений

4
attr.c
Просмотреть файл

@ -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;

Просмотреть файл

@ -429,10 +429,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)
@ -653,7 +656,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;

Просмотреть файл

@ -302,13 +302,13 @@ 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());
} }
static void check_linked_checkout(const char *branch, const char *id) static void check_linked_checkout(const char *branch, const char *id)

Просмотреть файл

@ -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);

Просмотреть файл

@ -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, *ptr; const char *end = repo + strlen(repo), *start, *ptr;

Просмотреть файл

@ -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"

Просмотреть файл

@ -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)

Просмотреть файл

@ -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;
} }

Просмотреть файл

@ -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."));

Просмотреть файл

@ -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;
} }

Просмотреть файл

@ -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);
} }
} }

Просмотреть файл

@ -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
Просмотреть файл

@ -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

Просмотреть файл

@ -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
Просмотреть файл

@ -2174,6 +2174,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;
@ -2188,7 +2190,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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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)

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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:

Просмотреть файл

@ -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());
} }

Просмотреть файл

@ -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)

Просмотреть файл

@ -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, ...);

Просмотреть файл

@ -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;

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 &&

Просмотреть файл

@ -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));

Просмотреть файл

@ -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);