* [PATCH 5/6] Do not allow ".lock" at the end of any refname component
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
In-Reply-To: <1315568778-3592-1-git-send-email-mhagger@alum.mit.edu>
Allowing any refname component to end with ".lock" is looking for
trouble; for example,
$ git br foo.lock/bar
$ git br foo
fatal: Unable to create '[...]/.git/refs/heads/foo.lock': File exists.
Therefore, do not allow any refname component to end with ".lock".
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
Documentation/git-check-ref-format.txt | 4 +---
refs.c | 6 +++---
t/t1402-check-ref-format.sh | 4 ++++
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 3ab22b9..f2d21c7 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -28,7 +28,7 @@ git imposes the following rules on how references are named:
. They can include slash `/` for hierarchical (directory)
grouping, but no slash-separated component can begin with a
- dot `.`.
+ dot `.` or end with the sequence `.lock`.
. They must contain at least one `/`. This enforces the presence of a
category like `heads/`, `tags/` etc. but the actual names are not
@@ -47,8 +47,6 @@ git imposes the following rules on how references are named:
. They cannot end with a slash `/` nor a dot `.`.
-. They cannot end with the sequence `.lock`.
-
. They cannot contain a sequence `@{`.
. They cannot contain a `\`.
diff --git a/refs.c b/refs.c
index 372350e..6985a3f 100644
--- a/refs.c
+++ b/refs.c
@@ -933,14 +933,14 @@ int normalize_refname(char *dst, int dstlen, const char *ref, int flags)
if (component[0] == '.')
/* Components must not start with '.'. */
return -1;
+ if (component_len >= 5 && !memcmp(&component[component_len - 5], ".lock", 5))
+ /* Components must not end with ".lock". */
+ return -1;
} while (ch != 0);
if (last == '.')
/* Refname must not end with '.'. */
return -1;
- if (component_len >= 5 && !memcmp(&component[component_len - 5], ".lock", 5))
- /* Refname must not end with ".lock". */
- return -1;
if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
/* Refname must have at least two components. */
return -1;
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 20a7782..6848bfb 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -40,6 +40,8 @@ invalid_ref 'heads/foo?bar'
valid_ref 'foo./bar'
invalid_ref 'heads/foo.lock'
invalid_ref 'heads///foo.lock'
+invalid_ref 'foo.lock/bar'
+invalid_ref 'foo.lock///bar'
valid_ref 'heads/foo@bar'
invalid_ref 'heads/v@{ation'
invalid_ref 'heads/foo\bar'
@@ -155,5 +157,7 @@ invalid_ref_normalized 'heads/./foo'
invalid_ref_normalized 'heads\foo'
invalid_ref_normalized 'heads/foo.lock'
invalid_ref_normalized 'heads///foo.lock'
+invalid_ref_normalized 'foo.lock/bar'
+invalid_ref_normalized 'foo.lock///bar'
test_done
--
1.7.6.8.gd2879
^ permalink raw reply related
* [PATCH 2/6] git check-ref-format: add options --onelevel-ok and --refname-pattern
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
In-Reply-To: <1315568778-3592-1-git-send-email-mhagger@alum.mit.edu>
Also add tests of the new options. (Actually, one big reason to add
the new options is to make it easy to test check_ref_format(), though
the options should also be useful to other scripts.)
Interpret the result of check_ref_format() based on which types of
refnames are allowed. However, because check_ref_format() can only
return a single value, one test case is still broken. Specifically,
the case "git check-ref-format --onelevel '*'" incorrectly succeeds
because check_ref_format() returns CHECK_REF_FORMAT_ONELEVEL for this
refname even though the refname is also CHECK_REF_FORMAT_WILDCARD.
The type of check that leads to this failure is used elsewhere in
"real" code and could lead to bugs; it will be fixed over the next few
commits.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
The failing test is expressed awkwardly in
t/t1402-check-ref-format.sh, but since it will be fixed in the next
commit it doesn't seem worth investing any work in it.
Documentation/git-check-ref-format.txt | 29 +++++++++--
builtin/check-ref-format.c | 56 +++++++++++++++++---
t/t1402-check-ref-format.sh | 87 +++++++++++++++++++++++++++++---
3 files changed, 151 insertions(+), 21 deletions(-)
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index c9fdf84..3ab22b9 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -8,8 +8,8 @@ git-check-ref-format - Ensures that a reference name is well formed
SYNOPSIS
--------
[verse]
-'git check-ref-format' <refname>
-'git check-ref-format' --print <refname>
+'git check-ref-format' [--print]
+ [--[no-]allow-onelevel] [--refspec-pattern] <refname>
'git check-ref-format' --branch <branchname-shorthand>
DESCRIPTION
@@ -32,14 +32,18 @@ git imposes the following rules on how references are named:
. They must contain at least one `/`. This enforces the presence of a
category like `heads/`, `tags/` etc. but the actual names are not
- restricted.
+ restricted. If the `--allow-onelevel` option is used, this rule
+ is waived.
. They cannot have two consecutive dots `..` anywhere.
. They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
- or open bracket `[` anywhere.
+ caret `{caret}`, or colon `:` anywhere.
+
+. They cannot have question-mark `?`, asterisk `*`, or open bracket
+ `[` anywhere. See the `--refspec-pattern` option below for an
+ exception to this rule.
. They cannot end with a slash `/` nor a dot `.`.
@@ -78,6 +82,21 @@ were on. This option should be used by porcelains to accept this
syntax anywhere a branch name is expected, so they can act as if you
typed the branch name.
+OPTIONS
+-------
+--allow-onelevel::
+--no-allow-onelevel::
+ Controls whether one-level refnames are accepted (i.e.,
+ refnames that do not contain multiple `/`-separated
+ components). The default is `--no-allow-onelevel`.
+
+--refspec-pattern::
+ Interpret <refname> as a reference name pattern for a refspec
+ (as used with remote repositories). If this option is
+ enabled, <refname> is allowed to contain a single `*` in place
+ of a one full pathname component (e.g., `foo/*/bar` but not
+ `foo/bar*`).
+
EXAMPLES
--------
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 0723cf2..6bb9377 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -8,7 +8,7 @@
#include "strbuf.h"
static const char builtin_check_ref_format_usage[] =
-"git check-ref-format [--print] <refname>\n"
+"git check-ref-format [--print] [options] <refname>\n"
" or: git check-ref-format --branch <branchname-shorthand>";
/*
@@ -45,27 +45,65 @@ static int check_ref_format_branch(const char *arg)
return 0;
}
-static int check_ref_format_print(const char *arg)
+static void refname_format_print(const char *arg)
{
char *refname = xmalloc(strlen(arg) + 1);
- if (check_ref_format(arg))
- return 1;
collapse_slashes(refname, arg);
printf("%s\n", refname);
- return 0;
}
+#define REFNAME_ALLOW_ONELEVEL 1
+#define REFNAME_REFSPEC_PATTERN 2
+
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
{
+ int i;
+ int print = 0;
+ int flags = 0;
+
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_check_ref_format_usage);
if (argc == 3 && !strcmp(argv[1], "--branch"))
return check_ref_format_branch(argv[2]);
- if (argc == 3 && !strcmp(argv[1], "--print"))
- return check_ref_format_print(argv[2]);
- if (argc != 2)
+
+ for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
+ if (!strcmp(argv[i], "--print"))
+ print = 1;
+ else if (!strcmp(argv[i], "--allow-onelevel"))
+ flags |= REFNAME_ALLOW_ONELEVEL;
+ else if (!strcmp(argv[i], "--no-allow-onelevel"))
+ flags &= ~REFNAME_ALLOW_ONELEVEL;
+ else if (!strcmp(argv[i], "--refspec-pattern"))
+ flags |= REFNAME_REFSPEC_PATTERN;
+ else
+ usage(builtin_check_ref_format_usage);
+ }
+ if (! (i == argc - 1))
usage(builtin_check_ref_format_usage);
- return !!check_ref_format(argv[1]);
+
+ switch (check_ref_format(argv[i])) {
+ case CHECK_REF_FORMAT_OK:
+ break;
+ case CHECK_REF_FORMAT_ERROR:
+ return 1;
+ case CHECK_REF_FORMAT_ONELEVEL:
+ if (!(flags & REFNAME_ALLOW_ONELEVEL))
+ return 1;
+ else
+ break;
+ case CHECK_REF_FORMAT_WILDCARD:
+ if (!(flags & REFNAME_REFSPEC_PATTERN))
+ return 1;
+ else
+ break;
+ default:
+ die("internal error: unexpected value from check_ref_format()");
+ }
+
+ if (print)
+ refname_format_print(argv[i]);
+
+ return 0;
}
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index ed4275a..95dcd31 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -5,23 +5,35 @@ test_description='Test git check-ref-format'
. ./test-lib.sh
valid_ref() {
- test_expect_success "ref name '$1' is valid" \
- "git check-ref-format '$1'"
+ if test "$#" = 1
+ then
+ test_expect_success "ref name '$1' is valid" \
+ "git check-ref-format '$1'"
+ else
+ test_expect_success "ref name '$1' is valid with options $2" \
+ "git check-ref-format $2 '$1'"
+ fi
}
invalid_ref() {
- test_expect_success "ref name '$1' is not valid" \
- "test_must_fail git check-ref-format '$1'"
+ if test "$#" = 1
+ then
+ test_expect_success "ref name '$1' is invalid" \
+ "test_must_fail git check-ref-format '$1'"
+ else
+ test_expect_success "ref name '$1' is invalid with options $2" \
+ "test_must_fail git check-ref-format $2 '$1'"
+ fi
}
-valid_ref 'heads/foo'
-invalid_ref 'foo'
valid_ref 'foo/bar/baz'
valid_ref 'refs///heads/foo'
invalid_ref 'heads/foo/'
valid_ref '/heads/foo'
valid_ref '///heads/foo'
-invalid_ref '/foo'
invalid_ref './foo'
+invalid_ref './foo/bar'
+invalid_ref 'foo/./bar'
+invalid_ref 'foo/bar/.'
invalid_ref '.refs/foo'
invalid_ref 'heads/foo..bar'
invalid_ref 'heads/foo?bar'
@@ -33,6 +45,67 @@ invalid_ref 'heads/foo\bar'
invalid_ref "$(printf 'heads/foo\t')"
invalid_ref "$(printf 'heads/foo\177')"
valid_ref "$(printf 'heads/fu\303\237')"
+invalid_ref 'heads/*foo/bar' --refspec-pattern
+invalid_ref 'heads/foo*/bar' --refspec-pattern
+invalid_ref 'heads/f*o/bar' --refspec-pattern
+
+ref='foo'
+invalid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/bar'
+valid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*/bar'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*'
+invalid_ref "$ref"
+
+#invalid_ref "$ref" --allow-onelevel
+test_expect_failure "ref name '$ref' is invalid with options --allow-onelevel" \
+ "test_must_fail git check-ref-format --allow-onelevel '$ref'"
+
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/*/foo'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='/foo'
+invalid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
test_expect_success "check-ref-format --branch @{-1}" '
T=$(git write-tree) &&
--
1.7.6.8.gd2879
^ permalink raw reply related
* [PATCH 3/6] Change check_ref_format() to take a flags argument
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
In-Reply-To: <1315568778-3592-1-git-send-email-mhagger@alum.mit.edu>
Change check_ref_format() to take a flags argument that indicates what
is acceptable in the reference name (analogous to --allow-onelevel and
--refspec-pattern). This is more convenient for callers and also
fixes a failure in the test suite (and likely elsewhere in the code)
by enabling "onelevel" and "refspec-pattern" to be allowed
independently of each other.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
builtin/check-ref-format.c | 21 +----------------
builtin/checkout.c | 2 +-
builtin/fetch-pack.c | 2 +-
builtin/receive-pack.c | 2 +-
builtin/replace.c | 2 +-
builtin/show-ref.c | 2 +-
builtin/tag.c | 4 +-
connect.c | 2 +-
environment.c | 2 +-
fast-import.c | 7 +-----
notes-merge.c | 5 ++-
pack-refs.c | 2 +-
refs.c | 42 +++++++++++++++------------------
refs.h | 17 +++++++++----
remote.c | 53 +++++++++++-------------------------------
sha1_name.c | 4 +-
t/t1402-check-ref-format.sh | 6 +----
transport.c | 15 ++---------
walker.c | 2 +-
19 files changed, 67 insertions(+), 125 deletions(-)
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 6bb9377..c639400 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -53,9 +53,6 @@ static void refname_format_print(const char *arg)
printf("%s\n", refname);
}
-#define REFNAME_ALLOW_ONELEVEL 1
-#define REFNAME_REFSPEC_PATTERN 2
-
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
{
int i;
@@ -83,24 +80,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
if (! (i == argc - 1))
usage(builtin_check_ref_format_usage);
- switch (check_ref_format(argv[i])) {
- case CHECK_REF_FORMAT_OK:
- break;
- case CHECK_REF_FORMAT_ERROR:
+ if (check_ref_format(argv[i], flags))
return 1;
- case CHECK_REF_FORMAT_ONELEVEL:
- if (!(flags & REFNAME_ALLOW_ONELEVEL))
- return 1;
- else
- break;
- case CHECK_REF_FORMAT_WILDCARD:
- if (!(flags & REFNAME_REFSPEC_PATTERN))
- return 1;
- else
- break;
- default:
- die("internal error: unexpected value from check_ref_format()");
- }
if (print)
refname_format_print(argv[i]);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3bb6525..2882116 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -882,7 +882,7 @@ 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 (!check_ref_format(new->path, 0) &&
resolve_ref(new->path, branch_rev, 1, NULL))
hashcpy(rev, branch_rev);
else
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 412bd32..411aa7d 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -544,7 +544,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
for (ref = *refs; ref; ref = next) {
next = ref->next;
if (!memcmp(ref->name, "refs/", 5) &&
- check_ref_format(ref->name + 5))
+ check_ref_format(ref->name + 5, 0))
; /* trash */
else if (args.fetch_all &&
(!args.depth || prefixcmp(ref->name, "refs/tags/") )) {
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index ae164da..4e880ef 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -356,7 +356,7 @@ static const char *update(struct command *cmd)
struct ref_lock *lock;
/* only refs/... are allowed */
- if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
+ if (prefixcmp(name, "refs/") || check_ref_format(name + 5, 0)) {
rp_error("refusing to create funny ref '%s' remotely", name);
return "funny refname";
}
diff --git a/builtin/replace.c b/builtin/replace.c
index fe3a647..15f0e5e 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -94,7 +94,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,
"refs/replace/%s",
sha1_to_hex(object)) > sizeof(ref) - 1)
die("replace ref name too long: %.*s...", 50, ref);
- if (check_ref_format(ref))
+ if (check_ref_format(ref, 0))
die("'%s' is not a valid ref name.", ref);
if (!resolve_ref(ref, prev, 1, NULL))
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 45f0340..375a14b 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -145,7 +145,7 @@ static int exclude_existing(const char *match)
if (strncmp(ref, match, matchlen))
continue;
}
- if (check_ref_format(ref)) {
+ if (check_ref_format(ref, 0)) {
warning("ref '%s' ignored", ref);
continue;
}
diff --git a/builtin/tag.c b/builtin/tag.c
index 667515e..7aceaab 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -407,12 +407,12 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
{
if (name[0] == '-')
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
strbuf_reset(sb);
strbuf_addf(sb, "refs/tags/%s", name);
- return check_ref_format(sb->buf);
+ return check_ref_format(sb->buf, 0);
}
int cmd_tag(int argc, const char **argv, const char *prefix)
diff --git a/connect.c b/connect.c
index ee1d4b4..292a9e2 100644
--- a/connect.c
+++ b/connect.c
@@ -22,7 +22,7 @@ static int check_ref(const char *name, int len, unsigned int flags)
len -= 5;
/* REF_NORMAL means that we don't want the magic fake tag refs */
- if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
+ if ((flags & REF_NORMAL) && check_ref_format(name, 0))
return 0;
/* REF_HEADS means that we want regular branch heads */
diff --git a/environment.c b/environment.c
index e96edcf..8acbb87 100644
--- a/environment.c
+++ b/environment.c
@@ -106,7 +106,7 @@ static char *expand_namespace(const char *raw_namespace)
if (strcmp((*c)->buf, "/") != 0)
strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
strbuf_list_free(components);
- if (check_ref_format(buf.buf) != CHECK_REF_FORMAT_OK)
+ if (check_ref_format(buf.buf, 0))
die("bad git namespace path \"%s\"", raw_namespace);
strbuf_addch(&buf, '/');
return strbuf_detach(&buf, NULL);
diff --git a/fast-import.c b/fast-import.c
index 742e7da..4d55ee6 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -722,13 +722,8 @@ static struct branch *new_branch(const char *name)
if (b)
die("Invalid attempt to create duplicate branch: %s", name);
- switch (check_ref_format(name)) {
- case 0: break; /* its valid */
- case CHECK_REF_FORMAT_ONELEVEL:
- break; /* valid, but too few '/', allow anyway */
- default:
+ if (check_ref_format(name, REFNAME_ALLOW_ONELEVEL))
die("Branch name doesn't conform to GIT standards: %s", name);
- }
b = pool_calloc(1, sizeof(struct branch));
b->name = pool_strdup(name);
diff --git a/notes-merge.c b/notes-merge.c
index e1aaf43..bb8d7c8 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -570,7 +570,8 @@ int notes_merge(struct notes_merge_options *o,
/* Dereference o->local_ref into local_sha1 */
if (!resolve_ref(o->local_ref, local_sha1, 0, NULL))
die("Failed to resolve local notes ref '%s'", o->local_ref);
- else if (!check_ref_format(o->local_ref) && is_null_sha1(local_sha1))
+ else if (!check_ref_format(o->local_ref, 0) &&
+ is_null_sha1(local_sha1))
local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */
else if (!(local = lookup_commit_reference(local_sha1)))
die("Could not parse local commit %s (%s)",
@@ -583,7 +584,7 @@ int notes_merge(struct notes_merge_options *o,
* Failed to get remote_sha1. If o->remote_ref looks like an
* unborn ref, perform the merge using an empty notes tree.
*/
- if (!check_ref_format(o->remote_ref)) {
+ if (!check_ref_format(o->remote_ref, 0)) {
hashclr(remote_sha1);
remote = NULL;
} else {
diff --git a/pack-refs.c b/pack-refs.c
index 1290570..bc0032d 100644
--- a/pack-refs.c
+++ b/pack-refs.c
@@ -72,7 +72,7 @@ static void try_remove_empty_parents(char *name)
for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */
while (*p && *p != '/')
p++;
- /* tolerate duplicate slashes; see check_ref_format() */
+ /* tolerate duplicate slashes; see normalize_refname() */
while (*p == '/')
p++;
}
diff --git a/refs.c b/refs.c
index fd29d89..a206a4c 100644
--- a/refs.c
+++ b/refs.c
@@ -872,10 +872,9 @@ static inline int bad_ref_char(int ch)
return 0;
}
-int check_ref_format(const char *ref)
+int check_ref_format(const char *ref, int flags)
{
int ch, level, last;
- int ret = CHECK_REF_FORMAT_OK;
const char *cp = ref;
level = 0;
@@ -884,41 +883,42 @@ int check_ref_format(const char *ref)
; /* tolerate duplicated slashes */
if (!ch)
/* should not end with slashes */
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
/* we are at the beginning of the path component */
if (ch == '.')
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
if (bad_ref_char(ch)) {
- if (ch == '*' && (!*cp || *cp == '/') &&
- ret == CHECK_REF_FORMAT_OK)
- ret = CHECK_REF_FORMAT_WILDCARD;
+ if ((flags & REFNAME_REFSPEC_PATTERN) && ch == '*' &&
+ (!*cp || *cp == '/'))
+ /* Accept one wildcard as a full refname component. */
+ flags &= ~REFNAME_REFSPEC_PATTERN;
else
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
}
last = ch;
/* scan the rest of the path component */
while ((ch = *cp++) != 0) {
if (bad_ref_char(ch))
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
if (ch == '/')
break;
if (last == '.' && ch == '.')
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
if (last == '@' && ch == '{')
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
last = ch;
}
level++;
if (!ch) {
if (ref <= cp - 2 && cp[-2] == '.')
- return CHECK_REF_FORMAT_ERROR;
- if (level < 2)
- return CHECK_REF_FORMAT_ONELEVEL;
+ return -1;
+ if (level < 2 && !(flags & REFNAME_ALLOW_ONELEVEL))
+ return -1;
if (has_extension(ref, ".lock"))
- return CHECK_REF_FORMAT_ERROR;
- return ret;
+ return -1;
+ return 0;
}
}
}
@@ -1103,7 +1103,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
{
char refpath[PATH_MAX];
- if (check_ref_format(ref))
+ if (check_ref_format(ref, 0))
return NULL;
strcpy(refpath, mkpath("refs/%s", ref));
return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
@@ -1111,13 +1111,9 @@ struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags)
{
- switch (check_ref_format(ref)) {
- default:
+ if (check_ref_format(ref, REFNAME_ALLOW_ONELEVEL))
return NULL;
- case 0:
- case CHECK_REF_FORMAT_ONELEVEL:
- return lock_ref_sha1_basic(ref, old_sha1, flags, NULL);
- }
+ return lock_ref_sha1_basic(ref, old_sha1, flags, NULL);
}
static struct lock_file packlock;
diff --git a/refs.h b/refs.h
index dfb086e..b248ce6 100644
--- a/refs.h
+++ b/refs.h
@@ -97,11 +97,18 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long, voi
*/
extern int for_each_reflog(each_ref_fn, void *);
-#define CHECK_REF_FORMAT_OK 0
-#define CHECK_REF_FORMAT_ERROR (-1)
-#define CHECK_REF_FORMAT_ONELEVEL (-2)
-#define CHECK_REF_FORMAT_WILDCARD (-3)
-extern int check_ref_format(const char *target);
+#define REFNAME_ALLOW_ONELEVEL 1
+#define REFNAME_REFSPEC_PATTERN 2
+
+/*
+ * Return 0 iff ref has the correct format for a refname according to
+ * the rules described in Documentation/git-check-ref-format.txt. If
+ * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
+ * reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
+ * allow a "*" wildcard character in place of one of the name
+ * components.
+ */
+extern int check_ref_format(const char *target, int flags);
extern const char *prettify_refname(const char *refname);
extern char *shorten_unambiguous_ref(const char *ref, int strict);
diff --git a/remote.c b/remote.c
index b8ecfa5..7059885 100644
--- a/remote.c
+++ b/remote.c
@@ -493,23 +493,6 @@ static void read_config(void)
}
/*
- * We need to make sure the remote-tracking branches are well formed, but a
- * wildcard refspec in "struct refspec" must have a trailing slash. We
- * temporarily drop the trailing '/' while calling check_ref_format(),
- * and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL
- * error return is Ok for a wildcard refspec.
- */
-static int verify_refname(char *name, int is_glob)
-{
- int result;
-
- result = check_ref_format(name);
- if (is_glob && result == CHECK_REF_FORMAT_WILDCARD)
- result = CHECK_REF_FORMAT_OK;
- return result;
-}
-
-/*
* This function frees a refspec array.
* Warning: code paths should be checked to ensure that the src
* and dst pointers are always freeable pointers as well
@@ -532,13 +515,13 @@ static void free_refspecs(struct refspec *refspec, int nr_refspec)
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
{
int i;
- int st;
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
for (i = 0; i < nr_refspec; i++) {
size_t llen;
int is_glob;
const char *lhs, *rhs;
+ int flags;
is_glob = 0;
@@ -576,6 +559,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
rs[i].pattern = is_glob;
rs[i].src = xstrndup(lhs, llen);
+ flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
if (fetch) {
/*
@@ -585,26 +569,20 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
*/
if (!*rs[i].src)
; /* empty is ok */
- else {
- st = verify_refname(rs[i].src, is_glob);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL)
- goto invalid;
- }
+ else if (check_ref_format(rs[i].src, flags))
+ goto invalid;
/*
* RHS
* - missing is ok, and is same as empty.
* - empty is ok; it means not to store.
* - otherwise it must be a valid looking ref.
*/
- if (!rs[i].dst) {
+ if (!rs[i].dst)
; /* ok */
- } else if (!*rs[i].dst) {
+ else if (!*rs[i].dst)
; /* ok */
- } else {
- st = verify_refname(rs[i].dst, is_glob);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL)
- goto invalid;
- }
+ else if (check_ref_format(rs[i].dst, flags))
+ goto invalid;
} else {
/*
* LHS
@@ -616,8 +594,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
if (!*rs[i].src)
; /* empty is ok */
else if (is_glob) {
- st = verify_refname(rs[i].src, is_glob);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL)
+ if (check_ref_format(rs[i].src, flags))
goto invalid;
}
else
@@ -630,14 +607,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
* - otherwise it must be a valid looking ref.
*/
if (!rs[i].dst) {
- st = verify_refname(rs[i].src, is_glob);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL)
+ if (check_ref_format(rs[i].src, flags))
goto invalid;
} else if (!*rs[i].dst) {
goto invalid;
} else {
- st = verify_refname(rs[i].dst, is_glob);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL)
+ if (check_ref_format(rs[i].dst, flags))
goto invalid;
}
}
@@ -1427,8 +1402,8 @@ int get_fetch_map(const struct ref *remote_refs,
for (rmp = &ref_map; *rmp; ) {
if ((*rmp)->peer_ref) {
- int st = check_ref_format((*rmp)->peer_ref->name + 5);
- if (st && st != CHECK_REF_FORMAT_ONELEVEL) {
+ if (check_ref_format((*rmp)->peer_ref->name + 5,
+ REFNAME_ALLOW_ONELEVEL)) {
struct ref *ignore = *rmp;
error("* Ignoring funny ref '%s' locally",
(*rmp)->peer_ref->name);
@@ -1620,7 +1595,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla
int len;
/* we already know it starts with refs/ to get here */
- if (check_ref_format(refname + 5))
+ if (check_ref_format(refname + 5, 0))
return 0;
len = strlen(refname) + 1;
diff --git a/sha1_name.c b/sha1_name.c
index ff5992a..975ec3b 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -972,9 +972,9 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
{
strbuf_branchname(sb, name);
if (name[0] == '-')
- return CHECK_REF_FORMAT_ERROR;
+ return -1;
strbuf_splice(sb, 0, 0, "refs/heads/", 11);
- return check_ref_format(sb->buf);
+ return check_ref_format(sb->buf, 0);
}
/*
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 95dcd31..6ac5025 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -81,11 +81,7 @@ valid_ref "$ref" '--refspec-pattern --allow-onelevel'
ref='*'
invalid_ref "$ref"
-
-#invalid_ref "$ref" --allow-onelevel
-test_expect_failure "ref name '$ref' is invalid with options --allow-onelevel" \
- "test_must_fail git check-ref-format --allow-onelevel '$ref'"
-
+invalid_ref "$ref" --allow-onelevel
invalid_ref "$ref" --refspec-pattern
valid_ref "$ref" '--refspec-pattern --allow-onelevel'
diff --git a/transport.c b/transport.c
index fa279d5..225d9b8 100644
--- a/transport.c
+++ b/transport.c
@@ -754,18 +754,9 @@ void transport_verify_remote_names(int nr_heads, const char **heads)
continue;
remote = remote ? (remote + 1) : local;
- switch (check_ref_format(remote)) {
- case 0: /* ok */
- case CHECK_REF_FORMAT_ONELEVEL:
- /* ok but a single level -- that is fine for
- * a match pattern.
- */
- case CHECK_REF_FORMAT_WILDCARD:
- /* ok but ends with a pattern-match character */
- continue;
- }
- die("remote part of refspec is not a valid name in %s",
- heads[i]);
+ if (check_ref_format(remote, REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
+ die("remote part of refspec is not a valid name in %s",
+ heads[i]);
}
}
diff --git a/walker.c b/walker.c
index dce7128..e5d8eb2 100644
--- a/walker.c
+++ b/walker.c
@@ -190,7 +190,7 @@ static int interpret_target(struct walker *walker, char *target, unsigned char *
{
if (!get_sha1_hex(target, sha1))
return 0;
- if (!check_ref_format(target)) {
+ if (!check_ref_format(target, 0)) {
struct ref *ref = alloc_ref(target);
if (!walker->fetch_ref(walker, ref)) {
hashcpy(sha1, ref->old_sha1);
--
1.7.6.8.gd2879
^ permalink raw reply related
* [PATCH 4/6] Add a library function normalize_refname()
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
In-Reply-To: <1315568778-3592-1-git-send-email-mhagger@alum.mit.edu>
Implement check_ref_format() using the new function. Also use it to
replace collapse_slashes() in check-ref-format.c.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
builtin/check-ref-format.c | 41 ++++-------------
refs.c | 109 +++++++++++++++++++++++++++----------------
refs.h | 24 +++++++---
t/t1402-check-ref-format.sh | 3 +
4 files changed, 98 insertions(+), 79 deletions(-)
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index c639400..4c202af 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -11,28 +11,6 @@ static const char builtin_check_ref_format_usage[] =
"git check-ref-format [--print] [options] <refname>\n"
" or: git check-ref-format --branch <branchname-shorthand>";
-/*
- * Remove leading slashes and replace each run of adjacent slashes in
- * src with a single slash, and write the result to dst.
- *
- * This function is similar to normalize_path_copy(), but stripped down
- * to meet check_ref_format's simpler needs.
- */
-static void collapse_slashes(char *dst, const char *src)
-{
- char ch;
- char prev = '/';
-
- while ((ch = *src++) != '\0') {
- if (prev == '/' && ch == prev)
- continue;
-
- *dst++ = ch;
- prev = ch;
- }
- *dst = '\0';
-}
-
static int check_ref_format_branch(const char *arg)
{
struct strbuf sb = STRBUF_INIT;
@@ -45,12 +23,15 @@ static int check_ref_format_branch(const char *arg)
return 0;
}
-static void refname_format_print(const char *arg)
+static int check_ref_format_print(const char *arg, int flags)
{
- char *refname = xmalloc(strlen(arg) + 1);
+ int refnamelen = strlen(arg) + 1;
+ char *refname = xmalloc(refnamelen);
- collapse_slashes(refname, arg);
+ if (normalize_refname(refname, refnamelen, arg, flags))
+ return 1;
printf("%s\n", refname);
+ return 0;
}
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
@@ -79,12 +60,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
}
if (! (i == argc - 1))
usage(builtin_check_ref_format_usage);
-
- if (check_ref_format(argv[i], flags))
- return 1;
-
if (print)
- refname_format_print(argv[i]);
-
- return 0;
+ return check_ref_format_print(argv[i], flags);
+ else
+ return !!check_ref_format(argv[i], flags);
}
diff --git a/refs.c b/refs.c
index a206a4c..372350e 100644
--- a/refs.c
+++ b/refs.c
@@ -872,55 +872,84 @@ static inline int bad_ref_char(int ch)
return 0;
}
-int check_ref_format(const char *ref, int flags)
+int normalize_refname(char *dst, int dstlen, const char *ref, int flags)
{
- int ch, level, last;
- const char *cp = ref;
-
- level = 0;
- while (1) {
- while ((ch = *cp++) == '/')
- ; /* tolerate duplicated slashes */
- if (!ch)
- /* should not end with slashes */
- return -1;
+ int ch, last, component_len, component_count = 0;
+ const char *cp = ref, *component;
- /* we are at the beginning of the path component */
- if (ch == '.')
- return -1;
- if (bad_ref_char(ch)) {
- if ((flags & REFNAME_REFSPEC_PATTERN) && ch == '*' &&
- (!*cp || *cp == '/'))
- /* Accept one wildcard as a full refname component. */
- flags &= ~REFNAME_REFSPEC_PATTERN;
- else
- return -1;
- }
+ ch = *cp;
+ do {
+ while (ch == '/')
+ ch = *++cp; /* tolerate leading and repeated slashes */
- last = ch;
- /* scan the rest of the path component */
- while ((ch = *cp++) != 0) {
- if (bad_ref_char(ch))
- return -1;
- if (ch == '/')
- break;
+ /*
+ * We are at the start of a path component. Record
+ * its start for later reference. If we are copying
+ * to dst, use the copy there, because we might be
+ * overwriting ref; otherwise, use the copy from the
+ * input string.
+ */
+ component = dst ? dst : cp;
+ component_len = 0;
+ last = '\0';
+ while (1) {
+ if (ch != 0 && bad_ref_char(ch)) {
+ if ((flags & REFNAME_REFSPEC_PATTERN) &&
+ ch == '*' &&
+ component_len == 0 &&
+ (cp[1] == 0 || cp[1] == '/')) {
+ /* Accept one wildcard as a full refname component. */
+ flags &= ~REFNAME_REFSPEC_PATTERN;
+ } else {
+ /* Illegal character in refname */
+ return -1;
+ }
+ }
if (last == '.' && ch == '.')
+ /* Refname must not contain "..". */
return -1;
if (last == '@' && ch == '{')
+ /* Refname must not contain "@{". */
return -1;
+ if (dst) {
+ if (dstlen-- <= 0)
+ /* Output array was too small. */
+ return -1;
+ *dst++ = ch;
+ }
+ if (ch == 0 || ch == '/')
+ break;
+ ++component_len;
last = ch;
+ ch = *++cp;
}
- level++;
- if (!ch) {
- if (ref <= cp - 2 && cp[-2] == '.')
- return -1;
- if (level < 2 && !(flags & REFNAME_ALLOW_ONELEVEL))
- return -1;
- if (has_extension(ref, ".lock"))
- return -1;
- return 0;
- }
- }
+
+ /* We are at the end of a path component. */
+ ++component_count;
+ if (component_len == 0)
+ /* Either ref was zero length or it ended with slash. */
+ return -1;
+
+ if (component[0] == '.')
+ /* Components must not start with '.'. */
+ return -1;
+ } while (ch != 0);
+
+ if (last == '.')
+ /* Refname must not end with '.'. */
+ return -1;
+ if (component_len >= 5 && !memcmp(&component[component_len - 5], ".lock", 5))
+ /* Refname must not end with ".lock". */
+ return -1;
+ if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
+ /* Refname must have at least two components. */
+ return -1;
+ return 0;
+}
+
+int check_ref_format(const char *ref, int flags)
+{
+ return normalize_refname(NULL, 0, ref, flags);
}
const char *prettify_refname(const char *name)
diff --git a/refs.h b/refs.h
index b248ce6..8a15f83 100644
--- a/refs.h
+++ b/refs.h
@@ -101,14 +101,24 @@ extern int for_each_reflog(each_ref_fn, void *);
#define REFNAME_REFSPEC_PATTERN 2
/*
- * Return 0 iff ref has the correct format for a refname according to
- * the rules described in Documentation/git-check-ref-format.txt. If
- * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
- * reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
- * allow a "*" wildcard character in place of one of the name
- * components.
+ * Check that ref is a valid refname according to the rules described
+ * in Documentation/git-check-ref-format.txt and normalize it by
+ * stripping out superfluous "/" characters. If dst != NULL, write
+ * the normalized refname to dst, which must be an allocated character
+ * array with length dstlen (typically at least as long as ref). dst
+ * may point at the same memory as ref. Return 0 iff the refname was
+ * OK and fit into dst. If REFNAME_ALLOW_ONELEVEL is set in flags,
+ * then accept one-level reference names. If REFNAME_REFSPEC_PATTERN
+ * is set in flags, then allow a "*" wildcard characters in place of
+ * one of the name components.
*/
-extern int check_ref_format(const char *target, int flags);
+extern int normalize_refname(char *dst, int dstlen, const char *ref, int flags);
+
+/*
+ * Return 0 iff ref has the correct format for a refname. See
+ * normalize_refname() for details.
+ */
+extern int check_ref_format(const char *ref, int flags);
extern const char *prettify_refname(const char *refname);
extern char *shorten_unambiguous_ref(const char *ref, int strict);
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 6ac5025..20a7782 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -39,6 +39,7 @@ invalid_ref 'heads/foo..bar'
invalid_ref 'heads/foo?bar'
valid_ref 'foo./bar'
invalid_ref 'heads/foo.lock'
+invalid_ref 'heads///foo.lock'
valid_ref 'heads/foo@bar'
invalid_ref 'heads/v@{ation'
invalid_ref 'heads/foo\bar'
@@ -152,5 +153,7 @@ invalid_ref_normalized '/foo'
invalid_ref_normalized 'heads/foo/../bar'
invalid_ref_normalized 'heads/./foo'
invalid_ref_normalized 'heads\foo'
+invalid_ref_normalized 'heads/foo.lock'
+invalid_ref_normalized 'heads///foo.lock'
test_done
--
1.7.6.8.gd2879
^ permalink raw reply related
* [PATCH 1/6] Change bad_ref_char() to return a boolean value
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
In-Reply-To: <1315568778-3592-1-git-send-email-mhagger@alum.mit.edu>
Previously most bad characters were indicated by returning 1, but "*"
was special-cased to return 2 instead of 1. One caller examined the
return value to see whether the special case occurred.
But it is easier (to document and understand) for bad_ref_char()
simply to return a boolean value, treating "*" like any other bad
character. Special-case the handling of "*" (which only occurs in
very specific circumstances) at the caller. The resulting calling
code thereby also becomes more transparent.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
This is just a random refactoring.
refs.c | 15 ++++++---------
1 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/refs.c b/refs.c
index a615043..fd29d89 100644
--- a/refs.c
+++ b/refs.c
@@ -860,22 +860,21 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
* - it contains a "\" (backslash)
*/
+/* Return true iff ch is not allowed in reference names. */
static inline int bad_ref_char(int ch)
{
if (((unsigned) ch) <= ' ' || ch == 0x7f ||
ch == '~' || ch == '^' || ch == ':' || ch == '\\')
return 1;
/* 2.13 Pattern Matching Notation */
- if (ch == '?' || ch == '[') /* Unsupported */
+ if (ch == '*' || ch == '?' || ch == '[') /* Unsupported */
return 1;
- if (ch == '*') /* Supported at the end */
- return 2;
return 0;
}
int check_ref_format(const char *ref)
{
- int ch, level, bad_type, last;
+ int ch, level, last;
int ret = CHECK_REF_FORMAT_OK;
const char *cp = ref;
@@ -890,9 +889,8 @@ int check_ref_format(const char *ref)
/* we are at the beginning of the path component */
if (ch == '.')
return CHECK_REF_FORMAT_ERROR;
- bad_type = bad_ref_char(ch);
- if (bad_type) {
- if (bad_type == 2 && (!*cp || *cp == '/') &&
+ if (bad_ref_char(ch)) {
+ if (ch == '*' && (!*cp || *cp == '/') &&
ret == CHECK_REF_FORMAT_OK)
ret = CHECK_REF_FORMAT_WILDCARD;
else
@@ -902,8 +900,7 @@ int check_ref_format(const char *ref)
last = ch;
/* scan the rest of the path component */
while ((ch = *cp++) != 0) {
- bad_type = bad_ref_char(ch);
- if (bad_type)
+ if (bad_ref_char(ch))
return CHECK_REF_FORMAT_ERROR;
if (ch == '/')
break;
--
1.7.6.8.gd2879
^ permalink raw reply related
* [PATCH 0/6] Improved infrastructure for refname normalization
From: Michael Haggerty @ 2011-09-09 11:46 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, cmn, Michael Haggerty
As a prerequisite to storing references caches hierarchically (itself
needed for performance reasons), here is a patch series to help us get
refname normalization under control.
The problem is that some UI accepts unnormalized reference names (like
"/foo/bar" or "foo///bar" instead of "foo/bar") and passes them on to
library routines without normalizing them. The library, on the other
hand, assumes that the refnames are normalized. Sometimes (mostly in
the case of loose references) unnormalized refnames happen to work,
but in other cases (like packed references or when looking up refnames
in the cache) they silently fail. Given that refnames are sometimes
treated as path names, there is a chance that some security-relevant
bugs are lurking in this area, if not in git proper then in scripts
that interact with git.
This patch series adds the following tools for dealing with refnames
and their normalization (without actually doing much to fix the
problem; see below):
* Fix check_ref_format() to make it easier and reliable to specify
which types of refnames are allowed in a particular situation
(multi-level vs. one-level, with vs. without a refspec-like "*",
normalized or unnormalized).
* Add a function normalize_refname() that can check and optionally
normalize refnames according to the one true set of rules.
* Add options to "git check-ref-format" to give scripts access to
these facilities (and to allow them to be tested in the test suite).
* Forbid ".lock" at the end of any refname component, as directories
with such names can conflict with attempts to create lock files for
other refnames.
The patches just provide the tools for handling refnames more
consistently. How do we actually fix the problem of inconsistent
handling of refname normalization? First we need policy. I suggest
the following:
Unnormalized refnames should only be accepted at the UI level and
should be normalized before use. This can be done using code like
char normalized_refname[strlen(arg) + 1];
if (normalize_refname(normalized_refname, sizeof(normalized_refname),
arg, REFNAME_ALLOW_UNNORMALIZED|other_flags))
die("invalid refname '%s'", arg);
/* From now on, use normalized_refname. */
Refnames coming from other sources, such as from a remote repository,
should be checked that they are in the correct *normalized* format,
like so:
if (check_ref_format(refname, other_flags))
die("invalid refname '%s'", refname);
Refnames from the local repository (e.g., from the packed references
file) should also be checked that they are in the correct normalized
format, though this policy could be debated if there are performance
concerns.
Refnames probably do not need to be checked at the entrance to the
refs.{c,h} library functions because callers are responsible for not
passing invalid or unnormalized refnames in. However, some assert()s
would probably be justified, especially during the transition while we
are fixing broken callers.
If there is agreement about this policy, I would be happy to write it
up (presumably in Documentation/technical/api-ref.txt, maybe also
incorporating the content from
Documentation/technical/api-ref-iteration.txt).
I do not yet have enough global overview of the code to know which
callers need fixing, but once these tools are in place the callers can
be fixed incrementally.
Michael Haggerty (6):
Change bad_ref_char() to return a boolean value
git check-ref-format: add options --onelevel-ok and --refname-pattern
Change check_ref_format() to take a flags argument
Add a library function normalize_refname()
Do not allow ".lock" at the end of any refname component
Add a REFNAME_ALLOW_UNNORMALIZED flag to check_ref_format()
Documentation/git-check-ref-format.txt | 42 ++++++++--
builtin/check-ref-format.c | 62 ++++++++--------
builtin/checkout.c | 2 +-
builtin/fetch-pack.c | 2 +-
builtin/receive-pack.c | 3 +-
builtin/replace.c | 2 +-
builtin/show-ref.c | 2 +-
builtin/tag.c | 4 +-
connect.c | 2 +-
environment.c | 2 +-
fast-import.c | 7 +--
notes-merge.c | 5 +-
pack-refs.c | 2 +-
refs.c | 133 +++++++++++++++++++-------------
refs.h | 30 ++++++-
remote.c | 55 ++++---------
sha1_name.c | 4 +-
t/t1402-check-ref-format.sh | 93 ++++++++++++++++++++--
transport.c | 18 ++---
walker.c | 2 +-
20 files changed, 294 insertions(+), 178 deletions(-)
--
1.7.6.8.gd2879
^ permalink raw reply
* merge result
From: Lynn Lin @ 2011-09-09 10:54 UTC (permalink / raw)
To: git
Hi All,
When I merge branch A back to master branch,if there are same
commit(developer do double commit) both in master and A branch, there
will be two same commit in master branch.For example
1->2->3-4>5 Master
|
4->6->7 A
When I merge A branch into master,the two same 4 commit will present
in master branch.
Is there any wrong with my operation?
Thanks for your help
Lynn
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: John Szakmeister @ 2011-09-09 10:54 UTC (permalink / raw)
To: kusmabite; +Cc: git, Kyle Neath, Jeff King
In-Reply-To: <CABPQNSbrjNR73GxE4xXFPqaVSUOaa5Drt4Je+zGY82rzajQxuw@mail.gmail.com>
On Fri, Sep 9, 2011 at 6:48 AM, Erik Faye-Lund <kusmabite@gmail.com> wrote:
[snip]
> Actually, it seems recent Windows versions does have a credential
> manager, including an API:
>
> http://www.yanzzee.com/2009/09/windows-keychain.html
> http://msdn.microsoft.com/en-us/library/aa374731(v=VS.85).aspx#credentials_management_functions
Yay! It's about time they grew that feature. :-)
-John
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: Erik Faye-Lund @ 2011-09-09 10:48 UTC (permalink / raw)
To: John Szakmeister; +Cc: git, Kyle Neath, Jeff King
In-Reply-To: <CAEBDL5VtVZcmQnj2CH7XzZ0YV_X61gO69-dXriGiYsAqk=NLPg@mail.gmail.com>
On Fri, Sep 9, 2011 at 12:32 PM, John Szakmeister <john@szakmeister.net> wrote:
> [Added back some of the CC's]
>
> Ted: we don't usually cull the CC list on the git mailing list.
>
> 2011/9/9 Ted Zlatanov <tzz@lifelogs.com>:
> [snip]
>> MJG> ... and one for Git on Windows? It seems we're lacking both Win and OS X
>> MJG> developers here.
>>
>> Windows doesn't have a standard keychain service, does it?
>
> No, it doesn't, but you can use the wincrypt API which allows you to
> at least encrypt the password from the user's login credentials. In
> particular, CryptProtectData() and CryptUnprotectData(). That way you
> can at least have the password stored encrypted on disk.
Actually, it seems recent Windows versions does have a credential
manager, including an API:
http://www.yanzzee.com/2009/09/windows-keychain.html
http://msdn.microsoft.com/en-us/library/aa374731(v=VS.85).aspx#credentials_management_functions
^ permalink raw reply
* Re: can Git encrypt/decrypt .gpg on push/fetch?
From: Aneesh Bhasin @ 2011-09-09 10:50 UTC (permalink / raw)
To: tzz; +Cc: git
In-Reply-To: <87lityxbg7.fsf@lifelogs.com>
Hi Ted,
2011/9/9 Ted Zlatanov <tzz@lifelogs.com>
>
> I need to store some encrypted files in Git but for some clients with
> the right GPG keys, decrypt them on checkout (possibly also encrypt them
> back on commit, but that's not as important).
>
> diff doesn't have to work, this is just for convenience. Can Git do
> this (matching only .gpg files) or do I need my own command to run after
> the checkout/fetch and before commit? It seems pretty out of Git's
> scope but perhaps others have done this before.
>
Have you looked at git hooks (e.g. here : http://progit.org/book/ch7-3.html).
You could do the encryption/decryption in pre-commit and post-checkout
hooks scripts respectively...
regards,
Aneesh
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: John Szakmeister @ 2011-09-09 10:32 UTC (permalink / raw)
To: git; +Cc: Kyle Neath, Jeff King
In-Reply-To: <87pqjaxbrm.fsf@lifelogs.com>
[Added back some of the CC's]
Ted: we don't usually cull the CC list on the git mailing list.
2011/9/9 Ted Zlatanov <tzz@lifelogs.com>:
[snip]
> MJG> ... and one for Git on Windows? It seems we're lacking both Win and OS X
> MJG> developers here.
>
> Windows doesn't have a standard keychain service, does it?
No, it doesn't, but you can use the wincrypt API which allows you to
at least encrypt the password from the user's login credentials. In
particular, CryptProtectData() and CryptUnprotectData(). That way you
can at least have the password stored encrypted on disk.
-John
^ permalink raw reply
* can Git encrypt/decrypt .gpg on push/fetch?
From: Ted Zlatanov @ 2011-09-09 10:22 UTC (permalink / raw)
To: git
I need to store some encrypted files in Git but for some clients with
the right GPG keys, decrypt them on checkout (possibly also encrypt them
back on commit, but that's not as important).
diff doesn't have to work, this is just for convenience. Can Git do
this (matching only .gpg files) or do I need my own command to run after
the checkout/fetch and before commit? It seems pretty out of Git's
scope but perhaps others have done this before.
Thanks
Ted
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: Ted Zlatanov @ 2011-09-09 10:15 UTC (permalink / raw)
To: git
In-Reply-To: <4E69C8F0.9070204@drmicha.warpmail.net>
On Fri, 09 Sep 2011 10:06:08 +0200 Michael J Gruber <git@drmicha.warpmail.net> wrote:
>> In the meantime, the best thing we can do to push it forward is to write
>> helpers. I implemented some basic ones that should work anywhere, but
>> aren't as nice as integration with existing keychains. Some people are
>> working on Linux ones. The single best thing GitHub can do to push this
>> forward right now is to provide a well-written OS X Keychain helper, and
>> to provide feedback on whether git's end of the API is good enough.
MJG> ... and one for Git on Windows? It seems we're lacking both Win and OS X
MJG> developers here.
Windows doesn't have a standard keychain service, does it?
The OS X Keychain helper should be pretty easy in terms of the system
calls (he says after a quick Google search), the hard part IMHO is
figuring out the right way to store credentials in it. There are
several ways to structure the schema.
For modern Linux systems it's best to target the Secrets API, which is
DBUS and XML-based and works with both the KDE and GNOME keychains. I
only know about it what I have learned from Michael Albinus' interface
in the Emacs source tree, but it certainly seems capable enough. This
is what Jeff King was alluding to, I think, about what I'm working on.
I have not been able to work on it so far, not for lack of trying.
My #1 target is to implement a GPG-based credential helper using a
netrc-style file. I believe that would be the most useful one, though
not the easiest one to set up for inexperienced users.
Ted
^ permalink raw reply
* [PATCH v3] date.c: Support iso8601 timezone formats
From: Haitao Li @ 2011-09-09 10:10 UTC (permalink / raw)
To: gitster; +Cc: Haitao Li, git
In-Reply-To: <1315320996-1997-1-git-send-email-lihaitao@gmail.com>
Timezone designators including additional separator (`:`) are ignored.
Actually zone designators in below formats are all valid according to
ISO8601:2004, section 4.3.2:
[+-]hh, [+-]hhmm, [+-]hh:mm
Steps to reproduce the issue this patch fixes:
$ mkdir /tmp/test
$ cd /tmp/test
$ git init
$ echo 'timezone' > file.txt
$ git add .
$ git update-index
$ git write-tree
3e168d57e1c32a4598af134430384f0587581503
# Commit the tree returned above. Give a date with colon separated
# timezone
$ echo "Test commit" | \
TZ=UTC GIT_AUTHOR_DATE='2011-09-03T12:34:56+08:00' \
git commit-tree 3e168d57e1c32a4598af134430384f0587581503 | \
xargs git show | grep Date
Date: Sat Sep 3 12:34:56 2011 +0000
while the expected result is:
Date: Sat Sep 3 12:34:56 2011 +0800
^---
This patch teaches git recognizing zone designators with hours and
minutes separated by colon, or minutes are empty.
Signed-off-by: Haitao Li <lihaitao@gmail.com>
---
date.c | 32 ++++++++++++++++++++++++++------
t/t0006-date.sh | 5 +++++
2 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/date.c b/date.c
index 896fbb4..f8722c1 100644
--- a/date.c
+++ b/date.c
@@ -556,15 +556,35 @@ static int match_tz(const char *date, int *offp)
int min, hour;
int n = end - date - 1;
- min = offset % 100;
- hour = offset / 100;
+ /*
+ * ISO8601:2004(E) allows time zone designator been separated
+ * by a clone in the extended format
+ */
+ if (*end == ':') {
+ if (isdigit(end[1])) {
+ hour = offset;
+ min = strtoul(end+1, &end, 10);
+ } else {
+ /* Mark as invalid */
+ n = -1;
+ }
+ } else {
+ if (n == 1 || n == 2) {
+ /* Only hours specified */
+ hour = offset;
+ min = 0;
+ } else {
+ hour = offset / 100;
+ min = offset % 100;
+ }
+ }
/*
- * Don't accept any random crap.. At least 3 digits, and
- * a valid minute. We might want to check that the minutes
- * are divisible by 30 or something too.
+ * Don't accept any random crap.. We might want to check that
+ * the minutes are divisible by 15 or something too. (Offset of
+ * Kathmandu, Nepal is UTC+5:45)
*/
- if (min < 60 && n > 2) {
+ if (n > 0 && min < 60) {
offset = hour*60+min;
if (*date == '-')
offset = -offset;
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index f87abb5..5235b7a 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -40,6 +40,11 @@ check_parse 2008-02 bad
check_parse 2008-02-14 bad
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'
check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
+check_parse '2008-02-14 20:30:45 -0015' '2008-02-14 20:30:45 -0015'
+check_parse '2008-02-14 20:30:45 -5' '2008-02-14 20:30:45 -0500'
+check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500'
+check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
+check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
check_approxidate() {
--
1.7.5.4
^ permalink raw reply related
* Re: git-p4.skipSubmitEdit
From: Vitor Antunes @ 2011-09-09 10:05 UTC (permalink / raw)
To: git
In-Reply-To: <1315514452.10046.0.camel@uncle-pecos>
L. A. Linden Levy <alevy <at> mobitv.com> writes:
>
> Hi All,
>
> I have been using git-p4 for a while and it has allowed me to completely
> change the way I develop and still be able to use perforce which my
> company has for its main VCS. One thing that was driving me nuts was
> that "git p4 submit" cycles through all of my individual commits and
> asks me if I want to change them. The way I develop I often am checking
> in 20 to 50 different small commits each with a descriptive git comment.
> I felt like I was doing double duty by having emacs open on every commit
> into perforce. So I modified git-p4 to have an option to skip the
> editor. This option coupled with git-p4.skipSubmitEditCheck will make
> the submission non-interactive for "git p4 submit".
Hi Loren,
This option was already included in a recent commit. The name that was
used is "skipSubmitEditCheck". Please make sure you are using the most
recent version of the script.
But don't let this discourage you from submitting patches. Just makesure
you clone git's repository and apply your patch over "maint" or "master"
branches. For more details on how to submit patches you can read
Documentation/SubmittingPatches.
Vitor
^ permalink raw reply
* Re: git credential helper design [was: What's cooking in git.git (Aug 2011, #07; Wed, 24)]
From: John Szakmeister @ 2011-09-09 9:55 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Lukas Sandström, Ted Zlatanov, git
In-Reply-To: <20110831023801.GB3340@sigill.intra.peff.net>
On Tue, Aug 30, 2011 at 10:38 PM, Jeff King <peff@peff.net> wrote:
[snip]
> It's "http:github.com", which has always looked a bit ugly to me. I had
> hoped they would just be opaque blobs and nobody would need to look at
> them. But when you get into things like setting the username via the
> config, then users see them, and they need to look sane. Making them
> look more like a canonicalized URL is probably a good thing.
A little feedback here: I do look into my keychain on Mac OS X. I
tend to keep most of my credentials in a separate keychain that gets
whenever my computer sleeps or the screen saver kicks on. So that
blob ends up being user-visible to some degree. Could I munge it into
something else? Sure. But I do wonder if it might be better to make
it something closer to what the user expects to see.
> After seeing the helper that Lukas posted recently on the list, I am
> wondering if they should include the username, too. I had left it
> separate, because I wanted helpers to be able to index "foo@example.com"
> and "example.com" in the same slot. I.e., to realize that the latter
> could use the same credentials cached for the former. But it also
> complicates the helpers; instead of doing:
Having the username separate is useful. At least under Mac OS X, the
"account name" field is a separate search field. It does make it
easier to fallback to just looking at the domain and path without
having to parse the unique token. But as it is, we stand a chance at
being able to reuse credentials already cached by the browser.
> credential = secure_storage_lookup(unique_token);
> return credential /* could be NULL */
>
> they have to do:
>
> for credential in secure_storage_lookup(unique_token) {
> if (!username)
> return credential; /* take first one arbitrarily */
> else if (username == credential.username)
> return credential; /* ok, matched preferred username */
> }
> return NULL;
>
> which implies that the secure storage can even store a list indexed
> under the token.
>
> So perhaps a better model is to give the helper some canonicalized URL,
> like:
>
> https://foo@example.com
>
> (where the canonicalization is important, because we want the helper to
> be able to just treat it like a string of bytes if it wants). And then
> we can naturally extend that to:
>
> https://foo@example.com/specific-repo.git
>
> if the user wants a repo-specific authentication context.
Or pass that the information via --domain and --path parameters. It'd
be nice to keep most credential backends from having to parse urls.
Not that its hard, just cumbersome. But the keychain implementation
and the gnome-keyring implementation could both benefit from having
the pieces broken out separately. Likewise, it's probably not
difficult to parse it out of the token if we needed to.
[snip good discussion]
One thing that crossed my mind while looking at this: what happens
when a command is meant to be non-interactive? Looking at the
kdewallet implementation, it appears that not only is the credential
helper intended to help do the lookup, but also ask the user for a
password, if it doesn't find anything. That doesn't seem like it
would play well in a non-interactive environment. Additionally, the
act of looking up the entry could pop up a dialog in most
keychain-like applications. Is there a need to be sensitive to the
fact that we may be run non-interactively?
-John
^ permalink raw reply
* [PATCH 2/2] pretty: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:53 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Alexey Shumkin
In-Reply-To: <1315558437-6295-1-git-send-email-zapped@mail.ru>
The following two ought to give the same output to a terminal:
$ git log --oneline --no-color
$ git log --pretty=format:'%h %s'
However, the former pays attention to i18n.logOutputEncoding
configuration, while the latter does not when it format "%s". A log
messages written in an encoding i18n.commitEncoding that differs
from terminal encoding are shown corrupted with the latter even
when i18n.logOutputEncoding and terminal encoding are the same.
The same corruption is true for
$ git diff --submodule=log
and
$ git rev-list --pretty=format:%s HEAD
Signed-off-by: Alexey Shumkin <zapped@mail.ru>
---
builtin/rev-list.c | 1 +
builtin/shortlog.c | 1 +
log-tree.c | 1 +
submodule.c | 3 +++
4 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 56727e8..831077d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -105,6 +105,7 @@ static void show_commit(struct commit *commit, void *data)
ctx.abbrev = revs->abbrev;
ctx.date_mode = revs->date_mode;
ctx.fmt = revs->commit_format;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &buf);
if (revs->graph) {
if (buf.len) {
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 37f3193..eba4086 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -163,6 +163,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &ufbuf);
buffer = ufbuf.buf;
} else if (*buffer) {
diff --git a/log-tree.c b/log-tree.c
index e945701..39913d7 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -488,6 +488,7 @@ void show_log(struct rev_info *opt)
ctx.preserve_subject = opt->preserve_subject;
ctx.reflog_info = opt->reflog_info;
ctx.fmt = opt->commit_format;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &msgbuf);
if (opt->add_signoff)
diff --git a/submodule.c b/submodule.c
index b6dec70..26efef4 100644
--- a/submodule.c
+++ b/submodule.c
@@ -213,10 +213,13 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
static const char format[] = " %m %s";
struct strbuf sb = STRBUF_INIT;
struct commit *commit;
+ const char *log_output_encoding;
+ log_output_encoding = get_log_output_encoding();
while ((commit = get_revision(rev))) {
struct pretty_print_context ctx = {0};
ctx.date_mode = rev->date_mode;
+ ctx.output_encoding = log_output_encoding;
strbuf_setlen(&sb, 0);
if (commit->object.flags & SYMMETRIC_LEFT) {
if (del)
--
1.7.6.1.g8f21c
^ permalink raw reply related
* [PATCH 1/2] pretty: Add failing tests: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:53 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Alexey Shumkin
In-Reply-To: <1315558437-6295-1-git-send-email-zapped@mail.ru>
The following two ought to give the same output to a terminal:
$ git log --oneline --no-color
$ git log --pretty=format:'%h %s'
However, the former pays attention to i18n.logOutputEncoding
configuration, while the latter does not when it format "%s". A log
messages written in an encoding i18n.commitEncoding that differs
from terminal encoding are shown corrupted with the latter even
when i18n.logOutputEncoding and terminal encoding are the same.
The same corruption is true for
$ git diff --submodule=log
and
$ git rev-list --pretty=format:%s HEAD
Signed-off-by: Alexey Shumkin <zapped@mail.ru>
---
t/t4041-diff-submodule-option.sh | 44 +++++----
t/t4205-log-pretty-formats.sh | 22 ++++-
t/t6006-rev-list-format.sh | 192 +++++++++++++++++++++++---------------
3 files changed, 161 insertions(+), 97 deletions(-)
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index bf9a752..4460cff 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Support for verbose submodule differences in git diff
@@ -10,6 +11,7 @@ This test tries to verify the sanity of the --submodule option of git diff.
. ./test-lib.sh
+added=$(printf "\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275")
add_file () {
sm=$1
shift
@@ -19,8 +21,12 @@ add_file () {
echo "$name" > "$name" &&
git add "$name" &&
test_tick &&
- git commit -m "Add $name"
+ git config i18n.commitEncoding cp1251 &&
+ echo "Add $name ($added $name)" \
+ | iconv -f utf-8 -t cp1251 \
+ | xargs -I{} git commit -m "{}"
done >/dev/null
+ git config --unset i18n.commitEncoding
git rev-parse --verify HEAD | cut -c1-7
cd "$owd"
}
@@ -37,7 +43,7 @@ head1=$(add_file sm1 foo1 foo2)
test_expect_success 'added submodule' "
git add sm1 &&
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 0000000...$head1 (new submodule)
EOF
test_cmp expected actual
@@ -48,27 +54,27 @@ head2=$(add_file sm1 foo3)
test_expect_success 'modified submodule(forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
test_expect_success 'modified submodule(forward)' "
git diff --submodule=log >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
test_expect_success 'modified submodule(forward) --submodule' "
git diff --submodule >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
@@ -98,10 +104,10 @@ head3=$(
test_expect_success 'modified submodule(backward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head2..$head3 (rewind):
- < Add foo3
- < Add foo2
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
"
@@ -110,12 +116,12 @@ head4=$(add_file sm1 foo4 foo5) &&
head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
test_expect_success 'modified submodule(backward and forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head2...$head4:
- > Add foo5
- > Add foo4
- < Add foo3
- < Add foo2
+ > Add foo5 ($added foo5)
+ > Add foo4 ($added foo4)
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
"
@@ -131,10 +137,10 @@ mv sm1-bak sm1
test_expect_success 'typechanged submodule(submodule->blob), --cached' "
git diff --submodule=log --cached >actual &&
cat >expected <<-EOF &&
-Submodule sm1 41fbea9...0000000 (submodule deleted)
+Submodule sm1 $head4...0000000 (submodule deleted)
diff --git a/sm1 b/sm1
new file mode 100644
-index 0000000..9da5fb8
+index 0000000..$head5
--- /dev/null
+++ b/sm1
@@ -0,0 +1 @@
@@ -148,7 +154,7 @@ test_expect_success 'typechanged submodule(submodule->blob)' "
cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
deleted file mode 100644
-index 9da5fb8..0000000
+index $head5..0000000
--- a/sm1
+++ /dev/null
@@ -1 +0,0 @@
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 2ae9faa..96e0229 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2010, Will Palmer
+# Copyright (c) 2011, Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Test pretty formats'
@@ -11,10 +12,13 @@ test_expect_success 'set up basic repos' '
>bar &&
git add foo &&
test_tick &&
- git commit -m initial &&
+ git config i18n.commitEncoding cp1251 &&
+ printf "initial \320\272\320\276\320\274\320\274\320\270\321\202" \
+ | iconv -f utf-8 -t cp1251 | xargs -I{} git commit -m "{}" &&
git add bar &&
test_tick &&
- git commit -m "add bar"
+ git commit -m "add bar" &&
+ git config --unset i18n.commitEncoding
'
test_expect_success 'alias builtin format' '
@@ -38,6 +42,20 @@ test_expect_success 'alias user-defined format' '
test_cmp expected actual
'
+test_expect_success 'alias user-defined tformat with %s (cp1251 encoding)' '
+ git config i18n.logOutputEncoding cp1251 &&
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ git config --unset i18n.logOutputEncoding &&
+ test_cmp expected-s actual-s
+'
+
+test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' '
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ test_cmp expected-s actual-s
+'
+
test_expect_success 'alias user-defined tformat' '
git log --pretty="tformat:%h" >expected &&
git config pretty.test-alias "tformat:%h" &&
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index d918cc0..8d99635 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -1,13 +1,34 @@
#!/bin/sh
+# Copyright (c) 2009 Jens Lehmann
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
+
test_description='git rev-list --pretty=format test'
. ./test-lib.sh
test_tick
+added=$(printf "added (\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275) foo")
+added_cp1251=$(echo "$added" | iconv -f utf-8 -t cp1251)
+changed=$(printf "changed (\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275) foo")
+changed_cp1251=$(echo "$changed" | iconv -f utf-8 -t cp1251)
+
test_expect_success 'setup' '
-touch foo && git add foo && git commit -m "added foo" &&
- echo changed >foo && git commit -a -m "changed foo"
+ touch foo &&
+ git add foo &&
+ git config i18n.commitEncoding cp1251 &&
+ git commit -m "$added_cp1251" &&
+ head1=$(git rev-parse --verify HEAD) &&
+ head1_7=$(echo $head1 | cut -c1-7) &&
+ echo "$changed" > foo &&
+ git commit -a -m "$changed_cp1251" &&
+ head2=$(git rev-parse --verify HEAD) &&
+ head2_7=$(echo $head2 | cut -c1-7) &&
+ tree2=$(git cat-file -p HEAD | grep tree | cut -f 2 -d" ") &&
+ tree2_7=$(echo $tree2 | cut -c1-7) &&
+ head2_parent=$(git cat-file -p HEAD | grep parent | cut -f 2 -d" ") &&
+ head2_parent_7=$(echo $head2_parent | cut -c1-7) &&
+ git config --unset i18n.commitEncoding
'
# usage: test_format name format_string <expected_output
@@ -19,49 +40,49 @@ test_cmp expect.$1 output.$1
"
}
-test_format percent %%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format percent %%h <<EOF
+commit $head2
%h
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
%h
EOF
-test_format hash %H%n%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-131a310eb913d107dd3c09a65d1651175898735d
-131a310
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
+test_format hash %H%n%h <<EOF
+commit $head2
+$head2
+$head2_7
+commit $head1
+$head1
+$head1_7
EOF
-test_format tree %T%n%t <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-fe722612f26da5064c32ca3843aa154bdb0b08a0
-fe72261
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format tree %T%n%t <<EOF
+commit $head2
+$tree2
+$tree2_7
+commit $head1
4d5fcadc293a348e88f777dc0920f11e7d71441c
4d5fcad
EOF
-test_format parents %P%n%p <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format parents %P%n%p <<EOF
+commit $head2
+$head1
+$head2_parent_7
+commit $head1
EOF
# we don't test relative here
-test_format author %an%n%ae%n%ad%n%aD%n%at <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format author %an%n%ae%n%ad%n%aD%n%at <<EOF
+commit $head2
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -69,14 +90,14 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<EOF
+commit $head2
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -84,86 +105,105 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format encoding %e <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format encoding %e <<EOF
+commit $head2
+commit $head1
EOF
-test_format subject %s <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+expected=$(printf "commit $head2\n\
+$changed\n\
+commit $head1\n\
+$added
+")
+
+test_format subject %s <<EOF
+$expected
EOF
-test_format body %b <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format body %b <<EOF
+commit $head2
+commit $head1
EOF
-test_format raw-body %B <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
+expected=$(printf "commit $head2\n\
+$changed\n\
+\n\
+commit $head1\n\
+$added
+")
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+test_format raw-body %B <<EOF
+$expected
EOF
-test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF
+commit $head2
^[[31mfoo^[[32mbar^[[34mbaz^[[mxyzzy
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
^[[31mfoo^[[32mbar^[[34mbaz^[[mxyzzy
EOF
-test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF
+commit $head2
^[[1;31;43mfoo^[[m
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
^[[1;31;43mfoo^[[m
EOF
-cat >commit-msg <<'EOF'
+iconv -f utf-8 -t cp1251 > commit-msg <<EOF
Test printing of complex bodies
This commit message is much longer than the others,
-and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+and it will be encoded in cp1251. We should therefore
+include an cp1251 character: так вот!
EOF
+
test_expect_success 'setup complex body' '
-git config i18n.commitencoding iso8859-1 &&
- echo change2 >foo && git commit -a -F commit-msg
+ git config i18n.commitencoding cp1251 &&
+ echo change2 >foo && git commit -a -F commit-msg &&
+ head3=$(git rev-parse --verify HEAD) &&
+ head3_7=$(echo $head3 | cut -c1-7)
'
-test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
-iso8859-1
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format complex-encoding %e <<EOF
+commit $head3
+cp1251
+commit $head2
+cp1251
+commit $head1
+cp1251
EOF
-test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
-Test printing of complex bodies
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+# unset commit encoding config
+# otherwise %e does not print encoding value
+# and following test fails
+git config --unset i18n.commitencoding
+
+expected=$(printf "commit $head3\n\
+Test printing of complex bodies\n\
+commit $head2\n\
+$changed\n\
+commit $head1\n\
+$added
+")
+
+test_format complex-subject %s <<EOF
+$expected
EOF
-test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+test_format complex-body %b <<EOF
+commit $head3
This commit message is much longer than the others,
-and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+and it will be encoded in cp1251. We should therefore
+include an cp1251 character: так вот!
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head2
+commit $head1
EOF
test_expect_success '%x00 shows NUL' '
- echo >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+ echo >expect commit $head3 &&
echo >>expect fooQbar &&
git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
nul_to_q <actual.nul >actual &&
@@ -210,12 +250,12 @@ test_expect_success 'add LF before non-empty (2)' '
test_expect_success 'add SP before non-empty (1)' '
git show -s --pretty=format:"%s% bThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 2
+ test $(wc -w <actual) = 3
'
test_expect_success 'add SP before non-empty (2)' '
git show -s --pretty=format:"%s% sThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 4
+ test $(wc -w <actual) = 6
'
test_expect_success '--abbrev' '
--
1.7.6.1.g8f21c
^ permalink raw reply related
* [PATCH v2] pretty: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:53 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
In-Reply-To: <7vwrf6qh49.fsf@alter.siamese.dyndns.org>
Ooops! previuos message haven't Cc-ed to Junio.
This one is CC-ed.
I discovered two more commands affected with this bug.
So I reroll this patch and tests for it.
>>(question) Does this change affect other commands, most notably
>>format-patch, and if so how?
No, it does not affect format-patch
---
builtin/rev-list.c | 1 +
builtin/shortlog.c | 1 +
log-tree.c | 1 +
submodule.c | 3 +
t/t4041-diff-submodule-option.sh | 44 +++++----
t/t4205-log-pretty-formats.sh | 22 ++++-
t/t6006-rev-list-format.sh | 192 +++++++++++++++++++++++---------------
7 files changed, 167 insertions(+), 97 deletions(-)
^ permalink raw reply
* [PATCH 2/2] pretty: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:43 UTC (permalink / raw)
To: git; +Cc: Alexey Shumkin
In-Reply-To: <1315557806-5555-1-git-send-email-zapped@mail.ru>
The following two ought to give the same output to a terminal:
$ git log --oneline --no-color
$ git log --pretty=format:'%h %s'
However, the former pays attention to i18n.logOutputEncoding
configuration, while the latter does not when it format "%s". A log
messages written in an encoding i18n.commitEncoding that differs
from terminal encoding are shown corrupted with the latter even
when i18n.logOutputEncoding and terminal encoding are the same.
The same corruption is true for
$ git diff --submodule=log
and
$ git rev-list --pretty=format:%s HEAD
Signed-off-by: Alexey Shumkin <zapped@mail.ru>
---
builtin/rev-list.c | 1 +
builtin/shortlog.c | 1 +
log-tree.c | 1 +
submodule.c | 3 +++
4 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 56727e8..831077d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -105,6 +105,7 @@ static void show_commit(struct commit *commit, void *data)
ctx.abbrev = revs->abbrev;
ctx.date_mode = revs->date_mode;
ctx.fmt = revs->commit_format;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &buf);
if (revs->graph) {
if (buf.len) {
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 37f3193..eba4086 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -163,6 +163,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &ufbuf);
buffer = ufbuf.buf;
} else if (*buffer) {
diff --git a/log-tree.c b/log-tree.c
index e945701..39913d7 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -488,6 +488,7 @@ void show_log(struct rev_info *opt)
ctx.preserve_subject = opt->preserve_subject;
ctx.reflog_info = opt->reflog_info;
ctx.fmt = opt->commit_format;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &msgbuf);
if (opt->add_signoff)
diff --git a/submodule.c b/submodule.c
index b6dec70..26efef4 100644
--- a/submodule.c
+++ b/submodule.c
@@ -213,10 +213,13 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
static const char format[] = " %m %s";
struct strbuf sb = STRBUF_INIT;
struct commit *commit;
+ const char *log_output_encoding;
+ log_output_encoding = get_log_output_encoding();
while ((commit = get_revision(rev))) {
struct pretty_print_context ctx = {0};
ctx.date_mode = rev->date_mode;
+ ctx.output_encoding = log_output_encoding;
strbuf_setlen(&sb, 0);
if (commit->object.flags & SYMMETRIC_LEFT) {
if (del)
--
1.7.6.1.g8f21c
^ permalink raw reply related
* [PATCH 1/2] pretty: Add failing tests: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:43 UTC (permalink / raw)
To: git; +Cc: Alexey Shumkin
In-Reply-To: <1315557806-5555-1-git-send-email-zapped@mail.ru>
The following two ought to give the same output to a terminal:
$ git log --oneline --no-color
$ git log --pretty=format:'%h %s'
However, the former pays attention to i18n.logOutputEncoding
configuration, while the latter does not when it format "%s". A log
messages written in an encoding i18n.commitEncoding that differs
from terminal encoding are shown corrupted with the latter even
when i18n.logOutputEncoding and terminal encoding are the same.
The same corruption is true for
$ git diff --submodule=log
and
$ git rev-list --pretty=format:%s HEAD
Signed-off-by: Alexey Shumkin <zapped@mail.ru>
---
t/t4041-diff-submodule-option.sh | 44 +++++----
t/t4205-log-pretty-formats.sh | 22 ++++-
t/t6006-rev-list-format.sh | 192 +++++++++++++++++++++++---------------
3 files changed, 161 insertions(+), 97 deletions(-)
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index bf9a752..4460cff 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Support for verbose submodule differences in git diff
@@ -10,6 +11,7 @@ This test tries to verify the sanity of the --submodule option of git diff.
. ./test-lib.sh
+added=$(printf "\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275")
add_file () {
sm=$1
shift
@@ -19,8 +21,12 @@ add_file () {
echo "$name" > "$name" &&
git add "$name" &&
test_tick &&
- git commit -m "Add $name"
+ git config i18n.commitEncoding cp1251 &&
+ echo "Add $name ($added $name)" \
+ | iconv -f utf-8 -t cp1251 \
+ | xargs -I{} git commit -m "{}"
done >/dev/null
+ git config --unset i18n.commitEncoding
git rev-parse --verify HEAD | cut -c1-7
cd "$owd"
}
@@ -37,7 +43,7 @@ head1=$(add_file sm1 foo1 foo2)
test_expect_success 'added submodule' "
git add sm1 &&
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 0000000...$head1 (new submodule)
EOF
test_cmp expected actual
@@ -48,27 +54,27 @@ head2=$(add_file sm1 foo3)
test_expect_success 'modified submodule(forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
test_expect_success 'modified submodule(forward)' "
git diff --submodule=log >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
test_expect_success 'modified submodule(forward) --submodule' "
git diff --submodule >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
"
@@ -98,10 +104,10 @@ head3=$(
test_expect_success 'modified submodule(backward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head2..$head3 (rewind):
- < Add foo3
- < Add foo2
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
"
@@ -110,12 +116,12 @@ head4=$(add_file sm1 foo4 foo5) &&
head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
test_expect_success 'modified submodule(backward and forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- cat >expected <<-EOF &&
+ cat >expected <<EOF
Submodule sm1 $head2...$head4:
- > Add foo5
- > Add foo4
- < Add foo3
- < Add foo2
+ > Add foo5 ($added foo5)
+ > Add foo4 ($added foo4)
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
"
@@ -131,10 +137,10 @@ mv sm1-bak sm1
test_expect_success 'typechanged submodule(submodule->blob), --cached' "
git diff --submodule=log --cached >actual &&
cat >expected <<-EOF &&
-Submodule sm1 41fbea9...0000000 (submodule deleted)
+Submodule sm1 $head4...0000000 (submodule deleted)
diff --git a/sm1 b/sm1
new file mode 100644
-index 0000000..9da5fb8
+index 0000000..$head5
--- /dev/null
+++ b/sm1
@@ -0,0 +1 @@
@@ -148,7 +154,7 @@ test_expect_success 'typechanged submodule(submodule->blob)' "
cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
deleted file mode 100644
-index 9da5fb8..0000000
+index $head5..0000000
--- a/sm1
+++ /dev/null
@@ -1 +0,0 @@
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 2ae9faa..96e0229 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2010, Will Palmer
+# Copyright (c) 2011, Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Test pretty formats'
@@ -11,10 +12,13 @@ test_expect_success 'set up basic repos' '
>bar &&
git add foo &&
test_tick &&
- git commit -m initial &&
+ git config i18n.commitEncoding cp1251 &&
+ printf "initial \320\272\320\276\320\274\320\274\320\270\321\202" \
+ | iconv -f utf-8 -t cp1251 | xargs -I{} git commit -m "{}" &&
git add bar &&
test_tick &&
- git commit -m "add bar"
+ git commit -m "add bar" &&
+ git config --unset i18n.commitEncoding
'
test_expect_success 'alias builtin format' '
@@ -38,6 +42,20 @@ test_expect_success 'alias user-defined format' '
test_cmp expected actual
'
+test_expect_success 'alias user-defined tformat with %s (cp1251 encoding)' '
+ git config i18n.logOutputEncoding cp1251 &&
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ git config --unset i18n.logOutputEncoding &&
+ test_cmp expected-s actual-s
+'
+
+test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' '
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ test_cmp expected-s actual-s
+'
+
test_expect_success 'alias user-defined tformat' '
git log --pretty="tformat:%h" >expected &&
git config pretty.test-alias "tformat:%h" &&
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index d918cc0..8d99635 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -1,13 +1,34 @@
#!/bin/sh
+# Copyright (c) 2009 Jens Lehmann
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
+
test_description='git rev-list --pretty=format test'
. ./test-lib.sh
test_tick
+added=$(printf "added (\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275) foo")
+added_cp1251=$(echo "$added" | iconv -f utf-8 -t cp1251)
+changed=$(printf "changed (\320\264\320\276\320\261\320\260\320\262\320\273\320\265\320\275) foo")
+changed_cp1251=$(echo "$changed" | iconv -f utf-8 -t cp1251)
+
test_expect_success 'setup' '
-touch foo && git add foo && git commit -m "added foo" &&
- echo changed >foo && git commit -a -m "changed foo"
+ touch foo &&
+ git add foo &&
+ git config i18n.commitEncoding cp1251 &&
+ git commit -m "$added_cp1251" &&
+ head1=$(git rev-parse --verify HEAD) &&
+ head1_7=$(echo $head1 | cut -c1-7) &&
+ echo "$changed" > foo &&
+ git commit -a -m "$changed_cp1251" &&
+ head2=$(git rev-parse --verify HEAD) &&
+ head2_7=$(echo $head2 | cut -c1-7) &&
+ tree2=$(git cat-file -p HEAD | grep tree | cut -f 2 -d" ") &&
+ tree2_7=$(echo $tree2 | cut -c1-7) &&
+ head2_parent=$(git cat-file -p HEAD | grep parent | cut -f 2 -d" ") &&
+ head2_parent_7=$(echo $head2_parent | cut -c1-7) &&
+ git config --unset i18n.commitEncoding
'
# usage: test_format name format_string <expected_output
@@ -19,49 +40,49 @@ test_cmp expect.$1 output.$1
"
}
-test_format percent %%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format percent %%h <<EOF
+commit $head2
%h
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
%h
EOF
-test_format hash %H%n%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-131a310eb913d107dd3c09a65d1651175898735d
-131a310
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
+test_format hash %H%n%h <<EOF
+commit $head2
+$head2
+$head2_7
+commit $head1
+$head1
+$head1_7
EOF
-test_format tree %T%n%t <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-fe722612f26da5064c32ca3843aa154bdb0b08a0
-fe72261
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format tree %T%n%t <<EOF
+commit $head2
+$tree2
+$tree2_7
+commit $head1
4d5fcadc293a348e88f777dc0920f11e7d71441c
4d5fcad
EOF
-test_format parents %P%n%p <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format parents %P%n%p <<EOF
+commit $head2
+$head1
+$head2_parent_7
+commit $head1
EOF
# we don't test relative here
-test_format author %an%n%ae%n%ad%n%aD%n%at <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format author %an%n%ae%n%ad%n%aD%n%at <<EOF
+commit $head2
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -69,14 +90,14 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<EOF
+commit $head2
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -84,86 +105,105 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format encoding %e <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format encoding %e <<EOF
+commit $head2
+commit $head1
EOF
-test_format subject %s <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+expected=$(printf "commit $head2\n\
+$changed\n\
+commit $head1\n\
+$added
+")
+
+test_format subject %s <<EOF
+$expected
EOF
-test_format body %b <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format body %b <<EOF
+commit $head2
+commit $head1
EOF
-test_format raw-body %B <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
+expected=$(printf "commit $head2\n\
+$changed\n\
+\n\
+commit $head1\n\
+$added
+")
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+test_format raw-body %B <<EOF
+$expected
EOF
-test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF
+commit $head2
^[[31mfoo^[[32mbar^[[34mbaz^[[mxyzzy
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
^[[31mfoo^[[32mbar^[[34mbaz^[[mxyzzy
EOF
-test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF
+commit $head2
^[[1;31;43mfoo^[[m
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
^[[1;31;43mfoo^[[m
EOF
-cat >commit-msg <<'EOF'
+iconv -f utf-8 -t cp1251 > commit-msg <<EOF
Test printing of complex bodies
This commit message is much longer than the others,
-and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+and it will be encoded in cp1251. We should therefore
+include an cp1251 character: так вот!
EOF
+
test_expect_success 'setup complex body' '
-git config i18n.commitencoding iso8859-1 &&
- echo change2 >foo && git commit -a -F commit-msg
+ git config i18n.commitencoding cp1251 &&
+ echo change2 >foo && git commit -a -F commit-msg &&
+ head3=$(git rev-parse --verify HEAD) &&
+ head3_7=$(echo $head3 | cut -c1-7)
'
-test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
-iso8859-1
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format complex-encoding %e <<EOF
+commit $head3
+cp1251
+commit $head2
+cp1251
+commit $head1
+cp1251
EOF
-test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
-Test printing of complex bodies
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+# unset commit encoding config
+# otherwise %e does not print encoding value
+# and following test fails
+git config --unset i18n.commitencoding
+
+expected=$(printf "commit $head3\n\
+Test printing of complex bodies\n\
+commit $head2\n\
+$changed\n\
+commit $head1\n\
+$added
+")
+
+test_format complex-subject %s <<EOF
+$expected
EOF
-test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+test_format complex-body %b <<EOF
+commit $head3
This commit message is much longer than the others,
-and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+and it will be encoded in cp1251. We should therefore
+include an cp1251 character: так вот!
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head2
+commit $head1
EOF
test_expect_success '%x00 shows NUL' '
- echo >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+ echo >expect commit $head3 &&
echo >>expect fooQbar &&
git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
nul_to_q <actual.nul >actual &&
@@ -210,12 +250,12 @@ test_expect_success 'add LF before non-empty (2)' '
test_expect_success 'add SP before non-empty (1)' '
git show -s --pretty=format:"%s% bThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 2
+ test $(wc -w <actual) = 3
'
test_expect_success 'add SP before non-empty (2)' '
git show -s --pretty=format:"%s% sThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 4
+ test $(wc -w <actual) = 6
'
test_expect_success '--abbrev' '
--
1.7.6.1.g8f21c
^ permalink raw reply related
* [PATCH v2] pretty: user format ignores i18n.logOutputEncoding setting
From: Alexey Shumkin @ 2011-09-09 8:43 UTC (permalink / raw)
To: git
In-Reply-To: <7vwrf6qh49.fsf@alter.siamese.dyndns.org>
I discovered two more commands affected with this bug.
So I reroll this patch and tests for it.
>>(question) Does this change affect other commands, most notably
format-patch, and if so how?
No, it does not affect format-patc
---
builtin/rev-list.c | 1 +
builtin/shortlog.c | 1 +
log-tree.c | 1 +
submodule.c | 3 +
t/t4041-diff-submodule-option.sh | 44 +++++----
t/t4205-log-pretty-formats.sh | 22 ++++-
t/t6006-rev-list-format.sh | 192 +++++++++++++++++++++++---------------
7 files changed, 167 insertions(+), 97 deletions(-)
^ permalink raw reply
* Re: git repository size / compression
From: Carlos Martín Nieto @ 2011-09-09 8:23 UTC (permalink / raw)
To: neubyr; +Cc: git
In-Reply-To: <CALFxCvzVjC+u=RDkDCQp0QqPETsv8ROE8tY=37tmMWxmQoJOEw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2087 bytes --]
On Thu, 2011-09-08 at 21:37 -0500, neubyr wrote:
> I have a test git repository with just two files in it. One of the
> file in it has a set of two lines that is repeated n times.
> e.g.:
> {{{
> $ for i in {1..5}; do cat ./lexico.txt >> lexico1.txt && cat
> ./lexico.txt >> lexico1.txt && mv ./lexico1.txt ./lexico.txt; done
> }}}
>
So you've just created some data that can be compressed quite
efficiently.
> I ran above command few times and performed commit after each run. Now
> disk usage of this repository directory is mentioned below. The 419M
> is working directory size and 2.7M is git repository/database size.
>
> {{{
> $ du -h -d 1 .
> 2.7M ./.git
> 419M .
>
> }}}
>
> Is it because of the compression performed by git before storing data
> (or before sending commit)??
>
Yes. Git stores its objects (the commit, the snapshot of the files,
etc.) compressed. When these objects are stored in a pack, the size can
be further reduced by storing some objects as deltas which describe the
difference between itself and some other object in the object-db.
> Following were results with subversion:
>
> Subversion client (redundant(?) copy exists in .svn/text-base/
> directory, hence double size in client):
> {{{
> $ du -h -d 1
> 416M ./.svn
> 832M .
> }}}
Subversion stores the "pristines" (which is the status of the files in
the latest revision) inside the .svn directory. I wouldn't call this
copy redundant, though, as it allows you to run diff locally. The
pristines are stored uncompressed, which is why you half of the space is
taken up by the .svn directory.
>
> Subversion repo/server:
> {{{
> $ du -h -d 1
> 12K ./conf
> 1.2M ./db
> 36K ./hooks
> 8.0K ./locks
> 1.2M .
> }}}
I don't know how the repository is stored in Subversion, but it may also
be compressed. You may be able to reduced your git repository size by
(re)generating packs with 'git repack' and doing some cleanups with 'git
gc', but the repository size is not often a concern.
cmn
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: Miles Bader @ 2011-09-09 8:12 UTC (permalink / raw)
To: Michael J Gruber; +Cc: Jeff King, John Szakmeister, Kyle Neath, git
In-Reply-To: <4E69C8DC.7060008@drmicha.warpmail.net>
Michael J Gruber <git@drmicha.warpmail.net> writes:
>> Agreed. Anything harder than ssh keys is right out the window,
>> because they're always the alternative these people could be using
>> (but can't or don't want to).
>
> Sue, the question was: What is easy enough? I hoped that people
> would be using gpg to check signed tags, and that there might be a
> simple, convenient gnupg installer for Win and Mac which ties into
> the respective wallet systems or provides one they use already.
I wouldn't be surprised if many people just don't check signed tags at
all -- if the repositories they're using even have them in the first
place -- particularly amongst the audience in question.
-miles
--
What the fuck do white people have to be blue about!? Banana Republic ran
out of Khakis? The Espresso Machine is jammed? Hootie and The Blowfish
are breaking up??! Shit, white people oughtta understand, their job is to
GIVE people the blues, not to get them! -- George Carlin
^ permalink raw reply
* Re: The imporantance of including http credential caching in 1.7.7
From: Michael J Gruber @ 2011-09-09 8:06 UTC (permalink / raw)
To: Jeff King; +Cc: Kyle Neath, git
In-Reply-To: <20110908191053.GA16064@sigill.intra.peff.net>
Jeff King venit, vidit, dixit 08.09.2011 21:10:
> On Wed, Sep 07, 2011 at 02:56:03PM +0200, Michael J Gruber wrote:
>
>> So, it's been a year or more that you've been aware of the importance
>> of this issue (from your/github's perspective), and we hear about it
>> now, at the end of the rc phase. I don't know whether
>> jk/http-auth-keyring has been done on github payroll or during spare
>> time.
>
> To be absolutely clear here, this feature was 100% paid for by GitHub
> (which isn't to say that I don't think it's a good idea. On the
> contrary, I think it's awesome; but GitHub money is what provided the
> time for me to work on it).
>
> When I started at GitHub in January, I was given a giant list of things
> that GitHub felt would make core git better, but that they hadn't the
> personnel to improve. And I was told to use my own judgement in adding
> or removing items from the list based on what I thought git needed, and
> to prioritize as I saw fit. The fact that it took six months for me to
> come up with credential patches is because that's how long it took me to
> figure out what I wanted to write, and to clear my backlog of other git
> tasks.
>
> So I think the wheels have been turning on this for quite a while from
> GitHub's perspective.
Thanks for clarifying. While it should make no difference for the
acceptance of patches, it's great to see GitHub invest into scratching
their Git itches, and thus contribute back. That's how open source works
as a business model :)
...
> In the meantime, the best thing we can do to push it forward is to write
> helpers. I implemented some basic ones that should work anywhere, but
> aren't as nice as integration with existing keychains. Some people are
> working on Linux ones. The single best thing GitHub can do to push this
> forward right now is to provide a well-written OS X Keychain helper, and
> to provide feedback on whether git's end of the API is good enough.
... and one for Git on Windows? It seems we're lacking both Win and OS X
developers here.
... continuing in the other subthread...
^ 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