Merge branch 'nd/multiple-work-trees'

A replacement for contrib/workdir/git-new-workdir that does not
rely on symbolic links and make sharing of objects and refs safer
by making the borrowee and borrowers aware of each other.

* nd/multiple-work-trees: (41 commits)
  prune --worktrees: fix expire vs worktree existence condition
  t1501: fix test with split index
  t2026: fix broken &&-chain
  t2026 needs procondition SANITY
  git-checkout.txt: a note about multiple checkout support for submodules
  checkout: add --ignore-other-wortrees
  checkout: pass whole struct to parse_branchname_arg instead of individual flags
  git-common-dir: make "modules/" per-working-directory directory
  checkout: do not fail if target is an empty directory
  t2025: add a test to make sure grafts is working from a linked checkout
  checkout: don't require a work tree when checking out into a new one
  git_path(): keep "info/sparse-checkout" per work-tree
  count-objects: report unused files in $GIT_DIR/worktrees/...
  gc: support prune --worktrees
  gc: factor out gc.pruneexpire parsing code
  gc: style change -- no SP before closing parenthesis
  checkout: clean up half-prepared directories in --to mode
  checkout: reject if the branch is already checked out elsewhere
  prune: strategies for linked checkouts
  checkout: support checking out into a new working directory
  ...
This commit is contained in:
Junio C Hamano
2015-05-11 14:23:39 -07:00
52 changed files with 1394 additions and 253 deletions

59
refs.c
View File

@ -1382,7 +1382,7 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
{
int fd, len;
char buffer[128], *p;
char *path;
const char *path;
if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
return -1;
@ -1475,7 +1475,11 @@ static int resolve_missing_loose_ref(const char *refname,
}
/* This function needs to return a meaningful errno on failure */
const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)
static const char *resolve_ref_unsafe_1(const char *refname,
int resolve_flags,
unsigned char *sha1,
int *flags,
struct strbuf *sb_path)
{
int depth = MAXDEPTH;
ssize_t len;
@ -1506,7 +1510,7 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
bad_name = 1;
}
for (;;) {
char path[PATH_MAX];
const char *path;
struct stat st;
char *buf;
int fd;
@ -1516,7 +1520,9 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
return NULL;
}
git_snpath(path, sizeof(path), "%s", refname);
strbuf_reset(sb_path);
strbuf_git_path(sb_path, "%s", refname);
path = sb_path->buf;
/*
* We might have to loop back here to avoid a race
@ -1643,6 +1649,16 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
}
}
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
unsigned char *sha1, int *flags)
{
struct strbuf sb_path = STRBUF_INIT;
const char *ret = resolve_ref_unsafe_1(refname, resolve_flags,
sha1, flags, &sb_path);
strbuf_release(&sb_path);
return ret;
}
char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
{
return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
@ -2274,7 +2290,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
const struct string_list *skip,
unsigned int flags, int *type_p)
{
char *ref_file;
const char *ref_file;
const char *orig_refname = refname;
struct ref_lock *lock;
int last_errno = 0;
@ -2343,7 +2359,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
ref_file = git_path("%s", refname);
retry:
switch (safe_create_leading_directories(ref_file)) {
switch (safe_create_leading_directories_const(ref_file)) {
case SCLD_OK:
break; /* success */
case SCLD_VANISHED:
@ -2721,7 +2737,7 @@ static int rename_tmp_log(const char *newrefname)
int attempts_remaining = 4;
retry:
switch (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) {
case SCLD_OK:
break; /* success */
case SCLD_VANISHED:
@ -2907,11 +2923,15 @@ static int copy_msg(char *buf, const char *msg)
}
/* This function must set a meaningful errno on failure */
int log_ref_setup(const char *refname, char *logfile, int bufsize)
int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
{
int logfd, oflags = O_APPEND | O_WRONLY;
char *logfile;
git_snpath(logfile, bufsize, "logs/%s", refname);
strbuf_git_path(sb_logfile, "logs/%s", refname);
logfile = sb_logfile->buf;
/* make sure the rest of the function can't change "logfile" */
sb_logfile = NULL;
if (log_all_ref_updates &&
(starts_with(refname, "refs/heads/") ||
starts_with(refname, "refs/remotes/") ||
@ -2982,18 +3002,22 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
return 0;
}
static int log_ref_write(const char *refname, const unsigned char *old_sha1,
const unsigned char *new_sha1, const char *msg)
static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
const unsigned char *new_sha1, const char *msg,
struct strbuf *sb_log_file)
{
int logfd, result, oflags = O_APPEND | O_WRONLY;
char log_file[PATH_MAX];
char *log_file;
if (log_all_ref_updates < 0)
log_all_ref_updates = !is_bare_repository();
result = log_ref_setup(refname, log_file, sizeof(log_file));
result = log_ref_setup(refname, sb_log_file);
if (result)
return result;
log_file = sb_log_file->buf;
/* make sure the rest of the function can't change "log_file" */
sb_log_file = NULL;
logfd = open(log_file, oflags);
if (logfd < 0)
@ -3016,6 +3040,15 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
return 0;
}
static int log_ref_write(const char *refname, const unsigned char *old_sha1,
const unsigned char *new_sha1, const char *msg)
{
struct strbuf sb = STRBUF_INIT;
int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
strbuf_release(&sb);
return ret;
}
int is_branch(const char *refname)
{
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");