* 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: 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
* 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: 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: 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: 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 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
* 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: 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
* 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
* [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
* [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 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 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
* 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
* 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
* Re: git send-email --notmuch expr
From: Jakub Narebski @ 2009-11-25 10:16 UTC (permalink / raw)
To: Jed Brown; +Cc: git, Pierre Habouzit
In-Reply-To: <87d4375ne0.fsf@59A2.org>
Jed Brown <jed@59A2.org> writes:
> } elsif (/^(?:To|Cc|Bcc):/i) {
> print "To/Cc/Bcc fields are not interpreted yet, they have been ignored\n";
> next;
> }
>
> This regex doesn't match these headers (is the leading ?: a typo?) so
> there is no warning.
(?: ... ) is in Perl non-capturing grouping
>From perlre(1)
"(?:pattern)"
"(?imsx-imsx:pattern)"
This is for clustering, not capturing; it groups subexpressions
like "()", but doesn't make backreferences as "()" does.
So it is not a bug, and it definitely should match... unless implicit
variable $_ (the default input and pattern-searching space) got
mangled. It would be better to use explicit form:
$variable =~ /pattern/
--
Jakub Narebski
Poland
ShadeHawk on #git
^ permalink raw reply
* Re: What is the best way to synchronize two *bare* repositories with each other?
From: Alex Riesen @ 2009-11-25 10:14 UTC (permalink / raw)
To: Liebich, Wolfgang; +Cc: git@vger.kernel.org
In-Reply-To: <7FF082147E322048955113B6CB87A7C0081731C659@MCHP058A.global-ad.net>
On Tue, Nov 24, 2009 at 22:19, Liebich, Wolfgang
<wolfgang.liebich@siemens-enterprise.com> wrote:
> Hi,
> Let's say I have two bare git repositories, bareA and bareB.
> I also have a third non-bare repo, lets call it workA. Coworkers also have their working repositories, they all
> synchronize back to repoA.
> My work repo can only synchronize directly with repoB.
> What is the best way to keep repoA and repoB synchronized to each other?
Take a look at "--mirror" option of "git clone" (it sets up a remote
with references
mapping like this: refs/*:refs/*).
^ permalink raw reply
* Re: Git repository mesh?
From: Alex Riesen @ 2009-11-25 10:08 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Git Mailing List
In-Reply-To: <fcaeb9bf0911242007t1294bddej87b48691ea283e21@mail.gmail.com>
On Wed, Nov 25, 2009 at 05:07, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> I work on a few machines so I have repositories on all of them. One
> repository can pull from or push to any other repositories (in case of
> push, it pushes on remote branches). I avoid a central repository
> because it's quite inconvenient when you just need to push some
> changes to a machine, you have to push it to the central repository
> then pull from that (and if the central repository is on WAN, double
> inconvenient). Maybe this model is just plain wrong, but it'd be fun
> to see if Git can work with this model.
You can always use fetch (and pull) without specifying a remote:
$ git fetch host:/path/repo some-branch
$ git log ..FETCH_HEAD # git merge FETCH_HEAD
Maybe fetch should be extended to record this operation in .git/config?
$ git fetch ---save=host-some host:/path/repo some-branch some-branch
$ git remote -v
...
host-some host:/path/repo (fetch)
$
^ permalink raw reply
* Re: OS X and umlauts in file names
From: Martin Langhoff @ 2009-11-25 10:07 UTC (permalink / raw)
To: Thomas Singer; +Cc: Daniel Barkalow, git
In-Reply-To: <4B0CEFCA.5020605@syntevo.com>
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?
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
* Re: OS X and umlauts in file names
From: B Smith-Mannschott @ 2009-11-25 9:51 UTC (permalink / raw)
To: Thomas Singer; +Cc: Daniel Barkalow, git
In-Reply-To: <4B0CEFCA.5020605@syntevo.com>
On Wed, Nov 25, 2009 at 09:50, Thomas Singer <thomas.singer@syntevo.com> wrote:
> I've did following:
>
> toms-mac-mini:git-umlauts tom$ ls
> Überlänge.txt
> toms-mac-mini:git-umlauts tom$ git status
> # On branch master
> #
> # Initial commit
> #
> # Changes to be committed:
> # (use "git rm --cached <file>..." to unstage)
> #
> # new file: "U\314\210berla\314\210nge.txt"
> #
> 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
>
> Note, that I copy-pasted the file name which 'git status' showed to the
> stage command. IMHO, this should work, especially, because different people
> said Git would treat the file name as byte-array without interpreting it in
> some kind.
>
> From the user with the German OS X (for which the staging is said to work),
> I've got the output of 'env' and hence also tried
>
> export LANG=de_DE.UTF-8
>
> before doing the above steps, but with the same results. :(
The problem you are having is not because of the *encoding*, it's the
Normalization form that's messing things up. The fact is that in
Unicode there are two ways to represent many -- but not all --
accented characters.
- "composed": one code point for the accented character)
- "decomposed": two code points: one for the base letter, one or more
combining characters for the accents.
The composed code points are really just backward compatibility to
legacy encodings (like LATIN-1). If you want to actually support
(rather than just tolerate) unicode you have to know how to deal with
the decomposed form, and once you can do that there's little point
beyond backward compatibility in continuing to use composed form
internally.
The Subversion people have run into this same problem because they
made the same error of assuming that any given sequence of glyphs has
only one possible representation as unicode code points and thus only
one representation as UTF-8 bytes. Dionisos has done written up the
issues involved here:
http://svn.apache.org/repos/asf/subversion/trunk/notes/unicode-composition-for-filenames
// Ben
^ permalink raw reply
* Re: OS X and umlauts in file names
From: Thomas Singer @ 2009-11-25 8:50 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <alpine.LNX.2.00.0911231403100.14365@iabervon.org>
I've did following:
toms-mac-mini:git-umlauts tom$ ls
Überlänge.txt
toms-mac-mini:git-umlauts tom$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: "U\314\210berla\314\210nge.txt"
#
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
Note, that I copy-pasted the file name which 'git status' showed to the
stage command. IMHO, this should work, especially, because different people
said Git would treat the file name as byte-array without interpreting it in
some kind.
From the user with the German OS X (for which the staging is said to work),
I've got the output of 'env' and hence also tried
export LANG=de_DE.UTF-8
before doing the above steps, but with the same results. :(
--
Tom
Daniel Barkalow wrote:
> On Mon, 23 Nov 2009, Thomas Singer wrote:
>
>> I'm on an English OS X 10.6.2 and I created a sample file with umlauts in
>> its name (Überlänge.txt). When I try to stage the file in the terminal, I
>> can't complete the file name by typing the Ü and hitting the tab key, but I
>> can complete it by typing an U and hitting the tab key.
>
> You've already got a bug before involving git at all. You create a
> file "Überlänge.txt", but OS X writes "U:berla:nge.txt" (typing the
> combining character umlaut as : so that you can see the difference), and
> the directory listing doesn't contain any files that start with Ü, so the
> terminal already can't find the file you created. Obviously, git is going
> to have all the problems that the OS-provided readline library has, and
> you're not going to be able to get predictable results in any case where
> user-supplied filenames are compared with directory listings.
>
> Part of the problem is that OS X does a canonicalization that is not what
> anybody else does, so you hit the problem every single time, but the
> fundamental issue is that there isn't any way to tell, when you create a
> file, what name that file will be listed under.
>
> Note that this isn't a matter of characters to byte sequences. OS X
> actually uses different characters for the filename in its listings than
> you've used.
>
> If there's a difference between German and English versions, I suspect
> that it's actually that you're not using a German keyboard with a key
> that, under OS X, produces the two-character sequence U:, but using some
> method that produces the single character Ü. I'd guess that your SmartGit
> problem is that Java is converting the U: that the user typed into Ü, and
> passing it to the OS, which turns it back into U: and then doesn't list
> the file that Java thinks the user asked for.
>
> -Daniel
> *This .sig left intentionally blank*
^ permalink raw reply
* Re: Git repository mesh?
From: Sergio @ 2009-11-25 8:42 UTC (permalink / raw)
To: git
In-Reply-To: <fcaeb9bf0911242007t1294bddej87b48691ea283e21@mail.gmail.com>
Nguyen Thai Ngoc Duy <pclouds <at> gmail.com> writes:
>
> Hi,
>
> I work on a few machines so I have repositories on all of them. One
> repository can pull from or push to any other repositories (in case of
> push, it pushes on remote branches). I avoid a central repository
> because it's quite inconvenient when you just need to push some
> changes to a machine, you have to push it to the central repository
> then pull from that (and if the central repository is on WAN, double
> inconvenient). Maybe this model is just plain wrong, but it'd be fun
> to see if Git can work with this model.
>
> The first thing that annoys me is remote repository management.
> Everytime I add a new repository to the mesh, I need to update .config
> of all repositories.
If I remember correctly, there was in the past the idea of allowing some limited
shell variable substitution in the config file.
This would allow to have a single config for all the machines with remote
entries. Something like
[remote "host1"]
url = ssh://host1/path
fetch = +refs/heads/*:refs/remotes/host1/*
push = +refs/heads/*:refs/remotes/$hostname/*
[remote "host2"]
url = ssh://host2/path
fetch = +refs/heads/*:refs/remotes/host2/*
push = +refs/heads/*:refs/remotes/$hostname/*
...
In other terms, admitting that all the candidate machines are known at the very
start, you could start a repo on any of the host, placing in the config file all
the possible hosts. Moreover, not needing to have a different config for each
host may make it easier to manage (propagate by simple scp) or even to version
control.
To the best of my knowledge the idea was not implemented in the end, but I think
that a patch for variable substitution in the config file might still be found
on the ML.
Sergio
^ permalink raw reply
* [PATCH] git-am: don't ignore --keep (-k) option
From: Jim Meyering @ 2009-11-25 8:13 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git list
In-Reply-To: <7vmy2b76ji.fsf@alter.siamese.dyndns.org>
Junio C Hamano wrote:
> Jim Meyering <meyering@redhat.com> writes:
>> Before this change, a [...] prefix would be removed only as long as
>> its length did not exceed 2/3 of the subject length. Now, when the
>> bracketed quantity starts with PATCH, it is removed unconditionally.
>> Otherwise, the existing behavior remains unchanged.
>
> Thanks, I think this is a good idea in general, but have two comments.
>
> - I am not sure how this should play with 17635fc (mailinfo: -b option
> keeps [bracketed] strings that is not a [PATCH] marker, 2009-07-15).
Ah ha! I see you've already scratched this itch,
and more thoroughly, to boot. Also, I prefer your
removal of the hard-to-describe 2/3 threshold.
> - Regardless of interaction with 17635fc, Things like [RFC PATCH]
> [SECURITY PATCH] might want a similar treatment.
As your patch does.
I started looking at git-am.sh and spotted what appears to be a typo.
There is only that one use of $keep_subject, so its value currently
comes from the environment.
>From 02f7e6433b5db8b18a4cccf58c302159c2f54fa5 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering@redhat.com>
Date: Wed, 25 Nov 2009 09:10:46 +0100
Subject: [PATCH] git-am: don't ignore --keep (-k) option
Fix typo in variable name: s/keep_subject/keep/.
Signed-off-by: Jim Meyering <meyering@redhat.com>
---
git-am.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/git-am.sh b/git-am.sh
index 151512a..f353e73 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -578,7 +578,7 @@ do
sed -e '1,/^$/d' >"$dotest/msg-clean"
else
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
- case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
+ case "$keep" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
(printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") |
git stripspace > "$dotest/msg-clean"
--
1.6.6.rc0.236.ge0b94
^ permalink raw reply related
* Re: Git repository mesh?
From: Nguyen Thai Ngoc Duy @ 2009-11-25 8:00 UTC (permalink / raw)
To: Matthieu Moy; +Cc: Git Mailing List
In-Reply-To: <vpqaaybf37f.fsf@bauges.imag.fr>
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".
--
Duy
^ 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