* Re: [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0705121144130.18541@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> +static int handle_config(const char *key, const char *value)
> +{
> + const char *name;
> + const char *subkey;
> + struct remote *remote;
> + if (!prefixcmp(key, "branch.") && current_branch &&
> + !strncmp(key + 7, current_branch, current_branch_len) &&
> + !strcmp(key + 7 + current_branch_len, ".remote")) {
> + free(default_remote_name);
> + default_remote_name = xstrdup(value);
> + }
> + if (prefixcmp(key, "remote."))
> + return 0;
> + name = key + 7;
> + subkey = strrchr(name, '.');
> + if (!subkey)
> + return error("Config with no key for remote %s", name);
> + remote = make_remote(name, subkey - name);
> + if (!strcmp(subkey, ".url")) {
> + add_uri(remote, xstrdup(value));
> + } else if (!strcmp(subkey, ".push")) {
> + add_push_refspec(remote, xstrdup(value));
> + } else if (!strcmp(subkey, ".receivepack")) {
> + if (!remote->receivepack)
> + remote->receivepack = xstrdup(value);
> + else
> + error("more than one receivepack given, using the first");
> + }
> + return 0;
> +}
You forgot to update this part? With your comments on not
erroring out, which made sense to me, how about this?
diff --git a/remote.c b/remote.c
index dbcc74e..b032e81 100644
--- a/remote.c
+++ b/remote.c
@@ -150,7 +150,26 @@ static int handle_config(const char *key, const char *value)
subkey = strrchr(name, '.');
if (!subkey)
return error("Config with no key for remote %s", name);
+ if (*subkey == '/') {
+ warning("Config remote shorthand cannot begin with '/': %s", name);
+ return 0;
+ }
remote = make_remote(name, subkey - name);
+ if (!value) {
+ /* if we ever have a boolean variable, e.g. "remote.*.disabled"
+ * [remote "frotz"]
+ * disabled
+ * is a valid way to set it to true; we get NULL in value so
+ * we need to handle it here.
+ *
+ * if (!strcmp(subkey, ".disabled")) {
+ * val = git_config_bool(key, value);
+ * return 0;
+ * } else
+ *
+ */
+ return 0; /* ignore unknown booleans */
+ }
if (!strcmp(subkey, ".url")) {
add_uri(remote, xstrdup(value));
} else if (!strcmp(subkey, ".push")) {
^ permalink raw reply related
* Re: [PATCH] git-archive: don't die when repository uses subprojects
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Lars Hjemli; +Cc: git
In-Reply-To: <11789025212823-git-send-email-hjemli@gmail.com>
Thanks.
^ permalink raw reply
* Re: Merging commits together into a super-commit
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Yann Dirson
Cc: Carl Worth, Petr Baudis, J. Bruce Fields, Linus Torvalds,
Johannes Sixt, git
In-Reply-To: <20070512144145.GF16903@nan92-1-81-57-214-146.fbx.proxad.net>
Yann Dirson <ydirson@altern.org> writes:
> On Sat, May 12, 2007 at 04:02:28PM +0200, Karl Hasselström wrote:
>> ...
>> What we should do is delete all stgit metadata when the last patch
>> goes away.
>
> This supposes there is no valuable branch-level metadata. Currently
> we have the description - something which could arguably be moved to
> the git level as well. Otherwise that sounds reasonable to me.
Will it be something like
[branch "master"]
description = "My primary development line"
if so I think that is a reasonable thing to do, from git-core's
point of view. Obviously, gitk, tig, gitweb and friends can use
this, too.
Are there other per-branch information StGIT wants to keep on an
active branch that might benefit the core as well?
>> And we shouldn't have "stg init", either. Initing should be done
>> automatically when needed.
>
> Good idea as well, that would make stg more accessible to the average
> plain-git user.
Yes, I wished for this often myself.
^ permalink raw reply
* Re: [PATCH] tiny fix in documentation of git-clone
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: git
In-Reply-To: <79265012-A444-4EE9-B374-C34A62358829@zib.de>
Thanks.
^ permalink raw reply
* Re: [PATCH] gitweb: Test if $from_id and $to_id are defined before comparison
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <200705121242.33156.jnareb@gmail.com>
Thanks.
^ permalink raw reply
* Re: [PATCH 0/3] Remotes library, take 4
From: Junio C Hamano @ 2007-05-12 19:27 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0705121137400.18541@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> Updated for recent review. If remote section name starts with '/', it is
> ignored (like in 1.5.0). If a remote section option has no value, it is
> also ignored (so it doesn't crash, and to be forward-compatible if we
> introduce a boolean option later).
>
> The struct refspec field and associated variables are spelled "dst".
>
> Part 3 is unchanged.
It cannot be left unchanged as it is affected by the dest stuff.
I'll push out a fixed-up one on 'pu' soonish. Let's stabilize
this a bit without too many resends.
^ permalink raw reply
* Re: [BUG?] Detaching head at checked out point does not work.
From: Jan Hudec @ 2007-05-12 19:18 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v7ird2902.fsf@assigned-by-dhcp.cox.net>
[-- Attachment #1: Type: text/plain, Size: 598 bytes --]
On Sat, May 12, 2007 at 11:26:53 -0700, Junio C Hamano wrote:
> Jan Hudec <bulb@ucw.cz> writes:
>
> > Hello,
> >
> > I can correctly detach head by saying:
> >
> > git checkout master^0
> >
> > (or git checkout master^{} or git checkout refs/heads/master), but NONE of
> > these work, if I currently have master checked out. Shouldn't it detach
> > anyway?
>
> Yes, and it does as far as I know.
>
> Do you have 3e0318a3?
It does not seem to be in 1.5.1.4, so no, I don't.
I apologise for not looking whether head has a fix.
--
Jan 'Bulb' Hudec <bulb@ucw.cz>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] Document patch syntax.
From: Junio C Hamano @ 2007-05-12 19:02 UTC (permalink / raw)
To: Karl Hasselström; +Cc: Yann Dirson, Catalin Marinas, git
In-Reply-To: <20070512183255.GD28039@diana.vm.bytemark.co.uk>
Karl Hasselström <kha@treskal.com> writes:
> On 2007-05-12 16:38:27 +0200, Yann Dirson wrote:
>
>> However, that makes me think we should probably use guideline for
>> the docs - here comes the question of which convention to use when
>> refering to the user. Do we address her directly ("you"), indirectly
>> ("the user", "her" - don't remember where the "female user" use
>> comes from, but we could maybe follow this), even more indirectly
>> ("one"), or any other way ?
>
> I'd go with "you", or possibly "one" (but I strongly prefer "you").
> Talking about the user in the third person ("the user", "her", etc.)
> seems actively wrong when we are instructing the user on how to do
> things.
With the context in question, I find 'the user' is the most
natural and neutral.
I think the "female user" use is not so widely accepted. I
always found it to be a sign that the author, a lonely male nerd
developer, is wishing to live in a dream world where he becomes
a hero by helping an attractive female user that he would never
have chance to interact with otherwise in his real life ;-).
For tutorial/walkthru type of documentation, my usual preference
is "we", not "you". "Now our little repository should be in
this shape." "Let's change our Makefile to do a bit more."
That sets the tone that a slightly more knowledgeable friend is
helping the user by working together with him, instead of an
expert talking to a stupid user from a high place, but that is a
bit offtopic.
^ permalink raw reply
* [StGIT PATCH v2] Document patch syntax.
From: Yann Dirson @ 2007-05-12 18:59 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=utf-8, Size: 1731 bytes --]
Acked-by: Karl Hasselström <kha@treskal.com>
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
Documentation/stg.txt | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/Documentation/stg.txt b/Documentation/stg.txt
index af57c37..bc2a6fe 100644
--- a/Documentation/stg.txt
+++ b/Documentation/stg.txt
@@ -51,6 +51,31 @@ Development branch::
In such a setup, not all commits on your branch need to be StGIT
patches; there may be regular GIT commits below your stack base.
+Patches
+~~~~~~~
+
+Many StGIT commands take references to StGIT patches as arguments.
+Patches in the stack are identified with a short name, which must be
+unique in the stack.
+
+Patches in the current stack are just refered to by their name. Some
+commands allow you to specify a patch in another stack of the repository;
+this is done by suffixing the patch name with an '@' sign followed by the
+branch name (eg. 'thispatch@otherbranch').
+
+A number of positions in the stack related to the patch are also
+accessible through '//' suffixes. For example, 'patch//top' is
+equivalent to 'patch', and 'patch//bottom' refers to the commit below
+'patch' (i.e. the patch below, or the stack base if this is the
+bottom-most patch). Similarly '//top.old' and '//bottom.old'
+refer to the previous version of the patch (before the last
+stglink:push[] or stglink:refresh[] operation). When referring to the
+current patch, its name can be omitted (eg. 'currentpatch//bottom.old'
+can be abbreviated as 'bottom.old').
+
+If you need to pass a given StGIT reference to a git command,
+stglink:id[] will convert it to a git commit id.
+
OPTIONS
-------
^ permalink raw reply related
* [PATCH] link to HTML version of external doc if available
From: Junio C Hamano @ 2007-05-12 18:47 UTC (permalink / raw)
To: J Bruce Fields; +Cc: git
Currently
$ git grep '\([^t]\|^\)'link: user-manual.txt
gives four hits that refer to .txt version of the documentation
set, but at least "hooks" and "cvs-migration" have HTML variants
installed, so refer to them instead.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
* The other two are howto/setup-git-server-over-http and
technical/pack-format.txt
Documentation/user-manual.txt | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 13db969..a7abeaa 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1875,7 +1875,7 @@ $ chmod a+x hooks/post-update
(For an explanation of the last two lines, see
gitlink:git-update-server-info[1], and the documentation
-link:hooks.txt[Hooks used by git].)
+link:hooks.html[Hooks used by git].)
Advertise the url of proj.git. Anybody else should then be able to
clone or pull from that url, for example with a commandline like:
@@ -1959,7 +1959,7 @@ Setting up a shared repository
Another way to collaborate is by using a model similar to that
commonly used in CVS, where several developers with special rights
all push to and pull from a single shared repository. See
-link:cvs-migration.txt[git for CVS users] for instructions on how to
+link:cvs-migration.html[git for CVS users] for instructions on how to
set this up.
[[setting-up-gitweb]]
^ permalink raw reply related
* Re: Transactions for git (and stgit) ?
From: Yann Dirson @ 2007-05-12 18:34 UTC (permalink / raw)
To: Carl Worth, Linus Torvalds, Johannes Sixt, git
In-Reply-To: <20070512104919.GA22735@diana.vm.bytemark.co.uk>
On Sat, May 12, 2007 at 12:49:19PM +0200, Karl Hasselström wrote:
> On 2007-05-12 11:53:12 +0200, Yann Dirson wrote:
>
> > It could even be more sensible to implement transactions at the git
> > level rather than at the stgit one...
>
> Yes, please. (Unless a convincing technical argument pops up against
> it, of course.) Any stgit invariant that isn't based on a git
> invariant is one more thing that can break when git and stgit commands
> are mixed.
For reference, I have written down some design ideas in january[1].
They were written with StGIT in mind, we'll have to see if it
transposes easily to plain git.
I fear it will not be that easy, at least with this design :)
OTOH, implementing transactions in StGIT could provide a first
experience on this particular field, that may later be transposed to
git core - not unlike cogito did for other features. There is the
risk, however, of seeing a different (hopefully better) design for the
feature in git afterwards, and this in turn is likely to make life
harder for StGIT...
[1] http://marc.info/?t=116803935800001&r=1&w=2
Best regards,
--
Yann.
^ permalink raw reply
* Re: [PATCH] Document patch syntax.
From: Karl Hasselström @ 2007-05-12 18:32 UTC (permalink / raw)
To: Yann Dirson; +Cc: Catalin Marinas, git
In-Reply-To: <20070512143827.GE16903@nan92-1-81-57-214-146.fbx.proxad.net>
On 2007-05-12 16:38:27 +0200, Yann Dirson wrote:
> However, that makes me think we should probably use guideline for
> the docs - here comes the question of which convention to use when
> refering to the user. Do we address her directly ("you"), indirectly
> ("the user", "her" - don't remember where the "female user" use
> comes from, but we could maybe follow this), even more indirectly
> ("one"), or any other way ?
I'd go with "you", or possibly "one" (but I strongly prefer "you").
Talking about the user in the third person ("the user", "her", etc.)
seems actively wrong when we are instructing the user on how to do
things.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: [BUG?] Detaching head at checked out point does not work.
From: Junio C Hamano @ 2007-05-12 18:26 UTC (permalink / raw)
To: Jan Hudec; +Cc: git
In-Reply-To: <20070512172105.GB32764@efreet.light.src>
Jan Hudec <bulb@ucw.cz> writes:
> Hello,
>
> I can correctly detach head by saying:
>
> git checkout master^0
>
> (or git checkout master^{} or git checkout refs/heads/master), but NONE of
> these work, if I currently have master checked out. Shouldn't it detach
> anyway?
Yes, and it does as far as I know.
Do you have 3e0318a3?
commit 3e0318a3613ae8e89dcb1fc39d909145e64287b9
Author: Junio C Hamano <junkio@cox.net>
Date: Thu Mar 29 01:02:50 2007 -0700
checkout: allow detaching to HEAD even when switching to the tip of a branch
You cannot currently checkout the tip of an existing branch
without moving to the branch.
This allows you to detach your HEAD and place it at such a
commit, with:
$ git checkout master^0
Signed-off-by: Junio C Hamano <junkio@cox.net>
^ permalink raw reply
* [BUG?] Detaching head at checked out point does not work.
From: Jan Hudec @ 2007-05-12 17:21 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 302 bytes --]
Hello,
I can correctly detach head by saying:
git checkout master^0
(or git checkout master^{} or git checkout refs/heads/master), but NONE of
these work, if I currently have master checked out. Shouldn't it detach
anyway?
Regards,
Jan
--
Jan 'Bulb' Hudec <bulb@ucw.cz>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] t9400: Use the repository config and nothing else.
From: Junio C Hamano @ 2007-05-12 17:21 UTC (permalink / raw)
To: Frank Lichtenheld; +Cc: junkio, git
In-Reply-To: <7vabwa3swp.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> Frank Lichtenheld <frank@lichtenheld.de> writes:
>
>> On Fri, May 11, 2007 at 04:35:18PM -0700, Junio Hamano wrote:
>>> This needs to be fixed, but thanks to that bug, a separate bug
>>> in t9400 test script was discovered. The test discarded
>>> GIT_CONFIG instead of pointing at the proper one to be used in
>>> the exoprted repository. This allowed user's .gitconfig and (if
>>> exists) systemwide /etc/gitconfig to affect the outcome of the
>>> test, which is a big no-no.
>>
>> Shouldn't you also remove the "unset GIT_CONFIG" then?
>
> I didn't test the side of the test that works on the git side,
> but I think you are right.
Actually that is not sufficient, as unsetting means using the
value set in test-lib.sh suitable for usual single-repository
tests.
When you prepare gitcvs.enabled config in the cloned gitcvs.git
repository, you do not want to have GIT_CONFIG=.git/config in
the environment. As you give GIT_DIR to these two commands, not
having GIT_CONFIG would make them do the right thing.
^ permalink raw reply
* [PATCH] Updated documentation of hooks in git-receive-pack.
From: Jan Hudec @ 2007-05-12 17:11 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Added documentation of pre-receive and post-receive hooks and updated
documentation of update and post-update hooks.
Signed-off-by: Jan Hudec <bulb@ucw.cz>
---
Recent question on the mailing-list made me to look at the post-receive hook
in the Documentation/hooks.txt, only to find it is not mentioned there at
all.
I looked up all the hooks and how they are called in receive-pack.c and
updated the documentation for them. Please review and apply.
Feel free to suggest syntactic or semantic fixes; I am not a native English
speaker, so there may well be some.
Regards,
Jan
Documentation/hooks.txt | 84 ++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index b083290..e36cf44 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -90,6 +90,37 @@ parameter, and is invoked after a commit is made.
This hook is meant primarily for notification, and cannot affect
the outcome of `git-commit`.
+[[pre-receive]]
+pre-receive
+-----------
+
+This hook is invoked by `git-receive-pack` on the remote repository,
+which happens when a `git push` is done on a local repository.
+Just before starting to update refs on the remote repository, the
+pre-receive hook is invoked. Its exit status determines the success
+or failure of the update.
+
+This hook executes once for the receive operation. It takes no
+arguments, but for each ref to be updated it receives on standard
+input a line of the format:
+
+ <old-value> SP <new-value> SP <ref-name> NL
+
+where `<old-value>` is the old object name stored in the ref,
+`<new-value>` is the new object name to be stored in the ref and
+`<ref-name>` is the full name of the ref.
+
+If the hook exits with non-zero status, none of the refs will be
+updated. If the hook returs zero, updating of individual refs can
+still be prevented by the <<update,'update'>> hook.
+
+The standard output of this hook is sent to `stderr`, so if you
+want to report something to the `git-send-pack` on the other end,
+you can simply `echo` your messages.
+
+There is no default 'pre-receive' hook.
+
+[[update]]
update
------
@@ -108,7 +139,7 @@ three parameters:
A zero exit from the update hook allows the ref to be updated.
Exiting with a non-zero status prevents `git-receive-pack`
-from updating the ref.
+from updating that ref.
This hook can be used to prevent 'forced' update on certain refs by
making sure that the object name is a commit object that is a
@@ -117,7 +148,8 @@ That is, to enforce a "fast forward only" policy.
It could also be used to log the old..new status. However, it
does not know the entire set of branches, so it would end up
-firing one e-mail per ref when used naively, though.
+firing one e-mail per ref when used naively, though. The
+<<post-receive,'post-receive'>> hook is more suited to that.
Another use suggested on the mailing list is to use this hook to
implement access control which is finer grained than the one
@@ -127,9 +159,45 @@ The standard output of this hook is sent to `stderr`, so if you
want to report something to the `git-send-pack` on the other end,
you can simply `echo` your messages.
-The default 'update' hook, when enabled, demonstrates how to
-send out a notification e-mail.
+The default 'update' hook, when enabled--and with
+`hooks.allowunannotated` config option turned on--prevents
+unannotated tags to be pushed.
+[[post-receive]]
+post-receive
+------------
+
+This hook is invoked by `git-receive-pack` on the remote repository,
+which happens when a `git push` is done on a local repository.
+It executes on the remote repository once after all the refs have
+been updated.
+
+This hook executes once for the receive operation. It takes no
+arguments, but for each ref that was updated it receives on standard
+input a line of the format:
+
+ <old-value> SP <new-value> SP <ref-name> NL
+
+on stdin, where `<old-value>` is the old object name stored in the
+ref, `<new-value>` is the new object name to be stored in the ref and
+`<ref-name>` is the full name of the ref.
+
+This hook cannot affect the outcome of `git-receive-pack`, as it's
+called after the real work is done.
+
+This superceedes the [[post-update]] hook in that it actually get's
+both old and new values of all the refs.
+
+The standard output of this hook is sent to `stderr`, so if you
+want to report something to the `git-send-pack` on the other end,
+you can simply `echo` your messages.
+
+The default 'post-receive' hook is empty, but there is
+a script `post-receive-email` provided in the `contrib/hooks`
+directory in git distribution, which implements sending commit
+emails.
+
+[[post-update]]
post-update
-----------
@@ -146,7 +214,8 @@ the outcome of `git-receive-pack`.
The 'post-update' hook can tell what are the heads that were pushed,
but it does not know what their original and updated values are,
-so it is a poor place to do log old..new.
+so it is a poor place to do log old..new. See
+<<post-receive,'post-receive'>> hook above for a better one.
When enabled, the default 'post-update' hook runs
`git-update-server-info` to keep the information used by dumb
@@ -154,6 +223,5 @@ transports (e.g., HTTP) up-to-date. If you are publishing
a git repository that is accessible via HTTP, you should
probably enable this hook.
-The standard output of this hook is sent to `/dev/null`; if you
-want to report something to the `git-send-pack` on the other end,
-you can redirect your output to your `stderr`.
+Both standard output and standard error output are forwarded to
+`git-send-pack` on the other end.
--
1.5.1.4
^ permalink raw reply related
* Re: Merging commits together into a super-commit
From: Karl Hasselström @ 2007-05-12 17:03 UTC (permalink / raw)
To: Yann Dirson
Cc: Carl Worth, Petr Baudis, J. Bruce Fields, Linus Torvalds,
Johannes Sixt, git
In-Reply-To: <20070512144145.GF16903@nan92-1-81-57-214-146.fbx.proxad.net>
On 2007-05-12 16:41:45 +0200, Yann Dirson wrote:
> On Sat, May 12, 2007 at 04:02:28PM +0200, Karl Hasselström wrote:
>
> > What we should do is delete all stgit metadata when the last patch
> > goes away.
>
> This supposes there is no valuable branch-level metadata. Currently
> we have the description - something which could arguably be moved to
> the git level as well. Otherwise that sounds reasonable to me.
I left the branch description out of the discussion on purpose, since
it's not that interesting -- if there is a description, we can simply
delete everything except that. And I wholeheartedly agree that the
branch description doesn't belong in stgit; it's orthogonal to the
business of managing a patch stack.
> > And we shouldn't have "stg init", either. Initing should be done
> > automatically when needed.
>
> Good idea as well, that would make stg more accessible to the
> average plain-git user.
Yes, that's my secret evil master plan.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Possible bug in git-svn
From: Martin Eisenhardt @ 2007-05-12 16:24 UTC (permalink / raw)
To: Git Mailing List; +Cc: Eric Wong
[-- Attachment #1: Type: text/plain, Size: 2675 bytes --]
Hello Eric,
hello list,
I came across what might just possibly be a bug in git-svn. My apologies if
this was already handled somewhere on the list but I was not able to find
this exact problem mentioned before.
Let's say I run a SVN repository at svn+ssh://svn@example.com/repos and have
it set up as described at
http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html#svn.serverconfig.svnserve.sshtricks
In essence, there is only one user "svn" with access to the repository, and
every developer has his/her public key in ~svn/.ssh/authorized_keys with a
line like
command="svnserve -t --tunnel-user=harry -r /svn/" TYPE1 KEY1
harry@example.com
This is desirable to limit the developers access to the repository; no shell,
access restricted to svn's home directory.
Now let's assume that within this repository, there are several projects, so
we have f.e. the following structure:
+-proj1-+-trunk
| +-branches
| +-tags
|
+-proj2-+-trunk
| +-branches
| +-tags
+-[more projects]
I have no problem setting up a local .git tracking such a project using
$ git-svn init svn+ssh://svn@example.com/repos/proj1/trunk
$ git-svn fetch
After having made local changes and commited them to git, I want to push them
to the remote subversion repository:
$ # do some work
$ git-commit -a
$ git-svn dcommit
The last command gives me (invariably):
Couldn't find a repository: No repository found
in 'svn+ssh://example.com/repos/proj1/trunk' at at /home/mneisen/bin/git-svn
line 403
What is odd is that git-svn uses the URL-prefix svn+ssh://example.com/[...]
instead of the correct svn+ssh://svn@example.com/[...], i.e., git-svn drops
the user name.
This behavior is surprisingly inconsistent as git-svn uses the correct user
name while fetching and stores it correctly in .git/config.
The server log contains the following lines:
May 12 18:18:50 [sshd] Accepted keyboard-interactive/pam for mneisen from
217.229.32.249 port 37685 ssh2
May 12 18:18:50 [sshd(pam_unix)] session opened for user mneisen by (uid=0)
May 12 18:18:51 [sshd(pam_unix)] session closed for user mneisen
which supports my suspicion that git-svn drops the user name for dcommit and
uses the current account name instead.
A git repository on the same machine as the subversion repository is able to
track the SVN repository, so it seems that my problems are directly related
to the combination of git-svn and the svn+ssh transport of subversion.
If this an error on my part, please advise me how to solve it.
Kind regards
Martin Eisenhardt
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] t9400: Use the repository config and nothing else.
From: Junio C Hamano @ 2007-05-12 16:31 UTC (permalink / raw)
To: Frank Lichtenheld; +Cc: junkio, git
In-Reply-To: <20070512162819.GA7184@planck.djpig.de>
Frank Lichtenheld <frank@lichtenheld.de> writes:
> On Fri, May 11, 2007 at 04:35:18PM -0700, Junio Hamano wrote:
>> This needs to be fixed, but thanks to that bug, a separate bug
>> in t9400 test script was discovered. The test discarded
>> GIT_CONFIG instead of pointing at the proper one to be used in
>> the exoprted repository. This allowed user's .gitconfig and (if
>> exists) systemwide /etc/gitconfig to affect the outcome of the
>> test, which is a big no-no.
>
> Shouldn't you also remove the "unset GIT_CONFIG" then?
I didn't test the side of the test that works on the git side,
but I think you are right.
^ permalink raw reply
* Re: [PATCH] t9400: Use the repository config and nothing else.
From: Frank Lichtenheld @ 2007-05-12 16:28 UTC (permalink / raw)
To: junkio, git
In-Reply-To: <7v8xbvj5mx.fsf@arte.twinsun.com>
On Fri, May 11, 2007 at 04:35:18PM -0700, Junio Hamano wrote:
> This needs to be fixed, but thanks to that bug, a separate bug
> in t9400 test script was discovered. The test discarded
> GIT_CONFIG instead of pointing at the proper one to be used in
> the exoprted repository. This allowed user's .gitconfig and (if
> exists) systemwide /etc/gitconfig to affect the outcome of the
> test, which is a big no-no.
Shouldn't you also remove the "unset GIT_CONFIG" then?
> @@ -26,6 +26,7 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
> unset GIT_DIR GIT_CONFIG
> WORKDIR=$(pwd)
> SERVERDIR=$(pwd)/gitcvs.git
> +git_config=$SERVERDIR/config
> CVSROOT=":fork:$SERVERDIR"
> CVSWORK=$(pwd)/cvswork
Gruesse,
--
Frank Lichtenheld <frank@lichtenheld.de>
www: http://www.djpig.de/
^ permalink raw reply
* Re: [PATCH] Fix an unmatched comment end in arm/sha1_arm.S
From: Nicolas Pitre @ 2007-05-12 15:50 UTC (permalink / raw)
To: Marco Costalba; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <e5bfff550705120335t6728ef82u234bb77d4f9e3d77@mail.gmail.com>
On Sat, 12 May 2007, Marco Costalba wrote:
> Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Since @ is already a line comment the spurious */ should already be
ignored. But worth cleaning up nevertheless.
Acked-by: Nicolas Pitre <nico@cam.org>
> ---
> arm/sha1_arm.S | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arm/sha1_arm.S b/arm/sha1_arm.S
> index da92d20..a328b73 100644
> --- a/arm/sha1_arm.S
> +++ b/arm/sha1_arm.S
> @@ -23,7 +23,7 @@ sha_transform:
> stmfd sp!, {r4 - r8, lr}
>
> @ for (i = 0; i < 16; i++)
> - @ W[i] = ntohl(((uint32_t *)data)[i]); */
> + @ W[i] = ntohl(((uint32_t *)data)[i]);
>
> #ifdef __ARMEB__
> mov r4, r0
> --
> 1.5.2.rc3
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Nicolas
^ permalink raw reply
* Re: Win32 version, was Re: quick bare clones taking longer?
From: Brian Gernhardt @ 2007-05-12 15:48 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0705121724000.4167@racer.site>
On May 12, 2007, at 11:25 AM, Johannes Schindelin wrote:
> On Thu, 10 May 2007, Brian Gernhardt wrote:
>
>> Someday Git may work on Windows without a funny (for MS) environment.
>> But that day is not today. Tomorrow doesn't look too good
>> either. ;-)
>
> It sure sounds like you would like that day rather sooner than
> later. In
> related news, that day will be sooner rather than later, if people who
> actually care deeply about this _do_ something about it.
Actually, at the moment, my only Windows environment is inside a VM
box on my Mac. So as long as it works on my Mac, I don't care how
long it takes. And I have neither the time nor build environment to
try to fix it. If that changes, I'll produce patches like a good
code monkey.
~~ Brian
^ permalink raw reply
* [PATCH 3/3] Add handlers for fetch-side configuration of remotes.
From: Daniel Barkalow @ 2007-05-12 15:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
These follow the pattern of the push side configuration, but aren't
taken from anywhere else, because git-fetch is still in shell.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
remote.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
remote.h | 10 ++++++++++
2 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/remote.c b/remote.c
index 1deada1..450b12d 100644
--- a/remote.c
+++ b/remote.c
@@ -17,6 +17,15 @@ static void add_push_refspec(struct remote *remote, const char *ref)
remote->push_refspec_nr = nr;
}
+static void add_fetch_refspec(struct remote *remote, const char *ref)
+{
+ int nr = remote->fetch_refspec_nr + 1;
+ remote->fetch_refspec =
+ xrealloc(remote->fetch_refspec, nr * sizeof(char *));
+ remote->fetch_refspec[nr-1] = ref;
+ remote->fetch_refspec_nr = nr;
+}
+
static void add_uri(struct remote *remote, const char *uri)
{
int nr = remote->uri_nr + 1;
@@ -74,6 +83,9 @@ static void read_remotes_file(struct remote *remote)
} else if (!prefixcmp(buffer, "Push:")) {
value_list = 1;
s = buffer + 5;
+ } else if (!prefixcmp(buffer, "Pull:")) {
+ value_list = 2;
+ s = buffer + 5;
} else
continue;
@@ -93,6 +105,9 @@ static void read_remotes_file(struct remote *remote)
case 1:
add_push_refspec(remote, xstrdup(s));
break;
+ case 2:
+ add_fetch_refspec(remote, xstrdup(s));
+ break;
}
}
fclose(f);
@@ -155,6 +170,8 @@ static int handle_config(const char *key, const char *value)
add_uri(remote, xstrdup(value));
} else if (!strcmp(subkey, ".push")) {
add_push_refspec(remote, xstrdup(value));
+ } else if (!strcmp(subkey, ".fetch")) {
+ add_fetch_refspec(remote, xstrdup(value));
} else if (!strcmp(subkey, ".receivepack")) {
if (!remote->receivepack)
remote->receivepack = xstrdup(value);
@@ -238,10 +255,52 @@ struct remote *remote_get(const char *name)
add_uri(ret, name);
if (!ret->uri)
return NULL;
+ ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);
ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
return ret;
}
+int remote_has_uri(struct remote *remote, const char *uri)
+{
+ int i;
+ for (i = 0; i < remote->uri_nr; i++) {
+ if (!strcmp(remote->uri[i], uri))
+ return 1;
+ }
+ return 0;
+}
+
+int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+{
+ int i;
+ for (i = 0; i < remote->fetch_refspec_nr; i++) {
+ struct refspec *fetch = &remote->fetch[i];
+ if (!fetch->dest)
+ continue;
+ if (fetch->pattern) {
+ if (!prefixcmp(refspec->src, fetch->src)) {
+ refspec->dest =
+ xmalloc(strlen(fetch->dest) +
+ strlen(refspec->src) -
+ strlen(fetch->src) + 1);
+ strcpy(refspec->dest, fetch->dest);
+ strcpy(refspec->dest + strlen(fetch->dest),
+ refspec->src + strlen(fetch->src));
+ refspec->force = fetch->force;
+ return 0;
+ }
+ } else {
+ if (!strcmp(refspec->src, fetch->src)) {
+ refspec->dest = xstrdup(fetch->dest);
+ refspec->force = fetch->force;
+ return 0;
+ }
+ }
+ }
+ refspec->dest = NULL;
+ return -1;
+}
+
static int count_refspec_match(const char *pattern,
struct ref *refs,
struct ref **matched_ref)
diff --git a/remote.h b/remote.h
index 3bc035b..babb135 100644
--- a/remote.h
+++ b/remote.h
@@ -11,11 +11,17 @@ struct remote {
struct refspec *push;
int push_refspec_nr;
+ const char **fetch_refspec;
+ struct refspec *fetch;
+ int fetch_refspec_nr;
+
const char *receivepack;
};
struct remote *remote_get(const char *name);
+int remote_has_uri(struct remote *remote, const char *uri);
+
struct refspec {
unsigned force : 1;
unsigned pattern : 1;
@@ -27,4 +33,8 @@ struct refspec {
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
int nr_refspec, char **refspec, int all);
+/** For the given remote, reads the refspec's src and sets the other fields.
+ **/
+int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+
#endif
--
1.5.2.rc2.45.g3d9b43-dirty
^ permalink raw reply related
* [PATCH 2/3] Move refspec parser from connect.c and cache.h to remote.{c,h}
From: Daniel Barkalow @ 2007-05-12 15:45 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
cache.h | 2 -
connect.c | 240 +---------------------------------------------------------
http-push.c | 1 +
remote.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
remote.h | 12 +++
send-pack.c | 1 +
6 files changed, 261 insertions(+), 241 deletions(-)
diff --git a/cache.h b/cache.h
index 8e76152..46057f8 100644
--- a/cache.h
+++ b/cache.h
@@ -465,8 +465,6 @@ struct ref {
extern pid_t git_connect(int fd[2], char *url, const char *prog);
extern int finish_connect(pid_t pid);
extern int path_match(const char *path, int nr, char **match);
-extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all);
extern int get_ack(int fd, unsigned char *result_sha1);
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
extern int server_supports(const char *feature);
diff --git a/connect.c b/connect.c
index da89c9c..50ec559 100644
--- a/connect.c
+++ b/connect.c
@@ -4,6 +4,7 @@
#include "quote.h"
#include "refs.h"
#include "run-command.h"
+#include "remote.h"
static char *server_capabilities;
@@ -128,245 +129,6 @@ int path_match(const char *path, int nr, char **match)
return 0;
}
-struct refspec {
- char *src;
- char *dst;
- char force;
-};
-
-/*
- * A:B means fast forward remote B with local A.
- * +A:B means overwrite remote B with local A.
- * +A is a shorthand for +A:A.
- * A is a shorthand for A:A.
- * :B means delete remote B.
- */
-static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
-{
- int i;
- struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1));
- for (i = 0; i < nr_refspec; i++) {
- char *sp, *dp, *ep;
- sp = refspec[i];
- if (*sp == '+') {
- rs[i].force = 1;
- sp++;
- }
- ep = strchr(sp, ':');
- if (ep) {
- dp = ep + 1;
- *ep = 0;
- }
- else
- dp = sp;
- rs[i].src = sp;
- rs[i].dst = dp;
- }
- rs[nr_refspec].src = rs[nr_refspec].dst = NULL;
- return rs;
-}
-
-static int count_refspec_match(const char *pattern,
- struct ref *refs,
- struct ref **matched_ref)
-{
- int patlen = strlen(pattern);
- struct ref *matched_weak = NULL;
- struct ref *matched = NULL;
- int weak_match = 0;
- int match = 0;
-
- for (weak_match = match = 0; refs; refs = refs->next) {
- char *name = refs->name;
- int namelen = strlen(name);
- int weak_match;
-
- if (namelen < patlen ||
- memcmp(name + namelen - patlen, pattern, patlen))
- continue;
- if (namelen != patlen && name[namelen - patlen - 1] != '/')
- continue;
-
- /* A match is "weak" if it is with refs outside
- * heads or tags, and did not specify the pattern
- * in full (e.g. "refs/remotes/origin/master") or at
- * least from the toplevel (e.g. "remotes/origin/master");
- * otherwise "git push $URL master" would result in
- * ambiguity between remotes/origin/master and heads/master
- * at the remote site.
- */
- if (namelen != patlen &&
- patlen != namelen - 5 &&
- prefixcmp(name, "refs/heads/") &&
- prefixcmp(name, "refs/tags/")) {
- /* We want to catch the case where only weak
- * matches are found and there are multiple
- * matches, and where more than one strong
- * matches are found, as ambiguous. One
- * strong match with zero or more weak matches
- * are acceptable as a unique match.
- */
- matched_weak = refs;
- weak_match++;
- }
- else {
- matched = refs;
- match++;
- }
- }
- if (!matched) {
- *matched_ref = matched_weak;
- return weak_match;
- }
- else {
- *matched_ref = matched;
- return match;
- }
-}
-
-static void link_dst_tail(struct ref *ref, struct ref ***tail)
-{
- **tail = ref;
- *tail = &ref->next;
- **tail = NULL;
-}
-
-static struct ref *try_explicit_object_name(const char *name)
-{
- unsigned char sha1[20];
- struct ref *ref;
- int len;
-
- if (!*name) {
- ref = xcalloc(1, sizeof(*ref) + 20);
- strcpy(ref->name, "(delete)");
- hashclr(ref->new_sha1);
- return ref;
- }
- if (get_sha1(name, sha1))
- return NULL;
- len = strlen(name) + 1;
- ref = xcalloc(1, sizeof(*ref) + len);
- memcpy(ref->name, name, len);
- hashcpy(ref->new_sha1, sha1);
- return ref;
-}
-
-static int match_explicit_refs(struct ref *src, struct ref *dst,
- struct ref ***dst_tail, struct refspec *rs)
-{
- int i, errs;
- for (i = errs = 0; rs[i].src; i++) {
- struct ref *matched_src, *matched_dst;
-
- matched_src = matched_dst = NULL;
- switch (count_refspec_match(rs[i].src, src, &matched_src)) {
- case 1:
- break;
- case 0:
- /* The source could be in the get_sha1() format
- * not a reference name. :refs/other is a
- * way to delete 'other' ref at the remote end.
- */
- matched_src = try_explicit_object_name(rs[i].src);
- if (matched_src)
- break;
- errs = 1;
- error("src refspec %s does not match any.",
- rs[i].src);
- break;
- default:
- errs = 1;
- error("src refspec %s matches more than one.",
- rs[i].src);
- break;
- }
- switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
- case 1:
- break;
- case 0:
- if (!memcmp(rs[i].dst, "refs/", 5)) {
- int len = strlen(rs[i].dst) + 1;
- matched_dst = xcalloc(1, sizeof(*dst) + len);
- memcpy(matched_dst->name, rs[i].dst, len);
- link_dst_tail(matched_dst, dst_tail);
- }
- else if (!strcmp(rs[i].src, rs[i].dst) &&
- matched_src) {
- /* pushing "master:master" when
- * remote does not have master yet.
- */
- int len = strlen(matched_src->name) + 1;
- matched_dst = xcalloc(1, sizeof(*dst) + len);
- memcpy(matched_dst->name, matched_src->name,
- len);
- link_dst_tail(matched_dst, dst_tail);
- }
- else {
- errs = 1;
- error("dst refspec %s does not match any "
- "existing ref on the remote and does "
- "not start with refs/.", rs[i].dst);
- }
- break;
- default:
- errs = 1;
- error("dst refspec %s matches more than one.",
- rs[i].dst);
- break;
- }
- if (errs)
- continue;
- if (matched_dst->peer_ref) {
- errs = 1;
- error("dst ref %s receives from more than one src.",
- matched_dst->name);
- }
- else {
- matched_dst->peer_ref = matched_src;
- matched_dst->force = rs[i].force;
- }
- }
- return -errs;
-}
-
-static struct ref *find_ref_by_name(struct ref *list, const char *name)
-{
- for ( ; list; list = list->next)
- if (!strcmp(list->name, name))
- return list;
- return NULL;
-}
-
-int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all)
-{
- struct refspec *rs = parse_ref_spec(nr_refspec, refspec);
-
- if (nr_refspec)
- return match_explicit_refs(src, dst, dst_tail, rs);
-
- /* pick the remainder */
- for ( ; src; src = src->next) {
- struct ref *dst_peer;
- if (src->peer_ref)
- continue;
- dst_peer = find_ref_by_name(dst, src->name);
- if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
- continue;
- if (!dst_peer) {
- /* Create a new one and link it */
- int len = strlen(src->name) + 1;
- dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
- memcpy(dst_peer->name, src->name, len);
- hashcpy(dst_peer->new_sha1, src->new_sha1);
- link_dst_tail(dst_peer, dst_tail);
- }
- dst_peer->peer_ref = src;
- }
- return 0;
-}
-
enum protocol {
PROTO_LOCAL = 1,
PROTO_SSH,
diff --git a/http-push.c b/http-push.c
index e3f7675..79d2c38 100644
--- a/http-push.c
+++ b/http-push.c
@@ -9,6 +9,7 @@
#include "diff.h"
#include "revision.h"
#include "exec_cmd.h"
+#include "remote.h"
#include <expat.h>
diff --git a/remote.c b/remote.c
index dbcc74e..1deada1 100644
--- a/remote.c
+++ b/remote.c
@@ -182,6 +182,44 @@ static void read_config(void)
git_config(handle_config);
}
+static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
+{
+ int i;
+ struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
+ for (i = 0; i < nr_refspec; i++) {
+ const char *sp, *ep, *gp;
+ sp = refspec[i];
+ if (*sp == '+') {
+ rs[i].force = 1;
+ sp++;
+ }
+ gp = strchr(sp, '*');
+ ep = strchr(sp, ':');
+ if (gp && ep && gp > ep)
+ gp = NULL;
+ if (ep) {
+ if (ep[1]) {
+ const char *glob = strchr(ep + 1, '*');
+ if (!glob)
+ gp = NULL;
+ if (gp)
+ rs[i].dst = xstrndup(ep + 1,
+ glob - ep - 1);
+ else
+ rs[i].dst = xstrdup(ep + 1);
+ }
+ } else {
+ ep = sp + strlen(sp);
+ }
+ if (gp) {
+ rs[i].pattern = 1;
+ ep = gp;
+ }
+ rs[i].src = xstrndup(sp, ep - sp);
+ }
+ return rs;
+}
+
struct remote *remote_get(const char *name)
{
struct remote *ret;
@@ -200,5 +238,213 @@ struct remote *remote_get(const char *name)
add_uri(ret, name);
if (!ret->uri)
return NULL;
+ ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
return ret;
}
+
+static int count_refspec_match(const char *pattern,
+ struct ref *refs,
+ struct ref **matched_ref)
+{
+ int patlen = strlen(pattern);
+ struct ref *matched_weak = NULL;
+ struct ref *matched = NULL;
+ int weak_match = 0;
+ int match = 0;
+
+ for (weak_match = match = 0; refs; refs = refs->next) {
+ char *name = refs->name;
+ int namelen = strlen(name);
+ int weak_match;
+
+ if (namelen < patlen ||
+ memcmp(name + namelen - patlen, pattern, patlen))
+ continue;
+ if (namelen != patlen && name[namelen - patlen - 1] != '/')
+ continue;
+
+ /* A match is "weak" if it is with refs outside
+ * heads or tags, and did not specify the pattern
+ * in full (e.g. "refs/remotes/origin/master") or at
+ * least from the toplevel (e.g. "remotes/origin/master");
+ * otherwise "git push $URL master" would result in
+ * ambiguity between remotes/origin/master and heads/master
+ * at the remote site.
+ */
+ if (namelen != patlen &&
+ patlen != namelen - 5 &&
+ prefixcmp(name, "refs/heads/") &&
+ prefixcmp(name, "refs/tags/")) {
+ /* We want to catch the case where only weak
+ * matches are found and there are multiple
+ * matches, and where more than one strong
+ * matches are found, as ambiguous. One
+ * strong match with zero or more weak matches
+ * are acceptable as a unique match.
+ */
+ matched_weak = refs;
+ weak_match++;
+ }
+ else {
+ matched = refs;
+ match++;
+ }
+ }
+ if (!matched) {
+ *matched_ref = matched_weak;
+ return weak_match;
+ }
+ else {
+ *matched_ref = matched;
+ return match;
+ }
+}
+
+static void link_dst_tail(struct ref *ref, struct ref ***tail)
+{
+ **tail = ref;
+ *tail = &ref->next;
+ **tail = NULL;
+}
+
+static struct ref *try_explicit_object_name(const char *name)
+{
+ unsigned char sha1[20];
+ struct ref *ref;
+ int len;
+
+ if (!*name) {
+ ref = xcalloc(1, sizeof(*ref) + 20);
+ strcpy(ref->name, "(delete)");
+ hashclr(ref->new_sha1);
+ return ref;
+ }
+ if (get_sha1(name, sha1))
+ return NULL;
+ len = strlen(name) + 1;
+ ref = xcalloc(1, sizeof(*ref) + len);
+ memcpy(ref->name, name, len);
+ hashcpy(ref->new_sha1, sha1);
+ return ref;
+}
+
+static int match_explicit_refs(struct ref *src, struct ref *dst,
+ struct ref ***dst_tail, struct refspec *rs,
+ int rs_nr)
+{
+ int i, errs;
+ for (i = errs = 0; i < rs_nr; i++) {
+ struct ref *matched_src, *matched_dst;
+
+ const char *dst_value = rs[i].dst;
+ if (dst_value == NULL)
+ dst_value = rs[i].src;
+
+ matched_src = matched_dst = NULL;
+ switch (count_refspec_match(rs[i].src, src, &matched_src)) {
+ case 1:
+ break;
+ case 0:
+ /* The source could be in the get_sha1() format
+ * not a reference name. :refs/other is a
+ * way to delete 'other' ref at the remote end.
+ */
+ matched_src = try_explicit_object_name(rs[i].src);
+ if (matched_src)
+ break;
+ errs = 1;
+ error("src refspec %s does not match any.",
+ rs[i].src);
+ break;
+ default:
+ errs = 1;
+ error("src refspec %s matches more than one.",
+ rs[i].src);
+ break;
+ }
+ switch (count_refspec_match(dst_value, dst, &matched_dst)) {
+ case 1:
+ break;
+ case 0:
+ if (!memcmp(dst_value, "refs/", 5)) {
+ int len = strlen(dst_value) + 1;
+ matched_dst = xcalloc(1, sizeof(*dst) + len);
+ memcpy(matched_dst->name, dst_value, len);
+ link_dst_tail(matched_dst, dst_tail);
+ }
+ else if (!strcmp(rs[i].src, dst_value) &&
+ matched_src) {
+ /* pushing "master:master" when
+ * remote does not have master yet.
+ */
+ int len = strlen(matched_src->name) + 1;
+ matched_dst = xcalloc(1, sizeof(*dst) + len);
+ memcpy(matched_dst->name, matched_src->name,
+ len);
+ link_dst_tail(matched_dst, dst_tail);
+ }
+ else {
+ errs = 1;
+ error("dst refspec %s does not match any "
+ "existing ref on the remote and does "
+ "not start with refs/.", dst_value);
+ }
+ break;
+ default:
+ errs = 1;
+ error("dst refspec %s matches more than one.",
+ dst_value);
+ break;
+ }
+ if (errs)
+ continue;
+ if (matched_dst->peer_ref) {
+ errs = 1;
+ error("dst ref %s receives from more than one src.",
+ matched_dst->name);
+ }
+ else {
+ matched_dst->peer_ref = matched_src;
+ matched_dst->force = rs[i].force;
+ }
+ }
+ return -errs;
+}
+
+static struct ref *find_ref_by_name(struct ref *list, const char *name)
+{
+ for ( ; list; list = list->next)
+ if (!strcmp(list->name, name))
+ return list;
+ return NULL;
+}
+
+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+ int nr_refspec, char **refspec, int all)
+{
+ struct refspec *rs =
+ parse_ref_spec(nr_refspec, (const char **) refspec);
+
+ if (nr_refspec)
+ return match_explicit_refs(src, dst, dst_tail, rs, nr_refspec);
+
+ /* pick the remainder */
+ for ( ; src; src = src->next) {
+ struct ref *dst_peer;
+ if (src->peer_ref)
+ continue;
+ dst_peer = find_ref_by_name(dst, src->name);
+ if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
+ continue;
+ if (!dst_peer) {
+ /* Create a new one and link it */
+ int len = strlen(src->name) + 1;
+ dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
+ memcpy(dst_peer->name, src->name, len);
+ hashcpy(dst_peer->new_sha1, src->new_sha1);
+ link_dst_tail(dst_peer, dst_tail);
+ }
+ dst_peer->peer_ref = src;
+ }
+ return 0;
+}
diff --git a/remote.h b/remote.h
index 73747a8..3bc035b 100644
--- a/remote.h
+++ b/remote.h
@@ -8,6 +8,7 @@ struct remote {
int uri_nr;
const char **push_refspec;
+ struct refspec *push;
int push_refspec_nr;
const char *receivepack;
@@ -15,4 +16,15 @@ struct remote {
struct remote *remote_get(const char *name);
+struct refspec {
+ unsigned force : 1;
+ unsigned pattern : 1;
+
+ const char *src;
+ char *dst;
+};
+
+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+ int nr_refspec, char **refspec, int all);
+
#endif
diff --git a/send-pack.c b/send-pack.c
index d5b5162..6851043 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -4,6 +4,7 @@
#include "refs.h"
#include "pkt-line.h"
#include "run-command.h"
+#include "remote.h"
static const char send_pack_usage[] =
"git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
--
1.5.2.rc2.45.g3d9b43-dirty
^ permalink raw reply related
* [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Daniel Barkalow @ 2007-05-12 15:45 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
The new parser is different from the one in builtin-push in two ways:
the default is to use the current branch's remote, if there is one,
before "origin"; and config is used in preference to remotes.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Makefile | 5 +-
builtin-push.c | 190 ++++++----------------------------------------------
remote.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
remote.h | 18 +++++
4 files changed, 245 insertions(+), 172 deletions(-)
create mode 100644 remote.c
create mode 100644 remote.h
diff --git a/Makefile b/Makefile
index 7cf146b..134fbd2 100644
--- a/Makefile
+++ b/Makefile
@@ -296,7 +296,8 @@ LIB_H = \
diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
- utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h
+ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
+ mailmap.h remote.h
DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -318,7 +319,7 @@ LIB_OBJS = \
write_or_die.o trace.o list-objects.o grep.o match-trees.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
- convert.o attr.o decorate.o progress.o mailmap.o
+ convert.o attr.o decorate.o progress.o mailmap.o remote.o
BUILTIN_OBJS = \
builtin-add.o \
diff --git a/builtin-push.c b/builtin-push.c
index cb78401..0e602f3 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -5,17 +5,13 @@
#include "refs.h"
#include "run-command.h"
#include "builtin.h"
-
-#define MAX_URI (16)
+#include "remote.h"
static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
static int all, tags, force, thin = 1, verbose;
static const char *receivepack;
-#define BUF_SIZE (2084)
-static char buffer[BUF_SIZE];
-
static const char **refspec;
static int refspec_nr;
@@ -137,175 +133,29 @@ static void set_refspecs(const char **refs, int nr)
expand_refspecs();
}
-static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
-{
- int n = 0;
- FILE *f = fopen(git_path("remotes/%s", repo), "r");
- int has_explicit_refspec = refspec_nr || all || tags;
-
- if (!f)
- return -1;
- while (fgets(buffer, BUF_SIZE, f)) {
- int is_refspec;
- char *s, *p;
-
- if (!prefixcmp(buffer, "URL:")) {
- is_refspec = 0;
- s = buffer + 4;
- } else if (!prefixcmp(buffer, "Push:")) {
- is_refspec = 1;
- s = buffer + 5;
- } else
- continue;
-
- /* Remove whitespace at the head.. */
- while (isspace(*s))
- s++;
- if (!*s)
- continue;
-
- /* ..and at the end */
- p = s + strlen(s);
- while (isspace(p[-1]))
- *--p = 0;
-
- if (!is_refspec) {
- if (n < MAX_URI)
- uri[n++] = xstrdup(s);
- else
- error("more than %d URL's specified, ignoring the rest", MAX_URI);
- }
- else if (is_refspec && !has_explicit_refspec) {
- if (!wildcard_ref(s))
- add_refspec(xstrdup(s));
- }
- }
- fclose(f);
- if (!n)
- die("remote '%s' has no URL", repo);
- return n;
-}
-
-static const char **config_uri;
-static const char *config_repo;
-static int config_repo_len;
-static int config_current_uri;
-static int config_get_refspecs;
-static int config_get_receivepack;
-
-static int get_remote_config(const char* key, const char* value)
-{
- if (!prefixcmp(key, "remote.") &&
- !strncmp(key + 7, config_repo, config_repo_len)) {
- if (!strcmp(key + 7 + config_repo_len, ".url")) {
- if (config_current_uri < MAX_URI)
- config_uri[config_current_uri++] = xstrdup(value);
- else
- error("more than %d URL's specified, ignoring the rest", MAX_URI);
- }
- else if (config_get_refspecs &&
- !strcmp(key + 7 + config_repo_len, ".push")) {
- if (!wildcard_ref(value))
- add_refspec(xstrdup(value));
- }
- else if (config_get_receivepack &&
- !strcmp(key + 7 + config_repo_len, ".receivepack")) {
- if (!receivepack) {
- char *rp = xmalloc(strlen(value) + 16);
- sprintf(rp, "--receive-pack=%s", value);
- receivepack = rp;
- } else
- error("more than one receivepack given, using the first");
- }
- }
- return 0;
-}
-
-static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
-{
- config_repo_len = strlen(repo);
- config_repo = repo;
- config_current_uri = 0;
- config_uri = uri;
- config_get_refspecs = !(refspec_nr || all || tags);
- config_get_receivepack = (receivepack == NULL);
-
- git_config(get_remote_config);
- return config_current_uri;
-}
-
-static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
-{
- const char *slash = strchr(repo, '/');
- int n = slash ? slash - repo : 1000;
- FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
- char *s, *p;
- int len;
-
- if (!f)
- return 0;
- s = fgets(buffer, BUF_SIZE, f);
- fclose(f);
- if (!s)
- return 0;
- while (isspace(*s))
- s++;
- if (!*s)
- return 0;
- p = s + strlen(s);
- while (isspace(p[-1]))
- *--p = 0;
- len = p - s;
- if (slash)
- len += strlen(slash);
- p = xmalloc(len + 1);
- strcpy(p, s);
- if (slash)
- strcat(p, slash);
- uri[0] = p;
- return 1;
-}
-
-/*
- * Read remotes and branches file, fill the push target URI
- * list. If there is no command line refspecs, read Push: lines
- * to set up the *refspec list as well.
- * return the number of push target URIs
- */
-static int read_config(const char *repo, const char *uri[MAX_URI])
-{
- int n;
-
- if (*repo != '/') {
- n = get_remotes_uri(repo, uri);
- if (n > 0)
- return n;
-
- n = get_config_remotes_uri(repo, uri);
- if (n > 0)
- return n;
-
- n = get_branches_uri(repo, uri);
- if (n > 0)
- return n;
- }
-
- uri[0] = repo;
- return 1;
-}
-
static int do_push(const char *repo)
{
- const char *uri[MAX_URI];
- int i, n, errs;
+ int i, errs;
int common_argc;
const char **argv;
int argc;
+ struct remote *remote = remote_get(repo);
- n = read_config(repo, uri);
- if (n <= 0)
+ if (!remote)
die("bad repository '%s'", repo);
+ if (remote->receivepack) {
+ char *rp = xmalloc(strlen(remote->receivepack) + 16);
+ sprintf(rp, "--receive-pack=%s", remote->receivepack);
+ receivepack = rp;
+ }
+ if (!refspec && !all && !tags && remote->push_refspec_nr) {
+ for (i = 0; i < remote->push_refspec_nr; i++) {
+ if (!wildcard_ref(remote->push_refspec[i]))
+ add_refspec(remote->push_refspec[i]);
+ }
+ }
+
argv = xmalloc((refspec_nr + 10) * sizeof(char *));
argv[0] = "dummy-send-pack";
argc = 1;
@@ -318,12 +168,12 @@ static int do_push(const char *repo)
common_argc = argc;
errs = 0;
- for (i = 0; i < n; i++) {
+ for (i = 0; i < remote->uri_nr; i++) {
int err;
int dest_argc = common_argc;
int dest_refspec_nr = refspec_nr;
const char **dest_refspec = refspec;
- const char *dest = uri[i];
+ const char *dest = remote->uri[i];
const char *sender = "send-pack";
if (!prefixcmp(dest, "http://") ||
!prefixcmp(dest, "https://"))
@@ -341,7 +191,7 @@ static int do_push(const char *repo)
if (!err)
continue;
- error("failed to push to '%s'", uri[i]);
+ error("failed to push to '%s'", remote->uri[i]);
switch (err) {
case -ERR_RUN_COMMAND_FORK:
error("unable to fork for %s", sender);
@@ -362,7 +212,7 @@ static int do_push(const char *repo)
int cmd_push(int argc, const char **argv, const char *prefix)
{
int i;
- const char *repo = "origin"; /* default repository */
+ const char *repo = NULL; /* default repository */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/remote.c b/remote.c
new file mode 100644
index 0000000..dbcc74e
--- /dev/null
+++ b/remote.c
@@ -0,0 +1,204 @@
+#include "cache.h"
+#include "remote.h"
+#include "refs.h"
+
+static struct remote **remotes;
+static int allocated_remotes;
+
+#define BUF_SIZE (2048)
+static char buffer[BUF_SIZE];
+
+static void add_push_refspec(struct remote *remote, const char *ref)
+{
+ int nr = remote->push_refspec_nr + 1;
+ remote->push_refspec =
+ xrealloc(remote->push_refspec, nr * sizeof(char *));
+ remote->push_refspec[nr-1] = ref;
+ remote->push_refspec_nr = nr;
+}
+
+static void add_uri(struct remote *remote, const char *uri)
+{
+ int nr = remote->uri_nr + 1;
+ remote->uri =
+ xrealloc(remote->uri, nr * sizeof(char *));
+ remote->uri[nr-1] = uri;
+ remote->uri_nr = nr;
+}
+
+static struct remote *make_remote(const char *name, int len)
+{
+ int i, empty = -1;
+
+ for (i = 0; i < allocated_remotes; i++) {
+ if (!remotes[i]) {
+ if (empty < 0)
+ empty = i;
+ } else {
+ if (len ? (!strncmp(name, remotes[i]->name, len) &&
+ !remotes[i]->name[len]) :
+ !strcmp(name, remotes[i]->name))
+ return remotes[i];
+ }
+ }
+
+ if (empty < 0) {
+ empty = allocated_remotes;
+ allocated_remotes += allocated_remotes ? allocated_remotes : 1;
+ remotes = xrealloc(remotes,
+ sizeof(*remotes) * allocated_remotes);
+ memset(remotes + empty, 0,
+ (allocated_remotes - empty) * sizeof(*remotes));
+ }
+ remotes[empty] = xcalloc(1, sizeof(struct remote));
+ if (len)
+ remotes[empty]->name = xstrndup(name, len);
+ else
+ remotes[empty]->name = xstrdup(name);
+ return remotes[empty];
+}
+
+static void read_remotes_file(struct remote *remote)
+{
+ FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
+
+ if (!f)
+ return;
+ while (fgets(buffer, BUF_SIZE, f)) {
+ int value_list;
+ char *s, *p;
+
+ if (!prefixcmp(buffer, "URL:")) {
+ value_list = 0;
+ s = buffer + 4;
+ } else if (!prefixcmp(buffer, "Push:")) {
+ value_list = 1;
+ s = buffer + 5;
+ } else
+ continue;
+
+ while (isspace(*s))
+ s++;
+ if (!*s)
+ continue;
+
+ p = s + strlen(s);
+ while (isspace(p[-1]))
+ *--p = 0;
+
+ switch (value_list) {
+ case 0:
+ add_uri(remote, xstrdup(s));
+ break;
+ case 1:
+ add_push_refspec(remote, xstrdup(s));
+ break;
+ }
+ }
+ fclose(f);
+}
+
+static void read_branches_file(struct remote *remote)
+{
+ const char *slash = strchr(remote->name, '/');
+ int n = slash ? slash - remote->name : 1000;
+ FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
+ char *s, *p;
+ int len;
+
+ if (!f)
+ return;
+ s = fgets(buffer, BUF_SIZE, f);
+ fclose(f);
+ if (!s)
+ return;
+ while (isspace(*s))
+ s++;
+ if (!*s)
+ return;
+ p = s + strlen(s);
+ while (isspace(p[-1]))
+ *--p = 0;
+ len = p - s;
+ if (slash)
+ len += strlen(slash);
+ p = xmalloc(len + 1);
+ strcpy(p, s);
+ if (slash)
+ strcat(p, slash);
+ add_uri(remote, p);
+}
+
+static char *default_remote_name = NULL;
+static const char *current_branch = NULL;
+static int current_branch_len = 0;
+
+static int handle_config(const char *key, const char *value)
+{
+ const char *name;
+ const char *subkey;
+ struct remote *remote;
+ if (!prefixcmp(key, "branch.") && current_branch &&
+ !strncmp(key + 7, current_branch, current_branch_len) &&
+ !strcmp(key + 7 + current_branch_len, ".remote")) {
+ free(default_remote_name);
+ default_remote_name = xstrdup(value);
+ }
+ if (prefixcmp(key, "remote."))
+ return 0;
+ name = key + 7;
+ subkey = strrchr(name, '.');
+ if (!subkey)
+ return error("Config with no key for remote %s", name);
+ remote = make_remote(name, subkey - name);
+ if (!strcmp(subkey, ".url")) {
+ add_uri(remote, xstrdup(value));
+ } else if (!strcmp(subkey, ".push")) {
+ add_push_refspec(remote, xstrdup(value));
+ } else if (!strcmp(subkey, ".receivepack")) {
+ if (!remote->receivepack)
+ remote->receivepack = xstrdup(value);
+ else
+ error("more than one receivepack given, using the first");
+ }
+ return 0;
+}
+
+static void read_config(void)
+{
+ unsigned char sha1[20];
+ const char *head_ref;
+ int flag;
+ if (default_remote_name) // did this already
+ return;
+ default_remote_name = xstrdup("origin");
+ current_branch = NULL;
+ head_ref = resolve_ref("HEAD", sha1, 0, &flag);
+ if (head_ref && (flag & REF_ISSYMREF) &&
+ !prefixcmp(head_ref, "refs/heads/")) {
+ current_branch = head_ref + strlen("refs/heads/");
+ current_branch_len = strlen(current_branch);
+ }
+ git_config(handle_config);
+}
+
+struct remote *remote_get(const char *name)
+{
+ struct remote *ret;
+
+ read_config();
+ if (!name)
+ name = default_remote_name;
+ ret = make_remote(name, 0);
+ if (name[0] != '/') {
+ if (!ret->uri)
+ read_remotes_file(ret);
+ if (!ret->uri)
+ read_branches_file(ret);
+ }
+ if (!ret->uri)
+ add_uri(ret, name);
+ if (!ret->uri)
+ return NULL;
+ return ret;
+}
diff --git a/remote.h b/remote.h
new file mode 100644
index 0000000..73747a8
--- /dev/null
+++ b/remote.h
@@ -0,0 +1,18 @@
+#ifndef REMOTE_H
+#define REMOTE_H
+
+struct remote {
+ const char *name;
+
+ const char **uri;
+ int uri_nr;
+
+ const char **push_refspec;
+ int push_refspec_nr;
+
+ const char *receivepack;
+};
+
+struct remote *remote_get(const char *name);
+
+#endif
--
1.5.2.rc2.45.g3d9b43-dirty
^ permalink raw reply related
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