* Re: OS X and umlauts in file names
From: Martin Langhoff @ 2009-11-25 10:19 UTC (permalink / raw)
To: Thomas Singer; +Cc: Daniel Barkalow, git
In-Reply-To: <46a038f90911250207o214b3952s67a022a017dbe2d9@mail.gmail.com>
On Wed, Nov 25, 2009 at 11:07 AM, Martin Langhoff
<martin.langhoff@gmail.com> wrote:
> On Wed, Nov 25, 2009 at 9:50 AM, Thomas Singer
> <thomas.singer@syntevo.com> wrote:
>> toms-mac-mini:git-umlauts tom$ git stage "U\314\210berla\314\210nge.txt"
>> fatal: pathspec 'U\314\210berla\314\210nge.txt' did not match any files
>
> does a find * | xargs git add work?
Also, you can try with `find * -print0 | git-update-index --add
--stdin -z `. Find should report the exact filename that the OS has,
and git should add it as it is.
Background: git-add used to be a trivial shell script wrapping around
git-update-index. If you have a git checkout, try:
git show f25933987f29070e9cd79dfddf03018010e82e80:git-add.sh
If git cannot track this file in a pure OSX world, there is a good
chance it's a bug in git.
In in this narrow test case (single machine, running OSX) git *must*
be able to do the right thing. If you work on multi-platform projects
however, there is a good chance a Windows or Linux user will commit a
file with a name that _when you checkout on OSX_, OSX will save with a
different (but "equivalent") name due to its funny decomposition
rules. And all sorts of "fun" will ensue.
cheers,
m
--
martin.langhoff@gmail.com
martin@laptop.org -- School Server Architect
- ask interesting questions
- don't get distracted with shiny stuff - working code first
- http://wiki.laptop.org/go/User:Martinlanghoff
^ permalink raw reply
* Client-side mirroring patches (v0)
From: Sam Vilain @ 2009-11-25 10:06 UTC (permalink / raw)
To: git
Hey folks, this is the first stage of git mirroring - making the
client support it in the face of a completely ignorant server. I
intended to make the clean-up better, but I've been sitting on these
for a couple of weeks so I thought it would be better to have them out
there for people to have a squiz at.
The next stage would be for the mirror list to be communicated to
clients over the network protocol and updated in the git config.
Also there is the matter of falling over to the next mirror should one
not be reachable, but then we're getting into C weaknesses really.
Should I plan to do exception recovery using 'longjmp' ? Also the
process should be interruptible and provide a user menu. Again this
seems like it would be very tedious and clumsy in C. How do people
manage? Anyway, enjoy... Sam
^ permalink raw reply
* [PATCH 3/4] fetch --use-mirror: don't fetch with 'autotags' for actual fetch
From: Sam Vilain @ 2009-11-25 10:06 UTC (permalink / raw)
To: git; +Cc: Sam Vilain
In-Reply-To: <1259143617-26580-3-git-send-email-sam@vilain.net>
Unsetting 'autotags' at a late stage during the fetch process has the
useful behaviour of figuring out which refs to fetch where according to the
regular autotags rules, building a refspec (struct ref* linked list), and
then we turn them off for mirror fetch and no real tags are actually
changed, just the re-written ones under refs/mirrors/. The final fetch
will re-set autotags again, and uncannily the exact behaviour we are after
springs up: we get all the tags for the refs that are now changing, even
though we got the data from a mirror. All from one line of code. Win!
Signed-off-by: Sam Vilain <sam@vilain.net>
---
builtin-fetch.c | 1 +
t/t5560-mirror-fetch.sh | 12 +++++++++++-
2 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index b3b8766..daa287a 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -269,6 +269,7 @@ static struct ref *get_ref_map(struct transport *transport,
find_non_local_tags(transport, &ref_map, &tail);
ref_remove_duplicates(ref_map);
if (strcmp(transport->url, transport->remote->url[0]) != 0) {
+ *autotags = 0;
return mirror_refmap(transport, ref_map);
}
diff --git a/t/t5560-mirror-fetch.sh b/t/t5560-mirror-fetch.sh
index 940dc0e..58d5f3c 100644
--- a/t/t5560-mirror-fetch.sh
+++ b/t/t5560-mirror-fetch.sh
@@ -11,11 +11,13 @@ test_expect_success setup '
echo >file master initial &&
git add file &&
git commit -a -m "Master initial" &&
+ git tag -m "SEEN" initial &&
git clone . master &&
git clone master mirror &&
cd master &&
echo >file master update &&
git commit -a -m "Master update" &&
+ git tag -m "SEEN" update &&
cd .. &&
mkdir clone &&
cd clone &&
@@ -35,12 +37,20 @@ test_expect_success 'fetch using mirror - explicit' '
test_expect_success 'fetch using mirror - default' '
cd .. &&
+ cd mirror &&
+ git tag -m "badtag" badtag &&
+ cd .. &&
mkdir clone2 &&
cd clone2 &&
git init &&
git remote add origin ../master &&
git config remote.origin.mirror-url ../mirror
git fetch --use-mirror &&
- git rev-parse refs/mirrors/origin/localhost/heads/master
+ git rev-parse refs/mirrors/origin/localhost/heads/master &&
+ git rev-parse refs/mirrors/origin/localhost/tags/initial &&
+ ! git rev-parse refs/tags/badtag &&
+ git rev-parse refs/tags/initial &&
+ git rev-parse refs/tags/update
'
+
test_done
--
1.6.3.3
^ permalink raw reply related
* [PATCH 4/4] fetch: cleanup refs with --use-mirror
From: Sam Vilain @ 2009-11-25 10:06 UTC (permalink / raw)
To: git; +Cc: Sam Vilain
In-Reply-To: <1259143617-26580-4-git-send-email-sam@vilain.net>
Remove identical refs after a successful fetch. The ref under
'refs/mirrors/HOST/XXX' is compared with 'refs/XXX', and if matched,
then the 'refs/mirrors/' version is removed.
Signed-off-by: Sam Vilain <sam@vilain.net>
---
This is a simple mechanism for removing stale mirror refs; a more
sophisticated approach would use the revision walker.
builtin-fetch.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index daa287a..0c52f23 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -211,6 +211,57 @@ struct ref *mirror_refmap(struct transport* transport,
return rv;
}
+int clean_up_mirror_ref(const char *refname,
+ const unsigned char *sha1,
+ int flags,
+ void *leading)
+{
+ char *orig_refname;
+ char *target_refname;
+ char *x;
+ unsigned char found_sha1[20];
+
+ orig_refname = xmalloc(strlen(refname)+strlen(leading)+1);
+ x = strchr(refname, '/');
+ if (!x)
+ return 0;
+ target_refname = xmalloc(strlen(x)+strlen("refs/remotes/")+1);
+
+ strcpy(orig_refname, leading);
+ x = orig_refname + strlen(leading);
+ strcpy(x, refname);
+
+ warning("cleaning up mirror ref: %s (%s)",
+ orig_refname, sha1_to_hex(sha1));
+
+ strcpy(target_refname, "refs/remotes/");
+ strcpy(target_refname+5, strchr(refname, '/')+1);
+
+ warning("target ref is %s", target_refname);
+
+ if (resolve_ref(target_refname, found_sha1, 1, NULL)) {
+ if (!hashcmp(found_sha1, sha1)) {
+ warning("deleting ref %s", orig_refname);
+ delete_ref(orig_refname, sha1, REF_NODEREF);
+ }
+ }
+}
+
+void clean_up_mirror_refs(struct remote* remote)
+{
+ int rem_l = strlen(remote->name);
+ char *dst_name = xmalloc(rem_l+14);
+ char *x;
+ strcpy(dst_name, "refs/mirrors/");
+ x = dst_name + 13;
+ strcpy(x, remote->name);
+ x += rem_l;
+ *x++ = '/';
+
+ warning("cleaning up mirror refs for remote %s", remote->name);
+ for_each_ref_in(dst_name, clean_up_mirror_ref,
+ (void *)dst_name);
+}
static struct ref *get_ref_map(struct transport *transport,
struct refspec *refs, int ref_count, int tags,
@@ -884,9 +935,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
transport = NULL;
urls_remaining--;
if (use_mirror) {
- if (!exit_code && urls_remaining >= 1) {
- warning("successful fetch from mirror");
- urls_remaining = 1;
+ if (!exit_code) {
+ if (urls_remaining >= 1) {
+ warning("successful fetch from mirror");
+ urls_remaining = 1;
+ }
+ else {
+ clean_up_mirror_refs(remote);
+ }
}
if (urls_remaining == 1) {
transport = real_transport;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/4] fetch: try mirrors if selected
From: Sam Vilain @ 2009-11-25 10:06 UTC (permalink / raw)
To: git; +Cc: Sam Vilain
In-Reply-To: <1259143617-26580-2-git-send-email-sam@vilain.net>
If configured and selected, the mirrors are tried in turn until one
succeeds, re-writing the refs to a refs/mirrors/<remote>/<hostname>/ space.
No refs from the mirrors are ever written to the real refs/heads or
refs/tags spaces, but their being available locally will speed up fetching
from the real remote if they are more up to date than the local version.
Signed-off-by: Sam Vilain <sam@vilain.net>
---
builtin-fetch.c | 161 ++++++++++++++++++++++++++++++++++++++++++++--
remote.c | 14 ++++-
remote.h | 1 +
t/t5560-mirror-fetch.sh | 46 +++++++++++++
transport.c | 41 ++++++++++++
transport.h | 5 ++
6 files changed, 260 insertions(+), 8 deletions(-)
create mode 100644 t/t5560-mirror-fetch.sh
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 209f502..b3b8766 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -45,8 +45,8 @@ static struct option builtin_fetch_options[] = {
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
"allow updating of HEAD ref"),
- OPT_BOOLEAN('M', "mirror", &use_mirror,
- "use mirror if available"),
+ OPT_SET_INT('M', "use-mirror", &use_mirror,
+ "use mirror if available", 1),
OPT_STRING(0, "depth", &depth, "DEPTH",
"deepen history of shallow clone"),
OPT_END()
@@ -109,6 +109,109 @@ static void find_non_local_tags(struct transport *transport,
struct ref **head,
struct ref ***tail);
+char* get_url_hostname(const char *url)
+{
+ char *scratch = xstrdup(url);
+ char *host = strstr(url, "://");
+ char c;
+ char *end, *rh;
+ if (host) {
+ host += 3;
+ c = '/';
+ }
+ else {
+ host = scratch;
+ c = ':';
+ }
+
+ if (host[0] == '[') {
+ end = strchr(host + 1, ']');
+ if (end) {
+ *end = 0;
+ host++;
+ }
+ }
+ else {
+ end = strchr(host, c);
+ if (end && !has_dos_drive_prefix(url) ) {
+ *end = 0;
+ }
+ else {
+ host = "localhost";
+ }
+ }
+ rh = xstrdup(host);
+ free(scratch);
+ return rh;
+}
+
+const char *mirror_ref(const char* remote_name, const char* mirror_hostname,
+ const char* refname)
+{
+ int has_refs, new_sz;
+ char *rv, *dst;
+
+ // *rs[i] = *refspec[i]; ?
+ has_refs = ( strstr(refname, "refs/") == refname );
+ /* "refs/"(0 or 5) "mirrors/"(8) remote "/"(1) hostname "/"(1) */
+ new_sz = (has_refs ? 0 : 5) + 8
+ + strlen(remote_name) + 1
+ + strlen(mirror_hostname) + 1
+ + strlen(refname) + 1;
+ rv = xmalloc( new_sz );
+ strcpy(rv, "refs/mirrors/");
+ dst = rv + 13;
+ strcpy(dst, remote_name);
+ dst += strlen(remote_name);
+ *dst++ = '/';
+ strcpy(dst, mirror_hostname);
+ dst += strlen(mirror_hostname);
+ *dst++ = '/';
+ strcpy(dst, refname+(has_refs?5:0));
+ return rv;
+}
+
+struct ref *mirror_refmap(struct transport* transport,
+ struct ref* ref_map)
+{
+ struct ref *rm, *mirror_refmap, *last, *rv, *peer_ref;
+
+ const char* remote_name = transport->remote->name;
+ const char* mirror_hostname = get_url_hostname(transport->url);
+ int c = 0;
+
+ last = NULL;
+ rv = NULL;
+ for (rm = ref_map; rm; rm = rm->next) {
+ const char *new_dst;
+
+ // skip refs we already have locally, to avoid ref churn
+ if (has_sha1_file(rm->old_sha1))
+ continue;
+
+ mirror_refmap = alloc_ref(rm->name);
+ mirror_refmap->remote_status = rm->remote_status;
+ hashcpy(mirror_refmap->old_sha1, rm->old_sha1);
+ hashcpy(mirror_refmap->new_sha1, rm->new_sha1);
+
+ if (last)
+ last->next = mirror_refmap;
+ else
+ rv = mirror_refmap;
+ c++;
+
+ new_dst = mirror_ref(remote_name, mirror_hostname, rm->name);
+
+ peer_ref = alloc_ref(new_dst);
+ mirror_refmap->peer_ref = peer_ref;
+ peer_ref->force = 1;
+ last = mirror_refmap;
+ }
+
+ return rv;
+}
+
+
static struct ref *get_ref_map(struct transport *transport,
struct refspec *refs, int ref_count, int tags,
int *autotags)
@@ -165,10 +268,14 @@ static struct ref *get_ref_map(struct transport *transport,
if (tags == TAGS_DEFAULT && *autotags)
find_non_local_tags(transport, &ref_map, &tail);
ref_remove_duplicates(ref_map);
+ if (strcmp(transport->url, transport->remote->url[0]) != 0) {
+ return mirror_refmap(transport, ref_map);
+ }
return ref_map;
}
+
#define STORE_REF_ERROR_OTHER 1
#define STORE_REF_ERROR_DF_CONFLICT 2
@@ -638,6 +745,7 @@ static int do_fetch(struct transport *transport,
}
ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
+
if (!update_head_ok)
check_not_current_branch(ref_map);
@@ -688,13 +796,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
int i;
static const char **refs = NULL;
int ref_nr = 0;
- int exit_code;
+ int exit_code = 0;
+ int urls_remaining = 1;
+ struct transport *real_transport = NULL;
+ const char *mirror = NULL;
+ struct refspec *refspec;
/* Record the command line for the reflog */
strbuf_addstr(&default_rla, "fetch");
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
+ use_mirror = -1;
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
@@ -706,6 +819,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (!remote)
die("Where do you want to fetch from today?");
+ if (use_mirror == -1) {
+ use_mirror = remote->use_mirror ? 1 : 0;
+ }
+
transport = transport_get(remote, remote->url[0]);
if (verbosity >= 2)
transport->verbose = 1;
@@ -742,9 +859,39 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
- exit_code = do_fetch(transport,
- parse_fetch_refspec(ref_nr, refs), ref_nr);
- transport_disconnect(transport);
- transport = NULL;
+ refspec = parse_fetch_refspec(ref_nr, refs);
+ if (use_mirror) {
+ real_transport = transport;
+ urls_remaining = remote->mirror_url_nr + 1;
+ }
+ while (urls_remaining) {
+ if (use_mirror && (urls_remaining > 1) ) {
+ transport = transport_next_mirror(real_transport, mirror);
+ mirror = transport->url;
+ warning("trying mirror: %s", mirror);
+ // real_transport may not have these options - re-set them.
+ if (upload_pack)
+ set_option(TRANS_OPT_UPLOADPACK, upload_pack);
+ if (keep)
+ set_option(TRANS_OPT_KEEP, "yes");
+ if (depth)
+ set_option(TRANS_OPT_DEPTH, depth);
+
+ }
+ exit_code = do_fetch(transport, refspec, ref_nr);
+ transport_disconnect(transport);
+ transport = NULL;
+ urls_remaining--;
+ if (use_mirror) {
+ if (!exit_code && urls_remaining >= 1) {
+ warning("successful fetch from mirror");
+ urls_remaining = 1;
+ }
+ if (urls_remaining == 1) {
+ transport = real_transport;
+ warning("trying master: %s", transport->url);
+ }
+ }
+ }
return exit_code;
}
diff --git a/remote.c b/remote.c
index 65df03d..5f08e10 100644
--- a/remote.c
+++ b/remote.c
@@ -139,8 +139,9 @@ static struct remote *make_remote(const char *name, int len)
for (i = 0; i < remotes_nr; i++) {
if (len ? (!strncmp(name, remotes[i]->name, len) &&
!remotes[i]->name[len]) :
- !strcmp(name, remotes[i]->name))
+ !strcmp(name, remotes[i]->name)) {
return remotes[i];
+ }
}
ret = xcalloc(1, sizeof(struct remote));
@@ -683,6 +684,7 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
}
+
static int valid_remote_nick(const char *name)
{
if (!name[0] || is_dot_or_dotdot(name))
@@ -786,6 +788,16 @@ int remote_has_url(struct remote *remote, const char *url)
return 0;
}
+int remote_mirror_idx(struct remote *remote, const char *mirror_url)
+{
+ int i;
+ for (i = 0; i < remote->mirror_url_nr; i++) {
+ if (!strcmp(remote->mirror_url[i], mirror_url))
+ return i;
+ }
+ return -1;
+}
+
static int match_name_with_pattern(const char *key, const char *name,
const char *value, char **result)
{
diff --git a/remote.h b/remote.h
index c720b9a..da208ff 100644
--- a/remote.h
+++ b/remote.h
@@ -61,6 +61,7 @@ typedef int each_remote_fn(struct remote *remote, void *priv);
int for_each_remote(each_remote_fn fn, void *priv);
int remote_has_url(struct remote *remote, const char *url);
+int remote_mirror_idx(struct remote *remote, const char *mirror_url);
struct refspec {
unsigned force : 1;
diff --git a/t/t5560-mirror-fetch.sh b/t/t5560-mirror-fetch.sh
new file mode 100644
index 0000000..940dc0e
--- /dev/null
+++ b/t/t5560-mirror-fetch.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Sam Vilain
+#
+
+test_description='mirror fetch test'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo >file master initial &&
+ git add file &&
+ git commit -a -m "Master initial" &&
+ git clone . master &&
+ git clone master mirror &&
+ cd master &&
+ echo >file master update &&
+ git commit -a -m "Master update" &&
+ cd .. &&
+ mkdir clone &&
+ cd clone &&
+ git init &&
+ git remote add origin ../master &&
+ git config remote.origin.mirror-url ../mirror
+'
+
+# in later iterations we'll expect these mirror tracking refs to be
+# cleaned up once they are confirmed reachable from the master, but
+# for now they leave a sufficient breadcrumb of the operation
+
+test_expect_success 'fetch using mirror - explicit' '
+ git fetch --use-mirror origin refs/heads/*:refs/remotes/origin/* &&
+ git rev-parse refs/mirrors/origin/localhost/heads/master
+'
+
+test_expect_success 'fetch using mirror - default' '
+ cd .. &&
+ mkdir clone2 &&
+ cd clone2 &&
+ git init &&
+ git remote add origin ../master &&
+ git config remote.origin.mirror-url ../mirror
+ git fetch --use-mirror &&
+ git rev-parse refs/mirrors/origin/localhost/heads/master
+'
+test_done
diff --git a/transport.c b/transport.c
index 644a30a..0dc0185 100644
--- a/transport.c
+++ b/transport.c
@@ -859,6 +859,47 @@ struct transport *transport_get(struct remote *remote, const char *url)
return ret;
}
+struct transport *transport_next_mirror(struct transport *transport,
+ const char *last_mirror)
+{
+ struct transport *ret;
+ struct remote* remote = transport->remote;
+ int mirror_idx = -1;
+ const char* url;
+
+ if (!last_mirror) {
+ if (remote->preferred_mirror) {
+ mirror_idx = remote_mirror_idx(
+ remote,
+ remote->preferred_mirror
+ );
+ if (mirror_idx == -1) {
+ warning("preferred mirror '%s' not listed "
+ "in remote.%s.mirror-url",
+ remote->preferred_mirror,
+ remote->name);
+ }
+ }
+ else {
+ mirror_idx = 0;
+ }
+ }
+ else {
+ mirror_idx = remote_mirror_idx(remote, last_mirror) + 1;
+ // caller must check that we are not looping indefinitely
+ mirror_idx %= remote->mirror_url_nr;
+ }
+
+ url = remote->mirror_url[mirror_idx];
+ ret = transport_get(remote, url);
+
+ // copy settings - caller must re-set options
+ ret->verbose = transport->verbose;
+ ret->progress = transport->progress;
+
+ return ret;
+}
+
int transport_set_option(struct transport *transport,
const char *name, const char *value)
{
diff --git a/transport.h b/transport.h
index c14da6f..9890157 100644
--- a/transport.h
+++ b/transport.h
@@ -41,6 +41,9 @@ struct transport {
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
+/* Returns a transport for a mirror */
+struct transport *transport_next_mirror(struct transport *transport, const char *last_mirror);
+
/* Transport options which apply to git:// and scp-style URLs */
/* The program to use on the remote side to send a pack */
@@ -78,6 +81,8 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs);
void transport_unlock_pack(struct transport *transport);
int transport_disconnect(struct transport *transport);
char *transport_anonymize_url(const char *url);
+struct refspec *mirror_refspec(struct transport* transport,
+ struct refspec *refspec, int refspec_nr);
/* Transport methods defined outside transport.c */
int transport_helper_init(struct transport *transport, const char *name);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 1/4] remote: allow mirroring to be specified, and document settings
From: Sam Vilain @ 2009-11-25 10:06 UTC (permalink / raw)
To: git; +Cc: Sam Vilain
In-Reply-To: <1259143617-26580-1-git-send-email-sam@vilain.net>
Add a per-remote setting that can list alternate URLs that the same
repository (or a close fork) can be found, a fetch command-line
switch, a config flag to enable it by default, and finally a method
for selecting a default mirror.
If the preferred mirror does not exist in the list of mirrors it is
considered invalid, in preparation for the time when the mirror list
can be supplied or added to by the upload-pack protocol response.
Signed-off-by: Sam Vilain <sam@vilain.net>
---
Documentation/config.txt | 13 +++++++++++++
Documentation/fetch-options.txt | 24 ++++++++++++++++++++++++
builtin-fetch.c | 4 +++-
remote.c | 17 +++++++++++++++++
remote.h | 6 ++++++
5 files changed, 63 insertions(+), 1 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index d1e2120..edde0e4 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1375,6 +1375,19 @@ remote.<name>.url::
remote.<name>.pushurl::
The push URL of a remote repository. See linkgit:git-push[1].
+remote.<name>.mirror-url::
+ An alternate URL which should have many similar refs to the
+ real remote at least most of the time. This option can be
+ specified multiple times. See linkgit:git-fetch[1].
+
+remote.<name>.use-mirror::
+ Prefer to contact mirrors first (boolean). See
+ linkgit:git-fetch[1].
+
+remote.<name>.preferred-mirror::
+ Specify which mirror to try first (full URL). May be updated
+ by user interaction during 'fetch'. See linkgit:git-fetch[1].
+
remote.<name>.proxy::
For remotes that require curl (http, https and ftp), the URL to
the proxy to use for that remote. Set to the empty string to
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 2886874..8f07a56 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -62,6 +62,30 @@ ifndef::git-pull[]
Pass --quiet to git-fetch-pack and silence any other internally
used git commands.
+-M::
+--use-mirror::
+ Try to use a configured mirror for the bulk of the transfer
+ rather than the main upstream. See gitlink:git-config[1] for
+ the appropriate options to set.
++
+The preferred mirror (or the first if no preferred URL is defined) is
+first contacted and fetched from, and any refs it presents which match
+the source <refspec> (including the rules for fetching tags) are saved
+under `refs/mirrors/`<remote>`/hostname`. If there is a network
+timeout, or the user interrupts the fetch process, the next mirror
+will be tried.
++
+Once the fetch from the mirror is complete, the central host is
+contacted and fetched from. If the mirror was correct and up to date,
+then no more data will be required from the central host. At this
+point, all of the refs under `refs/mirrors/`<remote> which are
+reachable from the real `refs/remotes/`<remote> tracking branches will
+be removed. Extra refs which were not present on the real source will
+be left behind so they are not fetched again the next time around.
++
+This can be made the default for a remote using the
+`remote.`<remote>.`use-mirror` configuration option.
+
-v::
--verbose::
Be verbose.
diff --git a/builtin-fetch.c b/builtin-fetch.c
index a35a6f8..209f502 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -23,7 +23,7 @@ enum {
TAGS_SET = 2
};
-static int append, force, keep, update_head_ok, verbosity;
+static int append, force, keep, update_head_ok, verbosity, use_mirror;
static int tags = TAGS_DEFAULT;
static const char *depth;
static const char *upload_pack;
@@ -45,6 +45,8 @@ static struct option builtin_fetch_options[] = {
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
"allow updating of HEAD ref"),
+ OPT_BOOLEAN('M', "mirror", &use_mirror,
+ "use mirror if available"),
OPT_STRING(0, "depth", &depth, "DEPTH",
"deepen history of shallow clone"),
OPT_END()
diff --git a/remote.c b/remote.c
index 73d33f2..65df03d 100644
--- a/remote.c
+++ b/remote.c
@@ -111,6 +111,13 @@ static void add_pushurl(struct remote *remote, const char *pushurl)
remote->pushurl[remote->pushurl_nr++] = pushurl;
}
+static void add_mirror_url(struct remote *remote, const char *mirror_url)
+{
+ ALLOC_GROW(remote->mirror_url, remote->mirror_url_nr + 1,
+ remote->mirror_url_alloc);
+ remote->mirror_url[remote->mirror_url_nr++] = mirror_url;
+}
+
static void add_pushurl_alias(struct remote *remote, const char *url)
{
const char *pushurl = alias_url(url, &rewrites_push);
@@ -407,6 +414,16 @@ static int handle_config(const char *key, const char *value, void *cb)
if (git_config_string(&v, key, value))
return -1;
add_pushurl(remote, v);
+ } else if (!strcmp(subkey, ".mirror-url")) {
+ const char *v;
+ if (git_config_string(&v, key, value))
+ return -1;
+ add_mirror_url(remote, v);
+ } else if (!strcmp(subkey, ".use-mirror")) {
+ remote->use_mirror = git_config_bool(key, value);
+ } else if (!strcmp(subkey, ".preferred-mirror")) {
+ if (git_config_string(&remote->preferred_mirror, key, value))
+ return -1;
} else if (!strcmp(subkey, ".push")) {
const char *v;
if (git_config_string(&v, key, value))
diff --git a/remote.h b/remote.h
index 5db8420..c720b9a 100644
--- a/remote.h
+++ b/remote.h
@@ -19,6 +19,12 @@ struct remote {
int pushurl_nr;
int pushurl_alloc;
+ const char **mirror_url;
+ int mirror_url_nr;
+ int mirror_url_alloc;
+ int use_mirror;
+ const char *preferred_mirror;
+
const char **push_refspec;
struct refspec *push;
int push_refspec_nr;
--
1.6.3.3
^ permalink raw reply related
* Re: git-apply fails on creating a new file, with both -p and --directory specified
From: Junio C Hamano @ 2009-11-25 10:56 UTC (permalink / raw)
To: Steven J. Murdoch; +Cc: git
In-Reply-To: <20091123194523.GZ15966@cl.cam.ac.uk>
"Steven J. Murdoch" <git+Steven.Murdoch@cl.cam.ac.uk> writes:
> This appears to be because I was both using -p to strip some path
> components, and --directory to add different ones in. Only creating
> new files was affected.
A very nicely done report.
In addition to your test case, I suspect that a patch that only changes
mode would have acted funny with -p<n> option.
-- >8 --
[PATCH] builtin-apply.c: pay attention to -p<n> when determining the name
The patch structure has def_name component that is used to validate the
sanity of a "diff --git" patch by checking pathnames that appear on the
patch header lines for consistency. The git_header_name() function is
used to compute this out of "diff --git a/... b/..." line, but the code
always stripped one level of prefix (i.e. "a/" and "b/"), without paying
attention to -p<n> option. Code in find_name() function that parses other
lines in the patch header (e.g. "--- a/..." and "+++ b/..." lines) however
did strip the correct number of leading paths prefixes, and the sanity
check between these computed values failed.
Teach git_header_name() to honor -p<n> option like find_name() function
does.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-apply.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/builtin-apply.c b/builtin-apply.c
index f667368..36e2f9d 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -823,12 +823,13 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
static const char *stop_at_slash(const char *line, int llen)
{
+ int nslash = p_value;
int i;
for (i = 0; i < llen; i++) {
int ch = line[i];
- if (ch == '/')
- return line + i;
+ if (ch == '/' && --nslash <= 0)
+ return &line[i];
}
return NULL;
}
^ permalink raw reply related
* Re: Git repository mesh?
From: Matthieu Moy @ 2009-11-25 11:54 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Git Mailing List
In-Reply-To: <fcaeb9bf0911250000u395c0153q43c8c7a60ca9b876@mail.gmail.com>
Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> On Wed, Nov 25, 2009 at 2:55 PM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>>
>>> Never used Mercurial but the idea of "git in" and "git out" to see how
>>> many commits ahead/behind would be nice.
>>
>> In Git, you'd run "git fetch" to get everything locally, and then
>>
>> git log ..origin/master => what origin/master has that you don't
>> git log origin/master.. => what you have that origin/master doesn't
>>
>> (and you can define aliases for that)
>
> But I have many origins (any repository could be origin). "git status"
> also have this kind of information, but only for "origin".
Then, fetch from all of them and:
git log ^HEAD repo1/master repo2/master repo3/master
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply
* cvsexportcommit dies when applying an (empty) merge commit
From: Nick Woolley @ 2009-11-25 11:59 UTC (permalink / raw)
To: git
Hi,
I have a git repository with a merge point on the master branch. This merge
commit is empty, and just contains a commit message:
Merge commit 'otherbranch'
I'm trying to export this branch into CVS using git-cvsexportcommit (the latest
version from the master branch). It's actually done in a wrapper script [1] but
the command that gets invoked is essentially:
git cvsexportcommit -p -v -u -w 'cvscheckout/HEAD/my-cvs-module' -c \
<parent commit> <commit>
Where <commit> is the empty merge commit. However this invocation dies and
aborts the process of exporting the branch half way.
The fatal error I get is:
Applying to CVS commit <commit> from parent <parent commit>
Checking if patch will apply
Applying
error: No changes
cannot patch at /usr/lib/git-core/git-cvsexportcommit line 324.
The vicinity of line 324 is (with some lines wrapped):
print "Applying\n";
if ($opt_W) {
system("git checkout -q $commit^0") && die "cannot patch";
} else {
`GIT_DIR= git-apply $context --summary --numstat --apply
<.cvsexportcommit.diff` || die "cannot patch";
}
It seems that the file .cvsexportcommit.diff is empty, so git-apply is refusing
to apply it.
Presumably the application would be a no-op, so this git-apply step could be
skipped. So I tried modifying the script to do that and it seems to work:
print "Applying\n";
if ($opt_W) {
system("git checkout -q $commit^0") && die "cannot patch";
} elsif (-s ".cvsexportcommit.diff") {
`GIT_DIR= git-apply $context --summary --numstat --apply
<.cvsexportcommit.diff` || die "cannot patch";
} else {
print "No changes\n";
}
The modified git-cvsexportcommit script completes without errors, but
unsurprisingly, seems to export nothing, so that when imported back into git,
there is no empty commit. There appears to be no log message added in CVS, either.
This does seem more acceptable than dying, although it doesn't faithfully
reproduce the git history. However I'm not sure if that would be possible in
this case.
Is the existing behaviour deliberately fatal, or is this worth supplying a patch
for?
Cheers,
N
1. http://github.com/wu-lee/git-cvs
^ permalink raw reply
* Re: Git repository mesh?
From: Nguyen Thai Ngoc Duy @ 2009-11-25 12:16 UTC (permalink / raw)
To: Matthieu Moy; +Cc: Git Mailing List
In-Reply-To: <vpqy6lues5j.fsf@bauges.imag.fr>
On 11/25/09, Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> wrote:
> Then, fetch from all of them and:
>
> git log ^HEAD repo1/master repo2/master repo3/master
Very nice. Thanks I did not know about "^HEAD". Now I need to think of
how to avoid typing all "repo*/master" stuff..
--
Duy
^ permalink raw reply
* Re: insecurity in verify-tag?
From: Michael J Gruber @ 2009-11-25 12:54 UTC (permalink / raw)
To: Git Mailing List, David Roundy
In-Reply-To: <117f2cc80911240856lbbb923buc7d0407bc2cba6a9@mail.gmail.com>
David Roundy venit, vidit, dixit 24.11.2009 17:56:
> I've just been looking at the code and I see what looks like a (minor)
> security hole in the verify-tag feature. In particular, the tag
> verification code doesn't check that the tag is signed by the same
> user that created the tag. To be fair, gpg does output the identity
> of the key that created the signature as well as the key used to
> create the signature, so an astute user could detect that some
> shenanigans is going on.
>
> An attack would simply require getting one's own public key into the
> keyring of a user. This probably wouldn't be very easy at the moment,
> but if people were to actually use encrypted email (and if they set
> their mail agents to download public keys), it might require no more
> then sending a signed email to a mailing list.
>
> Of course, you'd also somehow have to trick them into pulling (or
> cloning) your corrupt tag, which probably requires compromising a
> server (or mirror) somewhere. But of course, the whole point of
> signing tags is to eliminate precisely this danger.
>
> What should be done about this? First, there ought to be a feature to
> limit git verify-tag to use a specific keyring. Maybe there is an
> environment variable, and it's just not documented in the man page?
>
> It would also seem like a good idea to at a minimum check that the
> name/email associated with the signature is the same as that of the
> tagger. This doesn't gain you *too* much, since an attacker can
> always create his own key with any name and email he likes, but at
> least it means that users could feel safe adding keys to their public
> keyring, as long as those keys have reasonable names/emails associated
> with them, and as long as they run git show on a tag before trusting
> that that tag came from a particular person. i.e. it seems reasonable
> for me to expect that if I run:
>
> $ git show v1.0
> tag v1.0
> Tagger: Linus Torvalds ...
> ...
> [user carefully reads the Tagger line...]
> $ git verify-tag v1.0 && make
>
> That I won't be running make on a repository that wasn't signed by a
> key that at least *claims* to belong to Linus Torvalds.
>
> Thoughts?
My thought is that this is the wrong way to deal with signatures, be it
signatures on tags or signatures on other documents such as e-mails.
Everyone can produce a valid signature. Everyone can set an arbitrary
tagger name or commit author. They are meaningless. A "Tagger" really is
the committer of a tag object, whereas the signer is the actual author
of the signature.
The only case where a signature bears any value is when
- the signature is valid (in the sense of formal validity)
AND
- you trust the signer (i.e. the person and the key).
Specifically, you are supposed NOT to go by the return code of gpg
--verify (which is behind verify-tag). It doesn't mean all that much. On
a side note, that was an attack vector on gpg users last year or so.
All that git itself could do is compare the tagger and the signer, and
warn you if they differ, that is: the signer's key contains no uid
matching the tagger. But this piece of information is really orthogonal
to the issue of trustworthiness.
Note that the actual signature verification process depends also on the
gpg trust model (pgp/classic/...) that you're using and your trustdb. If
you want to use a specific gpg setup or keyring for tag purposes you can
do something like
GNUPGHOME=~/.gpgforgit git verify-tag v1.6.5
Michael
^ permalink raw reply
* Re: git send-email --notmuch expr
From: Jed Brown @ 2009-11-25 13:06 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git, Pierre Habouzit
In-Reply-To: <m3hbsic3l5.fsf@localhost.localdomain>
On Wed, 25 Nov 2009 02:16:52 -0800 (PST), Jakub Narebski <jnareb@gmail.com> wrote:
> (?: ... ) is in Perl non-capturing grouping
Thanks. Actually that code only executes under --compose, the headers
provided by format-patch all just come through untouched (but all the
interesting ones are duplicated). So it looks like we just need to
actually parse the relevant headers from format-patch, before the part
where the user gets prompted. These are a little harder because they
can span multiple lines. The current validation with --compose is a bit
broken: suppose the user sets the perfectly valid header
To: foo@example.com,
bar@example.com
The validation will strip the first line while issuing warning, but
send the second through untouched.
Jed
^ permalink raw reply
* Re: cvsexportcommit dies when applying an (empty) merge commit
From: Michael J Gruber @ 2009-11-25 13:06 UTC (permalink / raw)
To: Nick Woolley; +Cc: git
In-Reply-To: <4B0D1C1A.60707@yahoo.co.uk>
Nick Woolley venit, vidit, dixit 25.11.2009 12:59:
> Hi,
>
> I have a git repository with a merge point on the master branch. This merge
> commit is empty, and just contains a commit message:
>
> Merge commit 'otherbranch'
>
> I'm trying to export this branch into CVS using git-cvsexportcommit (the latest
> version from the master branch). It's actually done in a wrapper script [1] but
> the command that gets invoked is essentially:
>
> git cvsexportcommit -p -v -u -w 'cvscheckout/HEAD/my-cvs-module' -c \
> <parent commit> <commit>
>
> Where <commit> is the empty merge commit. However this invocation dies and
> aborts the process of exporting the branch half way.
>
> The fatal error I get is:
>
> Applying to CVS commit <commit> from parent <parent commit>
> Checking if patch will apply
> Applying
> error: No changes
> cannot patch at /usr/lib/git-core/git-cvsexportcommit line 324.
>
> The vicinity of line 324 is (with some lines wrapped):
>
> print "Applying\n";
> if ($opt_W) {
> system("git checkout -q $commit^0") && die "cannot patch";
> } else {
> `GIT_DIR= git-apply $context --summary --numstat --apply
> <.cvsexportcommit.diff` || die "cannot patch";
> }
>
> It seems that the file .cvsexportcommit.diff is empty, so git-apply is refusing
> to apply it.
>
> Presumably the application would be a no-op, so this git-apply step could be
> skipped. So I tried modifying the script to do that and it seems to work:
>
> print "Applying\n";
> if ($opt_W) {
> system("git checkout -q $commit^0") && die "cannot patch";
> } elsif (-s ".cvsexportcommit.diff") {
> `GIT_DIR= git-apply $context --summary --numstat --apply
> <.cvsexportcommit.diff` || die "cannot patch";
> } else {
> print "No changes\n";
> }
>
> The modified git-cvsexportcommit script completes without errors, but
> unsurprisingly, seems to export nothing, so that when imported back into git,
> there is no empty commit. There appears to be no log message added in CVS, either.
>
> This does seem more acceptable than dying, although it doesn't faithfully
> reproduce the git history. However I'm not sure if that would be possible in
> this case.
>
> Is the existing behaviour deliberately fatal, or is this worth supplying a patch
> for?
I think the behavior is correct in the sense that you're telling git
cvsexportcommit to make a commit to cvs, and it can't, because there is
no change to commit. A merge can't be represented.
It leaves you the choice between omitting the trivial merge from cvs
history (that's what one would do for a merge based cvs<->git workflow)
and generating a fake commit in cvs. I don't know if it has something
like --allow-empty - it's file base, after all.
Michael
^ permalink raw reply
* Re: [PATCH] grep: --full-tree
From: Michael J Gruber @ 2009-11-25 13:16 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vk4xggv27.fsf@alter.siamese.dyndns.org>
Junio C Hamano venit, vidit, dixit 24.11.2009 09:56:
> While working inside a deep subdirectory, it sometimes is necessary to
> find a string you see in a file you are working on from the files in the
> entire project. This is especially true when you are dipping your toe
> into an unfamiliar project.
>
> By default, "git grep" limits its search space to the current directory
> and below (i.e. as if "-r ." is specified), and it is rather cumbersome to
> repeat ../ as many times as necessary. This new option tells "git grep"
> not to limit the search space to the current directory.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
> * In http://article.gmane.org/gmane.comp.version-control.git/111717, I
> once argued in the opposite way, but I think it is Ok to aim for making
> the default --full-tree in the longer run (cf. $gmane/127885). This is
> the first step in that direction.
>
> I am not sure if there can be a sane way to flip the default without
> hurting existing scripts and users. Backward compatibility always is
> a pain.
On a related note, I had planned for a while now to go through the
commands and check for inconsistencies w.r.t. to subdir default. For
example, ls-files behaves like grep, whereas status is different. We
already had discussions about the commit:path notation from a subdir. (I
don't remember the outcome.) Of course, defaulting status differently
could be dangerous. Having --full-tree as default for all commands and
requiring an explicit "." sounds safer for all commands and not overly
inconvenient. (I remember once wondering where my committed files are,
looking at git ls-files output from a subdir.)
I think we should make this behavior as uniform across commands as
possible. Do we have a time frame for 1.7.0 within which one should
achieve such incompatible changes?
Michael
^ permalink raw reply
* Re: Git repository mesh?
From: Jakub Narebski @ 2009-11-25 13:26 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Matthieu Moy, Git Mailing List
In-Reply-To: <fcaeb9bf0911250416u7e363ab2yf9334bad09f957fb@mail.gmail.com>
Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> On 11/25/09, Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> wrote:
> > Then, fetch from all of them and:
> >
> > git log ^HEAD repo1/master repo2/master repo3/master
>
> Very nice. Thanks I did not know about "^HEAD". Now I need to think of
> how to avoid typing all "repo*/master" stuff..
Hmmm... shouldn't 'repo1' expand to 'repo1/HEAD', which is 'repo1/master'?
I mean shouldn't simply
git log ^HEAD repo1 repo2 repo3
work?
Also, git aliases (so you would be able to just say "git in").
--
Jakub Narebski
Poland
^ permalink raw reply
* diff: ignoring changes in certain subdirectories
From: Zoltán Füzesi @ 2009-11-25 13:27 UTC (permalink / raw)
To: git
Hi All, I would like to check changes between branch 'A' and 'B',
ignoring subdirectory 'xyz'.
Is there a simple way?
Thx, Zé
^ permalink raw reply
* Re: diff: ignoring changes in certain subdirectories
From: Johannes Schindelin @ 2009-11-25 13:40 UTC (permalink / raw)
To: Zoltán Füzesi; +Cc: git
In-Reply-To: <9ab80d150911250527j60707333n736c09fcdbdba3a7@mail.gmail.com>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 336 bytes --]
Hi,
On Wed, 25 Nov 2009, Zoltán Füzesi wrote:
> Hi All, I would like to check changes between branch 'A' and 'B',
> ignoring subdirectory 'xyz'. Is there a simple way?
I implement half of this for --no-index some time ago:
http://article.gmane.org/gmane.comp.version-control.git/110846
Feel free to take it to completion,
Dscho
^ permalink raw reply
* jgit problems for file paths with non-ASCII characters
From: Marc Strapetz @ 2009-11-25 13:47 UTC (permalink / raw)
To: git
I have noticed that jgit converts file paths to UTF-8 when querying the
repository. Especially,
org.eclipse.jgit.treewalk.filter.PathFilter#PathFilter performs this
conversion:
private PathFilter(final String s) {
pathStr = s;
pathRaw = Constants.encode(pathStr);
}
Because of this conversion, a TreeWalk fails to identify a file with
German umlauts. When using platform encoding to convert the file path to
bytes:
private PathFilter(final String s) {
pathStr = s;
pathRaw = s.getBytes();
}
the TreeWalk works as expected. Actually, the file path seems to be
stored with platform encoding in the repository.
Is this a bug or a misconfiguration of my repository? I'm using jgit
(commit e16af839e8a0cc01c52d3648d2d28e4cb915f80f) on Windows.
Thanks!
--
Best regards,
Marc Strapetz
=============
syntevo GmbH
http://www.syntevo.com
http://blog.syntevo.com
^ permalink raw reply
* Re: [PATCH] shortlog: respect commit encoding
From: Uwe Kleine-König @ 2009-11-25 14:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jiri Kosina
In-Reply-To: <7vfx8376hd.fsf@alter.siamese.dyndns.org>
Hello Junio,
On Tue, Nov 24, 2009 at 05:12:14PM -0800, Junio C Hamano wrote:
> Uwe Kleine-König <u.kleine-koenig@pengutronix.de> writes:
>
> > Before this change the author was taken from the raw commit without
> > reencoding.
>
> I see people often begin with "before this change" and stop the log
> message after making a statement of a fact. I mildly dislike this style,
> especially when the resulting message does not state that it is bad (and
> if necessary why it is bad) nor state in what way the code after the
> change is good.
>
> Don't take the author name information without re-encoding
> from the raw commit object buffer.
>
> is easier to read, at least for me.
Yes, that's better. Thanks.
> > while (*buffer && *buffer != '\n') {
> > const char *eol = strchr(buffer, '\n');
> >
> > - if (eol == NULL)
> > + if (eol == NULL) {
> > eol = buffer + strlen(buffer);
> > - else
> > + } else
> > eol++;
> > if (!prefixcmp(buffer, "author "))
>
> What is this hunk for?
This is just a left-over from debugging. Removed.
> > @@ -157,20 +162,20 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
> > die("Missing author: %s",
> > sha1_to_hex(commit->object.sha1));
> > if (log->user_format) {
> > - struct strbuf buf = STRBUF_INIT;
> > struct pretty_print_context ctx = {0};
> > ctx.abbrev = DEFAULT_ABBREV;
> > ctx.subject = "";
> > ctx.after_subject = "";
> > ctx.date_mode = DATE_NORMAL;
> > + pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &ufbuf, &ctx);
> > + buffer = ufbuf.buf;
> > +
> > + } else if (*buffer)
> > buffer++;
> > +
>
> You probably wanted to add an extra pair of {} around this "else
> if" clause instead, not the earlier one.
I removed the new line (the last changed line you quoted) instead.
Good?
> > diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
> > index 405b971..118204b 100755
> > --- a/t/t4201-shortlog.sh
> > +++ b/t/t4201-shortlog.sh
> > @@ -51,5 +51,29 @@ git log HEAD > log
> > GIT_DIR=non-existing git shortlog -w < log > out
> >
> > test_expect_success 'shortlog from non-git directory' 'test_cmp expect out'
> > +iconvfromutf8toiso885915() {
> > + printf "%s" "$@" | iconv -f UTF-8 -t ISO-8859-15
> > +}
>
> A bad use of "$@" that expands to $# individual words; you meant
> to say "$*".
OK.
> Could we please have the following inside its own test, so that
> any failure while preparing the test data is caught as an error?
I put it in the test itself. Isn't it ugly to have a test saying
something like
* ok 3: prepare shortlog encoding test
? Or is it better to see where a failure occurs?
> > +git reset --hard "$commit"
> > +git config --unset i18n.commitencoding
> > +echo 2 > a1
> > +git commit --quiet -m "set a1 to 2 and some non-ASCII chars: Äßø" --author="Jöhännës \"Dschö\" Schindëlin <Johannes.Schindelin@gmx.de>" a1
> > +
> > +git config i18n.commitencoding "ISO-8859-15"
> > +echo 3 > a1
> > +git commit --quiet -m "$(iconvfromutf8toiso885915 "set a1 to 3 and some non-ASCII chars: áæï")" --author="$(iconvfromutf8toiso885915 "Jöhännës \"Dschö\" Schindëlin <Johannes.Schindelin@gmx.de>")" a1
> > +git config --unset i18n.commitencoding
> > +
> > +git shortlog HEAD~2.. > out
> > +
> > +cat > expect << EOF
> > +Jöhännës "Dschö" Schindëlin (2):
> > + set a1 to 2 and some non-ASCII chars: Äßø
> > + set a1 to 3 and some non-ASCII chars: áæï
> > +
> > +EOF
> > +
> > +test_expect_success 'shortlog encoding' 'test_cmp expect out'
>
> t3900-i18n-commit already uses 8859-1 so if it is not too much to
> ask, it would be much nicer to have these test work between UTF-8
> and 8859-1, not -15.
>
> That way, I do not have to worry about breaking tests for people
> who were able to run existing iconv tests because they do not have
> working 8859-15.
OK.
Below is the updated patch.
Best regards
Uwe
------------------>8----------------------
From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Subject: [PATCH] shortlog: respect commit encoding
Don't take the author name information without re-encoding from the raw
commit object buffer.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: Jiri Kosina <jkosina@suse.cz>
---
builtin-shortlog.c | 20 ++++++++++++--------
t/t4201-shortlog.sh | 23 +++++++++++++++++++++++
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index 8aa63c7..263adc1 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -139,8 +139,13 @@ static void read_from_stdin(struct shortlog *log)
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
{
const char *author = NULL, *buffer;
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf ufbuf = STRBUF_INIT;
+ struct pretty_print_context ctx = {0};
- buffer = commit->buffer;
+ pretty_print_commit(CMIT_FMT_RAW, commit, &buf, &ctx);
+
+ buffer = buf.buf;
while (*buffer && *buffer != '\n') {
const char *eol = strchr(buffer, '\n');
@@ -157,20 +162,19 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
die("Missing author: %s",
sha1_to_hex(commit->object.sha1));
if (log->user_format) {
- struct strbuf buf = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.abbrev = DEFAULT_ABBREV;
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
- pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, &ctx);
- insert_one_record(log, author, buf.buf);
- strbuf_release(&buf);
- return;
- }
- if (*buffer)
+ pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &ufbuf, &ctx);
+ buffer = ufbuf.buf;
+
+ } else if (*buffer)
buffer++;
insert_one_record(log, author, !*buffer ? "<none>" : buffer);
+ strbuf_release(&ufbuf);
+ strbuf_release(&buf);
}
static void get_from_rev(struct rev_info *rev, struct shortlog *log)
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 405b971..03b6950 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -52,4 +52,27 @@ GIT_DIR=non-existing git shortlog -w < log > out
test_expect_success 'shortlog from non-git directory' 'test_cmp expect out'
+iconvfromutf8toiso88591() {
+ printf "%s" "$*" | iconv -f UTF-8 -t ISO-8859-1
+}
+
+cat > expect << EOF
+Jöhännës "Dschö" Schindëlin (2):
+ set a1 to 2 and some non-ASCII chars: Äßø
+ set a1 to 3 and some non-ASCII chars: áæï
+
+EOF
+
+test_expect_success 'shortlog encoding' '
+git reset --hard "$commit" &&
+git config --unset i18n.commitencoding &&
+echo 2 > a1 &&
+git commit --quiet -m "set a1 to 2 and some non-ASCII chars: Äßø" --author="Jöhännës \"Dschö\" Schindëlin <Johannes.Schindelin@gmx.de>" a1 &&
+git config i18n.commitencoding "ISO-8859-1" &&
+echo 3 > a1 &&
+git commit --quiet -m "$(iconvfromutf8toiso88591 "set a1 to 3 and some non-ASCII chars: áæï")" --author="$(iconvfromutf8toiso88591 "Jöhännës \"Dschö\" Schindëlin <Johannes.Schindelin@gmx.de>")" a1 &&
+git config --unset i18n.commitencoding &&
+git shortlog HEAD~2.. > out &&
+test_cmp expect out'
+
test_done
--
1.6.5.3
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply related
* Re: git-subtree: directory mismatch
From: Marc Fournier @ 2009-11-25 14:32 UTC (permalink / raw)
To: Avery Pennarun; +Cc: git
In-Reply-To: <32541b130911241348s21e21fb8n12edf374e6a3c309@mail.gmail.com>
On Tue, Nov 24, 2009 at 04:48:26PM -0500, Avery Pennarun wrote:
> On Tue, Nov 24, 2009 at 2:53 PM, Marc Fournier
> <marc.fournier@camptocamp.com> wrote:
> > I was not able to reproduce this bug in any of the following cases:
> > - if the README file wasn't empty
> > - if modules/cognac is renamed to something else
> > - if modules/cognac doesn't have the same sub-directories than
> > modules/mapserver
> >
> > This bug happens using git 1.5.5.6 as well as 1.6.5. It seems to happen
> > when git-subtree calls "git merge -s subtree".
>
> Yup. This is basically a bug in "git merge -s subtree": it guesses
> which subtree to merge into, rather than actually taking a prefix
> parameter. I've been meaning to either submit a patch for this, or
> find a way to work around it.
I see. What sort of criteria does git-merge use to do this auto-guessing ?
I'm hoping to find a way to workaround this problem. I have a couple of
subtrees I'm completely unable to update. The best I found is:
"git rm -fr ..." followed by "git subtree add ..." again.
> This doesn't usually happen once your project is relatively mature
> (ie. doesn't have blank or "default" template files in it) since then
> the auto-guessing gets more reliable. But there's no good reason to
> do the auto-guessing, so it would be best to do this "properly."
The thing is I use dozens of different "modules" in my project, all merged
into using git-subtree. All these modules have the same structure, and most
of them have quite minimal content and won't really evolve more. In my
case, evolution will mean adding even more modules.
If I understand the thread Nanako Shiraishi pointed us to, a patch
implementing a prefix to "git merge -s subtree" is available somewhere but
hasn't been added in any official release yet ?
Marc
^ permalink raw reply
* Re: [PATCH] gitweb.js: Harden setting blamed commit info in incremental blame
From: Jakub Narebski @ 2009-11-25 14:36 UTC (permalink / raw)
To: Stephen Boyd; +Cc: git
In-Reply-To: <4B0CAC2E.1060105@gmail.com>
On Wed, 25 Nov 2009 05:01, Stephen Boyd wrote:
> Jakub Narebski wrote:
> >
> > Debugging this is serious PITA. After fix below it appears that this bug
> > is some intermittent bug, depending on XMLHttpRequest timing. It more
> > often than not (at least when I tried to debug it using build-in IE8
> > debugger) works correctly for the folowing files: README, GIT-VERSION-GEN,
> > revision.c (once even it did fail when first running for given file, and
> > then running correctly when reloading from debugger; fun it is not).
> >
> > It does consistently fail for gitweb/gitweb.perl... but when I tried
> > to debug it IE8 would hang up when trying to use debugger (with around
> > 600MB available RAM). Perhaps somebody else would have more luck...
>
> Interesting. I don't have time to look into this until early December,
> but if it's still around then I'll take a look. I wonder if IE6 or IE7
> works (I don't think everyone is on version 8 yet).
Well, the one time I was able to run debugger (F12, select 'Script', select
'gitweb.js') with error occurring and without IE hanging (for README file)
it did show an error for the following line:
if (xhr.readyState === 3 && xhr.status !== 200) {
When I checked 'xhr' object, it has "Unknown error" as contents of
xhr.statusText field and as contents of xhr.status (sic!), which should
be a number: HTTP status code.
Unfortunately I had to take a break... and I was not able to reproduce this
(without hanging web browser: "program not responding") since then...
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: [PATCH] grep: --full-tree
From: Sverre Rabbelier @ 2009-11-25 14:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vk4xggv27.fsf@alter.siamese.dyndns.org>
Heya,
On Tue, Nov 24, 2009 at 09:56, Junio C Hamano <gitster@pobox.com> wrote:
> I am not sure if there can be a sane way to flip the default without
> hurting existing scripts and users. Backward compatibility always is
> a pain.
I regularly rely on this behavior in my usage of git grep. For
example, the Melange project has this layout:
-- app
-- app/soc
-- app/django
-- app/... etc
-- scripts
-- tests
-- thirdparty
I almost always want only results from "app/soc", so when I run git
grep I do so from within "app/soc" to make sure I don't get false
positives from the many external sources we have.
Just chiming in for the "want to keep the current behavior" camp :).
PS: I don't mind having to set a config variable to keep the current
behavior though.
--
Cheers,
Sverre Rabbelier
^ permalink raw reply
* Commiting changes onto more than one branch
From: Mike Jarmy @ 2009-11-25 16:31 UTC (permalink / raw)
To: git
Hi,
At my day job, I'm doing the groundwork for recommending that we
switch to a DVCS from a proprietary centralized VCS. I find git's
branching ability very compelling, and I think we would use it
extensively. I work on a very large project (many thousands of files)
that has been around for many years, and has had several different
releases. Right now, each release has its own top level directory,
but I'd like to change that so we use branches instead, out of one
great big git repository. My plan is to set up the repository such
that the initial state at switchover will have a branch for the
current state of each of our releases. Lets say that the branches for
each release are called v1, v2, etc.
My question is this: How do I manage a checkin for a bugfix that
affects, say, only branches v3, v4, and v5?
Suppose that I checkout the v3 branch, and fix the bug by editing
several different files. (Lets assume for now that the files in
question have not diverged between any of the 3 branches, even though
tons of other files have changed). How do I commit the bugfix into
all of v3, v4 and v5? Clearly, merging the branches together would be
bad. So I think what I should do is perform 3 different commits, but
I'm not quite sure how to juggle the git index (or stash or whatever)
to accomplish this. This may be a really obvious question, but I'm a
confused git newbie.
Also, even though I may need to do 3 commits, it would be nice if the
commits were related together in some way, since in a sense they
represent only one action (namely, fixing the bug). Is there a way to
do that, so that its clear in gitk that it was really one unified
thing? The very worst thing about our current VCS is that it has no
concept of a 'commit', only individual file histories. Git would fix
that for us, but it would be nirvana if we could group commits for a
given bugfix across branches somehow, while not merging the branches
together.
One last question -- lets make the problem slightly more complicated
by specify that some of the edited files changed between, say, v4 and
v5. I know how to handle a simple merge conflict in git, but is there
anything different about my multi-branched, grouped-together case
here? The answer to this question may be obvious once I understand
how to do the simpler, unconflicting checkin.
Thanks,
Mike Jarmy
^ permalink raw reply
* Re: Commiting changes onto more than one branch
From: Eugene Sajine @ 2009-11-25 16:38 UTC (permalink / raw)
To: Mike Jarmy; +Cc: git
In-Reply-To: <6b4a562b0911250831q332ac3b5m6ee38f59e7a6f391@mail.gmail.com>
>
> Suppose that I checkout the v3 branch, and fix the bug by editing
> several different files. (Lets assume for now that the files in
> question have not diverged between any of the 3 branches, even though
> tons of other files have changed). How do I commit the bugfix into
> all of v3, v4 and v5? Clearly, merging the branches together would be
> bad. So I think what I should do is perform 3 different commits, but
> I'm not quite sure how to juggle the git index (or stash or whatever)
> to accomplish this. This may be a really obvious question, but I'm a
> confused git newbie.
It as not as clear for me why you think merge will be bad?
If you commit your changes to the v3, then merging to v4 and v5 (which
are not changed) should be very simple fast forward merge. Which means
just move the pointer to the last commit from v3
Am i missing something?
Thanks,
Eugene
^ permalink raw reply
* Re: Commiting changes onto more than one branch
From: Mike Jarmy @ 2009-11-25 16:47 UTC (permalink / raw)
To: Eugene Sajine; +Cc: git
In-Reply-To: <76c5b8580911250838x361ae081n271fcee2d1234703@mail.gmail.com>
On Wed, Nov 25, 2009 at 11:38 AM, Eugene Sajine <euguess@gmail.com> wrote:
>>
>> Suppose that I checkout the v3 branch, and fix the bug by editing
>> several different files. (Lets assume for now that the files in
>> question have not diverged between any of the 3 branches, even though
>> tons of other files have changed). How do I commit the bugfix into
>> all of v3, v4 and v5? Clearly, merging the branches together would be
>> bad. So I think what I should do is perform 3 different commits, but
>> I'm not quite sure how to juggle the git index (or stash or whatever)
>> to accomplish this. This may be a really obvious question, but I'm a
>> confused git newbie.
>
> It as not as clear for me why you think merge will be bad?
> If you commit your changes to the v3, then merging to v4 and v5 (which
> are not changed) should be very simple fast forward merge. Which means
> just move the pointer to the last commit from v3
>
> Am i missing something?
I guess I didn't explain it too well, I made it sound like v3, v4 and
v5 were still more-or-less the same. What I'm thinking about here is
a case where we have switched to git a while back, and then done a lot
of work on the various different branches, so that v3, v4 and v5 have
diverged very far from each other. In that case, we would never want
to merge them together.
^ 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