Skip to content

Commit f932729

Browse files
peffgitster
authored andcommitted
memoize common git-path "constant" files
One of the most common uses of git_path() is to pass a constant, like git_path("MERGE_MSG"). This has two drawbacks: 1. The return value is a static buffer, and the lifetime is dependent on other calls to git_path, etc. 2. There's no compile-time checking of the pathname. This is OK for a one-off (after all, we have to spell it correctly at least once), but many of these constant strings appear throughout the code. This patch introduces a series of functions to "memoize" these strings, which are essentially globals for the lifetime of the program. We compute the value once, take ownership of the buffer, and return the cached value for subsequent calls. cache.h provides a helper macro for defining these functions as one-liners, and defines a few common ones for global use. Using a macro is a little bit gross, but it does nicely document the purpose of the functions. If we need to touch them all later (e.g., because we learned how to change the git_dir variable at runtime, and need to invalidate all of the stored values), it will be much easier to have the complete list. Note that the shared-global functions have separate, manual declarations. We could do something clever with the macros (e.g., expand it to a declaration in some places, and a declaration _and_ a definition in path.c). But there aren't that many, and it's probably better to stay away from too-magical macros. Likewise, if we abandon the C preprocessor in favor of generating these with a script, we could get much fancier. E.g., normalizing "FOO/BAR-BAZ" into "git_path_foo_bar_baz". But the small amount of saved typing is probably not worth the resulting confusion to readers who want to grep for the function's definition. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 0ea68e4 commit f932729

17 files changed

+151
-119
lines changed

attr.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ static int git_attr_system(void)
490490
return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
491491
}
492492

493+
static GIT_PATH_FUNC(git_path_info_attributes, INFOATTRIBUTES_FILE)
494+
493495
static void bootstrap_attr_stack(void)
494496
{
495497
struct attr_stack *elem;
@@ -531,7 +533,7 @@ static void bootstrap_attr_stack(void)
531533
debug_push(elem);
532534
}
533535

534-
elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
536+
elem = read_attr_from_file(git_path_info_attributes(), 1);
535537
if (!elem)
536538
elem = xcalloc(1, sizeof(*elem));
537539
elem->origin = NULL;

bisect.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,13 @@ static int read_bisect_refs(void)
420420
return for_each_ref_in("refs/bisect/", register_ref, NULL);
421421
}
422422

423+
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
424+
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
425+
423426
static void read_bisect_paths(struct argv_array *array)
424427
{
425428
struct strbuf str = STRBUF_INIT;
426-
const char *filename = git_path("BISECT_NAMES");
429+
const char *filename = git_path_bisect_names();
427430
FILE *fp = fopen(filename, "r");
428431

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

645648
static int is_expected_rev(const struct object_id *oid)
646649
{
647-
const char *filename = git_path("BISECT_EXPECTED_REV");
650+
const char *filename = git_path_bisect_expected_rev();
648651
struct stat st;
649652
struct strbuf str = STRBUF_INIT;
650653
FILE *fp;

branch.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,11 @@ void create_branch(const char *head,
302302

303303
void remove_branch_state(void)
304304
{
305-
unlink(git_path("CHERRY_PICK_HEAD"));
306-
unlink(git_path("REVERT_HEAD"));
307-
unlink(git_path("MERGE_HEAD"));
308-
unlink(git_path("MERGE_RR"));
309-
unlink(git_path("MERGE_MSG"));
310-
unlink(git_path("MERGE_MODE"));
311-
unlink(git_path("SQUASH_MSG"));
305+
unlink(git_path_cherry_pick_head());
306+
unlink(git_path_revert_head());
307+
unlink(git_path_merge_head());
308+
unlink(git_path_merge_rr());
309+
unlink(git_path_merge_msg());
310+
unlink(git_path_merge_mode());
311+
unlink(git_path_squash_msg());
312312
}

builtin/blame.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -2227,20 +2227,19 @@ static struct commit_list **append_parent(struct commit_list **tail, const unsig
22272227
static void append_merge_parents(struct commit_list **tail)
22282228
{
22292229
int merge_head;
2230-
const char *merge_head_file = git_path("MERGE_HEAD");
22312230
struct strbuf line = STRBUF_INIT;
22322231

2233-
merge_head = open(merge_head_file, O_RDONLY);
2232+
merge_head = open(git_path_merge_head(), O_RDONLY);
22342233
if (merge_head < 0) {
22352234
if (errno == ENOENT)
22362235
return;
2237-
die("cannot open '%s' for reading", merge_head_file);
2236+
die("cannot open '%s' for reading", git_path_merge_head());
22382237
}
22392238

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

builtin/commit.c

+16-16
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
166166

167167
static void determine_whence(struct wt_status *s)
168168
{
169-
if (file_exists(git_path("MERGE_HEAD")))
169+
if (file_exists(git_path_merge_head()))
170170
whence = FROM_MERGE;
171-
else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
171+
else if (file_exists(git_path_cherry_pick_head())) {
172172
whence = FROM_CHERRY_PICK;
173173
if (file_exists(git_path(SEQ_DIR)))
174174
sequencer_in_use = 1;
@@ -725,12 +725,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
725725
format_commit_message(commit, "fixup! %s\n\n",
726726
&sb, &ctx);
727727
hook_arg1 = "message";
728-
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
729-
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
728+
} else if (!stat(git_path_merge_msg(), &statbuf)) {
729+
if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
730730
die_errno(_("could not read MERGE_MSG"));
731731
hook_arg1 = "merge";
732-
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
733-
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
732+
} else if (!stat(git_path_squash_msg(), &statbuf)) {
733+
if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
734734
die_errno(_("could not read SQUASH_MSG"));
735735
hook_arg1 = "squash";
736736
} else if (template_file) {
@@ -1684,10 +1684,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
16841684
if (!reflog_msg)
16851685
reflog_msg = "commit (merge)";
16861686
pptr = &commit_list_insert(current_head, pptr)->next;
1687-
fp = fopen(git_path("MERGE_HEAD"), "r");
1687+
fp = fopen(git_path_merge_head(), "r");
16881688
if (fp == NULL)
16891689
die_errno(_("could not open '%s' for reading"),
1690-
git_path("MERGE_HEAD"));
1690+
git_path_merge_head());
16911691
while (strbuf_getline(&m, fp, '\n') != EOF) {
16921692
struct commit *parent;
16931693

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

1778-
unlink(git_path("CHERRY_PICK_HEAD"));
1779-
unlink(git_path("REVERT_HEAD"));
1780-
unlink(git_path("MERGE_HEAD"));
1781-
unlink(git_path("MERGE_MSG"));
1782-
unlink(git_path("MERGE_MODE"));
1783-
unlink(git_path("SQUASH_MSG"));
1778+
unlink(git_path_cherry_pick_head());
1779+
unlink(git_path_revert_head());
1780+
unlink(git_path_merge_head());
1781+
unlink(git_path_merge_msg());
1782+
unlink(git_path_merge_mode());
1783+
unlink(git_path_squash_msg());
17841784

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

builtin/fetch.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
591591
const char *what, *kind;
592592
struct ref *rm;
593593
char *url;
594-
const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
594+
const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
595595
int want_status;
596596

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

835835
static int truncate_fetch_head(void)
836836
{
837-
const char *filename = git_path("FETCH_HEAD");
837+
const char *filename = git_path_fetch_head();
838838
FILE *fp = fopen(filename, "w");
839839

840840
if (!fp)

builtin/merge.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ static struct option builtin_merge_options[] = {
231231
/* Cleans up metadata that is uninteresting after a succeeded merge. */
232232
static void drop_save(void)
233233
{
234-
unlink(git_path("MERGE_HEAD"));
235-
unlink(git_path("MERGE_MSG"));
236-
unlink(git_path("MERGE_MODE"));
234+
unlink(git_path_merge_head());
235+
unlink(git_path_merge_msg());
236+
unlink(git_path_merge_mode());
237237
}
238238

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

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

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

767767
static void read_merge_msg(struct strbuf *msg)
768768
{
769-
const char *filename = git_path("MERGE_MSG");
769+
const char *filename = git_path_merge_msg();
770770
strbuf_reset(msg);
771771
if (strbuf_read_file(msg, filename, 0) < 0)
772772
die_errno(_("Could not read from '%s'"), filename);
@@ -799,10 +799,10 @@ static void prepare_to_commit(struct commit_list *remoteheads)
799799
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
800800
write_merge_msg(&msg);
801801
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
802-
git_path("MERGE_MSG"), "merge", NULL))
802+
git_path_merge_msg(), "merge", NULL))
803803
abort_commit(remoteheads, NULL);
804804
if (0 < option_edit) {
805-
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
805+
if (launch_editor(git_path_merge_msg(), NULL, NULL))
806806
abort_commit(remoteheads, NULL);
807807
}
808808
read_merge_msg(&msg);
@@ -865,7 +865,7 @@ static int suggest_conflicts(void)
865865
FILE *fp;
866866
struct strbuf msgbuf = STRBUF_INIT;
867867

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

980-
filename = git_path("MERGE_MODE");
980+
filename = git_path_merge_mode();
981981
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
982982
if (fd < 0)
983983
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
10701070
if (!merge_names)
10711071
merge_names = &fetch_head_file;
10721072

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

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

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

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

builtin/reset.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static const char *reset_type_names[] = {
3636

3737
static inline int is_merge(void)
3838
{
39-
return !access(git_path("MERGE_HEAD"), F_OK);
39+
return !access(git_path_merge_head(), F_OK);
4040
}
4141

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

cache.h

+26
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,32 @@ extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
735735

736736
extern void report_linked_checkout_garbage(void);
737737

738+
/*
739+
* You can define a static memoized git path like:
740+
*
741+
* static GIT_PATH_FUNC(git_path_foo, "FOO");
742+
*
743+
* or use one of the global ones below.
744+
*/
745+
#define GIT_PATH_FUNC(func, filename) \
746+
const char *func(void) \
747+
{ \
748+
static char *ret; \
749+
if (!ret) \
750+
ret = git_pathdup(filename); \
751+
return ret; \
752+
}
753+
754+
const char *git_path_cherry_pick_head(void);
755+
const char *git_path_revert_head(void);
756+
const char *git_path_squash_msg(void);
757+
const char *git_path_merge_msg(void);
758+
const char *git_path_merge_rr(void);
759+
const char *git_path_merge_mode(void);
760+
const char *git_path_merge_head(void);
761+
const char *git_path_fetch_head(void);
762+
const char *git_path_shallow(void);
763+
738764
/*
739765
* Return the name of the file in the local object database that would
740766
* be used to store a loose object with the specified sha1. The

contrib/examples/builtin-fetch--tool.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
516516

517517
if (argc != 8)
518518
return error("append-fetch-head takes 6 args");
519-
filename = git_path("FETCH_HEAD");
519+
filename = git_path_fetch_head();
520520
fp = fopen(filename, "a");
521521
if (!fp)
522522
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)
534534

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

dir.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -2185,6 +2185,8 @@ int remove_dir_recursively(struct strbuf *path, int flag)
21852185
return remove_dir_recurse(path, flag, NULL);
21862186
}
21872187

2188+
static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
2189+
21882190
void setup_standard_excludes(struct dir_struct *dir)
21892191
{
21902192
const char *path;
@@ -2199,7 +2201,7 @@ void setup_standard_excludes(struct dir_struct *dir)
21992201
dir->untracked ? &dir->ss_excludes_file : NULL);
22002202

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

fetch-pack.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ static void update_shallow(struct fetch_pack_args *args,
948948

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

path.c

+10
Original file line numberDiff line numberDiff line change
@@ -933,3 +933,13 @@ char *xdg_config_home(const char *filename)
933933
return mkpathdup("%s/.config/git/%s", home, filename);
934934
return NULL;
935935
}
936+
937+
GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD")
938+
GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD")
939+
GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG")
940+
GIT_PATH_FUNC(git_path_merge_msg, "MERGE_MSG")
941+
GIT_PATH_FUNC(git_path_merge_rr, "MERGE_RR")
942+
GIT_PATH_FUNC(git_path_merge_mode, "MERGE_MODE")
943+
GIT_PATH_FUNC(git_path_merge_head, "MERGE_HEAD")
944+
GIT_PATH_FUNC(git_path_fetch_head, "FETCH_HEAD")
945+
GIT_PATH_FUNC(git_path_shallow, "shallow")

0 commit comments

Comments
 (0)