* [PATCH] git-p4: Fix error message crash in P4Sync.commit.
From: Tor Arvid Lund @ 2011-02-08 12:20 UTC (permalink / raw)
To: git; +Cc: Tor Arvid Lund
There is an error message that crashes the script because of an invalid ref
to the non-existing "path" variable. It is almost never printed, which
would explain why nobody encountered this problem before... But anyway,
this oneliner fixes it.
---
contrib/fast-import/git-p4 | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index ca3cea0..29b9e32 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -1086,7 +1086,7 @@ class P4Sync(Command):
if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
new_files.append (f)
else:
- sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
+ sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
self.gitStream.write("commit %s\n" % branch)
# gitStream.write("mark :%s\n" % details["change"])
--
1.7.3.1.68.g06779.dirty
^ permalink raw reply related
* [PATCH] Teach git-p4 to ignore case in perforce filenames if configured.
From: Tor Arvid Lund @ 2011-02-08 11:11 UTC (permalink / raw)
To: git; +Cc: Tor Arvid Lund
When files are added to perforce, the path to that file has whichever case
configuration that exists on the machine of the user who added the file.
What does that mean? It means that when Alice adds a file
//depot/DirA/FileA.txt
... and Bob adds:
//depot/dirA/FileB.txt
... we may or may not get a problem. If a user sets the config variable
git-p4.ignorecase to "true", we will consider //depot/DirA and //depot/dirA
to be the same directory.
---
contrib/fast-import/git-p4 | 22 ++++++++++++++--------
contrib/fast-import/git-p4.txt | 12 ++++++++++++
2 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 04ce7e3..ca3cea0 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -452,6 +452,12 @@ def p4ChangesForPaths(depotPaths, changeRange):
changelist.sort()
return changelist
+def p4PathStartsWith(path, prefix):
+ ignorecase = gitConfig("git-p4.ignorecase").lower()
+ if ignorecase in ["true", "yes", "1"]:
+ return path.lower().startswith(prefix.lower())
+ return path.startswith(prefix)
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
@@ -599,7 +605,7 @@ class P4Submit(Command):
lastTab = path.rfind("\t")
if lastTab != -1:
path = path[:lastTab]
- if not path.startswith(self.depotPath):
+ if not p4PathStartsWith(path, self.depotPath):
continue
else:
inFilesSection = False
@@ -891,11 +897,11 @@ class P4Sync(Command):
path = commit["depotFile%s" % fnum]
if [p for p in self.cloneExclude
- if path.startswith (p)]:
+ if p4PathStartsWith(path, p)]:
found = False
else:
found = [p for p in self.depotPaths
- if path.startswith (p)]
+ if p4PathStartsWith(path, p)]
if not found:
fnum = fnum + 1
continue
@@ -914,7 +920,7 @@ class P4Sync(Command):
prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
for p in prefixes:
- if path.startswith(p):
+ if p4PathStartsWith(path, p):
path = path[len(p):]
return path
@@ -925,7 +931,7 @@ class P4Sync(Command):
while commit.has_key("depotFile%s" % fnum):
path = commit["depotFile%s" % fnum]
found = [p for p in self.depotPaths
- if path.startswith (p)]
+ if p4PathStartsWith(path, p)]
if not found:
fnum = fnum + 1
continue
@@ -1031,7 +1037,7 @@ class P4Sync(Command):
for f in files:
includeFile = True
for val in self.clientSpecDirs:
- if f['path'].startswith(val[0]):
+ if p4PathStartsWith(f['path'], val[0]):
if val[1] <= 0:
includeFile = False
break
@@ -1077,7 +1083,7 @@ class P4Sync(Command):
# create a commit.
new_files = []
for f in files:
- if [p for p in branchPrefixes if f['path'].startswith(p)]:
+ if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
new_files.append (f)
else:
sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
@@ -1241,7 +1247,7 @@ class P4Sync(Command):
source = paths[0]
destination = paths[1]
## HACK
- if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
+ if p4PathStartsWith(source, self.depotPaths[0]) and p4PathStartsWith(destination, self.depotPaths[0]):
source = source[len(self.depotPaths[0]):-4]
destination = destination[len(self.depotPaths[0]):-4]
diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt
index 49b3359..bf7904a 100644
--- a/contrib/fast-import/git-p4.txt
+++ b/contrib/fast-import/git-p4.txt
@@ -191,6 +191,18 @@ git-p4.useclientspec
git config [--global] git-p4.useclientspec false
+git-p4.ignorecase
+
+If this variable is set to 'true' (or 'yes' or '1'), perforce paths like:
+
+//depot/Path/
+//depot/path/
+//dePoT/PATH/
+
+will all be considered to be the same directory.
+
+ git config [--global] git-p4.ignorecase false
+
Implementation Details...
=========================
--
1.7.3.1.68.g06779.dirty
^ permalink raw reply related
* Re: [PATCH] cache-tree: do not cache empty trees
From: Ilari Liusvaara @ 2011-02-08 10:40 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy
Cc: Junio C Hamano, Jonathan Nieder, git, Jakub Narebski,
Dmitry S. Kravtsov, Shawn Pearce
In-Reply-To: <AANLkTim_G9cPs=+1GQ2qBEgriOyKYgXk17iHE4oq9h2C@mail.gmail.com>
On Tue, Feb 08, 2011 at 11:11:19AM +0700, Nguyen Thai Ngoc Duy wrote:
> On Tue, Feb 8, 2011 at 3:48 AM, Junio C Hamano <gitster@pobox.com> wrote:
> bug regardless directory tracking support in 1.8.0. A corner case that
> nobody would likely encounter (except Ilari and his "ghost directory"
> problem).
Except it wasn't me who directly saw those problems. It was somebody else
on #git (back when I was there). That was a while ago. That's the reason
I don't exactly remember what exactly it did (possibly false modifications
causing some commands (merge/rebase) to abort?).
Hmm. I should test what exactly happens (including with older git versions
to see if those problems have (possibly unintentionally) got fixed).
-Ilari
^ permalink raw reply
* [PATCH 3/3] checkout: rearrange update_refs_for_switch for clarity
From: Jonathan Nieder @ 2011-02-08 10:34 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, Martin von Zweigbergk, git
In-Reply-To: <20110208102605.GA29660@elie>
Take care of simple, exceptional cases before the meat of the "check
out by branch name" code begins. After this change, the function
vaguely follows the following pseudocode:
if (-B or -b)
create branch;
if (plain "git checkout" or "git checkout HEAD")
;
else if (--detach or checking out by non-branch commit name)
detach HEAD;
else if (checking out by branch name)
attach HEAD;
One nice side benefit is to make it possible to remove handling of
the --detach option from outside switch_branches.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
That's the end of the series. Thoughts welcome, as always.
'night,
Jonathan
builtin/checkout.c | 27 +++++++++++++--------------
1 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 51ec977..179d047 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -542,7 +542,17 @@ static void update_refs_for_switch(struct checkout_opts *opts,
strbuf_addf(&msg, "checkout: moving from %s to %s",
old_desc ? old_desc : "(invalid)", new->name);
- if (new->path) {
+ if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
+ /* Nothing to do. */
+ } else if (opts->force_detach || !new->path) { /* No longer on any branch. */
+ update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
+ REF_NODEREF, DIE_ON_ERR);
+ if (!opts->quiet) {
+ if (old->path && advice_detached_head)
+ detach_advice(old->path, new->name);
+ describe_detached_head("HEAD is now at", new->commit);
+ }
+ } else if (new->path) { /* Switch branches. */
create_symref("HEAD", new->path, msg.buf);
if (!opts->quiet) {
if (old->path && !strcmp(new->path, old->path))
@@ -564,14 +574,6 @@ static void update_refs_for_switch(struct checkout_opts *opts,
if (!file_exists(ref_file) && file_exists(log_file))
remove_path(log_file);
}
- } else if (opts->force_detach || strcmp(new->name, "HEAD")) {
- update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
- REF_NODEREF, DIE_ON_ERR);
- if (!opts->quiet) {
- if (old->path && advice_detached_head)
- detach_advice(old->path, new->name);
- describe_detached_head("HEAD is now at", new->commit);
- }
}
remove_branch_state();
strbuf_release(&msg);
@@ -679,7 +681,6 @@ static const char *unique_tracking_name(const char *name)
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
- int force_detach,
struct branch_info *new,
struct tree **source_tree,
unsigned char rev[20],
@@ -756,8 +757,7 @@ static int parse_branchname_arg(int argc, const char **argv,
new->name = arg;
setup_branch_path(new);
- if (!force_detach &&
- check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
+ if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
resolve_ref(new->path, branch_rev, 1, NULL))
hashcpy(rev, branch_rev);
else
@@ -906,8 +906,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
dwim_new_local_branch &&
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
- int n = parse_branchname_arg(argc, argv,
- dwim_ok, opts.force_detach,
+ int n = parse_branchname_arg(argc, argv, dwim_ok,
&new, &source_tree, rev, &opts.new_branch);
argv += n;
argc -= n;
--
1.7.4
^ permalink raw reply related
* [PATCH 2/3] checkout: introduce --detach synonym for "git checkout foo^{commit}"
From: Jonathan Nieder @ 2011-02-08 10:32 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, Martin von Zweigbergk, git
In-Reply-To: <20110208102605.GA29660@elie>
From: Junio C Hamano <gitster@pobox.com>
For example, one might use this when making a temporary merge to
test that two topics work well together.
Patch by Junio, with tests from Jeff King.
[jn: with some extra checks for bogus commandline usage]
Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Documentation/git-checkout.txt | 13 +++++-
builtin/checkout.c | 25 ++++++++--
t/t2020-checkout-detach.sh | 95 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 126 insertions(+), 7 deletions(-)
create mode 100755 t/t2020-checkout-detach.sh
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 22d3611..d162117 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -9,6 +9,7 @@ SYNOPSIS
--------
[verse]
'git checkout' [-q] [-f] [-m] [<branch>]
+'git checkout' [-q] [-f] [-m] [--detach] [<commit>]
'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
'git checkout' --patch [<tree-ish>] [--] [<paths>...]
@@ -22,9 +23,10 @@ branch.
'git checkout' [<branch>]::
'git checkout' -b|-B <new_branch> [<start point>]::
+'git checkout' [--detach] [<commit>]::
This form switches branches by updating the index, working
- tree, and HEAD to reflect the specified branch.
+ tree, and HEAD to reflect the specified branch or commit.
+
If `-b` is given, a new branch is created as if linkgit:git-branch[1]
were called and then checked out; in this case you can
@@ -115,6 +117,13 @@ explicitly give a name with '-b' in such a case.
Create the new branch's reflog; see linkgit:git-branch[1] for
details.
+--detach::
+ Rather than checking out a branch to work on it, check out a
+ commit for inspection and discardable experiments.
+ This is the default behavior of "git checkout <commit>" when
+ <commit> is not a branch name. See the "DETACHED HEAD" section
+ below for details.
+
--orphan::
Create a new 'orphan' branch, named <new_branch>, started from
<start_point> and switch to it. The first commit made on this
@@ -204,7 +213,7 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
-Detached HEAD
+DETACHED HEAD
-------------
It is sometimes useful to be able to 'checkout' a commit that is
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0e7a6a3..51ec977 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -30,6 +30,7 @@ struct checkout_opts {
int quiet;
int merge;
int force;
+ int force_detach;
int writeout_stage;
int writeout_error;
@@ -563,7 +564,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
if (!file_exists(ref_file) && file_exists(log_file))
remove_path(log_file);
}
- } else if (strcmp(new->name, "HEAD")) {
+ } else if (opts->force_detach || strcmp(new->name, "HEAD")) {
update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
REF_NODEREF, DIE_ON_ERR);
if (!opts->quiet) {
@@ -574,7 +575,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
}
remove_branch_state();
strbuf_release(&msg);
- if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
+ if (!opts->quiet &&
+ (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
report_tracking(new);
}
@@ -677,6 +679,7 @@ static const char *unique_tracking_name(const char *name)
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
+ int force_detach,
struct branch_info *new,
struct tree **source_tree,
unsigned char rev[20],
@@ -753,7 +756,8 @@ static int parse_branchname_arg(int argc, const char **argv,
new->name = arg;
setup_branch_path(new);
- if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
+ if (!force_detach &&
+ check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
resolve_ref(new->path, branch_rev, 1, NULL))
hashcpy(rev, branch_rev);
else
@@ -804,6 +808,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
"create/reset and checkout a branch"),
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
+ OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch",
BRANCH_TRACK_EXPLICIT),
OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
@@ -842,9 +847,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.new_branch = opts.new_branch_force;
if (patch_mode && (opts.track > 0 || opts.new_branch
- || opts.new_branch_log || opts.merge || opts.force))
+ || opts.new_branch_log || opts.merge || opts.force
+ || opts.force_detach))
die ("--patch is incompatible with all other options");
+ if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
+ die("--detach cannot be used with -b/-B/--orphan");
+ if (opts.force_detach && 0 < opts.track)
+ die("--detach cannot be used with -t");
+
/* --track without -b should DWIM */
if (0 < opts.track && !opts.new_branch) {
const char *argv0 = argv[0];
@@ -895,7 +906,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
dwim_new_local_branch &&
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
- int n = parse_branchname_arg(argc, argv, dwim_ok,
+ int n = parse_branchname_arg(argc, argv,
+ dwim_ok, opts.force_detach,
&new, &source_tree, rev, &opts.new_branch);
argv += n;
argc -= n;
@@ -922,6 +934,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
}
+ if (opts.force_detach)
+ die("git checkout: --detach does not take a path argument");
+
if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.");
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
new file mode 100755
index 0000000..0042145
--- /dev/null
+++ b/t/t2020-checkout-detach.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='checkout into detached HEAD state'
+. ./test-lib.sh
+
+check_detached () {
+ test_must_fail git symbolic-ref -q HEAD >/dev/null
+}
+
+check_not_detached () {
+ git symbolic-ref -q HEAD >/dev/null
+}
+
+reset () {
+ git checkout master &&
+ check_not_detached
+}
+
+test_expect_success 'setup' '
+ test_commit one &&
+ test_commit two &&
+ git branch branch &&
+ git tag tag
+'
+
+test_expect_success 'checkout branch does not detach' '
+ reset &&
+ git checkout branch &&
+ check_not_detached
+'
+
+test_expect_success 'checkout tag detaches' '
+ reset &&
+ git checkout tag &&
+ check_detached
+'
+
+test_expect_success 'checkout branch by full name detaches' '
+ reset &&
+ git checkout refs/heads/branch &&
+ check_detached
+'
+
+test_expect_success 'checkout non-ref detaches' '
+ reset &&
+ git checkout branch^ &&
+ check_detached
+'
+
+test_expect_success 'checkout ref^0 detaches' '
+ reset &&
+ git checkout branch^0 &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach detaches' '
+ reset &&
+ git checkout --detach branch &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach without branch name' '
+ reset &&
+ git checkout --detach &&
+ check_detached
+'
+
+test_expect_success 'checkout --detach errors out for non-commit' '
+ reset &&
+ test_must_fail git checkout --detach one^{tree} &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detach errors out for extra argument' '
+ reset &&
+ git checkout master &&
+ test_must_fail git checkout --detach tag one.t &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detached and -b are incompatible' '
+ reset &&
+ test_must_fail git checkout --detach -b newbranch tag &&
+ check_not_detached
+'
+
+test_expect_success 'checkout --detach moves HEAD' '
+ reset &&
+ git checkout one &&
+ git checkout --detach two &&
+ git diff --exit-code HEAD &&
+ git diff --exit-code two
+'
+
+test_done
--
1.7.4
^ permalink raw reply related
* [PATCH 1/3] checkout: split off a function to peel away branchname arg
From: Jonathan Nieder @ 2011-02-08 10:29 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, Martin von Zweigbergk, git
In-Reply-To: <20110208102605.GA29660@elie>
The code to parse and consume the tree name and "--" in commands such
as "git checkout @{-1} -- '*.c'" is intimidatingly long. Split it out
into a separate function and make it easier to skip on first reading
by making the data it uses and produces more explicit.
No functional change intended.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Just some code movement.
builtin/checkout.c | 229 ++++++++++++++++++++++++++++++----------------------
1 files changed, 131 insertions(+), 98 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 953abdd..0e7a6a3 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -675,11 +675,123 @@ static const char *unique_tracking_name(const char *name)
return NULL;
}
+static int parse_branchname_arg(int argc, const char **argv,
+ int dwim_new_local_branch_ok,
+ struct branch_info *new,
+ struct tree **source_tree,
+ unsigned char rev[20],
+ const char **new_branch)
+{
+ int argcount = 0;
+ unsigned char branch_rev[20];
+ const char *arg;
+ int has_dash_dash;
+
+ /*
+ * case 1: git checkout <ref> -- [<paths>]
+ *
+ * <ref> must be a valid tree, everything after the '--' must be
+ * a path.
+ *
+ * case 2: git checkout -- [<paths>]
+ *
+ * everything after the '--' must be paths.
+ *
+ * case 3: git checkout <something> [<paths>]
+ *
+ * With no paths, if <something> is a commit, that is to
+ * switch to the branch or detach HEAD at it. As a special case,
+ * if <something> is A...B (missing A or B means HEAD but you can
+ * omit at most one side), and if there is a unique merge base
+ * between A and B, A...B names that merge base.
+ *
+ * With no paths, if <something> is _not_ a commit, no -t nor -b
+ * was given, and there is a tracking branch whose name is
+ * <something> in one and only one remote, then this is a short-hand
+ * to fork local <something> from that remote tracking branch.
+ *
+ * Otherwise <something> shall not be ambiguous.
+ * - If it's *only* a reference, treat it like case (1).
+ * - If it's only a path, treat it like case (2).
+ * - else: fail.
+ *
+ */
+ if (!argc)
+ return 0;
+
+ if (!strcmp(argv[0], "--")) /* case (2) */
+ return 1;
+
+ arg = argv[0];
+ has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
+
+ if (!strcmp(arg, "-"))
+ arg = "@{-1}";
+
+ if (get_sha1_mb(arg, rev)) {
+ if (has_dash_dash) /* case (1) */
+ die("invalid reference: %s", arg);
+ if (dwim_new_local_branch_ok &&
+ !check_filename(NULL, arg) &&
+ argc == 1) {
+ const char *remote = unique_tracking_name(arg);
+ if (!remote || get_sha1(remote, rev))
+ return argcount;
+ *new_branch = arg;
+ arg = remote;
+ /* DWIMmed to create local branch */
+ } else {
+ return argcount;
+ }
+ }
+
+ /* we can't end up being in (2) anymore, eat the argument */
+ argcount++;
+ argv++;
+ argc--;
+
+ new->name = arg;
+ setup_branch_path(new);
+
+ if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
+ resolve_ref(new->path, branch_rev, 1, NULL))
+ hashcpy(rev, branch_rev);
+ else
+ new->path = NULL; /* not an existing branch */
+
+ new->commit = lookup_commit_reference_gently(rev, 1);
+ if (!new->commit) {
+ /* not a commit */
+ *source_tree = parse_tree_indirect(rev);
+ } else {
+ parse_commit(new->commit);
+ *source_tree = new->commit->tree;
+ }
+
+ if (!*source_tree) /* case (1): want a tree */
+ die("reference is not a tree: %s", arg);
+ if (!has_dash_dash) {/* case (3 -> 1) */
+ /*
+ * Do not complain the most common case
+ * git checkout branch
+ * even if there happen to be a file called 'branch';
+ * it would be extremely annoying.
+ */
+ if (argc)
+ verify_non_filename(NULL, arg);
+ } else {
+ argcount++;
+ argv++;
+ argc--;
+ }
+
+ return argcount;
+}
+
int cmd_checkout(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
- unsigned char rev[20], branch_rev[20];
- const char *arg;
+ unsigned char rev[20];
struct branch_info new;
struct tree *source_tree = NULL;
char *conflict_style = NULL;
@@ -709,7 +821,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END(),
};
- int has_dash_dash;
memset(&opts, 0, sizeof(opts));
memset(&new, 0, sizeof(new));
@@ -766,108 +877,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
die("git checkout: -f and -m are incompatible");
/*
- * case 1: git checkout <ref> -- [<paths>]
- *
- * <ref> must be a valid tree, everything after the '--' must be
- * a path.
- *
- * case 2: git checkout -- [<paths>]
- *
- * everything after the '--' must be paths.
- *
- * case 3: git checkout <something> [<paths>]
- *
- * With no paths, if <something> is a commit, that is to
- * switch to the branch or detach HEAD at it. As a special case,
- * if <something> is A...B (missing A or B means HEAD but you can
- * omit at most one side), and if there is a unique merge base
- * between A and B, A...B names that merge base.
- *
- * With no paths, if <something> is _not_ a commit, no -t nor -b
- * was given, and there is a tracking branch whose name is
- * <something> in one and only one remote, then this is a short-hand
- * to fork local <something> from that remote tracking branch.
- *
- * Otherwise <something> shall not be ambiguous.
- * - If it's *only* a reference, treat it like case (1).
- * - If it's only a path, treat it like case (2).
- * - else: fail.
- *
+ * Extract branch name from command line arguments, so
+ * all that is left is pathspecs.
+ *
+ * Handle
+ *
+ * 1) git checkout <tree> -- [<paths>]
+ * 2) git checkout -- [<paths>]
+ * 3) git checkout <something> [<paths>]
+ *
+ * including "last branch" syntax and DWIM-ery for names of
+ * remote branches, erroring out for invalid or ambiguous cases.
*/
if (argc) {
- if (!strcmp(argv[0], "--")) { /* case (2) */
- argv++;
- argc--;
- goto no_reference;
- }
-
- arg = argv[0];
- has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
-
- if (!strcmp(arg, "-"))
- arg = "@{-1}";
-
- if (get_sha1_mb(arg, rev)) {
- if (has_dash_dash) /* case (1) */
- die("invalid reference: %s", arg);
- if (!patch_mode &&
- dwim_new_local_branch &&
- opts.track == BRANCH_TRACK_UNSPECIFIED &&
- !opts.new_branch &&
- !check_filename(NULL, arg) &&
- argc == 1) {
- const char *remote = unique_tracking_name(arg);
- if (!remote || get_sha1(remote, rev))
- goto no_reference;
- opts.new_branch = arg;
- arg = remote;
- /* DWIMmed to create local branch */
- }
- else
- goto no_reference;
- }
-
- /* we can't end up being in (2) anymore, eat the argument */
- argv++;
- argc--;
-
- new.name = arg;
- setup_branch_path(&new);
-
- if (check_ref_format(new.path) == CHECK_REF_FORMAT_OK &&
- resolve_ref(new.path, branch_rev, 1, NULL))
- hashcpy(rev, branch_rev);
- else
- new.path = NULL; /* not an existing branch */
-
- if (!(new.commit = lookup_commit_reference_gently(rev, 1))) {
- /* not a commit */
- source_tree = parse_tree_indirect(rev);
- } else {
- parse_commit(new.commit);
- source_tree = new.commit->tree;
- }
-
- if (!source_tree) /* case (1): want a tree */
- die("reference is not a tree: %s", arg);
- if (!has_dash_dash) {/* case (3 -> 1) */
- /*
- * Do not complain the most common case
- * git checkout branch
- * even if there happen to be a file called 'branch';
- * it would be extremely annoying.
- */
- if (argc)
- verify_non_filename(NULL, arg);
- }
- else {
- argv++;
- argc--;
- }
+ int dwim_ok =
+ !patch_mode &&
+ dwim_new_local_branch &&
+ opts.track == BRANCH_TRACK_UNSPECIFIED &&
+ !opts.new_branch;
+ int n = parse_branchname_arg(argc, argv, dwim_ok,
+ &new, &source_tree, rev, &opts.new_branch);
+ argv += n;
+ argc -= n;
}
-no_reference:
-
if (opts.track == BRANCH_TRACK_UNSPECIFIED)
opts.track = git_branch_track;
--
1.7.4
^ permalink raw reply related
* [PATCH v2 0/3] checkout: introduce --detach synonym for "git checkout foo^{commit}"
From: Jonathan Nieder @ 2011-02-08 10:26 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, Martin von Zweigbergk, git
In-Reply-To: <20110208005238.GB24340@elie>
Jonathan Nieder wrote:
> Two of the new tests fail. :)
... and here's a reroll fixing them. Applies on top of the old
uk/checkout-ambiguous-ref (0cb6ad3, 2011-01-11).
Patch 1 is an irrelevant cleanup, for while I have your eyes on this
code. :)
Patch 2 introduces the --detach option, taking care to error out in
special cases.
Patch 3 is another cleanup, to make the effect of patch 2 more clear.
Thanks again for your help.
Jonathan Nieder (2):
checkout: split off a function to peel away branchname arg
checkout: rearrange update_refs_for_switch for clarity
Junio C Hamano (1):
checkout: introduce --detach synonym for "git checkout foo^{commit}"
Documentation/git-checkout.txt | 13 ++-
builtin/checkout.c | 265 +++++++++++++++++++++++----------------
t/t2020-checkout-detach.sh | 95 ++++++++++++++
3 files changed, 262 insertions(+), 111 deletions(-)
create mode 100755 t/t2020-checkout-detach.sh
^ permalink raw reply
* Re: "git add -u" broken in git 1.7.4?
From: SZEDER Gábor @ 2011-02-08 10:05 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Matthieu Moy, Sebastian Pipping, Git ML
In-Reply-To: <20110207195035.GA13461@sigill.intra.peff.net>
On Mon, Feb 07, 2011 at 02:50:35PM -0500, Jeff King wrote:
> On Sun, Feb 06, 2011 at 10:46:20PM -0800, Junio C Hamano wrote:
>
> > I actually do not mind too much myself if all commands that can take
> > pathspecs consistently defaulted to "full-tree" pathspec given no
> > pathspec. But if we were to go that route, everybody should join their
> > voice to defend that decision when outside people say "in 1.8.0 'git grep'
> > run from a subdirectory shows matches from all the irrelevant parts of the
> > tree; with all the cruft its output is unreadable". I won't be the sole
> > champion of such a behaviour when I do not fully believe in it.
>
> The problem is that I don't feel comfortable writing an RFC that says
> "in 1.8.0 we will default to full-tree because it is somehow better".
> Because I don't think it is better; it is simply a different way of
> thinking about it, and different people will have different preferences.
>
> I think even the same people may different preferences from project to
> project. For most of my projects, the scope of the repo is well-defined,
> and I want full-tree semantics (e.g., I hack on a bug, go into t/ to
> tweak and run the tests, and then want to "git add -u" the whole thing
> when everything looks good). But I also recently worked on a gigantic
> project that was split into several sub-components. I would cd 3 or 4
> levels deep into the sub-component that I was working on, and I would
> prefer my "git add -u" to stay in that sub-component, and my "git grep"
> to look only in that sub-component.
It sounds like your work focused solely on the sub-component you cd-d
into. Did you have any other changes outside of that sub-component?
Because when not, then both the current and the whole-tree "git add -u"
would have the same effect.
The current and the whole-tree "git grep" would behave differently, of
course. But even then a whole-tree "git grep" would be harmless and
easy to limit in scope, though might be a bit annoying in the "cd deep
down" case. In that case you would immediately see the matches
outside of cwd, know that you forgot to limit the operation to cwd, so
you hit the up key, simply append the "." to the last command, and you
get what you wanted.
As mentioned in this or other related threads, this is not at all that
simple the other way around, i.e. with current "git grep" when you are
in the sub-component and you happen to need a grep on the whole tree,
because you have to pay attention to use the right number of "../"s.
A whole-tree "git add -u" is just as easy to limit in scope as the
whole-tree "git grep" would be, but certainly more annoying when you
forget to limit it to cwd. But even in that case there is no harm
done, because all the changes you've made are there, but you have to
unstage changes from the index or split the commit.
Current "git add -u" is worst of all, because it's not just difficult
to circumvent (how many "../" do I need?), but it's downright
dangerous, because you can lose changes when forget that it's limited
in scope. I managed to do something like this while fixing two
already bisected bugs:
git checkout deadbeef # BugA was introduced in that commit
vim git.c # fix BugA
cd t
test ; vim test ; test
git add -u # again forgetting that a
# fundamentally whole-tree oriented
# tool has operations with
# non-whole-tree defaults...
git commit -m 'Fix BugA' # will write proper commit msg later
git branch fix_BugA # to find the commit later
git reset --hard babefeed # instead of "git checkout babefeed"
# BugB was introduced there
# goodbye bugfix!
# hack away to fix BugB # until realisation sets in
# Damn.
You could argue that there are several ways I could have prevented
shooting myself in the foot, e.g. using "git checkout" instead of "git
reset --hard", or by using plain "git commit" without the "-m" option
I might have noticed the unstaged changes in the commit template. I
would even tend to agree, but I still think that git should be
consistent with _itself_ in the first place, and since git's
fundamental concepts are whole-tree oriented and there are many
commands that only make sense on the whole tree, defaulting to
whole-tree operations for commands taking a pathspec is indeed better.
And safer too.
Best,
Gábor
^ permalink raw reply
* Re: [PATCH 8/8] git-p4: support clone --bare
From: Tor Arvid Lund @ 2011-02-08 9:18 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110205225247.GI30963@arf.padd.com>
On Sat, Feb 5, 2011 at 11:52 PM, Pete Wyckoff <pw@padd.com> wrote:
> Just like git clone --bare, build a .git directory but no
> checked out files.
>
> Signed-off-by: Pete Wyckoff <pw@padd.com>
Acked-By: Tor Arvid Lund <torarvid@gmail.com>
> ---
> contrib/fast-import/git-p4 | 17 +++++++++++++----
> t/t9800-git-p4.sh | 10 ++++++++++
> 2 files changed, 23 insertions(+), 4 deletions(-)
>
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index 5b08cd6..efc5dce 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -1771,10 +1771,13 @@ class P4Clone(P4Sync):
> help="where to leave result of the clone"),
> optparse.make_option("-/", dest="cloneExclude",
> action="append", type="string",
> - help="exclude depot path")
> + help="exclude depot path"),
> + optparse.make_option("--bare", dest="cloneBare",
> + action="store_true", default=False),
> ]
> self.cloneDestination = None
> self.needsGit = False
> + self.cloneBare = False
>
> # This is required for the "append" cloneExclude action
> def ensure_value(self, attr, value):
> @@ -1814,11 +1817,16 @@ class P4Clone(P4Sync):
> self.cloneDestination = self.defaultDestination(args)
>
> print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
> +
> if not os.path.exists(self.cloneDestination):
> os.makedirs(self.cloneDestination)
> chdir(self.cloneDestination)
> - system("git init")
> - self.gitdir = os.getcwd() + "/.git"
> +
> + init_cmd = [ "git", "init" ]
> + if self.cloneBare:
> + init_cmd.append("--bare")
> + subprocess.check_call(init_cmd)
> +
> if not P4Sync.run(self, depotPaths):
> return False
> if self.branch != "master":
> @@ -1828,7 +1836,8 @@ class P4Clone(P4Sync):
> masterbranch = "refs/heads/p4/master"
> if gitBranchExists(masterbranch):
> system("git branch master %s" % masterbranch)
> - system("git checkout -f")
> + if not self.cloneBare:
> + system("git checkout -f")
> else:
> print "Could not detect main branch. No checkout/master branch created."
>
> diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh
> index 72c38af..1e7639b 100755
> --- a/t/t9800-git-p4.sh
> +++ b/t/t9800-git-p4.sh
> @@ -87,6 +87,16 @@ test_expect_success 'wildcard files git-p4 clone' '
> rm -rf "$git" && mkdir "$git"
> '
>
> +test_expect_success 'clone bare' '
> + "$GITP4" clone --dest="$git" --bare //depot &&
> + cd "$git" &&
> + test ! -d .git &&
> + bare=`git config --get core.bare` &&
> + test "$bare" = true &&
> + cd "$TRASH_DIRECTORY" &&
> + rm -rf "$git" && mkdir "$git"
> +'
> +
> test_expect_success 'shutdown' '
> pid=`pgrep -f p4d` &&
> test -n "$pid" &&
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 7/8] git-p4: decode p4 wildcard characters
From: Tor Arvid Lund @ 2011-02-08 9:09 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110205225237.GH30963@arf.padd.com>
On Sat, Feb 5, 2011 at 11:52 PM, Pete Wyckoff <pw@padd.com> wrote:
> There are four wildcard characters in p4. Files with these
> characters can be added to p4 repos using the "-f" option.
> They are stored in %xx notation, and when checked out, p4
> converts them back to normal.
>
> This patch does the same thing when importing into git,
> converting the four special characters. Without this change,
> the files appear with literal %xx in their names.
>
> Signed-off-by: Pete Wyckoff <pw@padd.com>
> ---
> contrib/fast-import/git-p4 | 13 +++++++++++++
> t/t9800-git-p4.sh | 22 ++++++++++++++++++++++
> 2 files changed, 35 insertions(+), 0 deletions(-)
>
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index 04e6c3d..5b08cd6 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -884,6 +884,18 @@ class P4Sync(Command):
> if gitConfig("git-p4.syncFromOrigin") == "false":
> self.syncWithOrigin = False
>
> + # The p4 wildcards are not allowed in filenames. It complains
> + # if you try to add them, but you can override with "-f", in
> + # which case it translates them into %xx encoding. Search for
> + # and fix just these four characters. Do % last so it does
> + # not inadvertantly create new %-escapes.
> + def wildcard_decode(self, path):
> + path = path.replace("%23", "#") \
> + .replace("%2A", "*") \
This probably works fine on UNIX platforms, but the asterisk '*'
character is not allowed in windows filenames. I don't really know
what perforce does in that scenario. Does it make the most sense to
just keep the %2A in the filename if we are running on windows (??)
-- Tor Arvid
> + .replace("%40", "@") \
> + .replace("%25", "%")
> + return path
> +
> def extractFilesFromCommit(self, commit):
> self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
> for path in self.cloneExclude]
> @@ -962,6 +974,7 @@ class P4Sync(Command):
> return
>
> relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
> + relPath = self.wildcard_decode(relPath)
> if verbose:
> sys.stderr.write("%s\n" % relPath)
>
> diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh
> index 41e57bb..72c38af 100755
> --- a/t/t9800-git-p4.sh
> +++ b/t/t9800-git-p4.sh
> @@ -65,6 +65,28 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
> test_must_fail grep -q Traceback errs
> '
>
> +test_expect_success 'add p4 files with wildcards in the names' '
> + cd "$cli" &&
> + echo file-wild-hash >file-wild#hash &&
> + echo file-wild-star >file-wild\*star &&
> + echo file-wild-at >file-wild@at &&
> + echo file-wild-percent >file-wild%percent &&
> + p4 add -f file-wild* &&
> + p4 submit -d "file wildcards" &&
> + cd "$TRASH_DIRECTORY"
> +'
> +
> +test_expect_success 'wildcard files git-p4 clone' '
> + "$GITP4" clone --dest="$git" //depot &&
> + cd "$git" &&
> + test -f file-wild#hash &&
> + test -f file-wild\*star &&
> + test -f file-wild@at &&
> + test -f file-wild%percent &&
> + cd "$TRASH_DIRECTORY" &&
> + rm -rf "$git" && mkdir "$git"
> +'
> +
> test_expect_success 'shutdown' '
> pid=`pgrep -f p4d` &&
> test -n "$pid" &&
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 6/8] git-p4: better message for "git-p4 sync" when not cloned
From: Tor Arvid Lund @ 2011-02-08 8:55 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110205225224.GG30963@arf.padd.com>
On Sat, Feb 5, 2011 at 11:52 PM, Pete Wyckoff <pw@padd.com> wrote:
> A common error is to do "git-p4 sync" in a repository that
> was not initialized by "git-p4 clone". There will be no
> p4 refs. The error message in this case is a traceback
> for an assertion, which is confusing.
>
> Change it instead to explain the likely problem.
>
> Signed-off-by: Pete Wyckoff <pw@padd.com>
Acked-By: Tor Arvid Lund <torarvid@gmail.com>
> ---
> contrib/fast-import/git-p4 | 2 ++
> 1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index 6b847c4..04e6c3d 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -1676,6 +1676,8 @@ class P4Sync(Command):
>
> changes.sort()
> else:
> + if not self.p4BranchesInGit:
> + die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here.");
> if self.verbose:
> print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
> self.changeRange)
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 4/8] git-p4: accommodate new move/delete type in p4
From: Tor Arvid Lund @ 2011-02-08 8:52 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110205225206.GE30963@arf.padd.com>
On Sat, Feb 5, 2011 at 11:52 PM, Pete Wyckoff <pw@padd.com> wrote:
> Change 562d53f (2010-11-21) recognized the new move/delete type
> for git-p4 sync, but it can also show up in an initial clone and
> labels output. Instead of replicating this in three places,
> hoist the definition somewhere global.
>
> Signed-off-by: Pete Wyckoff <pw@padd.com>
Acked-By: Tor Arvid Lund <torarvid@gmail.com>
> ---
> contrib/fast-import/git-p4 | 12 +++++++-----
> 1 files changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index d2ba215..db19b17 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -834,6 +834,8 @@ class P4Submit(Command):
> return True
>
> class P4Sync(Command):
> + delete_actions = ( "delete", "move/delete", "purge" )
> +
> def __init__(self):
> Command.__init__(self)
> self.options = [
> @@ -1038,10 +1040,10 @@ class P4Sync(Command):
>
> if includeFile:
> filesForCommit.append(f)
> - if f['action'] not in ('delete', 'move/delete', 'purge'):
> - filesToRead.append(f)
> - else:
> + if f['action'] in self.delete_actions:
> filesToDelete.append(f)
> + else:
> + filesToRead.append(f)
>
> # deleted files...
> for f in filesToDelete:
> @@ -1127,7 +1129,7 @@ class P4Sync(Command):
>
> cleanedFiles = {}
> for info in files:
> - if info["action"] in ("delete", "purge"):
> + if info["action"] in self.delete_actions:
> continue
> cleanedFiles[info["depotFile"]] = info["rev"]
>
> @@ -1453,7 +1455,7 @@ class P4Sync(Command):
> if change > newestRevision:
> newestRevision = change
>
> - if info["action"] in ("delete", "purge"):
> + if info["action"] in self.delete_actions:
> # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
> #fileCnt = fileCnt + 1
> continue
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 3/8] git-p4: add missing newline in initial import message
From: Tor Arvid Lund @ 2011-02-08 8:48 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110205225155.GD30963@arf.padd.com>
On Sat, Feb 5, 2011 at 11:51 PM, Pete Wyckoff <pw@padd.com> wrote:
> The commit message looks wrong without the newline.
>
> Signed-off-by: Pete Wyckoff <pw@padd.com>
Acked-By: Tor Arvid Lund <torarvid@gmail.com>
> ---
> contrib/fast-import/git-p4 | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index 2fefea4..d2ba215 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -1429,7 +1429,7 @@ class P4Sync(Command):
> print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
>
> details = { "user" : "git perforce import user", "time" : int(time.time()) }
> - details["desc"] = ("Initial import of %s from the state at revision %s"
> + details["desc"] = ("Initial import of %s from the state at revision %s\n"
> % (' '.join(self.depotPaths), revision))
> details["change"] = revision
> newestRevision = 0
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [1.8.0] Provide proper remote ref namespaces
From: Johan Herland @ 2011-02-08 8:15 UTC (permalink / raw)
To: Dmitry Potapov
Cc: git, Junio C Hamano, Sverre Rabbelier, Jeff King,
Nguyen Thai Ngoc Duy, Nicolas Pitre
In-Reply-To: <20110208010648.GA3132@dpotapov.dyndns.org>
On Tuesday 08 February 2011, Dmitry Potapov wrote:
> On Mon, Feb 07, 2011 at 04:29:04AM +0100, Johan Herland wrote:
> > > So, IMHO, the proper solution should be ability to specify the
> > > desired namespace for any remote repository, like this:
> > >
> > > remote.<name>.tagNameSpace = foo
> >
> > Interesting. I'm not sure what "foo" means in this context. Would I use
> > it
> >
> > like this?:
> > remote.origin.tagNameSpace = refs/tags
>
> I was not sure about the specific when I wrote this, so I just put "foo",
> but it could be something like you wrote above.
>
> > (to place origin's tags in refs/tags/*)
> >
> > If so, what's the difference between this option, and using this?:
> > remote.origin.fetch = refs/tags/*:refs/tags/*
>
> I have not tried that, but I suspect that it will cause that all tags
> will be fetched even if they are not belong to tracked branches, i.e.
> "git fetch" will work as "git fetch -t". But maybe I am wrong here.
Ah, yes, I should have been more specific:
remote.origin.fetch = ~refs/tags/*:refs/tags/*
In my proposal, I suggest using a "~" prefix to signal auto-following
behavior. This is needed in order to be able to explicitly specify the
current fetch behavior in the configuration.
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply
* Re: Git describe finding wrong tag
From: Kevin Ballard @ 2011-02-08 7:23 UTC (permalink / raw)
To: Johannes Sixt; +Cc: git list
In-Reply-To: <4D50EE88.8070005@viscovery.net>
On Feb 7, 2011, at 11:19 PM, Johannes Sixt wrote:
> Am 2/8/2011 5:46, schrieb Kevin Ballard:
>> I just encountered an odd situation where `git describe` insists on finding the
>> wrong tag. In my case, I tagged a branch, then merged it into another branch,
>> and now `git describe` in that other branch decides that it should emit a tag
>> name that's over 200 commits old rather than the one that's a single commit
>> away.
>>
>> % git --version
>> git version 1.7.4.31.g3f8c4
>> % git describe
>> build_1.2.2_applestore_1-203-g742967b
>> % git describe HEAD^2
>> build_1.2.2
>>
>> Is there any rational for why git-describe is opting for the much older
>> commit?
>
> Most likely, the situation outlined in this commit message applies to your
> case:
>
> http://git.kernel.org/?p=git/git.git;a=commit;h=80dbae03
>
> Then what you observe is by design.
You are right, that does explain it. It feels rather odd that I can merge in
a tagged commit and have `git describe` not then use that tag, but I suppose
the new behavior makes sense.
Thanks for the explanation.
-Kevin Ballard
^ permalink raw reply
* Re: Git describe finding wrong tag
From: Johannes Sixt @ 2011-02-08 7:19 UTC (permalink / raw)
To: Kevin Ballard; +Cc: git list
In-Reply-To: <A76F5A9B-6E22-40D5-A8C9-C471A22DF1BE@sb.org>
Am 2/8/2011 5:46, schrieb Kevin Ballard:
> I just encountered an odd situation where `git describe` insists on finding the
> wrong tag. In my case, I tagged a branch, then merged it into another branch,
> and now `git describe` in that other branch decides that it should emit a tag
> name that's over 200 commits old rather than the one that's a single commit
> away.
>
> % git --version
> git version 1.7.4.31.g3f8c4
> % git describe
> build_1.2.2_applestore_1-203-g742967b
> % git describe HEAD^2
> build_1.2.2
>
> Is there any rational for why git-describe is opting for the much older
> commit?
Most likely, the situation outlined in this commit message applies to your
case:
http://git.kernel.org/?p=git/git.git;a=commit;h=80dbae03
Then what you observe is by design.
-- Hannes
^ permalink raw reply
* Git describe finding wrong tag
From: Kevin Ballard @ 2011-02-08 4:46 UTC (permalink / raw)
To: git list
I just encountered an odd situation where `git describe` insists on finding the
wrong tag. In my case, I tagged a branch, then merged it into another branch,
and now `git describe` in that other branch decides that it should emit a tag
name that's over 200 commits old rather than the one that's a single commit
away.
% git --version
git version 1.7.4.31.g3f8c4
% git describe
build_1.2.2_applestore_1-203-g742967b
% git describe HEAD^2
build_1.2.2
Is there any rational for why git-describe is opting for the much older
commit?
-Kevin Ballard
^ permalink raw reply
* Re: [PATCH v4 0/5] make open/unlink failures user friendly on windows using retry/abort
From: Junio C Hamano @ 2011-02-08 4:34 UTC (permalink / raw)
To: Heiko Voigt
Cc: kusmabite, Johannes Sixt, Pat Thoyts, msysgit, git,
Johannes Schindelin
In-Reply-To: <20110207204818.GA63976@book.hvoigt.net>
Thanks, will queue (with a handful of minor style fixes).
^ permalink raw reply
* Re: [PATCH] cache-tree: do not cache empty trees
From: Jonathan Nieder @ 2011-02-08 4:30 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy
Cc: Junio C Hamano, git, Ilari Liusvaara, Jakub Narebski,
Dmitry S. Kravtsov, Shawn Pearce, Yann Dirson
In-Reply-To: <AANLkTim_G9cPs=+1GQ2qBEgriOyKYgXk17iHE4oq9h2C@mail.gmail.com>
Nguyen Thai Ngoc Duy wrote:
> But empty trees are allowed in repo since 79b1138 (fsck.c: fix bogus
> "empty tree" check). Index can't handle empty trees, so it's a bug to
> me that index still accepts them as input and silently discard them.
FWIW my instinct points in the opposite direction. I wouldn't mind
seeing fsck warn about trees containing empty subtrees[1]. As for
cache-tree, while it is not obvious what the right thing to do is,
discarding empty subtrees sounds accepatable.
For storage of empty subtrees in repos imported from svn, Yann's idea
of using .gitattributes somehow (maybe in the parent directory or
maybe in the subdir itself) seems oddly appealing.
Just my unproductive two cents,
Jonathan
[1] I suspect 79b1138 was only meant to deal with the "git commit
--allow-empty from newly initialized repo" case.
^ permalink raw reply
* Re: [PATCH] cache-tree: do not cache empty trees
From: Nguyen Thai Ngoc Duy @ 2011-02-08 4:11 UTC (permalink / raw)
To: Junio C Hamano
Cc: Jonathan Nieder, git, Ilari Liusvaara, Jakub Narebski,
Dmitry S. Kravtsov, Shawn Pearce
In-Reply-To: <7v1v3jvaef.fsf@alter.siamese.dyndns.org>
On Tue, Feb 8, 2011 at 3:48 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> Perhaps it's not a good approach after all. What I wanted was to make
>> pre-1.8.0 tolerate empty trees created by 1.8.0. Perhaps it's better
>> to just let pre-1.8.0 refuse to work with empty trees, forcing users
>> to upgrade to 1.8.0?
>
> I don't think we saw even something remotely resembles an agreement that
> empty tree is a good thing to have yet. Why are you rushing things?
But empty trees are allowed in repo since 79b1138 (fsck.c: fix bogus
"empty tree" check). Index can't handle empty trees, so it's a bug to
me that index still accepts them as input and silently discard them. A
bug regardless directory tracking support in 1.8.0. A corner case that
nobody would likely encounter (except Ilari and his "ghost directory"
problem).
--
Duy
^ permalink raw reply
* [PATCH] mergetool: don't skip modify/remove conflicts
From: Martin von Zweigbergk @ 2011-02-08 3:08 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Martin von Zweigbergk
Since bb0a484 (mergetool: Skip autoresolved paths, 2010-08-17),
mergetool uses different ways of figuring out the list of files with
merge conflicts depending on whether rerere is active. If rerere is
active, mergetool will use 'git rerere status' to list the files with
remaining conflicts. However, the output from that command does not
list conflicts of types that rerere does not handle, such as
modify/remove conflicts.
Another problem with solely relying on the output from 'git rerere
status' is that, for new conflicts that are not yet known to rerere,
the output from the command will list the files even after adding them
to the index. This means that if the conflicts in some files have been
resolved and 'git mergetool' is run again, it will ask the user
something like the following for each of those files.
file1: file does not need merging
Continue merging other unresolved paths (y/n) ?
Solve the first of these problems by replacing the call to 'git rerere
status' with a call to the new 'git rerere remaining' that was
introduced in the previous commit. Solve the second problem by
modifying 'git rerere remaining' not to output files that have already
been staged.
Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
---
This applies on top of jc/rerere-remaining.
This is my first patch that touches any C code and I haven't written
anything in C for about 10 years. I hope it doesn't look too bad.
I also have another version of this patch that doesn't modify 'git
rerere remaining', but instead combines the output with the output
from 'git ls-files'. Tell me if you think that is better.
Is it correct to call "yes" with multiple arguments in the test script
the way I did?
builtin/rerere.c | 10 +++++++---
git-mergetool.sh | 2 +-
rerere.c | 31 ++++++++++++++++++++-----------
rerere.h | 3 +++
t/t7610-mergetool.sh | 40 ++++++++++++++++++++++++++++++++++------
5 files changed, 65 insertions(+), 21 deletions(-)
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 081fccc..9cbab27 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -147,7 +147,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[0], "clear")) {
for (i = 0; i < merge_rr.nr; i++) {
const char *name = (const char *)merge_rr.items[i].util;
- if (!name)
+ if (name == RERERE_UTIL_PUNTED || name == RERERE_UTIL_STAGED)
continue;
if (!has_rerere_resolution(name))
unlink_rr_item(name);
@@ -162,13 +162,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
printf("%s\n", merge_rr.items[i].string);
}
else if (!strcmp(argv[0], "remaining"))
- for (i = 0; i < merge_rr.nr; i++)
+ for (i = 0; i < merge_rr.nr; i++) {
+ const char *name = (const char *)merge_rr.items[i].util;
+ if (name == RERERE_UTIL_STAGED)
+ continue;
printf("%s\n", merge_rr.items[i].string);
+ }
else if (!strcmp(argv[0], "diff"))
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const char *name = (const char *)merge_rr.items[i].util;
- if (!name)
+ if (name == RERERE_UTIL_PUNTED || name == RERERE_UTIL_STAGED)
continue;
diff_two(rerere_path(name, "preimage"), path, path, path);
}
diff --git a/git-mergetool.sh b/git-mergetool.sh
index 2f8dc44..bacbda2 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -269,7 +269,7 @@ rerere=false
files_to_merge() {
if test "$rerere" = true
then
- git rerere status
+ git rerere remaining
else
git ls-files -u | sed -e 's/^[^ ]* //' | sort -u
fi
diff --git a/rerere.c b/rerere.c
index eb47f97..61cac54 100644
--- a/rerere.c
+++ b/rerere.c
@@ -7,6 +7,10 @@
#include "ll-merge.h"
#include "attr.h"
+#define RERERE_UTIL_ELIGIBLE NULL
+void *RERERE_UTIL_PUNTED = &RERERE_UTIL_PUNTED;
+void *RERERE_UTIL_STAGED = &RERERE_UTIL_STAGED;
+
/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
static int rerere_enabled = -1;
@@ -352,18 +356,20 @@ static int find_conflict(struct string_list *conflict)
return error("Could not read index");
/*
- * Collect paths with conflict, mark them with NULL (punted) or
- * !NULL (eligible) in their ->util field.
+ * Collect paths with conflict, mark them according to type in
+ * their ->util field.
*/
for (i = 0; i < active_nr; i++) {
struct cache_entry *e = active_cache[i];
struct string_list_item *it;
- if (!ce_stage(e))
+ if (!ce_stage(e)) {
continue;
+ }
it = string_list_insert(conflict, (const char *)e->name);
- it->util = NULL;
+ it->util = RERERE_UTIL_PUNTED;
if (ce_stage(e) == 1) {
+ it->util = RERERE_UTIL_STAGED;
if (active_nr <= ++i)
break;
}
@@ -377,7 +383,7 @@ static int find_conflict(struct string_list *conflict)
ce_same_name(e, e3) &&
S_ISREG(e2->ce_mode) &&
S_ISREG(e3->ce_mode))
- it->util = (void *) 1;
+ it->util = RERERE_UTIL_ELIGIBLE;
}
/* Skip the entries with the same name */
@@ -395,9 +401,10 @@ static void add_punted(struct string_list *merge_rr)
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
- if (conflict.items[i].util)
+ if (conflict.items[i].util == RERERE_UTIL_ELIGIBLE)
continue;
- string_list_insert(merge_rr, conflict.items[i].string);
+ string_list_insert(merge_rr, conflict.items[i].string)->util =
+ conflict.items[i].util;
}
}
@@ -487,8 +494,9 @@ static int do_plain_rerere(struct string_list *rr, int fd)
for (i = 0; i < conflict.nr; i++) {
const char *path = conflict.items[i].string;
- if (!conflict.items[i].util)
- continue; /* punted */
+ if (conflict.items[i].util == RERERE_UTIL_PUNTED ||
+ conflict.items[i].util == RERERE_UTIL_STAGED)
+ continue;
if (!string_list_has_string(rr, path)) {
unsigned char sha1[20];
char *hex;
@@ -648,8 +656,9 @@ int rerere_forget(const char **pathspec)
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
- if (!conflict.items[i].util)
- continue; /* punted */
+ if (conflict.items[i].util == RERERE_UTIL_PUNTED ||
+ conflict.items[i].util == RERERE_UTIL_STAGED)
+ continue;
if (!match_pathspec(pathspec, it->string, strlen(it->string),
0, NULL))
continue;
diff --git a/rerere.h b/rerere.h
index eaa9004..107a2bc 100644
--- a/rerere.h
+++ b/rerere.h
@@ -6,6 +6,9 @@
#define RERERE_AUTOUPDATE 01
#define RERERE_NOAUTOUPDATE 02
+extern void *RERERE_UTIL_PUNTED;
+extern void *RERERE_UTIL_STAGED;
+
extern int setup_rerere(struct string_list *, int);
extern int rerere(int);
extern const char *rerere_path(const char *hex, const char *file);
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index d78bdec..dc838c9 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -16,23 +16,33 @@ Testing basic merge tool invocation'
test_expect_success 'setup' '
git config rerere.enabled true &&
echo master >file1 &&
+ echo master file11 >file11 &&
+ echo master file12 >file12 &&
+ echo master file13 >file13 &&
+ echo master file14 >file14 &&
mkdir subdir &&
echo master sub >subdir/file3 &&
- git add file1 subdir/file3 &&
- git commit -m "added file1" &&
+ git add file1 file1[1-4] subdir/file3 &&
+ git commit -m "add initial versions" &&
git checkout -b branch1 master &&
echo branch1 change >file1 &&
echo branch1 newfile >file2 &&
+ echo branch1 change file11 >file11 &&
+ echo branch1 change file13 >file13 &&
echo branch1 sub >subdir/file3 &&
- git add file1 file2 subdir/file3 &&
+ git add file1 file11 file13 file2 subdir/file3 &&
+ git rm file12 &&
git commit -m "branch1 changes" &&
git checkout master &&
echo master updated >file1 &&
echo master new >file2 &&
+ echo master updated file12 >file12 &&
+ echo master updated file14 >file14 &&
echo master new sub >subdir/file3 &&
- git add file1 file2 subdir/file3 &&
+ git add file1 file12 file14 file2 subdir/file3 &&
+ git rm file11 &&
git commit -m "master updates" &&
git config merge.tool mytool &&
@@ -46,6 +56,8 @@ test_expect_success 'custom mergetool' '
( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
test "$(cat file1)" = "master updated" &&
test "$(cat file2)" = "master new" &&
test "$(cat subdir/file3)" = "master new sub" &&
@@ -59,6 +71,8 @@ test_expect_success 'mergetool crlf' '
( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" &&
test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" &&
test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" &&
@@ -82,6 +96,8 @@ test_expect_success 'mergetool on file in parent dir' '
cd subdir &&
( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
test "$(cat ../file1)" = "master updated" &&
test "$(cat ../file2)" = "master new" &&
git commit -m "branch1 resolved with mergetool - subdir"
@@ -92,6 +108,8 @@ test_expect_success 'mergetool skips autoresolved' '
git checkout -b test4 branch1 &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
+ ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+ ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
output="$(git mergetool --no-prompt)" &&
test "$output" = "No files need merging" &&
git reset --hard
@@ -102,13 +120,23 @@ test_expect_success 'mergetool merges all from subdir' '
cd subdir &&
git config rerere.enabled false &&
test_must_fail git merge master &&
- git mergetool --no-prompt &&
+ ( yes "d" "d" | git mergetool --no-prompt ) &&
test "$(cat ../file1)" = "master updated" &&
test "$(cat ../file2)" = "master new" &&
test "$(cat file3)" = "master new sub" &&
- git add ../file1 ../file2 file3 &&
git commit -m "branch2 resolved by mergetool from subdir"
)
'
+test_expect_success 'mergetool skips resolved paths when rerere is active' '
+ git config rerere.enabled true &&
+ rm -rf .git/rr-cache &&
+ git checkout -b test5 branch1
+ test_must_fail git merge master >/dev/null 2>&1 &&
+ ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) &&
+ output="$(yes "n" | git mergetool --no-prompt)" &&
+ test "$output" = "No files need merging" &&
+ git reset --hard
+'
+
test_done
--
1.7.4.rc2.33.g8a14f
^ permalink raw reply related
* Re: "git add -u" broken in git 1.7.4?
From: Junio C Hamano @ 2011-02-08 2:16 UTC (permalink / raw)
To: Eric Raible; +Cc: Jeff King, Matthieu Moy, Sebastian Pipping, Git ML
In-Reply-To: <4D509B8B.6090607@nextest.com>
Eric Raible <raible@nextest.com> writes:
> IFUC this shouldn't affect any (correctly written) scripts,
> and so the only downside is that (when run in a subdir) commands
> that are currently spelled:
>
> git xxx
>
> would with this change need to be spelled:
>
> git xxx .
If xxx is grep (or "add -u") and the script is running the former form,
you already broke it, and I think a script that expects "git grep" to
limit its scope to the current directory is "correctly written". That is
how these commands were defined and documented to work.
"Adding SP plus dot is just a two-byte change" is not a sensible reason to
break people's scripts. We need to be honest and say "sorry, but with
this release we are breaking your scripts. Let us convince you that the
benefit of the resulting consistency outweighs that cost".
^ permalink raw reply
* Re: Re: "git add -u" broken in git 1.7.4?
From: Eric Raible @ 2011-02-08 1:25 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, Matthieu Moy, Sebastian Pipping, Git ML
In-Reply-To: <7vhbcguytf.fsf@alter.siamese.dyndns.org>
On 11:59 AM, Junio C Hamano wrote:
> I actually do not mind too much myself if all commands that can take
> pathspecs consistently defaulted to "full-tree" pathspec given no
> pathspec. But if we were to go that route, everybody should join their
> voice to defend that decision when outside people say "in 1.8.0 'git grep'
> run from a subdirectory shows matches from all the irrelevant parts of the
> tree; with all the cruft its output is unreadable". I won't be the sole
> champion of such a behaviour when I do not fully believe in it.
IFUC this shouldn't affect any (correctly written) scripts,
and so the only downside is that (when run in a subdir) commands
that are currently spelled:
git xxx
would with this change need to be spelled:
git xxx .
One advantage of this approach is that one's fingers would
learn the "only this dir" two char sequence very quickly.
So FWIW, I will do my best to help defend such a decision.
^ permalink raw reply
* Re: rebase planning: determining blobs changed by multiple branches
From: Neal Kreitzinger @ 2011-02-08 1:27 UTC (permalink / raw)
To: Marc Weber; +Cc: git
In-Reply-To: <1297126350-sup-6606@localhost.localdomain>
On 2/7/2011 6:59 PM, Marc Weber wrote:
> Hi Neal,
>
> I'm not quite sure what you want to do?
> rebase all branches on top of commit l so that they are up to date?
>
> Why do you want to find common blobs?
> If the same conflict happens you could use gitrere and reuse a conflict
> resolution.
>
> git ls-files --with $HASH
> gives you a list of files
>
> git diff --name-only
> should give you a nice list of modified files.
>
> So using the intersection of ls-files of branch and tip should give you
> common files. Substracting changed files using --name-only should yield
> the files which were not modified.
> Maybe there are nicer solutions though.
>
> Rebasing is always bad. Have you considered using top-git?
> This way you can merge with tip and create the rebased patches using the
> export function.
Our master represents our new system and we want to have a linear
history so we use rebase. Each branch is a project. If a project does
not have any merges with other projects then it can rebase with little
impact. If projects are changing alot of the same blobs then they will
have alot of merged blobs and can be rebased on eachother in
throw-away-integration branches. In this way the branches can be
grouped into appropriate rebase groups so the merge-conflict resolutions
of these groups can be resolved simultaneously in different integration
repos. So lets say you have 5 groups, then you can rebase those 5
integration-branches onto master one-by-one instead of doing 15 project
branches one-by-one. I thought maybe git had a cool command for
analyzing this in one fell swoop.
v/r,
Neal
^ permalink raw reply
* Re: [PATCH] Support different branch layouts in git-p4
From: Pete Wyckoff @ 2011-02-08 1:22 UTC (permalink / raw)
To: Ian Wienand; +Cc: Tor Arvid Lund, git
In-Reply-To: <4D4F3738.7010603@vmware.com>
ianw@vmware.com wrote on Sun, 06 Feb 2011 16:05 -0800:
> I did consider this at first. My only issue is that it is a bit
> confusing to use the client spec for filtering (and in this case
> re-writing), but not for actually selecting the depots to clone, which
> I still need to replicate on the command line. However that is a much
> larger change.
>
> What do you think of this one?
>
> In this case, my client view is
>
> //depot/project/branch/... //client/branch/project/...
> //depot/project2/branch/... //client/branch/project2/...
>
> and my git directory layout ends up as
>
> branch/project/...
> branch/project2/...
We had such terrible p4 mappings too, before the last
rearrangement put us into a single-line view spec. I think
it would help others to include such support, though.
Back then, I hacked together similar code to deal with the
annoyance. My code was not pretty and not complete, either.
If you look at "p4 help views", they have lots of oddities
that in theory should be accounted for here. It doesn't
even mention the thing about quotes, but obviously that is
supported. Wildcards ... and * can appear multiple
times. And %%[1-9] can be used to reorder the path. Also the
order of lines matters, and "+" can be used to merge entries.
Whew.
In practice, I think you get most everything we care about. A
few comments below, beyond the bits that Tor Arvid caught.
-- Pete
> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
> index 04ce7e3..eb9620c 100755
> --- a/contrib/fast-import/git-p4
> +++ b/contrib/fast-import/git-p4
> @@ -878,6 +878,7 @@ class P4Sync(Command):
> self.cloneExclude = []
> self.useClientSpec = False
> self.clientSpecDirs = []
> + self.clientName = None
Unused.
> if gitConfig("git-p4.syncFromOrigin") == "false":
> self.syncWithOrigin = False
> @@ -910,6 +911,22 @@ class P4Sync(Command):
> return files
>
> def stripRepoPath(self, path, prefixes):
> + if self.useClientSpec:
> +
> + # if using the client spec, we use the output directory
> + # specified in the client. For example, a view
> + # //depot/foo/branch/... //client/branch/foo/...
> + # will end up putting all foo/branch files into
> + # branch/foo/
> + for val in self.clientSpecDirs:
> + if path.startswith(val[0]):
> + # replace the depot path with the client path
> + path = path.replace(val[0], val[1][1])
> + # now strip out the client (//client/...)
> + path = re.sub("^(//[^/]+/)", '', path)
> + # the rest is all path
> + return path
That's clever. Better than having to remember Client: and build
//client/ out of it. You could do this down in getClientSpec()
so that val[1] starts with the git-relative path.
> if self.keepRepoPath:
> prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
>
> @@ -1032,7 +1049,7 @@ class P4Sync(Command):
> includeFile = True
> for val in self.clientSpecDirs:
> if f['path'].startswith(val[0]):
> - if val[1] <= 0:
> + if val[1][0] <= 0:
> includeFile = False
> break
>
> @@ -1474,20 +1491,36 @@ class P4Sync(Command):
> temp = {}
> for entry in specList:
> for k,v in entry.iteritems():
> + if k.startswith("Client"):
> + self.clientName = v
Oh maybe here is where you thought you would need client, but
don't.
> if k.startswith("View"):
> if v.startswith('"'):
> start = 1
> else:
> start = 0
> index = v.find("...")
> +
> + # save the "client view"; i.e the RHS of the view
> + # line that tells the client where to put the
> + # files for this view.
> + cv = v[index+4:] # +4 to remove previous '... '
> + cv_index = cv.find("...")
> + cv=cv[:cv_index]
> +
> + # now save the view; +index means included, -index
> + # means it should be filtered out.
> v = v[start:index]
> if v.startswith("-"):
> v = v[1:]
> - temp[v] = -len(v)
> + include = -len(v)
> else:
> - temp[v] = len(v)
> + include = len(v)
> +
> + temp[v] = (include, cv)
> +
> self.clientSpecDirs = temp.items()
> - self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) )
> + self.clientSpecDirs.sort( lambda x, y: abs( y[1][0] ) - abs( x[1][0] ) )
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox