Merge branch 'ps/path-sans-the-repository'

The path.[ch] API takes an explicit repository parameter passed
throughout the callchain, instead of relying on the_repository
singleton instance.

* ps/path-sans-the-repository:
  path: adjust last remaining users of `the_repository`
  environment: move access to "core.sharedRepository" into repo settings
  environment: move access to "core.hooksPath" into repo settings
  repo-settings: introduce function to clear struct
  path: drop `git_path()` in favor of `repo_git_path()`
  rerere: let `rerere_path()` write paths into a caller-provided buffer
  path: drop `git_common_path()` in favor of `repo_common_path()`
  worktree: return allocated string from `get_worktree_git_dir()`
  path: drop `git_path_buf()` in favor of `repo_git_path_replace()`
  path: drop `git_pathdup()` in favor of `repo_git_path()`
  path: drop unused `strbuf_git_path()` function
  path: refactor `repo_submodule_path()` family of functions
  submodule: refactor `submodule_to_gitdir()` to accept a repo
  path: refactor `repo_worktree_path()` family of functions
  path: refactor `repo_git_path()` family of functions
  path: refactor `repo_common_path()` family of functions
maint
Junio C Hamano 2025-03-05 10:37:43 -08:00
commit feffb34257
62 changed files with 644 additions and 495 deletions

View File

@ -930,7 +930,7 @@ static enum bisect_error check_good_are_ancestors_of_bad(struct repository *r,
if (!current_bad_oid)
return error(_("a %s revision is needed"), term_bad);

filename = git_pathdup("BISECT_ANCESTORS_OK");
filename = repo_git_path(the_repository, "BISECT_ANCESTORS_OK");

/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))

View File

@ -397,7 +397,7 @@ static void prepare_checked_out_branches(void)
worktrees = get_worktrees();

while (worktrees[i]) {
char *old;
char *old, *wt_gitdir;
struct wt_status_state state = { 0 };
struct worktree *wt = worktrees[i++];
struct string_list update_refs = STRING_LIST_INIT_DUP;
@ -437,7 +437,8 @@ static void prepare_checked_out_branches(void)
}
wt_status_state_free_buffers(&state);

if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt),
wt_gitdir = get_worktree_git_dir(wt);
if (!sequencer_get_update_refs_state(wt_gitdir,
&update_refs)) {
struct string_list_item *item;
for_each_string_list_item(item, &update_refs) {
@ -448,6 +449,8 @@ static void prepare_checked_out_branches(void)
}
string_list_clear(&update_refs, 1);
}

free(wt_gitdir);
}

free_worktrees(worktrees);

View File

@ -158,7 +158,7 @@ static void am_state_init(struct am_state *state)

memset(state, 0, sizeof(*state));

state->dir = git_pathdup("rebase-apply");
state->dir = repo_git_path(the_repository, "rebase-apply");

state->prec = 4;


View File

@ -835,7 +835,7 @@ static void write_refspec_config(const char *src_ref_prefix,

static void dissociate_from_references(void)
{
char *alternates = git_pathdup("objects/info/alternates");
char *alternates = repo_git_path(the_repository, "objects/info/alternates");

if (!access(alternates, F_OK)) {
struct child_process cmd = CHILD_PROCESS_INIT;
@ -1219,7 +1219,7 @@ int cmd_clone(int argc,

strbuf_reset(&buf);
strbuf_addf(&buf, "%s/refs", git_dir);
safe_create_dir(buf.buf, 1);
safe_create_dir(the_repository, buf.buf, 1);

/*
* additional config can be injected with -c, make sure it's included

View File

@ -352,6 +352,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
struct pathspec pathspec;
int refresh_flags = REFRESH_QUIET;
const char *ret;
char *path = NULL;

if (is_status)
refresh_flags |= REFRESH_UNMERGED;
@ -524,9 +525,9 @@ static const char *prepare_index(const char **argv, const char *prefix,
if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to write new index file"));

hold_lock_file_for_update(&false_lock,
git_path("next-index-%"PRIuMAX,
(uintmax_t) getpid()),
path = repo_git_path(the_repository, "next-index-%"PRIuMAX,
(uintmax_t) getpid());
hold_lock_file_for_update(&false_lock, path,
LOCK_DIE_ON_ERROR);

create_base_index(current_head);
@ -542,6 +543,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
out:
string_list_clear(&partial, 0);
clear_pathspec(&pathspec);
free(path);
return ret;
}


View File

@ -775,13 +775,13 @@ static void location_options_init(struct config_location_options *opts,
opts->source.file = opts->file_to_free = git_system_config();
opts->source.scope = CONFIG_SCOPE_SYSTEM;
} else if (opts->use_local_config) {
opts->source.file = opts->file_to_free = git_pathdup("config");
opts->source.file = opts->file_to_free = repo_git_path(the_repository, "config");
opts->source.scope = CONFIG_SCOPE_LOCAL;
} else if (opts->use_worktree_config) {
struct worktree **worktrees = get_worktrees();
if (the_repository->repository_format_worktree_config)
opts->source.file = opts->file_to_free =
git_pathdup("config.worktree");
repo_git_path(the_repository, "config.worktree");
else if (worktrees[0] && worktrees[1])
die(_("--worktree cannot be used with multiple "
"working trees unless the config\n"
@ -790,7 +790,7 @@ static void location_options_init(struct config_location_options *opts,
"section in \"git help worktree\" for details"));
else
opts->source.file = opts->file_to_free =
git_pathdup("config");
repo_git_path(the_repository, "config");
opts->source.scope = CONFIG_SCOPE_LOCAL;
free_worktrees(worktrees);
} else if (opts->source.file) {
@ -1087,7 +1087,7 @@ static int show_editor(struct config_location_options *opts)
git_config(git_default_config, NULL);
config_file = opts->source.file ?
xstrdup(opts->source.file) :
git_pathdup("config");
repo_git_path(the_repository, "config");
if (opts->use_global_config) {
int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd >= 0) {

View File

@ -328,7 +328,7 @@ static void write_branch_report(FILE *rpt, struct branch *b)

static void write_crash_report(const char *err)
{
char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
char *loc = repo_git_path(the_repository, "fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
FILE *rpt = fopen(loc, "w");
struct branch *b;
unsigned long lu;
@ -3280,7 +3280,7 @@ static char* make_fast_import_path(const char *path)
{
if (!relative_marks_paths || is_absolute_path(path))
return prefix_filename(global_prefix, path);
return git_pathdup("info/fast-import/%s", path);
return repo_git_path(the_repository, "info/fast-import/%s", path);
}

static void option_import_marks(const char *marks,

View File

@ -326,7 +326,7 @@ static void check_unreachable_object(struct object *obj)
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
if (write_lost_and_found) {
char *filename = git_pathdup("lost-found/%s/%s",
char *filename = repo_git_path(the_repository, "lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
describe_object(&obj->oid));
FILE *f;
@ -1057,7 +1057,7 @@ int cmd_fsck(int argc,
struct worktree *wt = *p;
struct index_state istate =
INDEX_STATE_INIT(the_repository);
char *path;
char *path, *wt_gitdir;

/*
* Make a copy since the buffer is reusable
@ -1065,9 +1065,13 @@ int cmd_fsck(int argc,
* while we're examining the index.
*/
path = xstrdup(worktree_git_path(the_repository, wt, "index"));
read_index_from(&istate, path, get_worktree_git_dir(wt));
wt_gitdir = get_worktree_git_dir(wt);

read_index_from(&istate, path, wt_gitdir);
fsck_index(&istate, path, wt->is_current);

discard_index(&istate);
free(wt_gitdir);
free(path);
}
free_worktrees(worktrees);

View File

@ -99,9 +99,11 @@ static void process_log_file(void)
/* There was some error recorded in the lock file */
commit_lock_file(&log_lock);
} else {
char *path = repo_git_path(the_repository, "gc.log");
/* No error, clean up any old gc.log */
unlink(git_path("gc.log"));
unlink(path);
rollback_lock_file(&log_lock);
free(path);
}
}

@ -300,8 +302,11 @@ static int too_many_loose_objects(struct gc_config *cfg)
int num_loose = 0;
int needed = 0;
const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
char *path;

dir = opendir(git_path("objects/17"));
path = repo_git_path(the_repository, "objects/17");
dir = opendir(path);
free(path);
if (!dir)
return 0;

@ -550,7 +555,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
if (xgethostname(my_host, sizeof(my_host)))
xsnprintf(my_host, sizeof(my_host), "unknown");

pidfile_path = git_pathdup("gc.pid");
pidfile_path = repo_git_path(the_repository, "gc.pid");
fd = hold_lock_file_for_update(&lock, pidfile_path,
LOCK_DIE_ON_ERROR);
if (!force) {
@ -611,7 +616,7 @@ static int report_last_gc_error(void)
int ret = 0;
ssize_t len;
struct stat st;
char *gc_log_path = git_pathdup("gc.log");
char *gc_log_path = repo_git_path(the_repository, "gc.log");

if (stat(gc_log_path, &st)) {
if (errno == ENOENT)
@ -826,11 +831,12 @@ struct repository *repo UNUSED)
}

if (daemonized) {
hold_lock_file_for_update(&log_lock,
git_path("gc.log"),
char *path = repo_git_path(the_repository, "gc.log");
hold_lock_file_for_update(&log_lock, path,
LOCK_DIE_ON_ERROR);
dup2(get_lock_file_fd(&log_lock), 2);
atexit(process_log_file_at_exit);
free(path);
}

gc_before_repack(&opts, &cfg);
@ -892,8 +898,11 @@ struct repository *repo UNUSED)
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));

if (!daemonized)
unlink(git_path("gc.log"));
if (!daemonized) {
char *path = repo_git_path(the_repository, "gc.log");
unlink(path);
free(path);
}

out:
gc_config_release(&cfg);

View File

@ -132,8 +132,8 @@ int cmd_init_db(int argc,
* and we know shared_repository should always be 0;
* but just in case we play safe.
*/
saved = get_shared_repository();
set_shared_repository(0);
saved = repo_settings_get_shared_repository(the_repository);
repo_settings_set_shared_repository(the_repository, 0);
switch (safe_create_leading_directories_const(argv[0])) {
case SCLD_OK:
case SCLD_PERMS:
@ -145,7 +145,7 @@ int cmd_init_db(int argc,
die_errno(_("cannot mkdir %s"), argv[0]);
break;
}
set_shared_repository(saved);
repo_settings_set_shared_repository(the_repository, saved);
if (mkdir(argv[0], 0777) < 0)
die_errno(_("cannot mkdir %s"), argv[0]);
mkdir_tried = 1;
@ -175,7 +175,7 @@ int cmd_init_db(int argc,
}

if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
repo_settings_set_shared_repository(the_repository, init_shared_repository);

/*
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR

View File

@ -2309,8 +2309,8 @@ int cmd_format_patch(int argc,
* We consider <outdir> as 'outside of gitdir', therefore avoid
* applying adjust_shared_perm in s-c-l-d.
*/
saved = get_shared_repository();
set_shared_repository(0);
saved = repo_settings_get_shared_repository(the_repository);
repo_settings_set_shared_repository(the_repository, 0);
switch (safe_create_leading_directories_const(output_directory)) {
case SCLD_OK:
case SCLD_EXISTS:
@ -2319,7 +2319,7 @@ int cmd_format_patch(int argc,
die(_("could not create leading directories "
"of '%s'"), output_directory);
}
set_shared_repository(saved);
repo_settings_set_shared_repository(the_repository, saved);
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
die_errno(_("could not create directory '%s'"),
output_directory);

View File

@ -197,7 +197,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
struct strbuf buf = STRBUF_INIT;

/* write the template message before editing: */
d->edit_path = git_pathdup("NOTES_EDITMSG");
d->edit_path = repo_git_path(the_repository, "NOTES_EDITMSG");
fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);

if (d->msg_nr)
@ -979,6 +979,8 @@ static int merge(int argc, const char **argv, const char *prefix,
else { /* Merge has unresolved conflicts */
struct worktree **worktrees;
const struct worktree *wt;
char *path;

/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
refs_update_ref(get_main_ref_store(the_repository), msg.buf,
"NOTES_MERGE_PARTIAL", &result_oid, NULL,
@ -994,10 +996,13 @@ static int merge(int argc, const char **argv, const char *prefix,
if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref, NULL))
die(_("failed to store link to current notes ref (%s)"),
notes_ref);

path = repo_git_path(the_repository, NOTES_MERGE_WORKTREE);
fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
"and commit the result with 'git notes merge --commit', "
"or abort the merge with 'git notes merge --abort'.\n"),
git_path(NOTES_MERGE_WORKTREE));
path);
free(path);
}

free_notes(t);

View File

@ -644,7 +644,7 @@ static int run_am(struct rebase_options *opts)
return run_command(&am);
}

rebased_patches = xstrdup(git_path("rebased-patches"));
rebased_patches = repo_git_path(the_repository, "rebased-patches");
format_patch.out = open(rebased_patches,
O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (format_patch.out < 0) {

View File

@ -1435,7 +1435,8 @@ static const char *push_to_checkout(unsigned char *hash,

static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
{
const char *retval, *git_dir;
const char *retval;
char *git_dir;
struct strvec env = STRVEC_INIT;
int invoked_hook;

@ -1453,6 +1454,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
retval = push_to_deploy(sha1, &env, worktree->path);

strvec_clear(&env);
free(git_dir);
return retval;
}


View File

@ -644,9 +644,11 @@ static int migrate_file(struct remote *remote)
git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
#ifndef WITH_BREAKING_CHANGES
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name));
unlink_or_warn(repo_git_path_replace(the_repository, &buf,
"remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES)
unlink_or_warn(git_path("branches/%s", remote->name));
unlink_or_warn(repo_git_path_replace(the_repository, &buf,
"branches/%s", remote->name));
#endif /* WITH_BREAKING_CHANGES */
strbuf_release(&buf);


View File

@ -345,7 +345,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
}
strbuf_release(&ref);

tmpfile = git_pathdup("REPLACE_EDITOBJ");
tmpfile = repo_git_path(the_repository, "REPLACE_EDITOBJ");
if (export_object(&old_oid, type, raw, tmpfile)) {
free(tmpfile);
return -1;

View File

@ -4,9 +4,9 @@
#include "config.h"
#include "gettext.h"
#include "parse-options.h"

#include "string-list.h"
#include "rerere.h"
#include "strbuf.h"
#include "string-list.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
#include "pathspec.h"
@ -112,15 +112,18 @@ int cmd_rerere(int argc,
merge_rr.items[i].util = NULL;
}
} else if (!strcmp(argv[0], "diff")) {
struct strbuf buf = STRBUF_INIT;
if (setup_rerere(the_repository, &merge_rr,
flags | RERERE_READONLY) < 0)
return 0;
for (size_t i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const struct rerere_id *id = merge_rr.items[i].util;
if (diff_two(rerere_path(id, "preimage"), path, path, path))
die(_("unable to generate diff for '%s'"), rerere_path(id, NULL));
if (diff_two(rerere_path(&buf, id, "preimage"), path, path, path))
die(_("unable to generate diff for '%s'"), rerere_path(&buf, id, NULL));
}

strbuf_release(&buf);
} else
usage_with_options(rerere_usage, options);


View File

@ -789,8 +789,8 @@ int cmd_rev_parse(int argc,
if (!strcmp(arg, "--git-path")) {
if (!argv[i + 1])
die(_("--git-path requires an argument"));
strbuf_reset(&buf);
print_path(git_path("%s", argv[i + 1]), prefix,
print_path(repo_git_path_replace(the_repository, &buf,
"%s", argv[i + 1]), prefix,
format,
DEFAULT_RELATIVE_IF_SHARED);
i++;
@ -1083,7 +1083,7 @@ int cmd_rev_parse(int argc,
die(_("Could not read the index"));
if (the_repository->index->split_index) {
const struct object_id *oid = &the_repository->index->split_index->base_oid;
const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
const char *path = repo_git_path_replace(the_repository, &buf, "sharedindex.%s", oid_to_hex(oid));
print_path(path, prefix, format, DEFAULT_RELATIVE);
}
continue;

View File

@ -1301,7 +1301,7 @@ static void sync_submodule(const char *path, const char *prefix,
remote_key = xstrfmt("remote.%s.url", default_remote);
free(default_remote);

submodule_to_gitdir(&sb, path);
submodule_to_gitdir(the_repository, &sb, path);
strbuf_addstr(&sb, "/config");

if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
@ -1826,7 +1826,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,

connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);

p = git_pathdup_submodule(clone_data_path, "config");
p = repo_submodule_path(the_repository, clone_data_path, "config");
if (!p)
die(_("could not get submodule directory for '%s'"), clone_data_path);


View File

@ -667,7 +667,7 @@ int cmd_tag(int argc,
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
path = git_pathdup("TAG_EDITMSG");
path = repo_git_path(the_repository, "TAG_EDITMSG");
create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
&trailer_args, path);
}

View File

@ -151,7 +151,7 @@ static int delete_git_dir(const char *id)
struct strbuf sb = STRBUF_INIT;
int ret;

strbuf_addstr(&sb, git_common_path("worktrees/%s", id));
repo_common_path_append(the_repository, &sb, "worktrees/%s", id);
ret = remove_dir_recursively(&sb, 0);
if (ret < 0 && errno == ENOTDIR)
ret = unlink(sb.buf);
@ -163,7 +163,9 @@ static int delete_git_dir(const char *id)

static void delete_worktrees_dir_if_empty(void)
{
rmdir(git_path("worktrees")); /* ignore failed removal */
char *path = repo_git_path(the_repository, "worktrees");
rmdir(path); /* ignore failed removal */
free(path);
}

static void prune_worktree(const char *id, const char *reason)
@ -212,8 +214,13 @@ static void prune_worktrees(void)
struct strbuf reason = STRBUF_INIT;
struct strbuf main_path = STRBUF_INIT;
struct string_list kept = STRING_LIST_INIT_DUP;
DIR *dir = opendir(git_path("worktrees"));
char *path;
DIR *dir;
struct dirent *d;

path = repo_git_path(the_repository, "worktrees");
dir = opendir(path);
free(path);
if (!dir)
return;
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
@ -337,7 +344,7 @@ static void check_candidate_path(const char *path,

static void copy_sparse_checkout(const char *worktree_git_dir)
{
char *from_file = git_pathdup("info/sparse-checkout");
char *from_file = repo_git_path(the_repository, "info/sparse-checkout");
char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir);

if (file_exists(from_file)) {
@ -353,7 +360,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)

static void copy_filtered_worktree_config(const char *worktree_git_dir)
{
char *from_file = git_pathdup("config.worktree");
char *from_file = repo_git_path(the_repository, "config.worktree");
char *to_file = xstrfmt("%s/config.worktree", worktree_git_dir);

if (file_exists(from_file)) {
@ -457,7 +464,7 @@ static int add_worktree(const char *path, const char *refname,
BUG("How come '%s' becomes empty after sanitization?", sb.buf);
strbuf_reset(&sb);
name = sb_name.buf;
git_path_buf(&sb_repo, "worktrees/%s", name);
repo_git_path_replace(the_repository, &sb_repo, "worktrees/%s", name);
len = sb_repo.len;
if (safe_create_leading_directories_const(sb_repo.buf))
die_errno(_("could not create leading directories of '%s'"),
@ -657,8 +664,9 @@ static int can_use_local_refs(const struct add_opts *opts)
if (!opts->quiet) {
struct strbuf path = STRBUF_INIT;
struct strbuf contents = STRBUF_INIT;
char *wt_gitdir = get_worktree_git_dir(NULL);

strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
strbuf_add_real_path(&path, wt_gitdir);
strbuf_addstr(&path, "/HEAD");
strbuf_read_file(&contents, path.buf, 64);
strbuf_stripspace(&contents, NULL);
@ -670,6 +678,7 @@ static int can_use_local_refs(const struct add_opts *opts)
path.buf, contents.buf);
strbuf_release(&path);
strbuf_release(&contents);
free(wt_gitdir);
}
return 1;
}
@ -1100,6 +1109,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix,
OPT_END()
};
struct worktree **worktrees, *wt;
char *path;

ac = parse_options(ac, av, prefix, options, git_worktree_lock_usage, 0);
if (ac != 1)
@ -1120,9 +1130,11 @@ static int lock_worktree(int ac, const char **av, const char *prefix,
die(_("'%s' is already locked"), av[0]);
}

write_file(git_common_path("worktrees/%s/locked", wt->id),
"%s", reason);
path = repo_common_path(the_repository, "worktrees/%s/locked", wt->id);
write_file(path, "%s", reason);

free_worktrees(worktrees);
free(path);
return 0;
}

@ -1133,6 +1145,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix,
OPT_END()
};
struct worktree **worktrees, *wt;
char *path;
int ret;

ac = parse_options(ac, av, prefix, options, git_worktree_unlock_usage, 0);
@ -1147,8 +1160,12 @@ static int unlock_worktree(int ac, const char **av, const char *prefix,
die(_("The main working tree cannot be locked or unlocked"));
if (!worktree_lock_reason(wt))
die(_("'%s' is not locked"), av[0]);
ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id));

path = repo_common_path(the_repository, "worktrees/%s/locked", wt->id);
ret = unlink_or_warn(path);

free_worktrees(worktrees);
free(path);
return ret;
}

@ -1157,6 +1174,9 @@ static void validate_no_submodules(const struct worktree *wt)
struct index_state istate = INDEX_STATE_INIT(the_repository);
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
char *wt_gitdir;

wt_gitdir = get_worktree_git_dir(wt);

if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
/*
@ -1166,7 +1186,7 @@ static void validate_no_submodules(const struct worktree *wt)
*/
found_submodules = 1;
} else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0) {
wt_gitdir) > 0) {
for (i = 0; i < istate.cache_nr; i++) {
struct cache_entry *ce = istate.cache[i];
int err;
@ -1185,6 +1205,7 @@ static void validate_no_submodules(const struct worktree *wt)
}
discard_index(&istate);
strbuf_release(&path);
free(wt_gitdir);

if (found_submodules)
die(_("working trees containing submodules cannot be moved or removed"));

View File

@ -2084,7 +2084,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
return -1;
}

if (adjust_shared_perm(get_tempfile_path(graph_layer))) {
if (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {
error(_("unable to adjust shared permissions for '%s'"),
get_tempfile_path(graph_layer));
return -1;

View File

@ -50,15 +50,15 @@ void probe_utf8_pathname_composition(void)
int output_fd;
if (precomposed_unicode != -1)
return; /* We found it defined in the global config, respect it */
git_path_buf(&path, "%s", auml_nfc);
repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);
if (output_fd >= 0) {
close(output_fd);
git_path_buf(&path, "%s", auml_nfd);
repo_git_path_replace(the_repository, &path, "%s", auml_nfd);
precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
git_config_set("core.precomposeunicode",
precomposed_unicode ? "true" : "false");
git_path_buf(&path, "%s", auml_nfc);
repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
if (unlink(path.buf))
die_errno(_("failed to unlink '%s'"), path.buf);
}

View File

@ -1437,11 +1437,6 @@ static int git_default_core_config(const char *var, const char *value,
return git_config_pathname(&git_attributes_file, var, value);
}

if (!strcmp(var, "core.hookspath")) {
FREE_AND_NULL(git_hooks_path);
return git_config_pathname(&git_hooks_path, var, value);
}

if (!strcmp(var, "core.bare")) {
is_bare_repository_cfg = git_config_bool(var, value);
return 0;

4
copy.c
View File

@ -1,3 +1,5 @@
#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "copy.h"
#include "path.h"
@ -57,7 +59,7 @@ int copy_file(const char *dst, const char *src, int mode)
if (close(fdo) != 0)
return error_errno("%s: close error", dst);

if (!status && adjust_shared_perm(dst))
if (!status && adjust_shared_perm(the_repository, dst))
return -1;

return status;

2
dir.c
View File

@ -3451,7 +3451,7 @@ void setup_standard_excludes(struct dir_struct *dir)

char *get_sparse_checkout_filename(void)
{
return git_pathdup("info/sparse-checkout");
return repo_git_path(the_repository, "info/sparse-checkout");
}

int get_sparse_checkout_patterns(struct pattern_list *pl)

View File

@ -142,10 +142,8 @@ int strbuf_edit_interactively(struct repository *r,
struct strbuf sb = STRBUF_INIT;
int fd, res = 0;

if (!is_absolute_path(path)) {
strbuf_repo_git_path(&sb, r, "%s", path);
path = sb.buf;
}
if (!is_absolute_path(path))
path = repo_git_path_append(r, &sb, "%s", path);

fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)

View File

@ -43,7 +43,6 @@ char *git_log_output_encoding;
char *apply_default_whitespace;
char *apply_default_ignorewhitespace;
char *git_attributes_file;
char *git_hooks_path;
int zlib_compression_level = Z_BEST_SPEED;
int pack_compression_level = Z_DEFAULT_COMPRESSION;
int fsync_object_files = -1;
@ -208,32 +207,6 @@ const char *get_commit_output_encoding(void)
return git_commit_encoding ? git_commit_encoding : "UTF-8";
}

static int the_shared_repository = PERM_UMASK;
static int need_shared_repository_from_config = 1;

void set_shared_repository(int value)
{
the_shared_repository = value;
need_shared_repository_from_config = 0;
}

int get_shared_repository(void)
{
if (need_shared_repository_from_config) {
const char *var = "core.sharedrepository";
const char *value;
if (!git_config_get_value(var, &value))
the_shared_repository = git_config_perm(var, value);
need_shared_repository_from_config = 0;
}
return the_shared_repository;
}

void reset_shared_repository(void)
{
need_shared_repository_from_config = 1;
}

int use_optional_locks(void)
{
return git_env_bool(GIT_OPTIONAL_LOCKS_ENVIRONMENT, 1);

View File

@ -134,16 +134,6 @@ void setup_git_env(const char *git_dir);
*/
int have_git_dir(void);

/*
* Accessors for the core.sharedrepository config which lazy-load the value
* from the config (if not already set). The "reset" function can be
* used to unset "set" or cached value, meaning that the value will be loaded
* fresh from the config file on the next call to get_shared_repository().
*/
void set_shared_repository(int value);
int get_shared_repository(void);
void reset_shared_repository(void);

extern int is_bare_repository_cfg;
int is_bare_repository(void);
extern char *git_work_tree_cfg;
@ -160,7 +150,6 @@ extern int warn_on_object_refname_ambiguity;
extern char *apply_default_whitespace;
extern char *apply_default_ignorewhitespace;
extern char *git_attributes_file;
extern char *git_hooks_path;
extern int zlib_compression_level;
extern int pack_compression_level;
extern size_t packed_git_window_size;

3
hook.c
View File

@ -16,8 +16,7 @@ const char *find_hook(struct repository *r, const char *name)

int found_hook;

strbuf_reset(&path);
strbuf_repo_git_path(&path, r, "hooks/%s", name);
repo_git_path_replace(r, &path, "hooks/%s", name);
found_hook = access(path.buf, X_OK) >= 0;
#ifdef STRIP_EXTENSION
if (!found_hook) {

View File

@ -183,7 +183,7 @@ static void send_strbuf(struct strbuf *hdr,
static void send_local_file(struct strbuf *hdr, const char *the_type,
const char *name)
{
char *p = git_pathdup("%s", name);
char *p = repo_git_path(the_repository, "%s", name);
size_t buf_alloc = 8192;
char *buf = xmalloc(buf_alloc);
int fd;

View File

@ -75,7 +75,7 @@ static int load_one_loose_object_map(struct repository *repo, struct object_dire
insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);

strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
repo_common_path_replace(repo, &path, "objects/loose-object-idx");
fp = fopen(path.buf, "rb");
if (!fp) {
strbuf_release(&path);
@ -133,7 +133,7 @@ int repo_write_loose_object_map(struct repository *repo)
if (!should_use_loose_object_map(repo))
return 0;

strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
repo_common_path_replace(repo, &path, "objects/loose-object-idx");
fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
iter = kh_begin(map);
if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
@ -174,7 +174,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
struct stat st;
struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;

strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
repo_common_path_replace(repo, &path, "objects/loose-object-idx");
hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);

fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
@ -190,7 +190,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
goto errout;
if (close(fd))
goto errout;
adjust_shared_perm(path.buf);
adjust_shared_perm(repo, path.buf);
rollback_lock_file(&lock);
strbuf_release(&buf);
strbuf_release(&path);

View File

@ -1336,7 +1336,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
return -1;
}

if (adjust_shared_perm(get_tempfile_path(incr))) {
if (adjust_shared_perm(r, get_tempfile_path(incr))) {
error(_("unable to adjust shared permissions for '%s'"),
get_tempfile_path(incr));
return -1;

View File

@ -275,41 +275,45 @@ static void diff_tree_local(struct notes_merge_options *o,

static void check_notes_merge_worktree(struct notes_merge_options *o)
{
struct strbuf buf = STRBUF_INIT;

if (!o->has_worktree) {
/*
* Must establish NOTES_MERGE_WORKTREE.
* Abort if NOTES_MERGE_WORKTREE already exists
*/
if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
!is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
if (file_exists(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE)) &&
!is_empty_dir(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE))) {
if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
die(_("You have not concluded your previous "
"notes merge (%s exists).\nPlease, use "
"'git notes merge --commit' or 'git notes "
"merge --abort' to commit/abort the "
"previous merge before you start a new "
"notes merge."), git_path("NOTES_MERGE_*"));
"notes merge."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*"));
else
die(_("You have not concluded your notes merge "
"(%s exists)."), git_path("NOTES_MERGE_*"));
"(%s exists)."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*"));
}

if (safe_create_leading_directories_const(git_path(
if (safe_create_leading_directories_const(repo_git_path_replace(the_repository, &buf,
NOTES_MERGE_WORKTREE "/.test")))
die_errno("unable to create directory %s",
git_path(NOTES_MERGE_WORKTREE));
repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE));
o->has_worktree = 1;
} else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
} else if (!file_exists(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE)))
/* NOTES_MERGE_WORKTREE should already be established */
die("missing '%s'. This should not happen",
git_path(NOTES_MERGE_WORKTREE));
repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE));

strbuf_release(&buf);
}

static void write_buf_to_worktree(const struct object_id *obj,
const char *buf, unsigned long size)
{
int fd;
char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
char *path = repo_git_path(the_repository, NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
if (safe_create_leading_directories_const(path))
die_errno("unable to create directory for '%s'", path);

@ -695,7 +699,7 @@ int notes_merge_commit(struct notes_merge_options *o,
const char *msg = strstr(buffer, "\n\n");
int baselen;

git_path_buf(&path, NOTES_MERGE_WORKTREE);
repo_git_path_replace(the_repository, &path, NOTES_MERGE_WORKTREE);
if (o->verbosity >= 3)
printf("Committing notes in notes merge worktree at %s\n",
path.buf);
@ -757,7 +761,7 @@ int notes_merge_abort(struct notes_merge_options *o)
struct strbuf buf = STRBUF_INIT;
int ret;

git_path_buf(&buf, NOTES_MERGE_WORKTREE);
repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE);
if (o->verbosity >= 3)
printf("Removing notes merge worktree at %s/*\n", buf.buf);
ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);

View File

@ -394,7 +394,7 @@ int mkdir_in_gitdir(const char *path)
}
strbuf_release(&sb);
}
return adjust_shared_perm(path);
return adjust_shared_perm(the_repository, path);
}

static enum scld_error safe_create_leading_directories_1(char *path, int share)
@ -443,7 +443,7 @@ static enum scld_error safe_create_leading_directories_1(char *path, int share)
ret = SCLD_VANISHED;
else
ret = SCLD_FAILED;
} else if (share && adjust_shared_perm(path)) {
} else if (share && adjust_shared_perm(the_repository, path)) {
ret = SCLD_PERMS;
}
*slash = slash_character;
@ -482,14 +482,14 @@ int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
* restrictive except to remove write permission.
*/
int mode = 0444;
git_path_buf(temp_filename, "objects/%s", pattern);
repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
fd = git_mkstemp_mode(temp_filename->buf, mode);
if (0 <= fd)
return fd;

/* slow path */
/* some mkstemp implementations erase temp_filename on failure */
git_path_buf(temp_filename, "objects/%s", pattern);
repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
safe_create_leading_directories(temp_filename->buf);
return xmkstemp_mode(temp_filename->buf, mode);
}
@ -723,7 +723,7 @@ static void read_info_alternates(struct repository *r,
void add_to_alternates_file(const char *reference)
{
struct lock_file lock = LOCK_INIT;
char *alts = git_pathdup("objects/info/alternates");
char *alts = repo_git_path(the_repository, "objects/info/alternates");
FILE *in, *out;
int found = 0;

@ -2111,7 +2111,7 @@ retry:
}

out:
if (adjust_shared_perm(filename))
if (adjust_shared_perm(the_repository, filename))
return error(_("unable to set permission to '%s'"), filename);
return 0;
}
@ -2187,7 +2187,7 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
strbuf_add(tmp, filename, dirlen - 1);
if (mkdir(tmp->buf, 0777) && errno != EEXIST)
return -1;
if (adjust_shared_perm(tmp->buf))
if (adjust_shared_perm(the_repository, tmp->buf))
return -1;

/* Try again */

View File

@ -1072,7 +1072,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);

if (adjust_shared_perm(tmp_file.buf))
if (adjust_shared_perm(the_repository, tmp_file.buf))
die_errno("unable to make temporary bitmap file readable");

if (rename(tmp_file.buf, filename))

View File

@ -1,3 +1,5 @@
#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@ -287,7 +289,7 @@ char *write_rev_file_order(const struct git_hash_algo *hash_algo,
write_rev_index_positions(f, pack_order, nr_objects);
write_rev_trailer(hash_algo, f, hash);

if (adjust_shared_perm(path) < 0)
if (adjust_shared_perm(the_repository, path) < 0)
die(_("failed to make %s readable"), path);

finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
@ -350,7 +352,7 @@ static char *write_mtimes_file(const struct git_hash_algo *hash_algo,
write_mtimes_objects(f, to_pack, objects, nr_objects);
write_mtimes_trailer(hash_algo, f, hash);

if (adjust_shared_perm(mtimes_name) < 0)
if (adjust_shared_perm(the_repository, mtimes_name) < 0)
die(_("failed to make %s readable"), mtimes_name);

finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
@ -566,12 +568,12 @@ void stage_tmp_packfiles(const struct git_hash_algo *hash_algo,
char *rev_tmp_name = NULL;
char *mtimes_tmp_name = NULL;

if (adjust_shared_perm(pack_tmp_name))
if (adjust_shared_perm(the_repository, pack_tmp_name))
die_errno("unable to make temporary pack file readable");

*idx_tmp_name = (char *)write_idx_file(hash_algo, NULL, written_list,
nr_written, pack_idx_opts, hash);
if (adjust_shared_perm(*idx_tmp_name))
if (adjust_shared_perm(the_repository, *idx_tmp_name))
die_errno("unable to make temporary index file readable");

rev_tmp_name = write_rev_file(hash_algo, NULL, written_list, nr_written,

170
path.c
View File

@ -2,8 +2,6 @@
* Utilities for paths and pathnames
*/

#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "abspath.h"
#include "environment.h"
@ -30,7 +28,7 @@ static int get_st_mode_bits(const char *path, int *mode)
return 0;
}

struct strbuf *get_pathname(void)
static struct strbuf *get_pathname(void)
{
static struct strbuf pathname_array[4] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@ -387,10 +385,11 @@ void report_linked_checkout_garbage(struct repository *r)
strbuf_release(&sb);
}

static void adjust_git_path(const struct repository *repo,
static void adjust_git_path(struct repository *repo,
struct strbuf *buf, int git_dir_len)
{
const char *base = buf->buf + git_dir_len;

if (is_dir_file(base, "info", "grafts"))
strbuf_splice(buf, 0, buf->len,
repo->graft_file, strlen(repo->graft_file));
@ -399,8 +398,8 @@ static void adjust_git_path(const struct repository *repo,
repo->index_file, strlen(repo->index_file));
else if (dir_prefix(base, "objects"))
replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
else if (git_hooks_path && dir_prefix(base, "hooks"))
replace_dir(buf, git_dir_len + 5, git_hooks_path);
else if (repo_settings_get_hooks_path(repo) && dir_prefix(base, "hooks"))
replace_dir(buf, git_dir_len + 5, repo_settings_get_hooks_path(repo));
else if (repo->different_commondir)
update_common_dir(buf, git_dir_len, repo->commondir);
}
@ -414,12 +413,12 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
else if (!wt->id)
strbuf_addstr(buf, repo->commondir);
else
strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
repo_common_path_append(repo, buf, "worktrees/%s", wt->id);
}

void repo_git_pathv(const struct repository *repo,
const struct worktree *wt, struct strbuf *buf,
const char *fmt, va_list args)
static void repo_git_pathv(struct repository *repo,
const struct worktree *wt, struct strbuf *buf,
const char *fmt, va_list args)
{
int gitdir_len;
strbuf_worktree_gitdir(buf, repo, wt);
@ -432,7 +431,7 @@ void repo_git_pathv(const struct repository *repo,
strbuf_cleanup_path(buf);
}

char *repo_git_path(const struct repository *repo,
char *repo_git_path(struct repository *repo,
const char *fmt, ...)
{
struct strbuf path = STRBUF_INIT;
@ -443,14 +442,27 @@ char *repo_git_path(const struct repository *repo,
return strbuf_detach(&path, NULL);
}

void strbuf_repo_git_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
const char *repo_git_path_append(struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
repo_git_pathv(repo, NULL, sb, fmt, args);
va_end(args);
return sb->buf;
}

const char *repo_git_path_replace(struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;
strbuf_reset(sb);
va_start(args, fmt);
repo_git_pathv(repo, NULL, sb, fmt, args);
va_end(args);
return sb->buf;
}

char *mkpathdup(const char *fmt, ...)
@ -506,9 +518,6 @@ char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
struct strbuf path = STRBUF_INIT;
va_list args;

if (!repo->worktree)
return NULL;

va_start(args, fmt);
do_worktree_path(repo, &path, fmt, args);
va_end(args);
@ -516,29 +525,49 @@ char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
return strbuf_detach(&path, NULL);
}

void strbuf_repo_worktree_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
const char *repo_worktree_path_append(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;

if (!repo->worktree)
return;
return NULL;

va_start(args, fmt);
do_worktree_path(repo, sb, fmt, args);
va_end(args);

return sb->buf;
}

const char *repo_worktree_path_replace(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;

strbuf_reset(sb);
if (!repo->worktree)
return NULL;

va_start(args, fmt);
do_worktree_path(repo, sb, fmt, args);
va_end(args);

return sb->buf;
}

/* Returns 0 on success, negative on failure. */
static int do_submodule_path(struct strbuf *buf, const char *path,
static int do_submodule_path(struct repository *repo,
struct strbuf *buf, const char *path,
const char *fmt, va_list args)
{
struct strbuf git_submodule_common_dir = STRBUF_INIT;
struct strbuf git_submodule_dir = STRBUF_INIT;
int ret;

ret = submodule_to_gitdir(&git_submodule_dir, path);
ret = submodule_to_gitdir(repo, &git_submodule_dir, path);
if (ret)
goto cleanup;

@ -557,13 +586,14 @@ cleanup:
return ret;
}

char *git_pathdup_submodule(const char *path, const char *fmt, ...)
char *repo_submodule_path(struct repository *repo,
const char *path, const char *fmt, ...)
{
int err;
va_list args;
struct strbuf buf = STRBUF_INIT;
va_start(args, fmt);
err = do_submodule_path(&buf, path, fmt, args);
err = do_submodule_path(repo, &buf, path, fmt, args);
va_end(args);
if (err) {
strbuf_release(&buf);
@ -572,22 +602,41 @@ char *git_pathdup_submodule(const char *path, const char *fmt, ...)
return strbuf_detach(&buf, NULL);
}

int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
const char *fmt, ...)
const char *repo_submodule_path_append(struct repository *repo,
struct strbuf *buf,
const char *path,
const char *fmt, ...)
{
int err;
va_list args;
va_start(args, fmt);
err = do_submodule_path(buf, path, fmt, args);
err = do_submodule_path(repo, buf, path, fmt, args);
va_end(args);

return err;
if (err)
return NULL;
return buf->buf;
}

void repo_common_pathv(const struct repository *repo,
struct strbuf *sb,
const char *fmt,
va_list args)
const char *repo_submodule_path_replace(struct repository *repo,
struct strbuf *buf,
const char *path,
const char *fmt, ...)
{
int err;
va_list args;
strbuf_reset(buf);
va_start(args, fmt);
err = do_submodule_path(repo, buf, path, fmt, args);
va_end(args);
if (err)
return NULL;
return buf->buf;
}

static void repo_common_pathv(const struct repository *repo,
struct strbuf *sb,
const char *fmt,
va_list args)
{
strbuf_addstr(sb, repo->commondir);
if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
@ -596,14 +645,38 @@ void repo_common_pathv(const struct repository *repo,
strbuf_cleanup_path(sb);
}

void strbuf_git_common_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
char *repo_common_path(const struct repository *repo,
const char *fmt, ...)
{
struct strbuf sb = STRBUF_INIT;
va_list args;
va_start(args, fmt);
repo_common_pathv(repo, &sb, fmt, args);
va_end(args);
return strbuf_detach(&sb, NULL);
}

const char *repo_common_path_append(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
repo_common_pathv(repo, sb, fmt, args);
va_end(args);
return sb->buf;
}

const char *repo_common_path_replace(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
{
va_list args;
strbuf_reset(sb);
va_start(args, fmt);
repo_common_pathv(repo, sb, fmt, args);
va_end(args);
return sb->buf;
}

static struct passwd *getpw_str(const char *username, size_t len)
@ -765,21 +838,22 @@ const char *enter_repo(const char *path, unsigned flags)
return NULL;
}

int calc_shared_perm(int mode)
int calc_shared_perm(struct repository *repo,
int mode)
{
int tweak;

if (get_shared_repository() < 0)
tweak = -get_shared_repository();
if (repo_settings_get_shared_repository(repo) < 0)
tweak = -repo_settings_get_shared_repository(repo);
else
tweak = get_shared_repository();
tweak = repo_settings_get_shared_repository(repo);

if (!(mode & S_IWUSR))
tweak &= ~0222;
if (mode & S_IXUSR)
/* Copy read bits to execute bits */
tweak |= (tweak & 0444) >> 2;
if (get_shared_repository() < 0)
if (repo_settings_get_shared_repository(repo) < 0)
mode = (mode & ~0777) | tweak;
else
mode |= tweak;
@ -787,17 +861,17 @@ int calc_shared_perm(int mode)
return mode;
}


int adjust_shared_perm(const char *path)
int adjust_shared_perm(struct repository *repo,
const char *path)
{
int old_mode, new_mode;

if (!get_shared_repository())
if (!repo_settings_get_shared_repository(repo))
return 0;
if (get_st_mode_bits(path, &old_mode) < 0)
return -1;

new_mode = calc_shared_perm(old_mode);
new_mode = calc_shared_perm(repo, old_mode);
if (S_ISDIR(old_mode)) {
/* Copy read bits to execute bits */
new_mode |= (new_mode & 0444) >> 2;
@ -816,7 +890,7 @@ int adjust_shared_perm(const char *path)
return 0;
}

void safe_create_dir(const char *dir, int share)
void safe_create_dir(struct repository *repo, const char *dir, int share)
{
if (mkdir(dir, 0777) < 0) {
if (errno != EEXIST) {
@ -824,7 +898,7 @@ void safe_create_dir(const char *dir, int share)
exit(1);
}
}
else if (share && adjust_shared_perm(dir))
else if (share && adjust_shared_perm(repo, dir))
die(_("Could not make %s writable by group"), dir);
}


197
path.h
View File

@ -25,22 +25,20 @@ char *mkpathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));

/*
* The `strbuf_git_common_path` family of functions will construct a path into a
* The `repo_common_path` family of functions will construct a path into a
* repository's common git directory, which is shared by all worktrees.
*/

/*
* Constructs a path into the common git directory of repository `repo` and
* append it in the provided buffer `sb`.
*/
void strbuf_git_common_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
char *repo_common_path(const struct repository *repo,
const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
const char *repo_common_path_append(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
const char *repo_common_path_replace(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
void repo_common_pathv(const struct repository *repo,
struct strbuf *buf,
const char *fmt,
va_list args);

/*
* The `repo_git_path` family of functions will construct a path into a repository's
@ -54,29 +52,16 @@ void repo_common_pathv(const struct repository *repo,
* For an exhaustive list of the adjustments made look at `common_list` and
* `adjust_git_path` in path.c.
*/

/*
* Return a path into the git directory of repository `repo`.
*/
char *repo_git_path(const struct repository *repo,
char *repo_git_path(struct repository *repo,
const char *fmt, ...)
__attribute__((format (printf, 2, 3)));

/*
* Print a path into the git directory of repository `repo` into the provided
* buffer.
*/
void repo_git_pathv(const struct repository *repo,
const struct worktree *wt, struct strbuf *buf,
const char *fmt, va_list args);

/*
* Construct a path into the git directory of repository `repo` and append it
* to the provided buffer `sb`.
*/
void strbuf_repo_git_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
const char *repo_git_path_append(struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
const char *repo_git_path_replace(struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));

/*
@ -90,41 +75,45 @@ const char *worktree_git_path(struct repository *r,
__attribute__((format (printf, 3, 4)));

/*
* Return a path into the worktree of repository `repo`.
* The `repo_worktree_path` family of functions will construct a path into a
* repository's worktree.
*
* If the repository doesn't have a worktree NULL is returned.
* Returns a `NULL` pointer in case the repository has no worktree.
*/
char *repo_worktree_path(const struct repository *repo,
const char *fmt, ...)
__attribute__((format (printf, 2, 3)));

/*
* Construct a path into the worktree of repository `repo` and append it
* to the provided buffer `sb`.
*
* If the repository doesn't have a worktree nothing will be appended to `sb`.
*/
void strbuf_repo_worktree_path(struct strbuf *sb,
const struct repository *repo,
const char *repo_worktree_path_append(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));

/*
* Return a path into a submodule's git directory located at `path`. `path`
* must only reference a submodule of the main repository (the_repository).
*/
char *git_pathdup_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));

/*
* Construct a path into a submodule's git directory located at `path` and
* append it to the provided buffer `sb`. `path` must only reference a
* submodule of the main repository (the_repository).
*/
int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
const char *fmt, ...)
const char *repo_worktree_path_replace(const struct repository *repo,
struct strbuf *sb,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));

/*
* The `repo_submodule_path` family of functions will construct a path into a
* submodule's git directory located at `path`. `path` must be a submodule path
* as found in the index and must be part of the given repository.
*
* Returns a `NULL` pointer in case the submodule cannot be found.
*/
char *repo_submodule_path(struct repository *repo,
const char *path,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
const char *repo_submodule_path_append(struct repository *repo,
struct strbuf *sb,
const char *path,
const char *fmt, ...)
__attribute__((format (printf, 4, 5)));
const char *repo_submodule_path_replace(struct repository *repo,
struct strbuf *sb,
const char *path,
const char *fmt, ...)
__attribute__((format (printf, 4, 5)));

void report_linked_checkout_garbage(struct repository *r);

/*
@ -152,8 +141,8 @@ const char *git_path_shallow(struct repository *r);

int ends_with_path_components(const char *path, const char *components);

int calc_shared_perm(int mode);
int adjust_shared_perm(const char *path);
int calc_shared_perm(struct repository *repo, int mode);
int adjust_shared_perm(struct repository *repo, const char *path);

char *interpolate_path(const char *path, int real_home);

@ -230,101 +219,21 @@ char *xdg_cache_home(const char *filename);
* directories under $GIT_DIR. Don't use it for working tree
* directories.
*/
void safe_create_dir(const char *dir, int share);

/*
* Do not use this function. It is only exported to other subsystems until we
* can get rid of the below block of functions that implicitly rely on
* `the_repository`.
*/
struct strbuf *get_pathname(void);
void safe_create_dir(struct repository *repo, const char *dir, int share);

# ifdef USE_THE_REPOSITORY_VARIABLE
# include "strbuf.h"
# include "repository.h"

/*
* Return a statically allocated path into the main repository's
* (the_repository) common git directory.
*/
__attribute__((format (printf, 1, 2)))
static inline const char *git_common_path(const char *fmt, ...)
{
struct strbuf *pathname = get_pathname();
va_list args;
va_start(args, fmt);
repo_common_pathv(the_repository, pathname, fmt, args);
va_end(args);
return pathname->buf;
}

/*
* Construct a path into the main repository's (the_repository) git directory
* and place it in the provided buffer `buf`, the contents of the buffer will
* be overridden.
*/
__attribute__((format (printf, 2, 3)))
static inline char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
{
va_list args;
strbuf_reset(buf);
va_start(args, fmt);
repo_git_pathv(the_repository, NULL, buf, fmt, args);
va_end(args);
return buf->buf;
}

/*
* Construct a path into the main repository's (the_repository) git directory
* and append it to the provided buffer `sb`.
*/
__attribute__((format (printf, 2, 3)))
static inline void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
repo_git_pathv(the_repository, NULL, sb, fmt, args);
va_end(args);
}

/*
* Return a statically allocated path into the main repository's
* (the_repository) git directory.
*/
__attribute__((format (printf, 1, 2)))
static inline const char *git_path(const char *fmt, ...)
{
struct strbuf *pathname = get_pathname();
va_list args;
va_start(args, fmt);
repo_git_pathv(the_repository, NULL, pathname, fmt, args);
va_end(args);
return pathname->buf;
}

#define GIT_PATH_FUNC(func, filename) \
const char *func(void) \
{ \
static char *ret; \
if (!ret) \
ret = git_pathdup(filename); \
ret = repo_git_path(the_repository, filename); \
return ret; \
}

/*
* Return a path into the main repository's (the_repository) git directory.
*/
__attribute__((format (printf, 1, 2)))
static inline char *git_pathdup(const char *fmt, ...)
{
struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
repo_git_pathv(the_repository, NULL, &path, fmt, args);
va_end(args);
return strbuf_detach(&path, NULL);
}

# endif /* USE_THE_REPOSITORY_VARIABLE */

#endif /* PATH_H */

View File

@ -65,8 +65,10 @@ static void add_rebase_files(struct rev_info *revs)
struct worktree **worktrees = get_worktrees();

for (struct worktree **wt = worktrees; *wt; wt++) {
char *wt_gitdir = get_worktree_git_dir(*wt);

strbuf_reset(&buf);
strbuf_addstr(&buf, get_worktree_git_dir(*wt));
strbuf_addstr(&buf, wt_gitdir);
strbuf_complete(&buf, '/');
len = buf.len;
for (size_t i = 0; i < ARRAY_SIZE(path); i++) {
@ -74,6 +76,8 @@ static void add_rebase_files(struct rev_info *revs)
strbuf_addstr(&buf, path[i]);
add_one_file(buf.buf, revs);
}

free(wt_gitdir);
}
strbuf_release(&buf);
free_worktrees(worktrees);

View File

@ -3251,15 +3251,18 @@ static int clean_shared_index_files(const char *current_hex)

while ((de = readdir(dir)) != NULL) {
const char *sha1_hex;
const char *shared_index_path;
char *shared_index_path;
if (!skip_prefix(de->d_name, "sharedindex.", &sha1_hex))
continue;
if (!strcmp(sha1_hex, current_hex))
continue;
shared_index_path = git_path("%s", de->d_name);

shared_index_path = repo_git_path(the_repository, "%s", de->d_name);
if (should_delete_shared_index(shared_index_path) > 0 &&
unlink(shared_index_path))
warning_errno(_("unable to unlink: %s"), shared_index_path);

free(shared_index_path);
}
closedir(dir);

@ -3271,6 +3274,7 @@ static int write_shared_index(struct index_state *istate,
{
struct split_index *si = istate->split_index;
int ret, was_full = !istate->sparse_index;
char *path;

move_cache_to_base_index(istate);
convert_to_sparse(istate, 0);
@ -3286,18 +3290,20 @@ static int write_shared_index(struct index_state *istate,

if (ret)
return ret;
ret = adjust_shared_perm(get_tempfile_path(*temp));
ret = adjust_shared_perm(the_repository, get_tempfile_path(*temp));
if (ret) {
error(_("cannot fix permission bits on '%s'"), get_tempfile_path(*temp));
return ret;
}
ret = rename_tempfile(temp,
git_path("sharedindex.%s", oid_to_hex(&si->base->oid)));

path = repo_git_path(the_repository, "sharedindex.%s", oid_to_hex(&si->base->oid));
ret = rename_tempfile(temp, path);
if (!ret) {
oidcpy(&si->base_oid, &si->base->oid);
clean_shared_index_files(oid_to_hex(&si->base->oid));
}

free(path);
return ret;
}

@ -3378,9 +3384,12 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
if (new_shared_index) {
struct tempfile *temp;
int saved_errno;
char *path;

/* Same initial permissions as the main .git/index file */
temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
path = repo_git_path(the_repository, "sharedindex_XXXXXX");
temp = mks_tempfile_sm(path, 0, 0666);
free(path);
if (!temp) {
ret = do_write_locked_index(istate, lock, flags,
~WRITE_SPLIT_INDEX_EXTENSION);
@ -3401,9 +3410,10 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,

/* Freshen the shared index only if the split-index was written */
if (!ret && !new_shared_index && !is_null_oid(&si->base_oid)) {
const char *shared_index = git_path("sharedindex.%s",
oid_to_hex(&si->base_oid));
char *shared_index = repo_git_path(the_repository, "sharedindex.%s",
oid_to_hex(&si->base_oid));
freshen_shared_index(shared_index, 1);
free(shared_index);
}

out:

6
refs.c
View File

@ -2154,7 +2154,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
if (!is_nonbare_repository_dir(&submodule_sb))
goto done;

if (submodule_to_gitdir(&submodule_sb, submodule))
if (submodule_to_gitdir(repo, &submodule_sb, submodule))
goto done;

subrepo = xmalloc(sizeof(*subrepo));
@ -2192,8 +2192,8 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)

if (wt->id) {
struct strbuf common_path = STRBUF_INIT;
strbuf_git_common_path(&common_path, wt->repo,
"worktrees/%s", wt->id);
repo_common_path_append(wt->repo, &common_path,
"worktrees/%s", wt->id);
refs = ref_store_init(wt->repo, wt->repo->ref_storage_format,
common_path.buf, REF_STORE_ALL_CAPS);
strbuf_release(&common_path);

View File

@ -1831,7 +1831,7 @@ static int log_ref_setup(struct files_ref_store *refs,
}

if (*logfd >= 0)
adjust_shared_perm(logfile);
adjust_shared_perm(the_repository, logfile);

free(logfile);
return 0;
@ -3488,8 +3488,8 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
* they do not understand the reference format extension.
*/
strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
safe_create_dir(sb.buf, 1);
adjust_shared_perm(sb.buf);
safe_create_dir(the_repository, sb.buf, 1);
adjust_shared_perm(the_repository, sb.buf);

/*
* There is no need to create directories for common refs when creating
@ -3501,11 +3501,11 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
*/
strbuf_reset(&sb);
files_ref_path(refs, &sb, "refs/heads");
safe_create_dir(sb.buf, 1);
safe_create_dir(the_repository, sb.buf, 1);

strbuf_reset(&sb);
files_ref_path(refs, &sb, "refs/tags");
safe_create_dir(sb.buf, 1);
safe_create_dir(the_repository, sb.buf, 1);
}

strbuf_release(&sb);

View File

@ -380,7 +380,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
default:
BUG("unknown hash algorithm %d", repo->hash_algo->format_id);
}
refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
refs->write_options.default_permissions = calc_shared_perm(the_repository, 0666 & ~mask);
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
refs->write_options.lock_timeout_ms = 100;
@ -470,21 +470,21 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
struct strbuf sb = STRBUF_INIT;

strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
safe_create_dir(sb.buf, 1);
safe_create_dir(the_repository, sb.buf, 1);
strbuf_reset(&sb);

strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
write_file(sb.buf, "ref: refs/heads/.invalid");
adjust_shared_perm(sb.buf);
adjust_shared_perm(the_repository, sb.buf);
strbuf_reset(&sb);

strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
safe_create_dir(sb.buf, 1);
safe_create_dir(the_repository, sb.buf, 1);
strbuf_reset(&sb);

strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
write_file(sb.buf, "this repository uses the reftable format");
adjust_shared_perm(sb.buf);
adjust_shared_perm(the_repository, sb.buf);

strbuf_release(&sb);
return 0;

View File

@ -321,10 +321,11 @@ static void read_remotes_file(struct remote_state *remote_state,
struct remote *remote)
{
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen_or_warn(git_path("remotes/%s", remote->name), "r");
FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
"remotes/%s", remote->name), "r");

if (!f)
return;
goto out;

warn_about_deprecated_remote_type("remotes", remote);

@ -343,8 +344,10 @@ static void read_remotes_file(struct remote_state *remote_state,
else if (skip_prefix(buf.buf, "Pull:", &v))
refspec_append(&remote->fetch, skip_spaces(v));
}
strbuf_release(&buf);
fclose(f);

out:
strbuf_release(&buf);
}

static void read_branches_file(struct remote_state *remote_state,
@ -352,20 +355,19 @@ static void read_branches_file(struct remote_state *remote_state,
{
char *frag, *to_free = NULL;
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
"branches/%s", remote->name), "r");

if (!f)
return;
goto out;

warn_about_deprecated_remote_type("branches", remote);

strbuf_getline_lf(&buf, f);
fclose(f);
strbuf_trim(&buf);
if (!buf.len) {
strbuf_release(&buf);
return;
}
if (!buf.len)
goto out;

remote->configured_in_repo = 1;
remote->origin = REMOTE_BRANCHES;
@ -393,6 +395,7 @@ static void read_branches_file(struct remote_state *remote_state,
refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag);
remote->fetch_tags = 1; /* always auto-follow */

out:
strbuf_release(&buf);
free(to_free);
}

View File

@ -4,6 +4,7 @@
#include "repository.h"
#include "midx.h"
#include "pack-objects.h"
#include "setup.h"

static void repo_cfg_bool(struct repository *r, const char *key, int *dest,
int def)
@ -21,7 +22,6 @@ static void repo_cfg_int(struct repository *r, const char *key, int *dest,

void prepare_repo_settings(struct repository *r)
{
const struct repo_settings defaults = REPO_SETTINGS_INIT;
int experimental;
int value;
const char *strval;
@ -35,7 +35,7 @@ void prepare_repo_settings(struct repository *r)
if (r->settings.initialized)
return;

memcpy(&r->settings, &defaults, sizeof(defaults));
repo_settings_clear(r);
r->settings.initialized++;

/* Booleans config or default, cascades to other settings */
@ -143,6 +143,14 @@ void prepare_repo_settings(struct repository *r)
r->settings.packed_git_limit = ulongval;
}

void repo_settings_clear(struct repository *r)
{
struct repo_settings empty = REPO_SETTINGS_INIT;
FREE_AND_NULL(r->settings.fsmonitor);
FREE_AND_NULL(r->settings.hooks_path);
r->settings = empty;
}

enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
{
const char *value;
@ -167,3 +175,35 @@ int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
&repo->settings.warn_ambiguous_refs, 1);
return repo->settings.warn_ambiguous_refs;
}

const char *repo_settings_get_hooks_path(struct repository *repo)
{
if (!repo->settings.hooks_path)
repo_config_get_pathname(repo, "core.hookspath", &repo->settings.hooks_path);
return repo->settings.hooks_path;
}

int repo_settings_get_shared_repository(struct repository *repo)
{
if (!repo->settings.shared_repository_initialized) {
const char *var = "core.sharedrepository";
const char *value;
if (!repo_config_get_value(repo, var, &value))
repo->settings.shared_repository = git_config_perm(var, value);
else
repo->settings.shared_repository = PERM_UMASK;
repo->settings.shared_repository_initialized = 1;
}
return repo->settings.shared_repository;
}

void repo_settings_set_shared_repository(struct repository *repo, int value)
{
repo->settings.shared_repository = value;
repo->settings.shared_repository_initialized = 1;
}

void repo_settings_reset_shared_repository(struct repository *repo)
{
repo->settings.shared_repository_initialized = 0;
}

View File

@ -37,6 +37,9 @@ struct repo_settings {
int pack_use_bitmap_boundary_traversal;
int pack_use_multi_pack_reuse;

int shared_repository;
int shared_repository_initialized;

/*
* Does this repository have core.useReplaceRefs=true (on by
* default)? This provides a repository-scoped version of this
@ -61,8 +64,11 @@ struct repo_settings {
size_t delta_base_cache_limit;
size_t packed_git_window_size;
size_t packed_git_limit;

char *hooks_path;
};
#define REPO_SETTINGS_INIT { \
.shared_repository = -1, \
.index_version = -1, \
.core_untracked_cache = UNTRACKED_CACHE_KEEP, \
.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \
@ -73,10 +79,18 @@ struct repo_settings {
}

void prepare_repo_settings(struct repository *r);
void repo_settings_clear(struct repository *r);

/* Read the value for "core.logAllRefUpdates". */
enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
/* Read the value for "core.warnAmbiguousRefs". */
int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
/* Read the value for "core.hooksPath". */
const char *repo_settings_get_hooks_path(struct repository *repo);

/* Read, set or reset the value for "core.sharedRepository". */
int repo_settings_get_shared_repository(struct repository *repo);
void repo_settings_set_shared_repository(struct repository *repo, int value);
void repo_settings_reset_shared_repository(struct repository *repo);

#endif /* REPO_SETTINGS_H */

View File

@ -312,8 +312,8 @@ int repo_submodule_init(struct repository *subrepo,
struct strbuf worktree = STRBUF_INIT;
int ret = 0;

strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
repo_worktree_path_append(superproject, &gitdir, "%s/.git", path);
repo_worktree_path_append(superproject, &worktree, "%s", path);

if (repo_init(subrepo, gitdir.buf, worktree.buf)) {
/*
@ -380,7 +380,7 @@ void repo_clear(struct repository *repo)
parsed_object_pool_clear(repo->parsed_objects);
FREE_AND_NULL(repo->parsed_objects);

FREE_AND_NULL(repo->settings.fsmonitor);
repo_settings_clear(repo);

if (repo->config) {
git_configset_clear(repo->config);

101
rerere.c
View File

@ -91,16 +91,18 @@ static void assign_variant(struct rerere_id *id)
id->variant = variant;
}

const char *rerere_path(const struct rerere_id *id, const char *file)
const char *rerere_path(struct strbuf *buf, const struct rerere_id *id, const char *file)
{
if (!file)
return git_path("rr-cache/%s", rerere_id_hex(id));
return repo_git_path_replace(the_repository, buf, "rr-cache/%s",
rerere_id_hex(id));

if (id->variant <= 0)
return git_path("rr-cache/%s/%s", rerere_id_hex(id), file);
return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s",
rerere_id_hex(id), file);

return git_path("rr-cache/%s/%s.%d",
rerere_id_hex(id), file, id->variant);
return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s.%d",
rerere_id_hex(id), file, id->variant);
}

static int is_rr_file(const char *name, const char *filename, int *variant)
@ -125,8 +127,12 @@ static int is_rr_file(const char *name, const char *filename, int *variant)
static void scan_rerere_dir(struct rerere_dir *rr_dir)
{
struct dirent *de;
DIR *dir = opendir(git_path("rr-cache/%s", rr_dir->name));
char *path;
DIR *dir;

path = repo_git_path(the_repository, "rr-cache/%s", rr_dir->name);
dir = opendir(path);
free(path);
if (!dir)
return;
while ((de = readdir(dir)) != NULL) {
@ -624,9 +630,10 @@ static int try_merge(struct index_state *istate,
{
enum ll_merge_result ret;
mmfile_t base = {NULL, 0}, other = {NULL, 0};
struct strbuf buf = STRBUF_INIT;

if (read_mmfile(&base, rerere_path(id, "preimage")) ||
read_mmfile(&other, rerere_path(id, "postimage"))) {
if (read_mmfile(&base, rerere_path(&buf, id, "preimage")) ||
read_mmfile(&other, rerere_path(&buf, id, "postimage"))) {
ret = LL_MERGE_CONFLICT;
} else {
/*
@ -637,6 +644,7 @@ static int try_merge(struct index_state *istate,
istate, NULL);
}

strbuf_release(&buf);
free(base.ptr);
free(other.ptr);

@ -657,6 +665,7 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
{
FILE *f;
int ret;
struct strbuf buf = STRBUF_INIT;
mmfile_t cur = {NULL, 0};
mmbuffer_t result = {NULL, 0};

@ -664,8 +673,8 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
* Normalize the conflicts in path and write it out to
* "thisimage" temporary file.
*/
if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) ||
read_mmfile(&cur, rerere_path(id, "thisimage"))) {
if ((handle_file(istate, path, NULL, rerere_path(&buf, id, "thisimage")) < 0) ||
read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) {
ret = 1;
goto out;
}
@ -678,9 +687,9 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
* A successful replay of recorded resolution.
* Mark that "postimage" was used to help gc.
*/
if (utime(rerere_path(id, "postimage"), NULL) < 0)
if (utime(rerere_path(&buf, id, "postimage"), NULL) < 0)
warning_errno(_("failed utime() on '%s'"),
rerere_path(id, "postimage"));
rerere_path(&buf, id, "postimage"));

/* Update "path" with the resolution */
f = fopen(path, "w");
@ -694,6 +703,7 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
out:
free(cur.ptr);
free(result.ptr);
strbuf_release(&buf);

return ret;
}
@ -720,9 +730,11 @@ static void update_paths(struct repository *r, struct string_list *update)

static void remove_variant(struct rerere_id *id)
{
unlink_or_warn(rerere_path(id, "postimage"));
unlink_or_warn(rerere_path(id, "preimage"));
struct strbuf buf = STRBUF_INIT;
unlink_or_warn(rerere_path(&buf, id, "postimage"));
unlink_or_warn(rerere_path(&buf, id, "preimage"));
id->collection->status[id->variant] = 0;
strbuf_release(&buf);
}

/*
@ -739,6 +751,7 @@ static void do_rerere_one_path(struct index_state *istate,
const char *path = rr_item->string;
struct rerere_id *id = rr_item->util;
struct rerere_dir *rr_dir = id->collection;
struct strbuf buf = STRBUF_INIT;
int variant;

variant = id->variant;
@ -746,12 +759,12 @@ static void do_rerere_one_path(struct index_state *istate,
/* Has the user resolved it already? */
if (variant >= 0) {
if (!handle_file(istate, path, NULL, NULL)) {
copy_file(rerere_path(id, "postimage"), path, 0666);
copy_file(rerere_path(&buf, id, "postimage"), path, 0666);
id->collection->status[variant] |= RR_HAS_POSTIMAGE;
fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
free_rerere_id(rr_item);
rr_item->util = NULL;
return;
goto out;
}
/*
* There may be other variants that can cleanly
@ -787,22 +800,25 @@ static void do_rerere_one_path(struct index_state *istate,
path);
free_rerere_id(rr_item);
rr_item->util = NULL;
return;
goto out;
}

/* None of the existing one applies; we need a new variant */
assign_variant(id);

variant = id->variant;
handle_file(istate, path, NULL, rerere_path(id, "preimage"));
handle_file(istate, path, NULL, rerere_path(&buf, id, "preimage"));
if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
const char *path = rerere_path(id, "postimage");
const char *path = rerere_path(&buf, id, "postimage");
if (unlink(path))
die_errno(_("cannot unlink stray '%s'"), path);
id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
}
id->collection->status[variant] |= RR_HAS_PREIMAGE;
fprintf_ln(stderr, _("Recorded preimage for '%s'"), path);

out:
strbuf_release(&buf);
}

static int do_plain_rerere(struct repository *r,
@ -810,6 +826,7 @@ static int do_plain_rerere(struct repository *r,
{
struct string_list conflict = STRING_LIST_INIT_DUP;
struct string_list update = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
int i;

find_conflict(r, &conflict);
@ -843,7 +860,7 @@ static int do_plain_rerere(struct repository *r,
string_list_insert(rr, path)->util = id;

/* Ensure that the directory exists. */
mkdir_in_gitdir(rerere_path(id, NULL));
mkdir_in_gitdir(rerere_path(&buf, id, NULL));
}

for (i = 0; i < rr->nr; i++)
@ -854,6 +871,7 @@ static int do_plain_rerere(struct repository *r,

string_list_clear(&conflict, 0);
string_list_clear(&update, 0);
strbuf_release(&buf);
return write_rr(rr, fd);
}

@ -1033,6 +1051,7 @@ static int rerere_forget_one_path(struct index_state *istate,
struct rerere_id *id;
unsigned char hash[GIT_MAX_RAWSZ];
int ret;
struct strbuf buf = STRBUF_INIT;
struct string_list_item *item;

/*
@ -1056,8 +1075,8 @@ static int rerere_forget_one_path(struct index_state *istate,
if (!has_rerere_resolution(id))
continue;

handle_cache(istate, path, hash, rerere_path(id, "thisimage"));
if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
handle_cache(istate, path, hash, rerere_path(&buf, id, "thisimage"));
if (read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) {
free(cur.ptr);
error(_("failed to update conflicted state in '%s'"), path);
goto fail_exit;
@ -1074,7 +1093,7 @@ static int rerere_forget_one_path(struct index_state *istate,
goto fail_exit;
}

filename = rerere_path(id, "postimage");
filename = rerere_path(&buf, id, "postimage");
if (unlink(filename)) {
if (errno == ENOENT)
error(_("no remembered resolution for '%s'"), path);
@ -1088,7 +1107,7 @@ static int rerere_forget_one_path(struct index_state *istate,
* conflict in the working tree, run us again to record
* the postimage.
*/
handle_cache(istate, path, hash, rerere_path(id, "preimage"));
handle_cache(istate, path, hash, rerere_path(&buf, id, "preimage"));
fprintf_ln(stderr, _("Updated preimage for '%s'"), path);

/*
@ -1099,9 +1118,11 @@ static int rerere_forget_one_path(struct index_state *istate,
free_rerere_id(item);
item->util = id;
fprintf(stderr, _("Forgot resolution for '%s'\n"), path);
strbuf_release(&buf);
return 0;

fail_exit:
strbuf_release(&buf);
free(id);
return -1;
}
@ -1147,16 +1168,26 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)

static timestamp_t rerere_created_at(struct rerere_id *id)
{
struct strbuf buf = STRBUF_INIT;
struct stat st;
timestamp_t ret;

return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
ret = stat(rerere_path(&buf, id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;

strbuf_release(&buf);
return ret;
}

static timestamp_t rerere_last_used_at(struct rerere_id *id)
{
struct strbuf buf = STRBUF_INIT;
struct stat st;
timestamp_t ret;

return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
ret = stat(rerere_path(&buf, id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;

strbuf_release(&buf);
return ret;
}

/*
@ -1164,9 +1195,11 @@ static timestamp_t rerere_last_used_at(struct rerere_id *id)
*/
static void unlink_rr_item(struct rerere_id *id)
{
unlink_or_warn(rerere_path(id, "thisimage"));
struct strbuf buf = STRBUF_INIT;
unlink_or_warn(rerere_path(&buf, id, "thisimage"));
remove_variant(id);
id->collection->status[id->variant] = 0;
strbuf_release(&buf);
}

static void prune_one(struct rerere_id *id,
@ -1205,6 +1238,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
timestamp_t now = time(NULL);
timestamp_t cutoff_noresolve = now - 15 * 86400;
timestamp_t cutoff_resolve = now - 60 * 86400;
struct strbuf buf = STRBUF_INIT;

if (setup_rerere(r, rr, 0) < 0)
return;
@ -1214,7 +1248,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved",
&cutoff_noresolve, now);
git_config(git_default_config, NULL);
dir = opendir(git_path("rr-cache"));
dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache"));
if (!dir)
die_errno(_("unable to open rr-cache directory"));
/* Collect stale conflict IDs ... */
@ -1243,9 +1277,12 @@ void rerere_gc(struct repository *r, struct string_list *rr)

/* ... and then remove the empty directories */
for (i = 0; i < to_remove.nr; i++)
rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
rmdir(repo_git_path_replace(the_repository, &buf,
"rr-cache/%s", to_remove.items[i].string));

string_list_clear(&to_remove, 0);
rollback_lock_file(&write_lock);
strbuf_release(&buf);
}

/*
@ -1264,10 +1301,14 @@ void rerere_clear(struct repository *r, struct string_list *merge_rr)

for (i = 0; i < merge_rr->nr; i++) {
struct rerere_id *id = merge_rr->items[i].util;
struct strbuf buf = STRBUF_INIT;

if (!has_rerere_resolution(id)) {
unlink_rr_item(id);
rmdir(rerere_path(id, NULL));
rmdir(rerere_path(&buf, id, NULL));
}

strbuf_release(&buf);
}
unlink_or_warn(git_path_merge_rr(r));
rollback_lock_file(&write_lock);

View File

@ -32,7 +32,8 @@ int repo_rerere(struct repository *, int);
* path to that filesystem entity. With "file" specified with NULL,
* return the path to the directory that houses these files.
*/
const char *rerere_path(const struct rerere_id *, const char *file);
const char *rerere_path(struct strbuf *buf, const struct rerere_id *,
const char *file);
int rerere_forget(struct repository *, struct pathspec *);
int rerere_remaining(struct repository *, struct string_list *);
void rerere_clear(struct repository *, struct string_list *);

View File

@ -1874,15 +1874,20 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate = INDEX_STATE_INIT(revs->repo);
char *wt_gitdir;

if (wt->is_current)
continue; /* current index already taken care of */

wt_gitdir = get_worktree_git_dir(wt);

if (read_index_from(&istate,
worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0)
wt_gitdir) > 0)
do_add_index_objects_to_pending(revs, &istate, flags);

discard_index(&istate);
free(wt_gitdir);
}
free_worktrees(worktrees);
}

View File

@ -125,7 +125,7 @@ static int update_info_file(struct repository *r, char *path,
uic.cur_fp = NULL;

if (uic_is_stale(&uic)) {
if (adjust_shared_perm(get_tempfile_path(f)) < 0)
if (adjust_shared_perm(r, get_tempfile_path(f)) < 0)
goto out;
if (rename_tempfile(&f, path) < 0)
goto out;

70
setup.c
View File

@ -792,7 +792,7 @@ int upgrade_repository_format(int target_version)
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
int ret;

strbuf_git_common_path(&sb, the_repository, "config");
repo_common_path_append(the_repository, &sb, "config");
read_repository_format(&repo_fmt, sb.buf);
strbuf_release(&sb);

@ -2088,7 +2088,7 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
* with the way the namespace under .git/ is organized, should
* be really carefully chosen.
*/
safe_create_dir(path->buf, 1);
safe_create_dir(the_repository, path->buf, 1);
while ((de = readdir(dir)) != NULL) {
struct stat st_git, st_template;
int exists = 0;
@ -2242,7 +2242,7 @@ void initialize_repository_version(int hash_algo,
struct strbuf config = STRBUF_INIT;
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;

strbuf_git_common_path(&config, the_repository, "config");
repo_common_path_append(the_repository, &config, "config");
read_repository_format(&repo_fmt, config.buf);

if (repo_fmt.v1_only_extensions.nr)
@ -2264,7 +2264,7 @@ static int is_reinit(void)
char junk[2];
int ret;

git_path_buf(&buf, "HEAD");
repo_git_path_replace(the_repository, &buf, "HEAD");
ret = !access(buf.buf, R_OK) || readlink(buf.buf, junk, sizeof(junk) - 1) != -1;
strbuf_release(&buf);
return ret;
@ -2316,8 +2316,7 @@ static int create_default_files(const char *template_path,
int init_shared_repository)
{
struct stat st1;
struct strbuf buf = STRBUF_INIT;
char *path;
struct strbuf path = STRBUF_INIT;
int reinit;
int filemode;
const char *work_tree = repo_get_work_tree(the_repository);
@ -2333,7 +2332,7 @@ static int create_default_files(const char *template_path,
*/
copy_templates(template_path);
git_config_clear();
reset_shared_repository();
repo_settings_reset_shared_repository(the_repository);
git_config(git_default_config, NULL);

reinit = is_reinit();
@ -2343,7 +2342,8 @@ static int create_default_files(const char *template_path,
* values we might have just re-read from the config.
*/
if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
repo_settings_set_shared_repository(the_repository,
init_shared_repository);

is_bare_repository_cfg = !work_tree;

@ -2351,21 +2351,21 @@ static int create_default_files(const char *template_path,
* We would have created the above under user's umask -- under
* shared-repository settings, we would need to fix them up.
*/
if (get_shared_repository()) {
adjust_shared_perm(repo_get_git_dir(the_repository));
if (repo_settings_get_shared_repository(the_repository)) {
adjust_shared_perm(the_repository, repo_get_git_dir(the_repository));
}

initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, reinit);

/* Check filemode trustability */
path = git_path_buf(&buf, "config");
repo_git_path_replace(the_repository, &path, "config");
filemode = TEST_FILEMODE;
if (TEST_FILEMODE && !lstat(path, &st1)) {
if (TEST_FILEMODE && !lstat(path.buf, &st1)) {
struct stat st2;
filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
!lstat(path, &st2) &&
filemode = (!chmod(path.buf, st1.st_mode ^ S_IXUSR) &&
!lstat(path.buf, &st2) &&
st1.st_mode != st2.st_mode &&
!chmod(path, st1.st_mode));
!chmod(path.buf, st1.st_mode));
if (filemode && !reinit && (st1.st_mode & S_IXUSR))
filemode = 0;
}
@ -2384,24 +2384,24 @@ static int create_default_files(const char *template_path,

if (!reinit) {
/* Check if symlink is supported in the work tree */
path = git_path_buf(&buf, "tXXXXXX");
if (!close(xmkstemp(path)) &&
!unlink(path) &&
!symlink("testing", path) &&
!lstat(path, &st1) &&
repo_git_path_replace(the_repository, &path, "tXXXXXX");
if (!close(xmkstemp(path.buf)) &&
!unlink(path.buf) &&
!symlink("testing", path.buf) &&
!lstat(path.buf, &st1) &&
S_ISLNK(st1.st_mode))
unlink(path); /* good */
unlink(path.buf); /* good */
else
git_config_set("core.symlinks", "false");

/* Check if the filesystem is case-insensitive */
path = git_path_buf(&buf, "CoNfIg");
if (!access(path, F_OK))
repo_git_path_replace(the_repository, &path, "CoNfIg");
if (!access(path.buf, F_OK))
git_config_set("core.ignorecase", "true");
probe_utf8_pathname_composition();
}

strbuf_release(&buf);
strbuf_release(&path);
return reinit;
}

@ -2413,15 +2413,15 @@ static void create_object_directory(void)
strbuf_addstr(&path, repo_get_object_directory(the_repository));
baselen = path.len;

safe_create_dir(path.buf, 1);
safe_create_dir(the_repository, path.buf, 1);

strbuf_setlen(&path, baselen);
strbuf_addstr(&path, "/pack");
safe_create_dir(path.buf, 1);
safe_create_dir(the_repository, path.buf, 1);

strbuf_setlen(&path, baselen);
strbuf_addstr(&path, "/info");
safe_create_dir(path.buf, 1);
safe_create_dir(the_repository, path.buf, 1);

strbuf_release(&path);
}
@ -2592,7 +2592,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
*/
git_config(platform_core_config, NULL);

safe_create_dir(git_dir, 0);
safe_create_dir(the_repository, git_dir, 0);

reinit = create_default_files(template_dir, original_git_dir,
&repo_fmt, init_shared_repository);
@ -2602,7 +2602,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
initial_branch, flags & INIT_DB_QUIET);
create_object_directory();

if (get_shared_repository()) {
if (repo_settings_get_shared_repository(the_repository)) {
char buf[10];
/* We do not spell "group" and such, so that
* the configuration can be read by older version
@ -2610,12 +2610,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
* and compatibility values for PERM_GROUP and
* PERM_EVERYBODY.
*/
if (get_shared_repository() < 0)
if (repo_settings_get_shared_repository(the_repository) < 0)
/* force to the mode value */
xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
else if (get_shared_repository() == PERM_GROUP)
xsnprintf(buf, sizeof(buf), "0%o", -repo_settings_get_shared_repository(the_repository));
else if (repo_settings_get_shared_repository(the_repository) == PERM_GROUP)
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
else if (get_shared_repository() == PERM_EVERYBODY)
else if (repo_settings_get_shared_repository(the_repository) == PERM_EVERYBODY)
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
else
BUG("invalid value for shared_repository");
@ -2627,12 +2627,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
int len = strlen(git_dir);

if (reinit)
printf(get_shared_repository()
printf(repo_settings_get_shared_repository(the_repository)
? _("Reinitialized existing shared Git repository in %s%s\n")
: _("Reinitialized existing Git repository in %s%s\n"),
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
else
printf(get_shared_repository()
printf(repo_settings_get_shared_repository(the_repository)
? _("Initialized empty shared Git repository in %s%s\n")
: _("Initialized empty Git repository in %s%s\n"),
git_dir, len && git_dir[len-1] != '/' ? "/" : "");

View File

@ -364,7 +364,9 @@ const char *setup_temporary_shallow(const struct oid_array *extra)
struct strbuf sb = STRBUF_INIT;

if (write_shallow_commits(&sb, 0, extra)) {
temp = xmks_tempfile(git_path("shallow_XXXXXX"));
char *path = repo_git_path(the_repository, "shallow_XXXXXX");
temp = xmks_tempfile(path);
free(path);

if (write_in_full(temp->fd, sb.buf, sb.len) < 0 ||
close_tempfile_gently(temp) < 0)

View File

@ -536,7 +536,8 @@ static struct repository *open_submodule(const char *path)
struct strbuf sb = STRBUF_INIT;
struct repository *out = xmalloc(sizeof(*out));

if (submodule_to_gitdir(&sb, path) || repo_init(out, sb.buf, NULL)) {
if (submodule_to_gitdir(the_repository, &sb, path) ||
repo_init(out, sb.buf, NULL)) {
strbuf_release(&sb);
free(out);
return NULL;
@ -1315,7 +1316,7 @@ static int repo_has_absorbed_submodules(struct repository *r)
int ret;
struct strbuf buf = STRBUF_INIT;

strbuf_repo_git_path(&buf, r, "modules/");
repo_git_path_append(r, &buf, "modules/");
ret = file_exists(buf.buf) && !is_empty_dir(buf.buf);
strbuf_release(&buf);
return ret;
@ -2572,7 +2573,8 @@ int get_superproject_working_tree(struct strbuf *buf)
* Put the gitdir for a submodule (given relative to the main
* repository worktree) into `buf`, or return -1 on error.
*/
int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
int submodule_to_gitdir(struct repository *repo,
struct strbuf *buf, const char *submodule)
{
const struct submodule *sub;
const char *git_dir;
@ -2592,14 +2594,13 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
strbuf_addstr(buf, git_dir);
}
if (!is_git_directory(buf->buf)) {
sub = submodule_from_path(the_repository, null_oid(),
submodule);
sub = submodule_from_path(repo, null_oid(), submodule);
if (!sub) {
ret = -1;
goto cleanup;
}
strbuf_reset(buf);
submodule_name_to_gitdir(buf, the_repository, sub->name);
submodule_name_to_gitdir(buf, repo, sub->name);
}

cleanup:
@ -2629,6 +2630,6 @@ void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r,
* administrators can explicitly set. Nothing has been decided,
* so for now, just append the name at the end of the path.
*/
strbuf_repo_git_path(buf, r, "modules/");
repo_git_path_append(r, buf, "modules/");
strbuf_addstr(buf, submodule_name);
}

View File

@ -136,7 +136,8 @@ int push_unpushed_submodules(struct repository *r,
* path of that submodule in 'buf'. Return -1 on error or when the
* submodule is not initialized.
*/
int submodule_to_gitdir(struct strbuf *buf, const char *submodule);
int submodule_to_gitdir(struct repository *repo,
struct strbuf *buf, const char *submodule);

/*
* Given a submodule name, create a path to where the submodule's gitdir lives

View File

@ -75,11 +75,10 @@ static const char **get_store(const char **argv, struct ref_store **refs)
*refs = get_main_ref_store(the_repository);
} else if (skip_prefix(argv[0], "submodule:", &gitdir)) {
struct strbuf sb = STRBUF_INIT;
int ret;

ret = strbuf_git_path_submodule(&sb, gitdir, "objects/");
if (ret)
die("strbuf_git_path_submodule failed: %d", ret);
if (!repo_submodule_path_append(the_repository,
&sb, gitdir, "objects/"))
die("computing submodule path failed");
add_to_alternates_memory(sb.buf);
strbuf_release(&sb);


View File

@ -42,6 +42,8 @@
* file created by its parent.
*/

#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "abspath.h"
#include "path.h"
@ -148,7 +150,7 @@ struct tempfile *create_tempfile_mode(const char *path, int mode)
return NULL;
}
activate_tempfile(tempfile);
if (adjust_shared_perm(tempfile->filename.buf)) {
if (adjust_shared_perm(the_repository, tempfile->filename.buf)) {
int save_errno = errno;
error("cannot fix permission bits on %s", tempfile->filename.buf);
delete_tempfile(&tempfile);

View File

@ -207,10 +207,12 @@ static int read_dir_paths(struct string_list *out, const char *path)
return 0;
}

static int migrate_paths(struct strbuf *src, struct strbuf *dst,
static int migrate_paths(struct tmp_objdir *t,
struct strbuf *src, struct strbuf *dst,
enum finalize_object_file_flags flags);

static int migrate_one(struct strbuf *src, struct strbuf *dst,
static int migrate_one(struct tmp_objdir *t,
struct strbuf *src, struct strbuf *dst,
enum finalize_object_file_flags flags)
{
struct stat st;
@ -219,11 +221,11 @@ static int migrate_one(struct strbuf *src, struct strbuf *dst,
return -1;
if (S_ISDIR(st.st_mode)) {
if (!mkdir(dst->buf, 0777)) {
if (adjust_shared_perm(dst->buf))
if (adjust_shared_perm(t->repo, dst->buf))
return -1;
} else if (errno != EEXIST)
return -1;
return migrate_paths(src, dst, flags);
return migrate_paths(t, src, dst, flags);
}
return finalize_object_file_flags(src->buf, dst->buf, flags);
}
@ -233,7 +235,8 @@ static int is_loose_object_shard(const char *name)
return strlen(name) == 2 && isxdigit(name[0]) && isxdigit(name[1]);
}

static int migrate_paths(struct strbuf *src, struct strbuf *dst,
static int migrate_paths(struct tmp_objdir *t,
struct strbuf *src, struct strbuf *dst,
enum finalize_object_file_flags flags)
{
size_t src_len = src->len, dst_len = dst->len;
@ -255,7 +258,7 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst,
if (is_loose_object_shard(name))
flags_copy |= FOF_SKIP_COLLISION_CHECK;

ret |= migrate_one(src, dst, flags_copy);
ret |= migrate_one(t, src, dst, flags_copy);

strbuf_setlen(src, src_len);
strbuf_setlen(dst, dst_len);
@ -283,7 +286,7 @@ int tmp_objdir_migrate(struct tmp_objdir *t)
strbuf_addbuf(&src, &t->path);
strbuf_addstr(&dst, repo_get_object_directory(t->repo));

ret = migrate_paths(&src, &dst, 0);
ret = migrate_paths(t, &src, &dst, 0);

strbuf_release(&src);
strbuf_release(&dst);

View File

@ -59,8 +59,9 @@ static void add_head_info(struct worktree *wt)
static int is_current_worktree(struct worktree *wt)
{
char *git_dir = absolute_pathdup(repo_get_git_dir(the_repository));
const char *wt_git_dir = get_worktree_git_dir(wt);
char *wt_git_dir = get_worktree_git_dir(wt);
int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir));
free(wt_git_dir);
free(git_dir);
return is_current;
}
@ -127,7 +128,7 @@ struct worktree *get_linked_worktree(const char *id,
if (!id)
die("Missing linked worktree name");

strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
repo_common_path_append(the_repository, &path, "worktrees/%s/gitdir", id);
if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
/* invalid gitdir file */
goto done;
@ -198,14 +199,14 @@ struct worktree **get_worktrees(void)
return get_worktrees_internal(0);
}

const char *get_worktree_git_dir(const struct worktree *wt)
char *get_worktree_git_dir(const struct worktree *wt)
{
if (!wt)
return repo_get_git_dir(the_repository);
return xstrdup(repo_get_git_dir(the_repository));
else if (!wt->id)
return repo_get_common_dir(the_repository);
return xstrdup(repo_get_common_dir(the_repository));
else
return git_common_path("worktrees/%s", wt->id);
return repo_common_path(the_repository, "worktrees/%s", wt->id);
}

static struct worktree *find_worktree_by_suffix(struct worktree **list,
@ -336,6 +337,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
{
struct strbuf wt_path = STRBUF_INIT;
struct strbuf realpath = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
char *path = NULL;
int err, ret = -1;

@ -365,7 +367,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
if (!is_absolute_path(wt->path)) {
strbuf_addf_gently(errmsg,
_("'%s' file does not contain absolute path to the working tree location"),
git_common_path("worktrees/%s/gitdir", wt->id));
repo_common_path_replace(the_repository, &buf, "worktrees/%s/gitdir", wt->id));
goto done;
}

@ -387,14 +389,16 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
goto done;
}

strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
strbuf_realpath(&realpath, repo_common_path_replace(the_repository, &buf, "worktrees/%s", wt->id), 1);
ret = fspathcmp(path, realpath.buf);

if (ret)
strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
wt->path, git_common_path("worktrees/%s", wt->id));
wt->path, repo_common_path_replace(the_repository, &buf,
"worktrees/%s", wt->id));
done:
free(path);
strbuf_release(&buf);
strbuf_release(&wt_path);
strbuf_release(&realpath);
return ret;
@ -406,11 +410,13 @@ void update_worktree_location(struct worktree *wt, const char *path_,
struct strbuf path = STRBUF_INIT;
struct strbuf dotgit = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
char *wt_gitdir;

if (is_main_worktree(wt))
BUG("can't relocate main worktree");

strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
wt_gitdir = repo_common_path(the_repository, "worktrees/%s/gitdir", wt->id);
strbuf_realpath(&gitdir, wt_gitdir, 1);
strbuf_realpath(&path, path_, 1);
strbuf_addf(&dotgit, "%s/.git", path.buf);
if (fspathcmp(wt->path, path.buf)) {
@ -422,6 +428,7 @@ void update_worktree_location(struct worktree *wt, const char *path_,
strbuf_release(&path);
strbuf_release(&dotgit);
strbuf_release(&gitdir);
free(wt_gitdir);
}

int is_worktree_being_rebased(const struct worktree *wt,
@ -510,7 +517,8 @@ int submodule_uses_worktrees(const char *path)
int ret = 0;
struct repository_format format = REPOSITORY_FORMAT_INIT;

submodule_gitdir = git_pathdup_submodule(path, "%s", "");
submodule_gitdir = repo_submodule_path(the_repository,
path, "%s", "");
if (!submodule_gitdir)
return 0;

@ -606,6 +614,7 @@ static void repair_gitfile(struct worktree *wt,
struct strbuf backlink = STRBUF_INIT;
char *dotgit_contents = NULL;
const char *repair = NULL;
char *path = NULL;
int err;

/* missing worktree can't be repaired */
@ -617,7 +626,8 @@ static void repair_gitfile(struct worktree *wt,
goto done;
}

strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
path = repo_common_path(the_repository, "worktrees/%s", wt->id);
strbuf_realpath(&repo, path, 1);
strbuf_addf(&dotgit, "%s/.git", wt->path);
strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
@ -647,6 +657,7 @@ static void repair_gitfile(struct worktree *wt,

done:
free(dotgit_contents);
free(path);
strbuf_release(&repo);
strbuf_release(&dotgit);
strbuf_release(&gitdir);
@ -678,11 +689,13 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
struct strbuf gitdir = STRBUF_INIT;
struct strbuf dotgit = STRBUF_INIT;
int is_relative_path;
char *path = NULL;

if (is_main_worktree(wt))
goto done;

strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
path = repo_common_path(the_repository, "worktrees/%s/gitdir", wt->id);
strbuf_realpath(&gitdir, path, 1);

if (strbuf_read_file(&dotgit, gitdir.buf, 0) < 0)
goto done;
@ -701,6 +714,7 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
done:
strbuf_release(&gitdir);
strbuf_release(&dotgit);
free(path);
}

void repair_worktrees_after_gitdir_move(const char *old_path)
@ -754,8 +768,7 @@ static ssize_t infer_backlink(const char *gitfile, struct strbuf *inferred)
id++; /* advance past '/' to point at <id> */
if (!*id)
goto error;
strbuf_reset(inferred);
strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id);
repo_common_path_replace(the_repository, inferred, "worktrees/%s", id);
if (!is_directory(inferred->buf))
goto error;

@ -893,7 +906,11 @@ int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath,
ssize_t read_result;

*wtpath = NULL;
strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1);

path = repo_common_path(the_repository, "worktrees/%s", id);
strbuf_realpath(&repo, path, 1);
FREE_AND_NULL(path);

strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
if (!is_directory(repo.buf)) {
strbuf_addstr(reason, _("not a valid directory"));

View File

@ -39,7 +39,7 @@ int submodule_uses_worktrees(const char *path);
* Return git dir of the worktree. Note that the path may be relative.
* If wt is NULL, git dir of current worktree is returned.
*/
const char *get_worktree_git_dir(const struct worktree *wt);
char *get_worktree_git_dir(const struct worktree *wt);

/*
* Search for the worktree identified unambiguously by `arg` -- typically

View File

@ -1289,7 +1289,8 @@ static void show_am_in_progress(struct wt_status *s,
static char *read_line_from_git_path(const char *filename)
{
struct strbuf buf = STRBUF_INIT;
FILE *fp = fopen_or_warn(git_path("%s", filename), "r");
FILE *fp = fopen_or_warn(repo_git_path_append(the_repository, &buf,
"%s", filename), "r");

if (!fp) {
strbuf_release(&buf);
@ -1383,27 +1384,33 @@ static void abbrev_oid_in_line(struct strbuf *line)

static int read_rebase_todolist(const char *fname, struct string_list *lines)
{
struct strbuf line = STRBUF_INIT;
FILE *f = fopen(git_path("%s", fname), "r");
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen(repo_git_path_append(the_repository, &buf, "%s", fname), "r");
int ret;

if (!f) {
if (errno == ENOENT)
return -1;
if (errno == ENOENT) {
ret = -1;
goto out;
}
die_errno("Could not open file %s for reading",
git_path("%s", fname));
repo_git_path_replace(the_repository, &buf, "%s", fname));
}
while (!strbuf_getline_lf(&line, f)) {
if (starts_with(line.buf, comment_line_str))
while (!strbuf_getline_lf(&buf, f)) {
if (starts_with(buf.buf, comment_line_str))
continue;
strbuf_trim(&line);
if (!line.len)
strbuf_trim(&buf);
if (!buf.len)
continue;
abbrev_oid_in_line(&line);
string_list_append(lines, line.buf);
abbrev_oid_in_line(&buf);
string_list_append(lines, buf.buf);
}
fclose(f);
strbuf_release(&line);
return 0;

ret = 0;
out:
strbuf_release(&buf);
return ret;
}

static void show_rebase_information(struct wt_status *s,
@ -1434,9 +1441,12 @@ static void show_rebase_information(struct wt_status *s,
i < have_done.nr;
i++)
status_printf_ln(s, color, " %s", have_done.items[i].string);
if (have_done.nr > nr_lines_to_show && s->hints)
if (have_done.nr > nr_lines_to_show && s->hints) {
char *path = repo_git_path(the_repository, "rebase-merge/done");
status_printf_ln(s, color,
_(" (see more in file %s)"), git_path("rebase-merge/done"));
_(" (see more in file %s)"), path);
free(path);
}
}

if (yet_to_do.nr == 0)