Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Documentation/config/core.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,31 @@ confusion unless you know what you are doing (e.g. you are creating a
read-only snapshot of the same index to a location different from the
repository's usual working tree).

core.lockfilePid::
A comma-separated list of components for which Git should create
a PID file alongside the lock file. When a lock acquisition fails
and a PID file exists, Git can provide additional diagnostic
information about the process holding the lock, including whether
it is still running.
+
This feature is disabled by default. You can enable it for specific
components or use `all` to enable for all components.
+
* `none` disables PID file creation for all components.
* `index` creates PID files for index lock operations.
* `config` creates PID files for config file lock operations.
* `refs` creates PID files for reference lock operations.
* `commit-graph` creates PID files for commit-graph lock operations.
* `midx` creates PID files for multi-pack-index lock operations.
* `shallow` creates PID files for shallow file lock operations.
* `gc` creates PID files for garbage collection lock operations.
* `other` creates PID files for other miscellaneous lock operations.
* `all` enables PID file creation for all components.
+
The PID file is named by inserting `-pid` before the `.lock` suffix.
For example, if the lock file is `index.lock`, the PID file will be
`index-pid.lock`.

core.logAllRefUpdates::
Enable the reflog. Updates to a ref <ref> is logged to the file
"`$GIT_DIR/logs/<ref>`", by appending the new and old
Expand Down
10 changes: 10 additions & 0 deletions Documentation/git.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,16 @@ be in the future).
the background which do not want to cause lock contention with
other operations on the repository. Defaults to `1`.

`GIT_LOCK_PID_INFO`::
If this Boolean environment variable is set to `1`, Git will create
a `.lock.pid` file alongside each lock file containing the PID of the
process that created the lock. This information is displayed in error
messages when a lock conflict occurs, making it easier to identify
stale locks or debug locking issues. The PID files are automatically
cleaned up via signal and atexit handlers; however, if a process is
terminated abnormally (e.g., SIGKILL), the file may remain as a stale
indicator. Disabled by default.

`GIT_REDIRECT_STDIN`::
`GIT_REDIRECT_STDOUT`::
`GIT_REDIRECT_STDERR`::
Expand Down
6 changes: 4 additions & 2 deletions apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -4173,7 +4173,8 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
}
}

hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR);
hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR,
LOCKFILE_PID_OTHER);
res = write_locked_index(&result, &lock, COMMIT_LOCK);
discard_index(&result);

Expand Down Expand Up @@ -4830,7 +4831,8 @@ static int apply_patch(struct apply_state *state,
if (state->index_file)
hold_lock_file_for_update(&state->lock_file,
state->index_file,
LOCK_DIE_ON_ERROR);
LOCK_DIE_ON_ERROR,
LOCKFILE_PID_INDEX);
else
repo_hold_locked_index(state->repo, &state->lock_file,
LOCK_DIE_ON_ERROR);
Expand Down
2 changes: 1 addition & 1 deletion builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
path = repo_git_path(the_repository, "next-index-%"PRIuMAX,
(uintmax_t) getpid());
hold_lock_file_for_update(&false_lock, path,
LOCK_DIE_ON_ERROR);
LOCK_DIE_ON_ERROR, LOCKFILE_PID_OTHER);

create_base_index(current_head);
add_remove_files(&partial);
Expand Down
3 changes: 2 additions & 1 deletion builtin/credential-store.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
int timeout_ms = 1000;

repo_config_get_int(the_repository, "credentialstore.locktimeoutms", &timeout_ms);
if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms) < 0)
if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms,
LOCKFILE_PID_CONFIG) < 0)
die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
if (extra)
print_line(extra);
Expand Down
3 changes: 2 additions & 1 deletion builtin/difftool.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,8 @@ static int run_dir_diff(struct repository *repo,
struct lock_file lock = LOCK_INIT;
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/wtindex", tmpdir.buf);
if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
if (hold_lock_file_for_update(&lock, buf.buf, 0,
LOCKFILE_PID_OTHER) < 0 ||
write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
ret = error("could not write %s", buf.buf);
goto finish;
Expand Down
3 changes: 2 additions & 1 deletion builtin/fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -1734,7 +1734,8 @@ static void dump_marks(void)
return;
}

if (hold_lock_file_for_update(&mark_lock, export_marks_file, 0) < 0) {
if (hold_lock_file_for_update(&mark_lock, export_marks_file, 0,
LOCKFILE_PID_OTHER) < 0) {
failure |= error_errno(_("unable to write marks file %s"),
export_marks_file);
return;
Expand Down
13 changes: 8 additions & 5 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)

pidfile_path = repo_git_path(the_repository, "gc.pid");
fd = hold_lock_file_for_update(&lock, pidfile_path,
LOCK_DIE_ON_ERROR);
LOCK_DIE_ON_ERROR, LOCKFILE_PID_GC);
if (!force) {
static char locking_host[HOST_NAME_MAX + 1];
static char *scan_fmt;
Expand Down Expand Up @@ -1017,7 +1017,7 @@ int cmd_gc(int argc,
if (daemonized) {
char *path = repo_git_path(the_repository, "gc.log");
hold_lock_file_for_update(&log_lock, path,
LOCK_DIE_ON_ERROR);
LOCK_DIE_ON_ERROR, LOCKFILE_PID_GC);
dup2(get_lock_file_fd(&log_lock), 2);
atexit(process_log_file_at_exit);
free(path);
Expand Down Expand Up @@ -1797,7 +1797,8 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
struct repository *r = the_repository;
char *lock_path = xstrfmt("%s/maintenance", r->objects->sources->path);

if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF,
LOCKFILE_PID_GC) < 0) {
/*
* Another maintenance command is running.
*
Expand Down Expand Up @@ -2561,7 +2562,8 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
lock_file_timeout_ms = 150;

fd = hold_lock_file_for_update_timeout(&lk, filename, LOCK_DIE_ON_ERROR,
lock_file_timeout_ms);
lock_file_timeout_ms,
LOCKFILE_PID_GC);

/*
* Does this file already exist? With the intended contents? Is it
Expand Down Expand Up @@ -3372,7 +3374,8 @@ static int update_background_schedule(const struct maintenance_start_opts *opts,
struct lock_file lk;
char *lock_path = xstrfmt("%s/schedule", the_repository->objects->sources->path);

if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF,
LOCKFILE_PID_GC) < 0) {
if (errno == EEXIST)
error(_("unable to create '%s.lock': %s.\n\n"
"Another scheduled git-maintenance(1) process seems to be running in this\n"
Expand Down
3 changes: 2 additions & 1 deletion builtin/sparse-checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ static int write_patterns_and_update(struct repository *repo,
if (safe_create_leading_directories(repo, sparse_filename))
die(_("failed to create directory for sparse-checkout file"));

hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR,
LOCKFILE_PID_OTHER);

result = update_working_directory(repo, pl);
if (result) {
Expand Down
3 changes: 2 additions & 1 deletion bundle.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,8 @@ int create_bundle(struct repository *r, const char *path,
bundle_fd = 1;
else
bundle_fd = hold_lock_file_for_update(&lock, path,
LOCK_DIE_ON_ERROR);
LOCK_DIE_ON_ERROR,
LOCKFILE_PID_OTHER);

if (version == -1)
version = min_version;
Expand Down
3 changes: 2 additions & 1 deletion cache-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,8 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
struct lock_file lock_file = LOCK_INIT;
int ret;

hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR,
LOCKFILE_PID_INDEX);

entries = read_index_from(index_state, index_path,
repo_get_git_dir(the_repository));
Expand Down
6 changes: 4 additions & 2 deletions commit-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -2075,7 +2075,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
char *lock_name = get_commit_graph_chain_filename(ctx->odb_source);

hold_lock_file_for_update_mode(&lk, lock_name,
LOCK_DIE_ON_ERROR, 0444);
LOCK_DIE_ON_ERROR, 0444,
LOCKFILE_PID_COMMIT_GRAPH);
free(lock_name);

graph_layer = mks_tempfile_m(ctx->graph_name, 0444);
Expand All @@ -2094,7 +2095,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));
} else {
hold_lock_file_for_update_mode(&lk, ctx->graph_name,
LOCK_DIE_ON_ERROR, 0444);
LOCK_DIE_ON_ERROR, 0444,
LOCKFILE_PID_COMMIT_GRAPH);
f = hashfd(ctx->r->hash_algo,
get_lock_file_fd(&lk), get_lock_file_path(&lk));
}
Expand Down
6 changes: 4 additions & 2 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2985,7 +2985,8 @@ int repo_config_set_multivar_in_file_gently(struct repository *r,
* The lock serves a purpose in addition to locking: the new
* contents of .git/config will be written into it.
*/
fd = hold_lock_file_for_update(&lock, config_filename, 0);
fd = hold_lock_file_for_update(&lock, config_filename, 0,
LOCKFILE_PID_CONFIG);
if (fd < 0) {
error_errno(_("could not lock config file %s"), config_filename);
ret = CONFIG_NO_LOCK;
Expand Down Expand Up @@ -3330,7 +3331,8 @@ static int repo_config_copy_or_rename_section_in_file(
if (!config_filename)
config_filename = filename_buf = repo_git_path(r, "config");

out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
out_fd = hold_lock_file_for_update(&lock, config_filename, 0,
LOCKFILE_PID_CONFIG);
if (out_fd < 0) {
ret = error(_("could not lock config file %s"), config_filename);
goto out;
Expand Down
80 changes: 80 additions & 0 deletions environment.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "gettext.h"
#include "git-zlib.h"
#include "ident.h"
#include "lockfile.h"
#include "mailmap.h"
#include "object-name.h"
#include "repository.h"
Expand Down Expand Up @@ -324,6 +325,78 @@ static enum fsync_component parse_fsync_components(const char *var, const char *
return (current & ~negative) | positive;
}

static const struct lockfile_pid_component_name {
const char *name;
enum lockfile_pid_component component_bits;
} lockfile_pid_component_names[] = {
{ "index", LOCKFILE_PID_INDEX },
{ "config", LOCKFILE_PID_CONFIG },
{ "refs", LOCKFILE_PID_REFS },
{ "commit-graph", LOCKFILE_PID_COMMIT_GRAPH },
{ "midx", LOCKFILE_PID_MIDX },
{ "shallow", LOCKFILE_PID_SHALLOW },
{ "gc", LOCKFILE_PID_GC },
{ "other", LOCKFILE_PID_OTHER },
{ "all", LOCKFILE_PID_ALL },
};

static enum lockfile_pid_component parse_lockfile_pid_components(const char *var,
const char *string)
{
enum lockfile_pid_component current = LOCKFILE_PID_DEFAULT;
enum lockfile_pid_component positive = 0, negative = 0;

while (string) {
size_t len;
const char *ep;
int negated = 0;
int found = 0;

string = string + strspn(string, ", \t\n\r");
ep = strchrnul(string, ',');
len = ep - string;
if (!strcmp(string, "none")) {
current = LOCKFILE_PID_NONE;
goto next_name;
}

if (*string == '-') {
negated = 1;
string++;
len--;
if (!len)
warning(_("invalid value for variable %s"), var);
}

if (!len)
break;

for (size_t i = 0; i < ARRAY_SIZE(lockfile_pid_component_names); ++i) {
const struct lockfile_pid_component_name *n = &lockfile_pid_component_names[i];

if (strncmp(n->name, string, len))
continue;

found = 1;
if (negated)
negative |= n->component_bits;
else
positive |= n->component_bits;
}

if (!found) {
char *component = xstrndup(string, len);
warning(_("ignoring unknown core.lockfilePid component '%s'"), component);
free(component);
}

next_name:
string = ep;
}

return (current & ~negative) | positive;
}

static int git_default_core_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
Expand Down Expand Up @@ -532,6 +605,13 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}

if (!strcmp(var, "core.lockfilepid")) {
if (!value)
return config_error_nonbool(var);
lockfile_pid_components = parse_lockfile_pid_components(var, value);
return 0;
}

if (!strcmp(var, "core.createobject")) {
if (!value)
return config_error_nonbool(var);
Expand Down
Loading
Loading