From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 00/34] nd/multiple-work-trees reroll
Date: Sun, 30 Nov 2014 15:24:25 +0700 [thread overview]
Message-ID: <1417335899-27307-1-git-send-email-pclouds@gmail.com> (raw)
This is rebased so the diff below (against the version on Junio's
repo) is only approximate. Changes include test fixes for Windows
port, $GIT_COMMON_DIR and $GIT_DIR/modules problems with submodules.
Patch 03/34 is rewritten to touch less in refs.c to reduce conflicts.
A lot of changes there are just revert.
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 2b30a92..7173b38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -248,9 +248,7 @@ commondir::
incomplete without the repository pointed by "commondir".
modules::
- Contains the git-repositories of the submodules. This
- directory is ignored if $GIT_COMMON_DIR is set and
- "$GIT_COMMON_DIR/modules" will be used instead.
+ Contains the git-repositories of the submodules.
worktrees::
Contains worktree specific information of linked
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 01d0f2f..e70e66c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,7 +865,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
if (!new->commit)
die(_("no branch specified"));
- if (file_exists(path))
+ if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
len = strlen(path);
@@ -1207,7 +1207,7 @@ static int parse_branchname_arg(int argc, const char **argv,
if (new->path && !force_detach && !*new_branch) {
unsigned char sha1[20];
int flag;
- char *head_ref = resolve_refdup("HEAD", sha1, 0, &flag);
+ char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
if (head_ref &&
(!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
check_linked_checkouts(new);
diff --git a/environment.c b/environment.c
index d5b0788..8351007 100644
--- a/environment.c
+++ b/environment.c
@@ -101,6 +101,7 @@ const char * const local_repo_env[] = {
NO_REPLACE_OBJECTS_ENVIRONMENT,
GIT_PREFIX_ENVIRONMENT,
GIT_SHALLOW_FILE_ENVIRONMENT,
+ GIT_COMMON_DIR_ENVIRONMENT,
NULL
};
diff --git a/path.c b/path.c
index 35d498e..a5c51a3 100644
--- a/path.c
+++ b/path.c
@@ -92,7 +92,7 @@ static void replace_dir(struct strbuf *buf, int len, const char *newdir)
}
static const char *common_list[] = {
- "/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
+ "/branches", "/hooks", "/info", "!/logs", "/lost-found",
"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
"config", "!gc.pid", "packed-refs", "shallow",
NULL
diff --git a/refs.c b/refs.c
index 3cefbd3..f7e48b0 100644
--- a/refs.c
+++ b/refs.c
@@ -1398,14 +1398,16 @@ static const char *handle_missing_loose_ref(const char *refname,
}
/* This function needs to return a meaningful errno on failure */
-const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
+static const char *resolve_ref_unsafe_1(const char *refname,
+ unsigned char *sha1,
+ int reading,
+ int *flags,
+ struct strbuf *sb_path)
{
- struct strbuf sb_path = STRBUF_INIT;
int depth = MAXDEPTH;
ssize_t len;
char buffer[256];
static char refname_buffer[256];
- const char *ret;
if (flag)
*flag = 0;
@@ -1423,12 +1425,12 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
if (--depth < 0) {
errno = ELOOP;
- goto fail;
+ return NULL;
}
- strbuf_reset(&sb_path);
- strbuf_git_path(&sb_path, "%s", refname);
- path = sb_path.buf;
+ 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
@@ -1442,11 +1444,10 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
stat_ref:
if (lstat(path, &st) < 0) {
if (errno == ENOENT)
- ret = handle_missing_loose_ref(refname, sha1,
- reading, flag);
+ return handle_missing_loose_ref(refname, sha1,
+ reading, flag);
else
- ret = NULL;
- goto done;
+ return NULL;
}
/* Follow "normalized" - ie "refs/.." symlinks by hand */
@@ -1457,7 +1458,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
/* inconsistent with lstat; retry */
goto stat_ref;
else
- goto fail;
+ return NULL;
}
buffer[len] = 0;
if (starts_with(buffer, "refs/") &&
@@ -1473,7 +1474,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
/* Is it a directory? */
if (S_ISDIR(st.st_mode)) {
errno = EISDIR;
- goto fail;
+ return NULL;
}
/*
@@ -1486,15 +1487,14 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
/* inconsistent with lstat; retry */
goto stat_ref;
else
- goto fail;
+ return NULL;
}
-
len = read_in_full(fd, buffer, sizeof(buffer)-1);
if (len < 0) {
int save_errno = errno;
close(fd);
errno = save_errno;
- goto fail;
+ return NULL;
}
close(fd);
while (len && isspace(buffer[len-1]))
@@ -1514,10 +1514,9 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
if (flag)
*flag |= REF_ISBROKEN;
errno = EINVAL;
- goto fail;
+ return NULL;
}
- ret = refname;
- goto done;
+ return refname;
}
if (flag)
*flag |= REF_ISSYMREF;
@@ -1528,13 +1527,17 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
if (flag)
*flag |= REF_ISBROKEN;
errno = EINVAL;
- goto fail;
+ return NULL;
}
refname = strcpy(refname_buffer, buf);
}
-fail:
- ret = NULL;
-done:
+}
+
+const char *resolve_ref_unsafe(const char *refname, int reading,
+ unsigned char *sha1, int *flags)
+{
+ struct strbuf sb_path = STRBUF_INIT;
+ const char *ret = resolve_ref_unsafe_1(refname, reading,, sha1, flags, &sb_path);
strbuf_release(&sb_path);
return ret;
}
@@ -2844,62 +2847,66 @@ 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, struct strbuf *logfile)
+int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
{
int logfd, oflags = O_APPEND | O_WRONLY;
+ char *logfile;
- strbuf_git_path(logfile, "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/") ||
starts_with(refname, "refs/notes/") ||
!strcmp(refname, "HEAD"))) {
- if (safe_create_leading_directories(logfile->buf) < 0) {
+ if (safe_create_leading_directories(logfile) < 0) {
int save_errno = errno;
- error("unable to create directory for %s", logfile->buf);
+ error("unable to create directory for %s", logfile);
errno = save_errno;
return -1;
}
oflags |= O_CREAT;
}
- logfd = open(logfile->buf, oflags, 0666);
+ logfd = open(logfile, oflags, 0666);
if (logfd < 0) {
if (!(oflags & O_CREAT) && errno == ENOENT)
return 0;
if ((oflags & O_CREAT) && errno == EISDIR) {
- if (remove_empty_directories(logfile->buf)) {
+ if (remove_empty_directories(logfile)) {
int save_errno = errno;
error("There are still logs under '%s'",
- logfile->buf);
+ logfile);
errno = save_errno;
return -1;
}
- logfd = open(logfile->buf, oflags, 0666);
+ logfd = open(logfile, oflags, 0666);
}
if (logfd < 0) {
int save_errno = errno;
- error("Unable to append to %s: %s", logfile->buf,
+ error("Unable to append to %s: %s", logfile,
strerror(errno));
errno = save_errno;
return -1;
}
}
- adjust_shared_perm(logfile->buf);
+ adjust_shared_perm(logfile);
close(logfd);
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, written, oflags = O_APPEND | O_WRONLY;
unsigned maxlen, len;
int msglen;
- struct strbuf sb_log_file = STRBUF_INIT;
const char *log_file;
char *logrec;
const char *committer;
@@ -2907,14 +2914,16 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
if (log_all_ref_updates < 0)
log_all_ref_updates = !is_bare_repository();
- result = log_ref_setup(refname, &sb_log_file);
+ result = log_ref_setup(refname, sb_log_file);
if (result)
- goto done;
- log_file = sb_log_file.buf;
+ 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)
- goto done;
+ return 0;
msglen = msg ? strlen(msg) : 0;
committer = git_committer_info(0);
maxlen = strlen(committer) + msglen + 100;
@@ -2932,19 +2941,24 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
close(logfd);
error("Unable to append to %s", log_file);
errno = save_errno;
- result = -1;
- goto done;
+ return -1;
}
if (close(logfd)) {
int save_errno = errno;
error("Unable to append to %s", log_file);
errno = save_errno;
- result = -1;
- goto done;
+ return -1;
}
-done:
- strbuf_release(&sb_log_file);
- return result;
+ 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)
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e6ac7a4..4df7a2f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -366,7 +366,7 @@ test_expect_success 'GIT_DIR set (1)' '
test_expect_success 'GIT_DIR set (2)' '
echo "gitdir: repo.git/repos/foo" >gitfile &&
- echo "$TRASH_DIRECTORY/repo.git" >repo.git/repos/foo/commondir &&
+ echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
(
cd work &&
GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index eddd325..915b506 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -13,10 +13,15 @@ test_expect_success 'checkout --to not updating paths' '
'
test_expect_success 'checkout --to an existing worktree' '
- mkdir existing &&
+ mkdir -p existing/subtree &&
test_must_fail git checkout --detach --to existing master
'
+test_expect_success 'checkout --to an existing empty worktree' '
+ mkdir existing_empty &&
+ git checkout --detach --to existing_empty master
+'
+
test_expect_success 'checkout --to refuses to checkout locked branch' '
test_must_fail git checkout --to zere master &&
! test -d zere &&
diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh
index 3622800..170aefe 100755
--- a/t/t2026-prune-linked-checkouts.sh
+++ b/t/t2026-prune-linked-checkouts.sh
@@ -57,7 +57,7 @@ test_expect_success 'prune directories with invalid gitdir' '
test_expect_success 'prune directories with gitdir pointing to nowhere' '
mkdir -p .git/worktrees/def/abc &&
: >.git/worktrees/def/def &&
- echo "$TRASH_DIRECTORY"/nowhere >.git/worktrees/def/gitdir &&
+ echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir &&
git prune --worktrees --verbose >actual &&
test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual &&
! test -d .git/worktrees/def &&
@@ -76,7 +76,7 @@ test_expect_success 'not prune recent checkouts' '
test_when_finished rm -r .git/worktrees
mkdir zz &&
mkdir -p .git/worktrees/jlm &&
- echo "$TRASH_DIRECTORY"/zz >.git/worktrees/jlm/gitdir &&
+ echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir &&
git prune --worktrees --verbose --expire=2.days.ago &&
test -d .git/worktrees/jlm
'
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
new file mode 100755
index 0000000..8f30aed
--- /dev/null
+++ b/t/t7410-submodule-checkout-to.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Combination of submodules and multiple workdirs'
+
+. ./test-lib.sh
+
+base_path=$(pwd -P)
+
+test_expect_success 'setup: make origin' \
+ 'mkdir -p origin/sub && ( cd origin/sub && git init &&
+ echo file1 >file1 &&
+ git add file1 &&
+ git commit -m file1 ) &&
+ mkdir -p origin/main && ( cd origin/main && git init &&
+ git submodule add ../sub &&
+ git commit -m "add sub" ) &&
+ ( cd origin/sub &&
+ echo file1updated >file1 &&
+ git add file1 &&
+ git commit -m "file1 updated" ) &&
+ ( cd origin/main/sub && git pull ) &&
+ ( cd origin/main &&
+ git add sub &&
+ git commit -m "sub updated" )'
+
+test_expect_success 'setup: clone' \
+ 'mkdir clone && ( cd clone &&
+ git clone --recursive "$base_path/origin/main")'
+
+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1")
+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1")
+
+test_expect_success 'checkout main' \
+ 'mkdir default_checkout &&
+ (cd clone/main &&
+ git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")'
+
+test_expect_failure 'can see submodule diffs just after checkout' \
+ '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")'
+
+test_expect_success 'checkout main and initialize independed clones' \
+ 'mkdir fully_cloned_submodule &&
+ (cd clone/main &&
+ git checkout --to "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") &&
+ (cd fully_cloned_submodule/main && git submodule update)'
+
+test_expect_success 'can see submodule diffs after independed cloning' \
+ '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")'
+
+test_done
next reply other threads:[~2014-11-30 8:25 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-30 8:24 Nguyễn Thái Ngọc Duy [this message]
2014-11-30 8:24 ` [PATCH 01/34] path.c: make get_pathname() return strbuf instead of static buffer Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 02/34] path.c: make get_pathname() call sites return const char * Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 03/34] git_snpath(): retire and replace with strbuf_git_path() Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 04/34] path.c: rename vsnpath() to do_git_path() Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 05/34] path.c: group git_path(), git_pathdup() and strbuf_git_path() together Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 06/34] git_path(): be aware of file relocation in $GIT_DIR Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 07/34] *.sh: respect $GIT_INDEX_FILE Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 08/34] reflog: avoid constructing .lock path with git_path Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 09/34] fast-import: use git_path() for accessing .git dir instead of get_git_dir() Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 10/34] commit: use SEQ_DIR instead of hardcoding "sequencer" Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 11/34] $GIT_COMMON_DIR: a new environment variable Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 12/34] git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objects Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 13/34] *.sh: avoid hardcoding $GIT_DIR/hooks/ Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 14/34] git-stash: avoid hardcoding $GIT_DIR/logs/ Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 15/34] setup.c: convert is_git_directory() to use strbuf Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 16/34] setup.c: detect $GIT_COMMON_DIR in is_git_directory() Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 17/34] setup.c: convert check_repository_format_gently to use strbuf Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 18/34] setup.c: detect $GIT_COMMON_DIR check_repository_format_gently() Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 19/34] setup.c: support multi-checkout repo setup Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 20/34] wrapper.c: wrapper to open a file, fprintf then close Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 21/34] use new wrapper write_file() for simple file writing Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 22/34] checkout: support checking out into a new working directory Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 23/34] prune: strategies for linked checkouts Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 24/34] checkout: reject if the branch is already checked out elsewhere Nguyễn Thái Ngọc Duy
2014-11-30 17:18 ` Mark Levedahl
2014-12-01 10:38 ` Duy Nguyen
2014-12-01 17:39 ` Junio C Hamano
2014-12-02 5:04 ` Mark Levedahl
2014-12-02 12:01 ` Duy Nguyen
2014-12-02 17:30 ` Junio C Hamano
2014-12-03 11:30 ` Mark Levedahl
2014-12-03 12:50 ` Duy Nguyen
2014-12-03 15:54 ` Junio C Hamano
2014-12-02 11:50 ` Duy Nguyen
2014-11-30 8:24 ` [PATCH 25/34] checkout: clean up half-prepared directories in --to mode Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 26/34] gc: style change -- no SP before closing parenthesis Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 27/34] gc: factor out gc.pruneexpire parsing code Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 28/34] gc: support prune --worktrees Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 29/34] count-objects: report unused files in $GIT_DIR/worktrees/ Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 30/34] git_path(): keep "info/sparse-checkout" per work-tree Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 31/34] checkout: don't require a work tree when checking out into a new one Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 32/34] t2025: add a test to make sure grafts is working from a linked checkout Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 33/34] checkout: do not fail if target is an empty directory Nguyễn Thái Ngọc Duy
2014-11-30 8:24 ` [PATCH 34/34] git-common-dir: make "modules/" per-working-directory directory Nguyễn Thái Ngọc Duy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1417335899-27307-1-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).