Merge branch 'pc/lockfile-pid'
Allow recording process ID of the process that holds the lock next to a lockfile for diagnosis. * pc/lockfile-pid: lockfile: add PID file for debugging stale locksmain
commit
5779c47fa0
|
|
@ -348,6 +348,17 @@ 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
|
read-only snapshot of the same index to a location different from the
|
||||||
repository's usual working tree).
|
repository's usual working tree).
|
||||||
|
|
||||||
|
core.lockfilePid::
|
||||||
|
If true, Git will create a PID file alongside lock files. 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. Defaults to `false`.
|
||||||
|
+
|
||||||
|
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`. The file contains a single line in the format
|
||||||
|
`pid <value>` followed by a newline.
|
||||||
|
|
||||||
core.logAllRefUpdates::
|
core.logAllRefUpdates::
|
||||||
Enable the reflog. Updates to a ref <ref> is logged to the file
|
Enable the reflog. Updates to a ref <ref> is logged to the file
|
||||||
"`$GIT_DIR/logs/<ref>`", by appending the new and old
|
"`$GIT_DIR/logs/<ref>`", by appending the new and old
|
||||||
|
|
|
||||||
|
|
@ -2220,6 +2220,16 @@ int mingw_kill(pid_t pid, int sig)
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* OpenProcess returns ERROR_INVALID_PARAMETER for
|
||||||
|
* non-existent PIDs. Map this to ESRCH for POSIX
|
||||||
|
* compatibility with kill(pid, 0).
|
||||||
|
*/
|
||||||
|
if (GetLastError() == ERROR_INVALID_PARAMETER)
|
||||||
|
errno = ESRCH;
|
||||||
|
else
|
||||||
|
errno = err_win_to_posix(GetLastError());
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "git-zlib.h"
|
#include "git-zlib.h"
|
||||||
#include "ident.h"
|
#include "ident.h"
|
||||||
|
#include "lockfile.h"
|
||||||
#include "mailmap.h"
|
#include "mailmap.h"
|
||||||
#include "object-name.h"
|
#include "object-name.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
|
|
@ -508,6 +509,11 @@ int git_default_core_config(const char *var, const char *value,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(var, "core.lockfilepid")) {
|
||||||
|
lockfile_pid_enabled = git_config_bool(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(var, "core.createobject")) {
|
if (!strcmp(var, "core.createobject")) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return config_error_nonbool(var);
|
return config_error_nonbool(var);
|
||||||
|
|
|
||||||
168
lockfile.c
168
lockfile.c
|
|
@ -6,6 +6,9 @@
|
||||||
#include "abspath.h"
|
#include "abspath.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "lockfile.h"
|
#include "lockfile.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
#include "wrapper.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* path = absolute or relative path name
|
* path = absolute or relative path name
|
||||||
|
|
@ -71,19 +74,115 @@ static void resolve_symlink(struct strbuf *path)
|
||||||
strbuf_reset(&link);
|
strbuf_reset(&link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock PID file functions - write PID to a foo~pid.lock file alongside
|
||||||
|
* the lock file for debugging stale locks. The PID file is registered
|
||||||
|
* as a tempfile so it gets cleaned up by signal/atexit handlers.
|
||||||
|
*
|
||||||
|
* Naming: For "foo.lock", the PID file is "foo~pid.lock". The tilde is
|
||||||
|
* forbidden in refnames and allowed in Windows filenames, guaranteeing
|
||||||
|
* no collision with the refs namespace.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Global config variable, initialized from core.lockfilePid */
|
||||||
|
int lockfile_pid_enabled;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Path generation helpers.
|
||||||
|
* Given base path "foo", generate:
|
||||||
|
* - lock path: "foo.lock"
|
||||||
|
* - pid path: "foo-pid.lock"
|
||||||
|
*/
|
||||||
|
static void get_lock_path(struct strbuf *out, const char *path)
|
||||||
|
{
|
||||||
|
strbuf_addstr(out, path);
|
||||||
|
strbuf_addstr(out, LOCK_SUFFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_pid_path(struct strbuf *out, const char *path)
|
||||||
|
{
|
||||||
|
strbuf_addstr(out, path);
|
||||||
|
strbuf_addstr(out, LOCK_PID_INFIX);
|
||||||
|
strbuf_addstr(out, LOCK_SUFFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tempfile *create_lock_pid_file(const char *pid_path, int mode)
|
||||||
|
{
|
||||||
|
struct strbuf content = STRBUF_INIT;
|
||||||
|
struct tempfile *pid_tempfile = NULL;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (!lockfile_pid_enabled)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
fd = open(pid_path, O_WRONLY | O_CREAT | O_EXCL, mode);
|
||||||
|
if (fd < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
strbuf_addf(&content, "pid %" PRIuMAX "\n", (uintmax_t)getpid());
|
||||||
|
if (write_in_full(fd, content.buf, content.len) < 0) {
|
||||||
|
warning_errno(_("could not write lock pid file '%s'"), pid_path);
|
||||||
|
close(fd);
|
||||||
|
unlink(pid_path);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
pid_tempfile = register_tempfile(pid_path);
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&content);
|
||||||
|
return pid_tempfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_lock_pid(const char *pid_path, uintmax_t *pid_out)
|
||||||
|
{
|
||||||
|
struct strbuf content = STRBUF_INIT;
|
||||||
|
const char *val;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (strbuf_read_file(&content, pid_path, LOCK_PID_MAXLEN) <= 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
strbuf_rtrim(&content);
|
||||||
|
|
||||||
|
if (skip_prefix(content.buf, "pid ", &val)) {
|
||||||
|
char *endptr;
|
||||||
|
*pid_out = strtoumax(val, &endptr, 10);
|
||||||
|
if (*pid_out > 0 && !*endptr)
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
warning(_("malformed lock pid file '%s'"), pid_path);
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&content);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure errno contains a meaningful value on error */
|
/* Make sure errno contains a meaningful value on error */
|
||||||
static int lock_file(struct lock_file *lk, const char *path, int flags,
|
static int lock_file(struct lock_file *lk, const char *path, int flags,
|
||||||
int mode)
|
int mode)
|
||||||
{
|
{
|
||||||
struct strbuf filename = STRBUF_INIT;
|
struct strbuf base_path = STRBUF_INIT;
|
||||||
|
struct strbuf lock_path = STRBUF_INIT;
|
||||||
|
struct strbuf pid_path = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_addstr(&filename, path);
|
strbuf_addstr(&base_path, path);
|
||||||
if (!(flags & LOCK_NO_DEREF))
|
if (!(flags & LOCK_NO_DEREF))
|
||||||
resolve_symlink(&filename);
|
resolve_symlink(&base_path);
|
||||||
|
|
||||||
strbuf_addstr(&filename, LOCK_SUFFIX);
|
get_lock_path(&lock_path, base_path.buf);
|
||||||
lk->tempfile = create_tempfile_mode(filename.buf, mode);
|
get_pid_path(&pid_path, base_path.buf);
|
||||||
strbuf_release(&filename);
|
|
||||||
|
lk->tempfile = create_tempfile_mode(lock_path.buf, mode);
|
||||||
|
if (lk->tempfile)
|
||||||
|
lk->pid_tempfile = create_lock_pid_file(pid_path.buf, mode);
|
||||||
|
|
||||||
|
strbuf_release(&base_path);
|
||||||
|
strbuf_release(&lock_path);
|
||||||
|
strbuf_release(&pid_path);
|
||||||
return lk->tempfile ? lk->tempfile->fd : -1;
|
return lk->tempfile ? lk->tempfile->fd : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,16 +250,49 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
|
||||||
void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
|
void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
|
||||||
{
|
{
|
||||||
if (err == EEXIST) {
|
if (err == EEXIST) {
|
||||||
strbuf_addf(buf, _("Unable to create '%s.lock': %s.\n\n"
|
const char *abs_path = absolute_path(path);
|
||||||
"Another git process seems to be running in this repository, e.g.\n"
|
struct strbuf lock_path = STRBUF_INIT;
|
||||||
"an editor opened by 'git commit'. Please make sure all processes\n"
|
struct strbuf pid_path = STRBUF_INIT;
|
||||||
"are terminated then try again. If it still fails, a git process\n"
|
uintmax_t pid;
|
||||||
"may have crashed in this repository earlier:\n"
|
int pid_status = 0; /* 0 = unknown, 1 = running, -1 = stale */
|
||||||
"remove the file manually to continue."),
|
|
||||||
absolute_path(path), strerror(err));
|
get_lock_path(&lock_path, abs_path);
|
||||||
} else
|
get_pid_path(&pid_path, abs_path);
|
||||||
|
|
||||||
|
strbuf_addf(buf, _("Unable to create '%s': %s.\n\n"),
|
||||||
|
lock_path.buf, strerror(err));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to read PID file unconditionally - it may exist if
|
||||||
|
* core.lockfilePid was enabled.
|
||||||
|
*/
|
||||||
|
if (!read_lock_pid(pid_path.buf, &pid)) {
|
||||||
|
if (kill((pid_t)pid, 0) == 0 || errno == EPERM)
|
||||||
|
pid_status = 1; /* running (or no permission to signal) */
|
||||||
|
else if (errno == ESRCH)
|
||||||
|
pid_status = -1; /* no such process - stale lock */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid_status == 1)
|
||||||
|
strbuf_addf(buf, _("Lock may be held by process %" PRIuMAX "; "
|
||||||
|
"if no git process is running, the lock file "
|
||||||
|
"may be stale (PIDs can be reused)"),
|
||||||
|
pid);
|
||||||
|
else if (pid_status == -1)
|
||||||
|
strbuf_addf(buf, _("Lock was held by process %" PRIuMAX ", "
|
||||||
|
"which is no longer running; the lock file "
|
||||||
|
"appears to be stale"),
|
||||||
|
pid);
|
||||||
|
else
|
||||||
|
strbuf_addstr(buf, _("Another git process seems to be running in this repository, "
|
||||||
|
"or the lock file may be stale"));
|
||||||
|
|
||||||
|
strbuf_release(&lock_path);
|
||||||
|
strbuf_release(&pid_path);
|
||||||
|
} else {
|
||||||
strbuf_addf(buf, _("Unable to create '%s.lock': %s"),
|
strbuf_addf(buf, _("Unable to create '%s.lock': %s"),
|
||||||
absolute_path(path), strerror(err));
|
absolute_path(path), strerror(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NORETURN void unable_to_lock_die(const char *path, int err)
|
NORETURN void unable_to_lock_die(const char *path, int err)
|
||||||
|
|
@ -207,6 +339,8 @@ int commit_lock_file(struct lock_file *lk)
|
||||||
{
|
{
|
||||||
char *result_path = get_locked_file_path(lk);
|
char *result_path = get_locked_file_path(lk);
|
||||||
|
|
||||||
|
delete_tempfile(&lk->pid_tempfile);
|
||||||
|
|
||||||
if (commit_lock_file_to(lk, result_path)) {
|
if (commit_lock_file_to(lk, result_path)) {
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
free(result_path);
|
free(result_path);
|
||||||
|
|
@ -216,3 +350,9 @@ int commit_lock_file(struct lock_file *lk)
|
||||||
free(result_path);
|
free(result_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rollback_lock_file(struct lock_file *lk)
|
||||||
|
{
|
||||||
|
delete_tempfile(&lk->pid_tempfile);
|
||||||
|
return delete_tempfile(&lk->tempfile);
|
||||||
|
}
|
||||||
|
|
|
||||||
43
lockfile.h
43
lockfile.h
|
|
@ -119,6 +119,7 @@
|
||||||
|
|
||||||
struct lock_file {
|
struct lock_file {
|
||||||
struct tempfile *tempfile;
|
struct tempfile *tempfile;
|
||||||
|
struct tempfile *pid_tempfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LOCK_INIT { 0 }
|
#define LOCK_INIT { 0 }
|
||||||
|
|
@ -127,6 +128,22 @@ struct lock_file {
|
||||||
#define LOCK_SUFFIX ".lock"
|
#define LOCK_SUFFIX ".lock"
|
||||||
#define LOCK_SUFFIX_LEN 5
|
#define LOCK_SUFFIX_LEN 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PID file naming: for a lock file "foo.lock", the PID file is "foo~pid.lock".
|
||||||
|
* The tilde is forbidden in refnames and allowed in Windows filenames, avoiding
|
||||||
|
* namespace collisions (e.g., refs "foo" and "foo~pid" cannot both exist).
|
||||||
|
*/
|
||||||
|
#define LOCK_PID_INFIX "~pid"
|
||||||
|
#define LOCK_PID_INFIX_LEN 4
|
||||||
|
|
||||||
|
/* Maximum length for PID file content */
|
||||||
|
#define LOCK_PID_MAXLEN 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whether to create PID files alongside lock files.
|
||||||
|
* Configured via core.lockfilePid (boolean).
|
||||||
|
*/
|
||||||
|
extern int lockfile_pid_enabled;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags
|
* Flags
|
||||||
|
|
@ -169,12 +186,12 @@ struct lock_file {
|
||||||
* handling, and mode are described above.
|
* handling, and mode are described above.
|
||||||
*/
|
*/
|
||||||
int hold_lock_file_for_update_timeout_mode(
|
int hold_lock_file_for_update_timeout_mode(
|
||||||
struct lock_file *lk, const char *path,
|
struct lock_file *lk, const char *path,
|
||||||
int flags, long timeout_ms, int mode);
|
int flags, long timeout_ms, int mode);
|
||||||
|
|
||||||
static inline int hold_lock_file_for_update_timeout(
|
static inline int hold_lock_file_for_update_timeout(
|
||||||
struct lock_file *lk, const char *path,
|
struct lock_file *lk, const char *path,
|
||||||
int flags, long timeout_ms)
|
int flags, long timeout_ms)
|
||||||
{
|
{
|
||||||
return hold_lock_file_for_update_timeout_mode(lk, path, flags,
|
return hold_lock_file_for_update_timeout_mode(lk, path, flags,
|
||||||
timeout_ms, 0666);
|
timeout_ms, 0666);
|
||||||
|
|
@ -186,15 +203,14 @@ static inline int hold_lock_file_for_update_timeout(
|
||||||
* argument and error handling are described above.
|
* argument and error handling are described above.
|
||||||
*/
|
*/
|
||||||
static inline int hold_lock_file_for_update(
|
static inline int hold_lock_file_for_update(
|
||||||
struct lock_file *lk, const char *path,
|
struct lock_file *lk, const char *path, int flags)
|
||||||
int flags)
|
|
||||||
{
|
{
|
||||||
return hold_lock_file_for_update_timeout(lk, path, flags, 0);
|
return hold_lock_file_for_update_timeout(lk, path, flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hold_lock_file_for_update_mode(
|
static inline int hold_lock_file_for_update_mode(
|
||||||
struct lock_file *lk, const char *path,
|
struct lock_file *lk, const char *path,
|
||||||
int flags, int mode)
|
int flags, int mode)
|
||||||
{
|
{
|
||||||
return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
|
return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
|
||||||
}
|
}
|
||||||
|
|
@ -319,13 +335,10 @@ static inline int commit_lock_file_to(struct lock_file *lk, const char *path)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Roll back `lk`: close the file descriptor and/or file pointer and
|
* Roll back `lk`: close the file descriptor and/or file pointer and
|
||||||
* remove the lockfile. It is a NOOP to call `rollback_lock_file()`
|
* remove the lockfile and any associated PID file. It is a NOOP to
|
||||||
* for a `lock_file` object that has already been committed or rolled
|
* call `rollback_lock_file()` for a `lock_file` object that has already
|
||||||
* back. No error will be returned in this case.
|
* been committed or rolled back. No error will be returned in this case.
|
||||||
*/
|
*/
|
||||||
static inline int rollback_lock_file(struct lock_file *lk)
|
int rollback_lock_file(struct lock_file *lk);
|
||||||
{
|
|
||||||
return delete_tempfile(&lk->tempfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LOCKFILE_H */
|
#endif /* LOCKFILE_H */
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ integration_tests = [
|
||||||
't0028-working-tree-encoding.sh',
|
't0028-working-tree-encoding.sh',
|
||||||
't0029-core-unsetenvvars.sh',
|
't0029-core-unsetenvvars.sh',
|
||||||
't0030-stripspace.sh',
|
't0030-stripspace.sh',
|
||||||
|
't0031-lockfile-pid.sh',
|
||||||
't0033-safe-directory.sh',
|
't0033-safe-directory.sh',
|
||||||
't0034-root-safe-directory.sh',
|
't0034-root-safe-directory.sh',
|
||||||
't0035-safe-bare-repository.sh',
|
't0035-safe-bare-repository.sh',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='lock file PID info tests
|
||||||
|
|
||||||
|
Tests for PID info file alongside lock files.
|
||||||
|
The feature is opt-in via core.lockfilePid config setting (boolean).
|
||||||
|
'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'stale lock detected when PID is not running' '
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
touch .git/index.lock &&
|
||||||
|
printf "pid 99999" >.git/index~pid.lock &&
|
||||||
|
test_must_fail git -c core.lockfilePid=true add . 2>err &&
|
||||||
|
test_grep "process 99999, which is no longer running" err &&
|
||||||
|
test_grep "appears to be stale" err
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'PID info not shown by default' '
|
||||||
|
git init repo2 &&
|
||||||
|
(
|
||||||
|
cd repo2 &&
|
||||||
|
touch .git/index.lock &&
|
||||||
|
printf "pid 99999" >.git/index~pid.lock &&
|
||||||
|
test_must_fail git add . 2>err &&
|
||||||
|
# Should not crash, just show normal error without PID
|
||||||
|
test_grep "Unable to create" err &&
|
||||||
|
! test_grep "is held by process" err
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'running process detected when PID is alive' '
|
||||||
|
git init repo3 &&
|
||||||
|
(
|
||||||
|
cd repo3 &&
|
||||||
|
echo content >file &&
|
||||||
|
# Get the correct PID for this platform
|
||||||
|
shell_pid=$$ &&
|
||||||
|
if test_have_prereq MINGW && test -f /proc/$shell_pid/winpid
|
||||||
|
then
|
||||||
|
# In Git for Windows, Bash uses MSYS2 PIDs but git.exe
|
||||||
|
# uses Windows PIDs. Use the Windows PID.
|
||||||
|
shell_pid=$(cat /proc/$shell_pid/winpid)
|
||||||
|
fi &&
|
||||||
|
# Create a lock and PID file with current shell PID (which is running)
|
||||||
|
touch .git/index.lock &&
|
||||||
|
printf "pid %d" "$shell_pid" >.git/index~pid.lock &&
|
||||||
|
# Verify our PID is shown in the error message
|
||||||
|
test_must_fail git -c core.lockfilePid=true add file 2>err &&
|
||||||
|
test_grep "held by process $shell_pid" err
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'PID info file cleaned up on successful operation when enabled' '
|
||||||
|
git init repo4 &&
|
||||||
|
(
|
||||||
|
cd repo4 &&
|
||||||
|
echo content >file &&
|
||||||
|
git -c core.lockfilePid=true add file &&
|
||||||
|
# After successful add, no lock or PID files should exist
|
||||||
|
test_path_is_missing .git/index.lock &&
|
||||||
|
test_path_is_missing .git/index~pid.lock
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'no PID file created by default' '
|
||||||
|
git init repo5 &&
|
||||||
|
(
|
||||||
|
cd repo5 &&
|
||||||
|
echo content >file &&
|
||||||
|
git add file &&
|
||||||
|
# PID file should not be created when feature is disabled
|
||||||
|
test_path_is_missing .git/index~pid.lock
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'core.lockfilePid=false does not create PID file' '
|
||||||
|
git init repo6 &&
|
||||||
|
(
|
||||||
|
cd repo6 &&
|
||||||
|
echo content >file &&
|
||||||
|
git -c core.lockfilePid=false add file &&
|
||||||
|
# PID file should not be created when feature is disabled
|
||||||
|
test_path_is_missing .git/index~pid.lock
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'existing PID files are read even when feature disabled' '
|
||||||
|
git init repo7 &&
|
||||||
|
(
|
||||||
|
cd repo7 &&
|
||||||
|
touch .git/index.lock &&
|
||||||
|
printf "pid 99999" >.git/index~pid.lock &&
|
||||||
|
# Even with lockfilePid disabled, existing PID files are read
|
||||||
|
# to help diagnose stale locks
|
||||||
|
test_must_fail git add . 2>err &&
|
||||||
|
test_grep "process 99999" err
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
||||||
Loading…
Reference in New Issue