* Re: quick bare clones taking longer?
From: David Miller @ 2007-05-10 0:29 UTC (permalink / raw)
To: junkio; +Cc: git
In-Reply-To: <7v7irhr08y.fsf@assigned-by-dhcp.cox.net>
From: Junio C Hamano <junkio@cox.net>
Date: Wed, 09 May 2007 17:27:41 -0700
> Side note. Earlier you said:
>
> master.kernel.org just upgraded to git-1.5.1.4 and I notice
> that doing something like this:
>
> git clone --bare -n -l -s ../torvalds/linux-2.6.git test-2.6.git
>
> is no longer an instantaneous operation, it seems to be doing a lot
> of stuff now:
>
> But I do not see any difference between v1.5.1.3 and v1.5.1.4 in
> this area. In fact, that get_repo_base() shell function has not
> changed since v0.99.
Correct. I happened to create and start using that symlink
around the same time they upgraded, that's why I made that
(false) connection.
There is no connection between git version and this problem, it's just
the symlink thing.
^ permalink raw reply
* Re: [FAQ?] Rationale for git's way to manage the index
From: Junio C Hamano @ 2007-05-10 0:31 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Petr Baudis, Martin Langhoff, git
In-Reply-To: <alpine.LFD.0.98.0705090825090.4062@woody.linux-foundation.org>
Linus Torvalds <torvalds@linux-foundation.org> writes:
> And unlike the "simpler" model of committing individual hunks
> with "git add -i" or something like that, my model is actually
> much superior!
I obviously agree with this. As I said a few times I regret
introducing "add -i" --- it encourages a wrong workflow, in that
what you commit in steps never match what you had in the working
tree and could have tested until the very end.
^ permalink raw reply
* Re: [PATCH] git-commit: Reformat log messages provided on commandline
From: Junio C Hamano @ 2007-05-10 0:45 UTC (permalink / raw)
To: Petr Baudis; +Cc: Johannes Schindelin, Matthieu Moy, git
In-Reply-To: <20070509142426.GV4489@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
> diff --git a/git-commit.sh b/git-commit.sh
> index f28fc24..28cbb55 100755
> --- a/git-commit.sh
> +++ b/git-commit.sh
> @@ -432,7 +432,7 @@ fi
>
> if test "$log_message" != ''
> then
> - echo "$log_message"
> + echo "$log_message" | fmt
> elif test "$logfile" != ""
Two points.
* You would not want to wrap the first line;
* 75-column is not ideal for every project, so this needs to be
customizable;
* If we were to munge the given message, we would probably also
want to enforce "single-liner summary, empty line, and then
the rest" convention.
Well, I have three there, but I suspect the first two somebody else
may have said already, so...
This is slightly related, but I have been wondering about the
interaction with "single-liner summary, empty line and then the
rest" convention and various commands in the log family.
Currently, --pretty=oneline and --pretty=email (hence format-patch)
take and use only the first line. I think we could change it to:
- take the first paragraph, where the definition of the first
paragraph is "skip all blank lines from the beginning, and
then grab everything up to the next empty line".
- replace all line breaks with a whitespace.
This change would not affect well-behaved commit messages that
adhere to the convention, as their first paragraph always
consist of a single line. On the other hand, people from
different culture can get frustrated by their commit message
chomped at the first linebreak in the middle of sentence right
now, which would be helped by this change.
Their Subject: and --pretty=oneline output would become very
long and unsightly, but their commit messages are already
ugly anyway, and such a change at least avoid the loss of
information.
If we were to do this, Subject: line would most likely use
RFC2822 line folding at the places where line breaks were in the
original, but that goes without saying.
What do people think?
^ permalink raw reply
* Re: [RFC] Second parent for reverts
From: Junio C Hamano @ 2007-05-10 1:43 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <7v7irhslx1.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
>> But a' doesn't actually take anything from b, since it's reverting all of
>> b (unless it's only reverting part of b), and, if b isn't there, it
>> doesn't need a commit message, either, so it's not different from a. So
>> the flow should be:
>>
>> a -> b -> c -> d -> e
>> \ /
>> --------------
>>
>> And this means blame work correctly: lines that b changed will be blamed
>> on a (or an ancestor), because e will match a there and be different from
>> d. So I think git-revert should simply add in the reverted patch's parent.
>> Does this analysis make sense to other people?
>
> The revert operation at the tree level (not commit level) treats
> AS IF b is a common ancestor between a and d and computes a
> merge between a and d using that fake common ancestor to reach
> at e. So it is understandable that you are confused that the
> result somehow has something to do with a merge between a and d.
>
> But other than that, the "analysis" does not make any sense to
> me.
Side note.
In the same spirit as gitk and history browsers pay attention to
the in-body SHA-1 of reverted commits, you could make git-blame
pay attention to the revert message. I think the rough outline
would go like this.
(1) you run pass_blame_to_parent() on 'e' as usual and give as
much blame as you can to 'd'; the remainder are attributed
to 'e' but it is actually a revert of what 'b' did.
(2) you notice that 'e' is a revert of 'b';
(3) 'b' always has only one parent, as we do not revert a
merge; so you can find 'a' easily.
(4) instead of "take the responsibility for the remaining
entries" as usual in assign_blame() while drilling down
'e', you find the matching blob using find_origin and
find_rename between 'a' and 'e'. And pass blames that are
attributed to 'e' down to 'a'.
(5) then you keep going, digging 'd' and 'a'.
^ permalink raw reply
* [PATCH 0/3] Add "remote" library
From: Daniel Barkalow @ 2007-05-10 2:03 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
This series makes a library for handling remotes, by moving code from less
appropriate places into a new header and source file pair. It shouldn't
have any major changes in behavior at this point, aside from a few
behavior improvements ("git push not-a-remote-name" before would give the
wrong error message; newer configuration methods should override older
ones; we should use the same default remote for push that we do for pull,
all else being equal).
Patches 1 and 2 mostly move code into remote.c from other files. Patch 3
adds useful code for the fetch side, corresponding to the code for the
push side, but this code isn't used yet, because the code that would use
it is still in shell. Patches 1 and 2 make sense without patch 3, however.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH] gitweb: choose appropriate view for file type if a= parameter missing.
From: Junio C Hamano @ 2007-05-10 2:04 UTC (permalink / raw)
To: Gerrit Pape; +Cc: git
In-Reply-To: <20070509221928.17244.qmail@f9729cdcdf57d1.315fe32.mid.smarden.org>
Gerrit Pape <pape@smarden.org> writes:
> See http://bugs.debian.org/410465
>
> gitweb URLs use the a= parameter for the view to use on the given path, such
> as "blob" or "tree". Currently, if a gitweb URL omits the a= parameter,
> gitweb just shows the top-level repository summary, regardless of the path
> given. gitweb could instead choose an appropriate view based on the file
> type: blob for blobs (files), tree for trees (directories), and summary if no
> path given (the URL included no f= parameter, or an empty f= parameter).
>
> Apart from making gitweb more robust and supporting URL editing more easily,
> this change would aid the creation of shortcuts to git repositories using
> simple substitution, such as:
> http://example.org/git/?p=path/to/repo.git;hb=HEAD;f=%s
>
> - Josh Triplett
>
> Signed-off-by: Gerrit Pape <pape@smarden.org>
I am not sure if this is a "good" feature or just "because we
can" feature, but I am slightly in favor. I do not know about
others.
I'd however request a few changes to the proposed commit log
message:
* "See http://..." is not the primary information, but "see
... for further details"; please have it at the end, not at
the beginning.
* Was the patch authored by you, or Josh? If the former,
what's his name doing here? Perhaps you wanted to say
"Reported by Josh Triplett"?
^ permalink raw reply
* [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Daniel Barkalow @ 2007-05-10 2:04 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
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 | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
remote.h | 18 +++++
4 files changed, 242 insertions(+), 172 deletions(-)
create mode 100644 remote.c
create mode 100644 remote.h
diff --git a/Makefile b/Makefile
index e0a1308..dd64b7d 100644
--- a/Makefile
+++ b/Makefile
@@ -288,7 +288,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 \
@@ -310,7 +311,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..32a0acf
--- /dev/null
+++ b/remote.c
@@ -0,0 +1,201 @@
+#include "cache.h"
+#include "remote.h"
+#include "refs.h"
+
+static struct remote **remotes;
+static int allocated_remotes;
+
+#define BUF_SIZE (2084)
+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;
+ }
+ }
+}
+
+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 == '/')
+ add_uri(ret, name);
+ if (!ret->uri)
+ read_remotes_file(ret);
+ if (!ret->uri)
+ read_branches_file(ret);
+ 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.22.g9bca
^ permalink raw reply related
* [PATCH 3/3] Add handlers for fetch-side configuration of remotes.
From: Daniel Barkalow @ 2007-05-10 2:04 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
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 f8c9327..fe5ee31 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;
}
}
}
@@ -154,6 +169,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);
@@ -235,10 +252,52 @@ struct remote *remote_get(const char *name)
read_branches_file(ret);
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 79cedde..3608119 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.22.g9bca
^ 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-10 2:04 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
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 32a0acf..f8c9327 100644
--- a/remote.c
+++ b/remote.c
@@ -181,6 +181,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].dest = xstrndup(ep + 1,
+ glob - ep - 1);
+ else
+ rs[i].dest = 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;
@@ -197,5 +235,213 @@ struct remote *remote_get(const char *name)
read_branches_file(ret);
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 *dest = rs[i].dest;
+ if (dest == NULL)
+ dest = 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(dest, dst, &matched_dst)) {
+ case 1:
+ break;
+ case 0:
+ if (!memcmp(dest, "refs/", 5)) {
+ int len = strlen(dest) + 1;
+ matched_dst = xcalloc(1, sizeof(*dst) + len);
+ memcpy(matched_dst->name, dest, len);
+ link_dst_tail(matched_dst, dst_tail);
+ }
+ else if (!strcmp(rs[i].src, dest) &&
+ 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].dest);
+ }
+ break;
+ default:
+ errs = 1;
+ error("dst refspec %s matches more than one.",
+ dest);
+ 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..79cedde 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 *dest;
+};
+
+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.22.g9bca
^ permalink raw reply related
* Re: [PATCH] Git.pm: config_boolean() -> config_bool()
From: Junio C Hamano @ 2007-05-10 2:12 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20070509151337.GX4489@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
> Looks like I forgot to make install or something
> when "testing" the patch, also judging by the error messages repo.or.cz
> spewed furiously in the last update round.
Well, at least I can trust Git.pm and gitweb patches coming thru
you better than patches from elsewhere, as I would know if they
are broken too badly. People would immediately notice the
breakage at repo.or.cz ;-).
Thanks.
^ permalink raw reply
* Re: [FAQ?] Rationale for git's way to manage the index
From: Steven Grimm @ 2007-05-10 2:27 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, Petr Baudis, Martin Langhoff, git
In-Reply-To: <7vzm4dplhu.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> I obviously agree with this. As I said a few times I regret
> introducing "add -i" --- it encourages a wrong workflow, in that
> what you commit in steps never match what you had in the working
> tree and could have tested until the very end.
>
On the other hand, not all changes require any testing at all. For
example, if you're using git to manage documentation, it is totally
reasonable to commit a fix for a simple spelling error in one part of a
file while not committing an in-progress rewrite of another part.
-Steve
^ permalink raw reply
* Re: [FAQ?] Rationale for git's way to manage the index
From: Linus Torvalds @ 2007-05-10 2:39 UTC (permalink / raw)
To: Steven Grimm; +Cc: Junio C Hamano, Petr Baudis, Martin Langhoff, git
In-Reply-To: <4642831C.2090401@midwinter.com>
On Wed, 9 May 2007, Steven Grimm wrote:
> Junio C Hamano wrote:
> > I obviously agree with this. As I said a few times I regret
> > introducing "add -i" --- it encourages a wrong workflow, in that
> > what you commit in steps never match what you had in the working
> > tree and could have tested until the very end.
> >
>
> On the other hand, not all changes require any testing at all. For example, if
> you're using git to manage documentation, it is totally reasonable to commit a
> fix for a simple spelling error in one part of a file while not committing an
> in-progress rewrite of another part.
Yeah, I don't think "git add -i" is a horrible flow - it just shouldn't be
the only or the primary one (ie apparently it *is* the primary one for
darcs, and that's a mistake!)
Of course, whether "git add -i" is a nice interface or not, I dunno.
Personally, if I wanted to do hunk selection, I think I'd stick to
something graphical where I can just click on the hunks. But that's just
me.
Linus
^ permalink raw reply
* Re: [PATCH] Add a birdview-on-the-source-code section to the user manual
From: Junio C Hamano @ 2007-05-10 4:15 UTC (permalink / raw)
To: J. Bruce Fields; +Cc: Johannes Schindelin, kha, barkalow, git
In-Reply-To: <20070509131801.GD14969@fieldses.org>
"J. Bruce Fields" <bfields@fieldses.org> writes:
> On Wed, May 09, 2007 at 02:19:03PM +0200, Johannes Schindelin wrote:
>> [PATCH] user-manual: Touch ups on the birdview section
>
> Those all look like sensible changes to me, thanks!
Likewise, except that big-endian bit I think everybody agrees on
just dropping.
^ permalink raw reply
* Re: git rebase chokes on directory -> symlink -> directory
From: Junio C Hamano @ 2007-05-10 6:44 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Alex Riesen, Git Mailing List, Linus Torvalds
In-Reply-To: <46424ECC.6030907@zytor.com>
"H. Peter Anvin" <hpa@zytor.com> writes:
> Applying 'Revert "x86-64: Make arch/x86-64/boot a symlink to
> arch/i386/boot"'
>
> Adds trailing whitespace.
> .dotest/patch:117:FDARGS =
> Adds trailing whitespace.
> .dotest/patch:350: * Page 0 is deliberately kept safe, since System
> Management Mode code in
> Adds trailing whitespace.
> .dotest/patch:352: * useful for future device drivers that either access
> the BIOS via VM86
> Adds trailing whitespace.
> .dotest/patch:648: *
> Adds trailing whitespace.
> .dotest/patch:649: * This is a collection of several routines from
> gzip-1.0.3
> error: arch/x86_64/boot/.gitignore: already exists in working directory
> error: arch/x86_64/boot/Makefile: already exists in working directory
> error: arch/x86_64/boot/compressed/Makefile: already exists in working
> directory
> error: arch/x86_64/boot/compressed/head.S: already exists in working
> directory
> error: arch/x86_64/boot/compressed/misc.c: already exists in working
> directory
> error: arch/x86_64/boot/compressed/vmlinux.lds: already exists in
> working directory
> error: arch/x86_64/boot/compressed/vmlinux.scr: already exists in
> working directory
> error: arch/x86_64/boot/install.sh: already exists in working directory
> error: arch/x86_64/boot/mtools.conf.in: already exists in working directory
> error: arch/x86_64/boot/tools/.gitignore: already exists in working
> directory
> error: arch/x86_64/boot/tools/build.c: already exists in working directory
Ahh.
* The tree state before this patch is applied has arch/x86_64/boot
as a symlink pointing at ../i386/boot/
* The patch tries to remove arch/x86_64/boot symlink, and
create bunch of files there: .gitignore, Makefile, etc.
This is unfortunately a bit deeper than just git-rebase. You
exposed a nasty corner case problem in the stock git-apply,
probably one of the most important tool the kernel project uses
every day.
git-apply tries to be careful while applying patches; it never
touches the working tree until it is convinced that the patch
would apply cleanly. One of the check it does is that when it
knows a path is going to be created by the patch (in your
example, arch/x86_64/boot/.gitignore), it runs lstat() on the
path to make sure it does not exist.
This leads to a false alarm. Because we do not touch the
working tree before all the check passes, when we try to make
sure that arch/x86_64/boot/.gitignore does not exist yet, we
haven't removed the arch/x86_64/boot symlink. The lstat() check
ends up seeing arch/i386/boot/.gitignore through the
yet-to-be-removed symlink, and says "Hey, you already have a
file there, but what you fed me is a patch to create a new
file. I am not going to clobber what you have in the working
tree."
We have similar checks to see a file we are going to modify does
exist and match the preimage of the diff, which is done by
directly opening and reading the file.
For a file we are going to delete, we make sure that it does
exist and matches what is going to be removed (a removal patch
records the full preimage, so we check what you have in your
working tree matches it in full -- otherwise we would risk
losing your local changes), which again is done by directly
opening and reading the file.
These checks need to be adjusted so that they are not fooled by
symlinks in the middle.
- To make sure something does not exist, first lstat(). If it
does not exist, it does not, so be happy. If it _does_, we
might be getting fooled by a symlink in the middle, so break
leading paths and see if there are symlinks involved. When
we are checking for a path a/b/c/d, if any of a, a/b, a/b/c
is a symlink, then a/b/c/d does _NOT_ exist, for the purpose
of our test.
This would fix this particular case you saw, and would not
add extra overhead in the usual case.
- To make sure something already exists, first lstat(). If it
does not exist, barf (up to this, we already do). Even if it
does seem to exist, we might be getting fooled by a symlink
in the middle, so make sure leading paths are not symlinks.
This would make the normal codepath much more expensive for
deep trees, which is a bit worrisome.
When the code writes out the result after the checks pass, we
first delete all the paths that are going to be deleted, and
also delete all the paths that are being modified. Then in the
second pass, we create all the paths that are being created and
also modified by writing their final contents out, while
creating leading directories as needed. Because of this, a
patch that removes a symlink and then makes it a directory to
hold new files would first remove the symlink and then create
the directory at the right location and deposit newly created
files there. So I do not expect any change is needed in the
writeout codepath.
By the way, I noticed a few things while diagnosing this.
* It was very considerate of you to leave "rebase-1" branch for
my postmortem in the repository. You know what are needed
for debugging very well.
* git-rebase with -m is dog slow. There were people who
advocated to make it the default, but they probably are
either working in a very small project, or working on a
filesystem that even git-apply is slow that the speed
difference does not matter to them.
^ permalink raw reply
* Re: [PATCH] Optimized cvsexportcommit: calling 'cvs status' only once instead of once per changed file.
From: Martin Langhoff @ 2007-05-10 6:53 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: Robin Rosenberg, git
In-Reply-To: <380B28A3-5CD0-4371-A717-1D2629E6302D@zib.de>
On 5/10/07, Steffen Prohaska <prohaska@zib.de> wrote:
> I'll post a patch soon that takes the best of both: Call cvs status
> once with the list of touched files and parse the output. Only one
> connection is needed and only the minimal amount of status data is
> transferred.
Yes, please :-) I wrote cvsexportcommit originally, and use it on a
huge cvs checkout that is hosted on SF.net (slow!). My commits are
small (3~5 files). I agree with using only one connection so commits
with many files are sanity-checked faster, but status needs to ask
explicitly about the files it's about to touch.
cheers,
m
^ permalink raw reply
* [PATCH] Added new git-gui library files to rpm spec
From: Quy Tonthat @ 2007-05-10 7:03 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
"make rpm" breaks without these files.
Signed-off-by: Quy Tonthat <qtonthat@gmail.com>
---
git.spec.in | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/git.spec.in b/git.spec.in
index 9de655c..16148d4 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -163,6 +163,7 @@ rm -rf $RPM_BUILD_ROOT
%defattr(-,root,root)
%{_bindir}/git-gui
%{_bindir}/git-citool
+%{_datadir}/git-gui/
# Not Yet...
# %{!?_without_docs: %{_mandir}/man1/git-gui.1}
# %{!?_without_docs: %doc Documentation/git-gui.html}
--
1.5.2.rc2.4q
^ permalink raw reply related
* Re: [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Junio C Hamano @ 2007-05-10 7:07 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0705092203130.18541@iabervon.org>
This seems to break t9400, with "fatal: bad repository 'gitcvs.git",
upon "git push".
: gitster t/db/remote; sh t9400-git-cvsserver-server.sh -i -v
* expecting success: cvs -Q co -d cvswork master &&
test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5))" = "empty/1.1/"
cvs checkout: Updating cvswork
U cvswork/empty
* ok 1: basic checkout
* expecting success: echo testfile1 >testfile1 &&
git add testfile1 &&
git commit -q -m "Add testfile1" &&
git push gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
diff -q testfile1 ../testfile1
fatal: bad repository 'gitcvs.git'
* FAIL 2: cvs update (create new file)
echo testfile1 >testfile1 &&
git add testfile1 &&
git commit -q -m "Add testfile1" &&
git push gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
diff -q testfile1 ../testfile1
: gitster t/db/remote;
^ permalink raw reply
* Re: [PATCH] Optimized cvsexportcommit: calling 'cvs status' only once instead of once per changed file.
From: Junio C Hamano @ 2007-05-10 7:08 UTC (permalink / raw)
To: Martin Langhoff; +Cc: Steffen Prohaska, Robin Rosenberg, git
In-Reply-To: <46a038f90705092353x107c738foa7db547ab29b1748@mail.gmail.com>
"Martin Langhoff" <martin.langhoff@gmail.com> writes:
> On 5/10/07, Steffen Prohaska <prohaska@zib.de> wrote:
>> I'll post a patch soon that takes the best of both: Call cvs status
>> once with the list of touched files and parse the output. Only one
>> connection is needed and only the minimal amount of status data is
>> transferred.
>
> Yes, please :-) I wrote cvsexportcommit originally, and use it on a
> huge cvs checkout that is hosted on SF.net (slow!). My commits are
> small (3~5 files). I agree with using only one connection so commits
> with many files are sanity-checked faster, but status needs to ask
> explicitly about the files it's about to touch.
>
> cheers,
Sounds like you are perfect guinea pig. A test in the real-life
use followed by an Ack is very appreciated.
^ permalink raw reply
* Re: [PATCH] Added new git-gui library files to rpm spec
From: Junio C Hamano @ 2007-05-10 7:09 UTC (permalink / raw)
To: Quy Tonthat; +Cc: git
In-Reply-To: <4642C3B3.7040205@gmail.com>
Thanks. Very much appreciated, as I am next to clueless in rpm.
^ permalink raw reply
* [PATCH] gitweb: choose appropriate view for file type if a= parameter missing
From: Gerrit Pape @ 2007-05-10 7:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvef1o2ni.fsf@assigned-by-dhcp.cox.net>
gitweb URLs use the a= parameter for the view to use on the given path, such
as "blob" or "tree". Currently, if a gitweb URL omits the a= parameter,
gitweb just shows the top-level repository summary, regardless of the path
given. gitweb could instead choose an appropriate view based on the file
type: blob for blobs (files), tree for trees (directories), and summary if
no path given (the URL included no f= parameter, or an empty f= parameter).
Apart from making gitweb more robust and supporting URL editing more easily,
this change would aid the creation of shortcuts to git repositories using
simple substitution, such as:
http://example.org/git/?p=path/to/repo.git;hb=HEAD;f=%s
With this patch, if given the hash through the h= parameter, or the hash
base (hb=) and a filename (f=), gitweb uses cat-file -t to automatically set
the a= parameter.
This feature was requested by Josh Triplett through
http://bugs.debian.org/410465
Signed-off-by: Gerrit Pape <pape@smarden.org>
---
On Wed, May 09, 2007 at 07:04:01PM -0700, Junio C Hamano wrote:
> I'd however request a few changes to the proposed commit log
> message:
>
> * "See http://..." is not the primary information, but "see
> ... for further details"; please have it at the end, not at
> the beginning.
Okay.
> * Was the patch authored by you, or Josh? If the former,
> what's his name doing here? Perhaps you wanted to say
> "Reported by Josh Triplett"?
Sometimes I'm lazy, it was just a copy&paste from the Debian bug report
submitted by Josh.
Regards, Gerrit.
gitweb/gitweb.perl | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 90243fd..21864c6 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -458,10 +458,16 @@ my %actions = (
"project_index" => \&git_project_index,
);
-if (defined $project) {
- $action ||= 'summary';
-} else {
- $action ||= 'project_list';
+if (!defined $action) {
+ if (defined $hash) {
+ $action = git_get_type($hash);
+ } elsif (defined $hash_base && defined $file_name) {
+ $action = git_get_type("$hash_base:$file_name");
+ } elsif (defined $project) {
+ $action = 'summary';
+ } else {
+ $action = 'project_list';
+ }
}
if (!defined($actions{$action})) {
die_error(undef, "Unknown action");
--
1.5.1.3
^ permalink raw reply related
* Re: [PATCH] Add --aggressive option to 'git gc'
From: Junio C Hamano @ 2007-05-10 7:38 UTC (permalink / raw)
To: Theodore Tso; +Cc: Daniel Barkalow, Git Mailing List
In-Reply-To: <20070509194839.GB10280@thunk.org>
Theodore Tso <tytso@mit.edu> writes:
> Junio, would you be willing to apply this?
Yes, but ;-).
> static int pack_refs = -1;
> +static int aggressive_window = -1;
>
> +#define MAX_ADD 10
> static const char *argv_pack_refs[] = {"pack-refs", "--prune", NULL};
> static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
> -static const char *argv_repack[] = {"repack", "-a", "-d", "-l", NULL};
> +static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};
> static const char *argv_prune[] = {"prune", NULL};
> static const char *argv_rerere[] = {"rerere", "gc", NULL};
>
> @@ -34,13 +36,34 @@ static int gc_config(const char *var, const char *value)
> pack_refs = git_config_bool(var, value);
> return 0;
> }
> + if (!strcmp(var, "gc.aggressiveWindow")) {
Callbacks to git_config() are called with variable names
downcased (except for the 2nd level for 3-level variables. E.g.
[REMOTE "Foo"] URL = ...; becomes var = "remote.Foo.url", val =
...).
> + aggressive_window = git_config_int(var, value);
> + printf("aggressive_window = %d\n", aggressive_window);
Did you mean to leave this in? Looks like a debug remnant...
> + return 0;
> + }
> return git_default_config(var, value);
> }
>
> +static append_option(const char **cmd, const char *opt, int max_length)
Type is "static void" I presume.
> +{
> + int i;
Funny tab here.
> +
> + for (i=0; cmd[i]; i++)
> + ;
SP around operator '='.
> +
> + if (i+2 >= max_length) {
Same for '+'
> + fprintf(stderr, "Too many options specified\n");
> + exit(1);
die("Too many...specified"); /* note the lack of \n at the end */
> + }
> + cmd[i++] = opt;
> + cmd[i] = 0;
We tend to spell out NULL, although we all are aware that C says
literal '0' is the null pointer.
All fixups are trivial so I'd take the patch and amend locally.
^ permalink raw reply
* Re: [PATCH] gitweb: choose appropriate view for file type if a= parameter missing
From: Junio C Hamano @ 2007-05-10 7:43 UTC (permalink / raw)
To: Gerrit Pape; +Cc: git
In-Reply-To: <20070510073207.21562.qmail@25d0c789693af2.315fe32.mid.smarden.org>
Thanks.
^ permalink raw reply
* Re: [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Daniel Barkalow @ 2007-05-10 7:45 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vhcqlma1l.fsf@assigned-by-dhcp.cox.net>
On Thu, 10 May 2007, Junio C Hamano wrote:
> This seems to break t9400, with "fatal: bad repository 'gitcvs.git",
> upon "git push".
>
> : gitster t/db/remote; sh t9400-git-cvsserver-server.sh -i -v
> * expecting success: cvs -Q co -d cvswork master &&
> test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5))" = "empty/1.1/"
> cvs checkout: Updating cvswork
> U cvswork/empty
> * ok 1: basic checkout
>
> * expecting success: echo testfile1 >testfile1 &&
> git add testfile1 &&
> git commit -q -m "Add testfile1" &&
> git push gitcvs.git >/dev/null &&
The man page doesn't think this is valid, since it only claims absolute
paths to work for local repositories. (Current builtin-push seems to be
sloppy; it has the die() that triggers in my version, but its
read_config() always returns a value that doesn't trigger it, suggesting
that there's some sort of bug.)
Following patch fixes t9400 to use absolute paths (assuming that's what it
expects "git push gitcvs.git" to mean).
=== cut here ===
Local repository names for git-push are only documented with absolute
paths, even though current git-push is lenient. Use an absolute path in
t9400-git-cvsserver-server.sh.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index f17be6b..178b9b4 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -45,7 +45,7 @@ test_expect_success 'cvs update (create new file)' \
'echo testfile1 >testfile1 &&
git add testfile1 &&
git commit -q -m "Add testfile1" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
@@ -56,7 +56,7 @@ test_expect_success 'cvs update (update existing file)' \
'echo line 2 >>testfile1 &&
git add testfile1 &&
git commit -q -m "Append to testfile1" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" &&
@@ -69,7 +69,7 @@ test_expect_failure "cvs update w/o -d doesn't create subdir (TODO)" \
echo >test/empty &&
git add test &&
git commit -q -m "Single Subdirectory" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test ! -d test'
@@ -82,7 +82,7 @@ test_expect_success 'cvs update (subdirectories)' \
git add $dir;
done) &&
git commit -q -m "deep sub directory structure" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update -d &&
(for dir in A A/B A/B/C A/D E; do
@@ -100,7 +100,7 @@ cd "$WORKDIR"
test_expect_success 'cvs update (delete file)' \
'git rm testfile1 &&
git commit -q -m "Remove testfile1" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test -z "$(grep testfile1 CVS/Entries)" &&
@@ -111,7 +111,7 @@ test_expect_success 'cvs update (re-add deleted file)' \
'echo readded testfile >testfile1 &&
git add testfile1 &&
git commit -q -m "Re-Add testfile1" &&
- git push gitcvs.git >/dev/null &&
+ git push $(pwd)/gitcvs.git >/dev/null &&
cd cvswork &&
cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
^ permalink raw reply related
* Re: [PATCH] SPECIFYING RANGES typo fix: it it => it is
From: Junio C Hamano @ 2007-05-10 7:45 UTC (permalink / raw)
To: Jari Aalto; +Cc: git
In-Reply-To: <irbdwvwa.fsf@cante.net>
Thanks.
^ permalink raw reply
* Re: [PATCH 1/3] Move remote parsing into a library file out of builtin-push.
From: Junio C Hamano @ 2007-05-10 7:52 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0705100328260.18541@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> On Thu, 10 May 2007, Junio C Hamano wrote:
>
>> This seems to break t9400, with "fatal: bad repository 'gitcvs.git",
>> upon "git push".
>>
>> : gitster t/db/remote; sh t9400-git-cvsserver-server.sh -i -v
>> * expecting success: cvs -Q co -d cvswork master &&
>> test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5))" = "empty/1.1/"
>> cvs checkout: Updating cvswork
>> U cvswork/empty
>> * ok 1: basic checkout
>>
>> * expecting success: echo testfile1 >testfile1 &&
>> git add testfile1 &&
>> git commit -q -m "Add testfile1" &&
>> git push gitcvs.git >/dev/null &&
>
> The man page doesn't think this is valid, since it only claims absolute
> paths to work for local repositories.
Does it? I suspect we need to fix the manpage then, as it is
fairly common to do
$ git fetch ../next-door-neighbour
and expect the opposite to work as well.
And I think it does today.
^ 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