* Re: [PATCHv3 0/3] git-gui: more robust handling of fancy repos
From: Giuseppe Bilotta @ 2009-12-06 13:43 UTC (permalink / raw)
To: Bert Wesarg; +Cc: git, Markus Heidelberg, Shawn O. Pearce
In-Reply-To: <36ca99e90912060459u1073288bj2114f8ab56c7224b@mail.gmail.com>
On Sun, Dec 6, 2009 at 1:59 PM, Bert Wesarg <bert.wesarg@googlemail.com> wrote:
> Here it is:
>
> [guitool "exclude/Ignore file"]
> cmd = echo \"$FILENAME\" >> \"${GIT_DIR:=.git}/info/exclude\"
> noconsole = yes
> needsfile = yes
>
> The purpose is simple: add the current file to the info/exclude file
> in the git dir As you can see, I have a workaround for not having
> GIT_DIR in the env, which should solve the issue. But it would be nice
> to rely on this.
Yup. I'm thinking about setting both $GIT_DIR and $GIT_WORK_TREE once
and for all at the end of the repo setup. This should also spare us
setting it up specifically for gitk (and then separately for the
tools). The question is: should it be done the way it's done for gitk
(i.e. normalizing the paths), or just use it as-is? In the latter
case, the question would be why is the path being normalized before
gitk is invoked.
Ideas?
--
Giuseppe "Oblomov" Bilotta
^ permalink raw reply
* Re: [ANNOUNCE] Git 1.6.5.5
From: Sergio @ 2009-12-06 13:47 UTC (permalink / raw)
To: git
In-Reply-To: <7vtyw4il13.fsf@alter.siamese.dyndns.org>
> * In configuration files, a few variables that name paths can begin with
> ~/ and ~username/ and they are expanded as expected. This is not a
> bugfix but 1.6.6 will have this and without backporting users cannot
> easily use the same ~/.gitconfig across versions.
Sorry if posting as a reply to the announcement is improper.
However I am noticing that some kind of shell-like expansion is now allowed in
the config file, wrt home directories, and my wish is somehow related to it.
I wonder if it could be possible in future releases to expand also $HOSTNAME in
fetch/push specs.
The use case is the following. Working on more than one machine (e.g. a
laptop A and a desktop B) you might need to periodically push to a server C and
like to share the same config on both machines. Having $HOSTNAME expansion,
whatever machine you push from, you can say git push C and have the branches go
on remote/A or remote/B automatically on the server.
Sergio
^ permalink raw reply
* Re: Running commands in wrong environment
From: Jeff King @ 2009-12-06 14:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Marinescu Paul dan, git@vger.kernel.org
In-Reply-To: <7vr5raslqa.fsf@alter.siamese.dyndns.org>
On Fri, Dec 04, 2009 at 09:16:45AM -0800, Junio C Hamano wrote:
> My gut feeling is xsetenv/xputenv would be sufficient. I do not think we
> make any setenv/putenv that we do not care about failing, perhaps other
> than the "if LESS is not there set it to this default value, as it would
> give users nicer experience if they use 'less'."
Here is a patch. I still feel a little silly writing this. The chances
that you will run out of memory doing setenv but _not_ doing any of the
other git operations seems very low. But it's not too invasive a patch.
-- >8 --
Subject: [PATCH] wrap setenv and putenv with error-checking
The setenv and putenv calls can fail if they run out of
memory. We would generally ignore such an error and continue
running, meaning in such an instance we could generate
incorrect results (e.g., if GIT_INDEX_FILE was not set
before running a hook, the hook would operate on the wrong
index).
This patch introduces xsetenv and xputenv wrappers which die
upon failure. The conversion to use these wrappers is almost
a purely mechanical s/\t(set|put)env/\tx\1env/, with two
exceptions:
1. set_git_dir actually checked the return value of setenv
and returned an error to its caller. However, most
callsites simply ignored the error; the only one that
did check immediately called die(). So set_git_dir has
had its return value removed, and just calls xsetenv.
2. The gitsetenv wrapper uses putenv. However, it properly
passes on the return value, so calling code using
xsetenv does the right thing.
Finally, there is one final callsite to note: in daemon.c,
we now call xsetenv to set REMOTE_ADDR. It is OK to die
here, though, as we only execute this function after we have
forked, so we are killing only a single connection, not the
whole daemon.
Signed-off-by: Jeff King <peff@peff.net>
---
I didn't do unsetenv. Should we bother? POSIX says it can return an
error, but only for feeding it a bogus name argument.
builtin-clone.c | 2 +-
builtin-commit.c | 2 +-
builtin-grep.c | 4 ++--
builtin-help.c | 4 ++--
builtin-init-db.c | 2 +-
builtin-merge.c | 4 ++--
builtin-reset.c | 2 +-
builtin-revert.c | 8 ++++----
cache.h | 2 +-
daemon.c | 2 +-
environment.c | 6 ++----
exec_cmd.c | 4 ++--
git-compat-util.h | 2 ++
git.c | 14 +++++++-------
path.c | 2 +-
run-command.c | 2 +-
setup.c | 7 +++----
wrapper.c | 11 +++++++++++
18 files changed, 45 insertions(+), 35 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index caf3025..e901e2c 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -452,7 +452,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
atexit(remove_junk);
sigchain_push_common(remove_junk_on_signal);
- setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
+ xsetenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
if (safe_create_leading_directories_const(git_dir) < 0)
die("could not create leading directories of '%s'", git_dir);
diff --git a/builtin-commit.c b/builtin-commit.c
index e93a647..f65df2b 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -756,7 +756,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (edit_flag)
use_editor = 1;
if (!use_editor)
- setenv("GIT_EDITOR", ":", 1);
+ xsetenv("GIT_EDITOR", ":", 1);
if (get_sha1("HEAD", head_sha1))
initial_commit = 1;
diff --git a/builtin-grep.c b/builtin-grep.c
index a5b6719..cb3845a 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -421,13 +421,13 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
struct strbuf sb = STRBUF_INIT;
grep_add_color(&sb, opt->color_match);
- setenv("GREP_COLOR", sb.buf, 1);
+ xsetenv("GREP_COLOR", sb.buf, 1);
strbuf_reset(&sb);
strbuf_addstr(&sb, "mt=");
grep_add_color(&sb, opt->color_match);
strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se=");
- setenv("GREP_COLORS", sb.buf, 1);
+ xsetenv("GREP_COLORS", sb.buf, 1);
strbuf_release(&sb);
diff --git a/builtin-help.c b/builtin-help.c
index 09ad4b0..886190c 100644
--- a/builtin-help.c
+++ b/builtin-help.c
@@ -329,7 +329,7 @@ static void setup_man_path(void)
if (old_path)
strbuf_addstr(&new_path, old_path);
- setenv("MANPATH", new_path.buf, 1);
+ xsetenv("MANPATH", new_path.buf, 1);
strbuf_release(&new_path);
}
@@ -370,7 +370,7 @@ static void show_man_page(const char *git_cmd)
static void show_info_page(const char *git_cmd)
{
const char *page = cmd_to_page(git_cmd);
- setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
+ xsetenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
execlp("info", "info", "gitman", page, NULL);
die("no info viewer handled the request");
}
diff --git a/builtin-init-db.c b/builtin-init-db.c
index dd84cae..67fd947 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -445,7 +445,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (is_bare_repository_cfg == 1) {
static char git_dir[PATH_MAX+1];
- setenv(GIT_DIR_ENVIRONMENT,
+ xsetenv(GIT_DIR_ENVIRONMENT,
getcwd(git_dir, sizeof(git_dir)), 0);
}
diff --git a/builtin-merge.c b/builtin-merge.c
index 56a1bb6..8e645eb 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -959,7 +959,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
strbuf_addstr(&buf, "merge");
for (i = 0; i < argc; i++)
strbuf_addf(&buf, " %s", argv[i]);
- setenv("GIT_REFLOG_ACTION", buf.buf, 0);
+ xsetenv("GIT_REFLOG_ACTION", buf.buf, 0);
strbuf_reset(&buf);
for (i = 0; i < argc; i++) {
@@ -974,7 +974,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
remotes = &commit_list_insert(commit, remotes)->next;
strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
- setenv(buf.buf, argv[i], 1);
+ xsetenv(buf.buf, argv[i], 1);
strbuf_reset(&buf);
}
diff --git a/builtin-reset.c b/builtin-reset.c
index 73e6022..ce54934 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -220,7 +220,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
reflog_action = args_to_str(argv);
- setenv("GIT_REFLOG_ACTION", reflog_action, 0);
+ xsetenv("GIT_REFLOG_ACTION", reflog_action, 0);
/*
* Possible arguments are:
diff --git a/builtin-revert.c b/builtin-revert.c
index 151aa6a..7d26a9f 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -188,9 +188,9 @@ static void set_author_ident_env(const char *message)
for (timestamp++; *timestamp && isspace(*timestamp);
timestamp++)
; /* do nothing */
- setenv("GIT_AUTHOR_NAME", line, 1);
- setenv("GIT_AUTHOR_EMAIL", email, 1);
- setenv("GIT_AUTHOR_DATE", timestamp, 1);
+ xsetenv("GIT_AUTHOR_NAME", line, 1);
+ xsetenv("GIT_AUTHOR_EMAIL", email, 1);
+ xsetenv("GIT_AUTHOR_DATE", timestamp, 1);
free(line);
return;
}
@@ -247,7 +247,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
git_config(git_default_config, NULL);
me = action == REVERT ? "revert" : "cherry-pick";
- setenv(GIT_REFLOG_ACTION, me, 0);
+ xsetenv(GIT_REFLOG_ACTION, me, 0);
parse_args(argc, argv);
/* this is copied from the shell script, but it's never triggered... */
diff --git a/cache.h b/cache.h
index bf468e5..be954f9 100644
--- a/cache.h
+++ b/cache.h
@@ -386,7 +386,7 @@ extern const char *get_git_dir(void);
extern char *get_object_directory(void);
extern char *get_index_file(void);
extern char *get_graft_file(void);
-extern int set_git_dir(const char *path);
+extern void set_git_dir(const char *path);
extern const char *get_git_work_tree(void);
extern const char *read_gitfile_gently(const char *path);
extern void set_git_work_tree(const char *tree);
diff --git a/daemon.c b/daemon.c
index 5783e24..9649a25 100644
--- a/daemon.c
+++ b/daemon.c
@@ -515,7 +515,7 @@ static int execute(struct sockaddr *addr)
#endif
}
loginfo("Connection from %s:%d", addrbuf, port);
- setenv("REMOTE_ADDR", addrbuf, 1);
+ xsetenv("REMOTE_ADDR", addrbuf, 1);
}
else {
unsetenv("REMOTE_ADDR");
diff --git a/environment.c b/environment.c
index 5171d9f..c750520 100644
--- a/environment.c
+++ b/environment.c
@@ -163,10 +163,8 @@ char *get_graft_file(void)
return git_graft_file;
}
-int set_git_dir(const char *path)
+void set_git_dir(const char *path)
{
- if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
- return error("Could not set GIT_DIR to '%s'", path);
+ xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
setup_git_env();
- return 0;
}
diff --git a/exec_cmd.c b/exec_cmd.c
index 408e4e5..132cc58 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -64,7 +64,7 @@ void git_set_argv_exec_path(const char *exec_path)
/*
* Propagate this setting to external programs.
*/
- setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
+ xsetenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
}
@@ -109,7 +109,7 @@ void setup_path(void)
else
strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
- setenv("PATH", new_path.buf, 1);
+ xsetenv("PATH", new_path.buf, 1);
strbuf_release(&new_path);
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 5c59687..ba4b13d 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -351,6 +351,8 @@ extern void *xcalloc(size_t nmemb, size_t size);
extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
extern ssize_t xread(int fd, void *buf, size_t len);
extern ssize_t xwrite(int fd, const void *buf, size_t len);
+extern void xsetenv(const char *name, const char *value, int overwrite);
+extern void xputenv(char *string);
extern int xdup(int fd);
extern FILE *xfdopen(int fd, const char *mode);
extern int xmkstemp(char *template);
diff --git a/git.c b/git.c
index 11544cd..e2c42cd 100644
--- a/git.c
+++ b/git.c
@@ -40,7 +40,7 @@ int check_pager_config(const char *cmd)
static void commit_pager_choice(void) {
switch (use_pager) {
case 0:
- setenv("GIT_PAGER", "cat", 1);
+ xsetenv("GIT_PAGER", "cat", 1);
break;
case 1:
setup_pager();
@@ -89,7 +89,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--no-replace-objects")) {
read_replace_refs = 0;
- setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
+ xsetenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--git-dir")) {
@@ -97,14 +97,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
fprintf(stderr, "No directory given for --git-dir.\n" );
usage(git_usage_string);
}
- setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
+ xsetenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
handled++;
} else if (!prefixcmp(cmd, "--git-dir=")) {
- setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+ xsetenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
@@ -112,19 +112,19 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
fprintf(stderr, "No directory given for --work-tree.\n" );
usage(git_usage_string);
}
- setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
+ xsetenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--work-tree=")) {
- setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+ xsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
is_bare_repository_cfg = 1;
- setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
+ xsetenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
if (envchanged)
*envchanged = 1;
} else {
diff --git a/path.c b/path.c
index 2ec950b..575ba1d 100644
--- a/path.c
+++ b/path.c
@@ -336,7 +336,7 @@ char *enter_repo(char *path, int strict)
if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
validate_headref("HEAD") == 0) {
- setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+ xsetenv(GIT_DIR_ENVIRONMENT, ".", 1);
check_repository_format();
return path;
}
diff --git a/run-command.c b/run-command.c
index cf2d8f7..b9777e5 100644
--- a/run-command.c
+++ b/run-command.c
@@ -114,7 +114,7 @@ fail_pipe:
if (cmd->env) {
for (; *cmd->env; cmd->env++) {
if (strchr(*cmd->env, '='))
- putenv((char *)*cmd->env);
+ xputenv((char *)*cmd->env);
else
unsetenv(*cmd->env);
}
diff --git a/setup.c b/setup.c
index f67250b..8d878bd 100644
--- a/setup.c
+++ b/setup.c
@@ -362,8 +362,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
for (;;) {
gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
if (gitfile_dir) {
- if (set_git_dir(gitfile_dir))
- die("Repository setup failed");
+ set_git_dir(gitfile_dir);
break;
}
if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
@@ -374,9 +373,9 @@ const char *setup_git_directory_gently(int *nongit_ok)
inside_work_tree = 0;
if (offset != len) {
cwd[offset] = '\0';
- setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+ xsetenv(GIT_DIR_ENVIRONMENT, cwd, 1);
} else
- setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+ xsetenv(GIT_DIR_ENVIRONMENT, ".", 1);
check_repository_format_gently(nongit_ok);
return NULL;
}
diff --git a/wrapper.c b/wrapper.c
index c9be140..8fa3643 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -305,3 +305,14 @@ int unlink_or_warn(const char *file)
return rc;
}
+void xsetenv(const char *name, const char *value, int overwrite)
+{
+ if (setenv(name, value, overwrite) != 0)
+ die_errno("unable to setenv %s", name);
+}
+
+void xputenv(char *string)
+{
+ if (putenv(string) != 0)
+ die_errno("unable to putenv %s", string);
+}
--
1.6.6.rc1.44.g4701a
> --
> 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
^ permalink raw reply related
* Re: Speedlimit at "git clone"
From: Jeff King @ 2009-12-06 14:43 UTC (permalink / raw)
To: git
In-Reply-To: <4B1AB717.9030601@access.denied>
On Sat, Dec 05, 2009 at 08:40:07PM +0100, Stefan Kuhne wrote:
> Stefan Kuhne schrieb:
> Hello,
> >
> > how can i limit the download speed at "git clone"?
> >
> no one any idea?
Git has no internal support for doing this. You would have to choke the
TCP connection elsewhere. Look for QoS options in your operating
system's network setup. I think I have also seen LD_PRELOAD libraries
that will limit I/O, but I can't recall the name of any right now.
-Peff
^ permalink raw reply
* Re: [PATCH] Allow --quiet option to git remote, particularly for `git remote update`
From: Jeff King @ 2009-12-06 14:50 UTC (permalink / raw)
To: Alex Vandiver; +Cc: git
In-Reply-To: <1260057623-28960-1-git-send-email-alex@chmrr.net>
On Sat, Dec 05, 2009 at 07:00:23PM -0500, Alex Vandiver wrote:
> @@ -84,9 +84,12 @@ static int opt_parse_track(const struct option *opt, const char *arg, int not)
> static int fetch_remote(const char *name)
> {
> const char *argv[] = { "fetch", name, NULL, NULL };
> - if (verbose) {
> + if (verbosity > 0) {
> argv[1] = "-v";
> argv[2] = name;
> + } else if (verbosity < 0) {
> + argv[1] = "-q";
> + argv[2] = name;
> }
> printf("Updating %s\n", name);
Should --quiet also affect this "Updating %s" line?
Actually, I have often wished for a way to shut up this line but keep
fetch at its normal verbosity. Fetch very sanely says nothing if there
is nothing to update, but you still get this "Updating" junk line, even
if nothing is transferred. But that would probably need an extra
"--quiet-remote" option to handle separately from what we pass to fetch.
-Peff
^ permalink raw reply
* Re: clang static analyzer
From: Jeff King @ 2009-12-06 14:57 UTC (permalink / raw)
To: Tomas Carnecky; +Cc: git list
In-Reply-To: <33ABC714-2BCC-4910-BCAE-D331AAF2A724@dbservice.com>
On Sun, Dec 06, 2009 at 07:11:24AM +0100, Tomas Carnecky wrote:
> Clang again found many dead assignments/increments, but in the earlier
> discussions you concluded that you want to keep those around. So I
> focussed on another class of potential bugs: Argument with 'nonnull'
> attribute passed null. There were a total of seven such issues. I then
> tried to look through the code and see if they are valid or false
> positives:
Thanks, I think you are moving in the right direction to manually
investigate the output of clang, since it obviously does generate some
false positives.
I think the next step for each site you found would be:
1. If it really is a problem, then it should be easy to show a simple
case that can trigger the issue. Submit a patch fixing that site,
either describing the test case in the commit message, or adding a
case to the test suite.
2. If it is a false positive, see what it would take to silence clang
and submit a patch. I don't think we are opposed to annotations
that help analysis tools as long as those annotations aren't too
intrusive or make the code less readable.
-Peff
^ permalink raw reply
* Re: clang static analyzer
From: Nicolas Pitre @ 2009-12-06 15:39 UTC (permalink / raw)
To: Jeff King; +Cc: Tomas Carnecky, git list
In-Reply-To: <20091206145744.GA6725@coredump.intra.peff.net>
On Sun, 6 Dec 2009, Jeff King wrote:
> On Sun, Dec 06, 2009 at 07:11:24AM +0100, Tomas Carnecky wrote:
>
> > Clang again found many dead assignments/increments, but in the earlier
> > discussions you concluded that you want to keep those around. So I
> > focussed on another class of potential bugs: Argument with 'nonnull'
> > attribute passed null. There were a total of seven such issues. I then
> > tried to look through the code and see if they are valid or false
> > positives:
>
> Thanks, I think you are moving in the right direction to manually
> investigate the output of clang, since it obviously does generate some
> false positives.
>
> I think the next step for each site you found would be:
>
> 1. If it really is a problem, then it should be easy to show a simple
> case that can trigger the issue. Submit a patch fixing that site,
> either describing the test case in the commit message, or adding a
> case to the test suite.
>
> 2. If it is a false positive, see what it would take to silence clang
> and submit a patch. I don't think we are opposed to annotations
> that help analysis tools as long as those annotations aren't too
> intrusive or make the code less readable.
I'm a bit skeptical here. Going down that route might mean that we'll
eventually have to add all sort of crap to accommodate everyone's
preferred static analysis tool of the day. Would be far nicer to try to
make those tools more intelligent instead, or at least make them
understand an out-of-line annotation format that does not clutter the
code itself.
Nicolas
^ permalink raw reply
* Re: What's cooking in git.git (Dec 2009, #02; Sat, 05)
From: Martin Storsjö @ 2009-12-06 15:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, rctay89
In-Reply-To: <7vpr6siki5.fsf@alter.siamese.dyndns.org>
On Sun, 6 Dec 2009, Junio C Hamano wrote:
> [Cooking]
>
> * tr/http-updates (2009-12-01) 3 commits
> - Allow curl to rewind the RPC read buffer
> - Add an option for using any HTTP authentication scheme, not only basic
> - http: maintain curl sessions
>
> There was a discussion on a better structure not to require rewinding in
> the first place? I didn't follow it closely...
I think the conclusion is: Rewinding support isn't strictly necessary,
there's a number of mechanisms in both git and curl that should make sure
that those cases shouldn't surface. A few of them in curl have an
unfortunate conincidence of bugs up until the latest version, though,
leaving much fewer mechanisms in place to avoid this.
Since that patch is quite non-intrusive I think it's a good safeguard,
though. What do you think, Tay, keep it or leave it?
// Martin
^ permalink raw reply
* Re: clang static analyzer
From: Jeff King @ 2009-12-06 16:04 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Tomas Carnecky, git list
In-Reply-To: <alpine.LFD.2.00.0912061032380.31174@xanadu.home>
On Sun, Dec 06, 2009 at 10:39:56AM -0500, Nicolas Pitre wrote:
> > 2. If it is a false positive, see what it would take to silence clang
> > and submit a patch. I don't think we are opposed to annotations
> > that help analysis tools as long as those annotations aren't too
> > intrusive or make the code less readable.
>
> I'm a bit skeptical here. Going down that route might mean that we'll
> eventually have to add all sort of crap to accommodate everyone's
> preferred static analysis tool of the day. Would be far nicer to try to
> make those tools more intelligent instead, or at least make them
> understand an out-of-line annotation format that does not clutter the
> code itself.
To be clear, I am a bit skeptical, too. I would really prefer an
out-of-line annotation if one is available. But I am trying to encourage
the OP to actually make a patch for one instance so we can see just what
it would look like. Then we actually have a data point to discuss.
-Peff
^ permalink raw reply
* [RFC PATCH v3 0/8] Remote helpers smart transport extensions
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
Changes from v2 to v3:
- Rename "FALLBACK" -> "fallback"
- Get rid of magic "layer6 ready" return
- Initialize paths when called as foo::bar://
- Remove dead code as NULL remote can't happen
- Move the stream dupping from unknown protocols patch to taking over
transports patch (that one needs it)
- Reorder the series so that debugging and mandatory cap patches are
first.
- Rename virtual_connected to got_remote_heads (that's what it is)
- Coding style fix ups
- Move transport connect code from smart transports to archive patch.
Ilari Liusvaara (8):
Add remote helper debug mode
Support mandatory capabilities
Pass unknown protocols to external protocol handlers
Refactor git transport options parsing
Support taking over transports
Support remote helpers implementing smart transports
Support remote archive from external protocol helpers
Remove special casing of http, https and ftp
.gitignore | 4 +
Documentation/git-remote-helpers.txt | 30 ++++-
Makefile | 24 +++-
builtin-archive.c | 17 ++-
transport-helper.c | 265 +++++++++++++++++++++++++++++-----
transport.c | 231 +++++++++++++++++++++++-------
transport.h | 28 ++++
7 files changed, 506 insertions(+), 93 deletions(-)
^ permalink raw reply
* [RFC PATCH v3 1/8] Add remote helper debug mode
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Remote helpers deadlock easily, so support debug mode which shows the
interaction steps.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
transport-helper.c | 90 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 65 insertions(+), 25 deletions(-)
diff --git a/transport-helper.c b/transport-helper.c
index 11f3d7e..914bed0 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -8,6 +8,8 @@
#include "quote.h"
#include "remote.h"
+static int debug = 0;
+
struct helper_data
{
const char *name;
@@ -22,6 +24,45 @@ struct helper_data
int refspec_nr;
};
+static void sendline(struct helper_data *helper, struct strbuf *buffer)
+{
+ if (debug)
+ fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
+ if (write_in_full(helper->helper->in, buffer->buf, buffer->len)
+ != buffer->len)
+ die_errno("Full write to remote helper failed");
+}
+
+static int recvline(struct helper_data *helper, struct strbuf *buffer)
+{
+ strbuf_reset(buffer);
+ if (debug)
+ fprintf(stderr, "Debug: Remote helper: Waiting...\n");
+ if (strbuf_getline(buffer, helper->out, '\n') == EOF) {
+ if (debug)
+ fprintf(stderr, "Debug: Remote helper quit.\n");
+ exit(128);
+ }
+
+ if (debug)
+ fprintf(stderr, "Debug: Remote helper: <- %s\n", buffer->buf);
+ return 0;
+}
+
+static void xchgline(struct helper_data *helper, struct strbuf *buffer)
+{
+ sendline(helper, buffer);
+ recvline(helper, buffer);
+}
+
+static void write_constant(int fd, const char *str)
+{
+ if (debug)
+ fprintf(stderr, "Debug: Remote helper: -> %s", str);
+ if (write_in_full(fd, str, strlen(str)) != strlen(str))
+ die_errno("Full write to remote helper failed");
+}
+
static struct child_process *get_helper(struct transport *transport)
{
struct helper_data *data = transport->data;
@@ -48,15 +89,15 @@ static struct child_process *get_helper(struct transport *transport)
die("Unable to run helper: git %s", helper->argv[0]);
data->helper = helper;
- write_str_in_full(helper->in, "capabilities\n");
+ write_constant(helper->in, "capabilities\n");
data->out = xfdopen(helper->out, "r");
while (1) {
- if (strbuf_getline(&buf, data->out, '\n') == EOF)
- exit(128); /* child died, message supplied already */
+ recvline(data, &buf);
if (!*buf.buf)
break;
+ if (debug) fprintf(stderr, "Debug: Got cap %s\n", buf.buf);
if (!strcmp(buf.buf, "fetch"))
data->fetch = 1;
if (!strcmp(buf.buf, "option"))
@@ -82,14 +123,19 @@ static struct child_process *get_helper(struct transport *transport)
free(refspecs);
}
strbuf_release(&buf);
+ if (debug) fprintf(stderr, "Debug: Capabilities complete.\n");
return data->helper;
}
static int disconnect_helper(struct transport *transport)
{
struct helper_data *data = transport->data;
+ struct strbuf buf = STRBUF_INIT;
+
if (data->helper) {
- write_str_in_full(data->helper->in, "\n");
+ if (debug) fprintf(stderr, "Debug: Disconnecting.\n");
+ strbuf_addf(&buf, "\n");
+ sendline(data, &buf);
close(data->helper->in);
fclose(data->out);
finish_command(data->helper);
@@ -117,10 +163,11 @@ static int set_helper_option(struct transport *transport,
const char *name, const char *value)
{
struct helper_data *data = transport->data;
- struct child_process *helper = get_helper(transport);
struct strbuf buf = STRBUF_INIT;
int i, ret, is_bool = 0;
+ get_helper(transport);
+
if (!data->option)
return 1;
@@ -143,12 +190,7 @@ static int set_helper_option(struct transport *transport,
quote_c_style(value, &buf, NULL, 0);
strbuf_addch(&buf, '\n');
- if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
- die_errno("cannot send option to %s", data->name);
-
- strbuf_reset(&buf);
- if (strbuf_getline(&buf, data->out, '\n') == EOF)
- exit(128); /* child died, message supplied already */
+ xchgline(data, &buf);
if (!strcmp(buf.buf, "ok"))
ret = 0;
@@ -208,13 +250,10 @@ static int fetch_with_fetch(struct transport *transport,
}
strbuf_addch(&buf, '\n');
- if (write_in_full(data->helper->in, buf.buf, buf.len) != buf.len)
- die_errno("cannot send fetch to %s", data->name);
+ sendline(data, &buf);
while (1) {
- strbuf_reset(&buf);
- if (strbuf_getline(&buf, data->out, '\n') == EOF)
- exit(128); /* child died, message supplied already */
+ recvline(data, &buf);
if (!prefixcmp(buf.buf, "lock ")) {
const char *name = buf.buf + 5;
@@ -249,12 +288,13 @@ static int fetch_with_import(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct child_process fastimport;
- struct child_process *helper = get_helper(transport);
struct helper_data *data = transport->data;
int i;
struct ref *posn;
struct strbuf buf = STRBUF_INIT;
+ get_helper(transport);
+
if (get_importer(transport, &fastimport))
die("Couldn't run fast-import");
@@ -264,7 +304,7 @@ static int fetch_with_import(struct transport *transport,
continue;
strbuf_addf(&buf, "import %s\n", posn->name);
- write_in_full(helper->in, buf.buf, buf.len);
+ sendline(data, &buf);
strbuf_reset(&buf);
}
disconnect_helper(transport);
@@ -369,17 +409,14 @@ static int push_refs(struct transport *transport,
}
strbuf_addch(&buf, '\n');
- if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
- exit(128);
+ sendline(data, &buf);
ref = remote_refs;
while (1) {
char *refname, *msg;
int status;
- strbuf_reset(&buf);
- if (strbuf_getline(&buf, data->out, '\n') == EOF)
- exit(128); /* child died, message supplied already */
+ recvline(data, &buf);
if (!buf.len)
break;
@@ -471,8 +508,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
while (1) {
char *eov, *eon;
- if (strbuf_getline(&buf, data->out, '\n') == EOF)
- exit(128); /* child died, message supplied already */
+ recvline(data, &buf);
if (!*buf.buf)
break;
@@ -497,6 +533,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
}
tail = &((*tail)->next);
}
+ if (debug) fprintf(stderr, "Debug: Read ref listing.\n");
strbuf_release(&buf);
for (posn = ret; posn; posn = posn->next)
@@ -510,6 +547,9 @@ int transport_helper_init(struct transport *transport, const char *name)
struct helper_data *data = xcalloc(sizeof(*data), 1);
data->name = name;
+ if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
+ debug = 1;
+
transport->data = data;
transport->set_option = set_helper_option;
transport->get_refs_list = get_refs_list;
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 2/8] Support mandatory capabilities
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Add support for marking capability as mandatory for hosting git version
to understand. This is useful for helpers which require various types
of assistance from main git binary.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
Documentation/git-remote-helpers.txt | 5 ++++-
transport-helper.c | 26 ++++++++++++++++++++------
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 5cfdc0c..20a05fe 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -25,7 +25,10 @@ Commands are given by the caller on the helper's standard input, one per line.
'capabilities'::
Lists the capabilities of the helper, one per line, ending
- with a blank line.
+ with a blank line. Each capability may be preceeded with '*'.
+ This marks them mandatory for git version using the remote
+ helper to understand (unknown mandatory capability is fatal
+ error).
'list'::
Lists the refs, one per line, in the format "<value> <name>
diff --git a/transport-helper.c b/transport-helper.c
index 914bed0..f5c585d 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -93,24 +93,38 @@ static struct child_process *get_helper(struct transport *transport)
data->out = xfdopen(helper->out, "r");
while (1) {
+ const char* capname;
+ int mandatory = 0;
recvline(data, &buf);
if (!*buf.buf)
break;
- if (debug) fprintf(stderr, "Debug: Got cap %s\n", buf.buf);
- if (!strcmp(buf.buf, "fetch"))
+
+ if (*buf.buf == '*') {
+ capname = buf.buf + 1;
+ mandatory = 1;
+ } else
+ capname = buf.buf;
+
+ if (debug) fprintf(stderr, "Debug: Got cap %s\n", capname);
+ if (!strcmp(capname, "fetch"))
data->fetch = 1;
- if (!strcmp(buf.buf, "option"))
+ else if (!strcmp(capname, "option"))
data->option = 1;
- if (!strcmp(buf.buf, "push"))
+ else if (!strcmp(capname, "push"))
data->push = 1;
- if (!strcmp(buf.buf, "import"))
+ else if (!strcmp(capname, "import"))
data->import = 1;
- if (!data->refspecs && !prefixcmp(buf.buf, "refspec ")) {
+ else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
ALLOC_GROW(refspecs,
refspec_nr + 1,
refspec_alloc);
refspecs[refspec_nr++] = strdup(buf.buf + strlen("refspec "));
+ } else if (mandatory) {
+ fflush(stderr);
+ die("Unknown madatory capability %s. This remote "
+ "helper probably needs newer version of Git.\n",
+ capname);
}
}
if (refspecs) {
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 4/8] Refactor git transport options parsing
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Refactor the transport options parsing so that protocols that aren't
directly smart transports (file://, git://, ssh:// & co) can record
the smart transport options for the case if it turns that transport
can actually be smart.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
transport.c | 78 +++++++++++++++++++++++++++++++++++-----------------------
transport.h | 13 ++++++++++
2 files changed, 60 insertions(+), 31 deletions(-)
diff --git a/transport.c b/transport.c
index eadd553..deaf983 100644
--- a/transport.c
+++ b/transport.c
@@ -395,41 +395,35 @@ static int close_bundle(struct transport *transport)
}
struct git_transport_data {
- unsigned thin : 1;
- unsigned keep : 1;
- unsigned followtags : 1;
- int depth;
+ struct git_transport_options options;
struct child_process *conn;
int fd[2];
- const char *uploadpack;
- const char *receivepack;
struct extra_have_objects extra_have;
};
-static int set_git_option(struct transport *connection,
+static int set_git_option(struct git_transport_options *opts,
const char *name, const char *value)
{
- struct git_transport_data *data = connection->data;
if (!strcmp(name, TRANS_OPT_UPLOADPACK)) {
- data->uploadpack = value;
+ opts->uploadpack = value;
return 0;
} else if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) {
- data->receivepack = value;
+ opts->receivepack = value;
return 0;
} else if (!strcmp(name, TRANS_OPT_THIN)) {
- data->thin = !!value;
+ opts->thin = !!value;
return 0;
} else if (!strcmp(name, TRANS_OPT_FOLLOWTAGS)) {
- data->followtags = !!value;
+ opts->followtags = !!value;
return 0;
} else if (!strcmp(name, TRANS_OPT_KEEP)) {
- data->keep = !!value;
+ opts->keep = !!value;
return 0;
} else if (!strcmp(name, TRANS_OPT_DEPTH)) {
if (!value)
- data->depth = 0;
+ opts->depth = 0;
else
- data->depth = atoi(value);
+ opts->depth = atoi(value);
return 0;
}
return 1;
@@ -439,7 +433,8 @@ static int connect_setup(struct transport *transport, int for_push, int verbose)
{
struct git_transport_data *data = transport->data;
data->conn = git_connect(data->fd, transport->url,
- for_push ? data->receivepack : data->uploadpack,
+ for_push ? data->options.receivepack :
+ data->options.uploadpack,
verbose ? CONNECT_VERBOSE : 0);
return 0;
}
@@ -469,15 +464,15 @@ static int fetch_refs_via_pack(struct transport *transport,
struct ref *refs_tmp = NULL;
memset(&args, 0, sizeof(args));
- args.uploadpack = data->uploadpack;
- args.keep_pack = data->keep;
+ args.uploadpack = data->options.uploadpack;
+ args.keep_pack = data->options.keep;
args.lock_pack = 1;
- args.use_thin_pack = data->thin;
- args.include_tag = data->followtags;
+ args.use_thin_pack = data->options.thin;
+ args.include_tag = data->options.followtags;
args.verbose = (transport->verbose > 0);
args.quiet = (transport->verbose < 0);
args.no_progress = args.quiet || (!transport->progress && !isatty(1));
- args.depth = data->depth;
+ args.depth = data->options.depth;
for (i = 0; i < nr_heads; i++)
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
@@ -734,7 +729,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
memset(&args, 0, sizeof(args));
args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
- args.use_thin_pack = data->thin;
+ args.use_thin_pack = data->options.thin;
args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
args.quiet = !!(flags & TRANSPORT_PUSH_QUIET);
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
@@ -858,12 +853,14 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->get_refs_list = get_refs_via_rsync;
ret->fetch = fetch_objs_via_rsync;
ret->push = rsync_transport_push;
+ ret->smart_options = NULL;
} else if (is_local(url) && is_file(url)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
ret->get_refs_list = get_refs_from_bundle;
ret->fetch = fetch_refs_from_bundle;
ret->disconnect = close_bundle;
+ ret->smart_options = NULL;
} else if (!is_url(url)
|| !prefixcmp(url, "file://")
|| !prefixcmp(url, "git://")
@@ -873,20 +870,14 @@ struct transport *transport_get(struct remote *remote, const char *url)
/* These are builtin smart transports. */
struct git_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
- ret->set_option = set_git_option;
+ ret->set_option = NULL;
ret->get_refs_list = get_refs_via_connect;
ret->fetch = fetch_refs_via_pack;
ret->push_refs = git_transport_push;
ret->disconnect = disconnect_git;
+ ret->smart_options = &(data->options);
- data->thin = 1;
data->conn = NULL;
- data->uploadpack = "git-upload-pack";
- if (remote->uploadpack)
- data->uploadpack = remote->uploadpack;
- data->receivepack = "git-receive-pack";
- if (remote->receivepack)
- data->receivepack = remote->receivepack;
} else if (!prefixcmp(url, "http://")
|| !prefixcmp(url, "https://")
|| !prefixcmp(url, "ftp://")) {
@@ -904,14 +895,39 @@ struct transport *transport_get(struct remote *remote, const char *url)
transport_helper_init(ret, handler);
}
+ if (ret->smart_options) {
+ ret->smart_options->thin = 1;
+ ret->smart_options->uploadpack = "git-upload-pack";
+ if (remote->uploadpack)
+ ret->smart_options->uploadpack = remote->uploadpack;
+ ret->smart_options->receivepack = "git-receive-pack";
+ if (remote->receivepack)
+ ret->smart_options->receivepack = remote->receivepack;
+ }
+
return ret;
}
int transport_set_option(struct transport *transport,
const char *name, const char *value)
{
+ int git_reports = 1, protocol_reports = 1;
+
+ if (transport->smart_options)
+ git_reports = set_git_option(transport->smart_options,
+ name, value);
+
if (transport->set_option)
- return transport->set_option(transport, name, value);
+ protocol_reports = transport->set_option(transport, name,
+ value);
+
+ /* If either report is 0, report 0 (success). */
+ if (!git_reports || !protocol_reports)
+ return 0;
+ /* If either reports -1 (invalid value), report -1. */
+ if ((git_reports == -1) || (protocol_reports == -1))
+ return -1;
+ /* Otherwise if both report unknown, report unknown. */
return 1;
}
diff --git a/transport.h b/transport.h
index 9e74406..d0192f9 100644
--- a/transport.h
+++ b/transport.h
@@ -4,6 +4,15 @@
#include "cache.h"
#include "remote.h"
+struct git_transport_options {
+ unsigned thin : 1;
+ unsigned keep : 1;
+ unsigned followtags : 1;
+ int depth;
+ const char *uploadpack;
+ const char *receivepack;
+};
+
struct transport {
struct remote *remote;
const char *url;
@@ -65,6 +74,10 @@ struct transport {
signed verbose : 3;
/* Force progress even if the output is not a tty */
unsigned progress : 1;
+ /* If transport is at least potentially smart, this points to
+ git_transport_options structure to use in case transport actually
+ turns out to be smart. */
+ struct git_transport_options* smart_options;
};
#define TRANSPORT_PUSH_ALL 1
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 6/8] Support remote helpers implementing smart transports
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
Documentation/git-remote-helpers.txt | 25 ++++++++++-
transport-helper.c | 84 +++++++++++++++++++++++++++++++++-
2 files changed, 106 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 20a05fe..b957813 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -93,6 +93,20 @@ Supported if the helper has the "push" capability.
+
Supported if the helper has the "import" capability.
+'connect' <service>::
+ Connects to given service. Stdin and stdout of helper are
+ connected to specified service (git prefix is included in service
+ name so e.g. fetching uses 'git-upload-pack' as service) on
+ remote side. Valid replies to this command are empty line
+ (connection established), 'fallback' (no smart transport support,
+ fall back to dumb transports) and just exiting with error message
+ printed (can't connect, don't bother trying to fall back). After
+ line feed terminating the positive (empty) response, the output
+ of service starts. After the connection ends, the remote
+ helper exits.
++
+Supported if the helper has the "connect" capability.
+
If a fatal error occurs, the program writes the error message to
stderr and exits. The caller should expect that a suitable error
message has been printed if the child closes the connection without
@@ -126,6 +140,9 @@ CAPABILITIES
all, it must cover all refs reported by the list command; if
it is not used, it is effectively "*:*"
+'connect'::
+ This helper supports the 'connect' command.
+
REF LIST ATTRIBUTES
-------------------
@@ -168,9 +185,15 @@ OPTIONS
but don't actually change any repository data. For most
helpers this only applies to the 'push', if supported.
+'option servpath <c-style-quoted-path>'::
+ Set service path (--upload-pack, --receive-pack etc.) for
+ next connect. Remote helper MAY support this option. Remote
+ helper MUST NOT rely on this option being set before
+ connect request occurs.
+
Documentation
-------------
-Documentation by Daniel Barkalow.
+Documentation by Daniel Barkalow and Ilari Liusvaara
GIT
---
diff --git a/transport-helper.c b/transport-helper.c
index 3d99fe1..e0254bc 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -18,7 +18,8 @@ struct helper_data
unsigned fetch : 1,
import : 1,
option : 1,
- push : 1;
+ push : 1,
+ connect : 1;
/* These go from remote name (as in "list") to private name */
struct refspec *refspecs;
int refspec_nr;
@@ -163,7 +164,10 @@ static struct child_process *get_helper(struct transport *transport)
refspec_nr + 1,
refspec_alloc);
refspecs[refspec_nr++] = strdup(buf.buf + strlen("refspec "));
- } else if (mandatory) {
+ }
+ else if (!strcmp(capname, "connect"))
+ data->connect = 1;
+ else if (mandatory) {
fflush(stderr);
die("Unknown madatory capability %s. This remote "
"helper probably needs newer version of Git.\n",
@@ -386,12 +390,78 @@ static int fetch_with_import(struct transport *transport,
return 0;
}
+static int _process_connect(struct transport *transport,
+ const char *name, const char *exec)
+{
+ struct helper_data *data = transport->data;
+ struct strbuf cmdbuf = STRBUF_INIT;
+ struct child_process *helper;
+ int r;
+
+ helper = get_helper(transport);
+
+ /* Handle --upload-pack and friends. This is fire and forget...
+ just warn if it fails. */
+ if (strcmp(name, exec)) {
+ r = set_helper_option(transport, "servpath", exec);
+ if (r > 0)
+ fprintf(stderr, "Warning: Setting remote service path "
+ "not supported by protocol.\n");
+ else if (r < 0)
+ fprintf(stderr, "Warning: Invalid remote service "
+ "path.\n");
+ }
+
+ if (data->connect)
+ strbuf_addf(&cmdbuf, "connect %s\n", name);
+ else
+ return 0;
+
+ xchgline(data, &cmdbuf);
+ if (!strcmp(cmdbuf.buf, "")) {
+ if (debug)
+ fprintf(stderr, "Debug: Smart transport connection "
+ "ready.\n");
+ return 1;
+ } else if (!strcmp(cmdbuf.buf, "fallback")) {
+ if (debug)
+ fprintf(stderr, "Debug: Falling back to dumb "
+ "transport.\n");
+ return 0;
+ } else
+ die("Unknown response to connect: %s",
+ cmdbuf.buf);
+
+ return 0; /* Shouldn't be here. */
+}
+
+static int process_connect(struct transport* transport,
+ int for_push)
+{
+ struct helper_data *data = transport->data;
+ const char *name;
+ const char *exec;
+
+ name = for_push ? "git-receive-pack" : "git-upload-pack";
+ if (for_push)
+ exec = data->gitoptions.receivepack;
+ else
+ exec = data->gitoptions.uploadpack;
+
+ return _process_connect(transport, name, exec);
+}
+
static int fetch(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct helper_data *data = transport->data;
int i, count;
+ if (process_connect(transport, 0)) {
+ transport_take_over(transport);
+ return transport->fetch(transport, nr_heads, to_fetch);
+ }
+
count = 0;
for (i = 0; i < nr_heads; i++)
if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
@@ -419,6 +489,11 @@ static int push_refs(struct transport *transport,
struct child_process *helper;
struct ref *ref;
+ if (process_connect(transport, 1)) {
+ transport_take_over(transport);
+ return transport->push_refs(transport, remote_refs, flags);
+ }
+
if (!remote_refs)
return 0;
@@ -559,6 +634,11 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
helper = get_helper(transport);
+ if (process_connect(transport, for_push)) {
+ transport_take_over(transport);
+ return transport->get_refs_list(transport, for_push);
+ }
+
if (data->push && for_push)
write_str_in_full(helper->in, "list for-push\n");
else
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 3/8] Pass unknown protocols to external protocol handlers
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Change URL handling to allow external protocol handlers to implement
new protocols without the '::' syntax if helper name does not conflict
with any built-in protocol.
foo:// now invokes git-remote-foo with foo:// URL.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
transport-helper.c | 22 ++++++++++++-
transport.c | 87 +++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 93 insertions(+), 16 deletions(-)
diff --git a/transport-helper.c b/transport-helper.c
index f5c585d..95aaa02 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -63,6 +63,26 @@ static void write_constant(int fd, const char *str)
die_errno("Full write to remote helper failed");
}
+const char* remove_ext_force(const char* url)
+{
+ const char* url2 = url;
+ const char* first_colon = NULL;
+
+ if (!url)
+ return NULL;
+
+ while (*url2 && !first_colon)
+ if (*url2 == ':')
+ first_colon = url2;
+ else
+ url2++;
+
+ if (first_colon && first_colon[1] == ':')
+ return first_colon + 2;
+ else
+ return url;
+}
+
static struct child_process *get_helper(struct transport *transport)
{
struct helper_data *data = transport->data;
@@ -83,7 +103,7 @@ static struct child_process *get_helper(struct transport *transport)
strbuf_addf(&buf, "remote-%s", data->name);
helper->argv[0] = strbuf_detach(&buf, NULL);
helper->argv[1] = transport->remote->name;
- helper->argv[2] = transport->url;
+ helper->argv[2] = remove_ext_force(transport->url);
helper->git_cmd = 1;
if (start_command(helper))
die("Unable to run helper: git %s", helper->argv[0]);
diff --git a/transport.c b/transport.c
index 3eea836..eadd553 100644
--- a/transport.c
+++ b/transport.c
@@ -780,6 +780,55 @@ static int is_file(const char *url)
return S_ISREG(buf.st_mode);
}
+static const char* strchrc(const char* str, int c)
+{
+ while (*str)
+ if (*str == c)
+ return str;
+ else
+ str++;
+ return NULL;
+}
+
+static int is_url(const char* url)
+{
+ if (!url)
+ return 0;
+
+ const char* url2 = url;
+ const char* first_slash = strchrc(url, '/');
+
+ /* Input with no slash at all or slash first can't be URL. */
+ if (!first_slash || first_slash == url)
+ return 0;
+ /* Character before must be : and next must be /. */
+ if (first_slash[-1] != ':' || first_slash[1] != '/')
+ return 0;
+ /* There must be something before the :// */
+ if (first_slash == url + 1)
+ return 0;
+ /* Check all characters up to first slash. Only alpha, num and
+ : are allowed. : must be followed by : or / */
+ url2 = url;
+ while (url2 < first_slash) {
+ if (*url2 != ':' && !isalnum((unsigned char)*url2))
+ return 0;
+ if (*url2 == ':' && url2[1] != ':' && url2[1] != '/')
+ return 0;
+ if (*url2 == ':')
+ url2++; /* Skip second : */
+ url2++;
+ }
+
+ /* Valid enough. */
+ return 1;
+}
+
+static int external_specification_len(const char* url)
+{
+ return strchrc(url, ':') - url;
+}
+
struct transport *transport_get(struct remote *remote, const char *url)
{
struct transport *ret = xcalloc(1, sizeof(*ret));
@@ -805,30 +854,23 @@ struct transport *transport_get(struct remote *remote, const char *url)
if (remote && remote->foreign_vcs) {
transport_helper_init(ret, remote->foreign_vcs);
- return ret;
- }
-
- if (!prefixcmp(url, "rsync:")) {
+ } else if (!prefixcmp(url, "rsync:")) {
ret->get_refs_list = get_refs_via_rsync;
ret->fetch = fetch_objs_via_rsync;
ret->push = rsync_transport_push;
-
- } else if (!prefixcmp(url, "http://")
- || !prefixcmp(url, "https://")
- || !prefixcmp(url, "ftp://")) {
- transport_helper_init(ret, "curl");
-#ifdef NO_CURL
- error("git was compiled without libcurl support.");
-#endif
-
} else if (is_local(url) && is_file(url)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
ret->get_refs_list = get_refs_from_bundle;
ret->fetch = fetch_refs_from_bundle;
ret->disconnect = close_bundle;
-
- } else {
+ } else if (!is_url(url)
+ || !prefixcmp(url, "file://")
+ || !prefixcmp(url, "git://")
+ || !prefixcmp(url, "ssh://")
+ || !prefixcmp(url, "git+ssh://")
+ || !prefixcmp(url, "ssh+git://")) {
+ /* These are builtin smart transports. */
struct git_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
ret->set_option = set_git_option;
@@ -845,6 +887,21 @@ struct transport *transport_get(struct remote *remote, const char *url)
data->receivepack = "git-receive-pack";
if (remote->receivepack)
data->receivepack = remote->receivepack;
+ } else if (!prefixcmp(url, "http://")
+ || !prefixcmp(url, "https://")
+ || !prefixcmp(url, "ftp://")) {
+ /* These three are just plain special. */
+ transport_helper_init(ret, "curl");
+#ifdef NO_CURL
+ error("git was compiled without libcurl support.");
+#endif
+ } else {
+ /* Unknown protocol in URL. Pass to external handler. */
+ int len = external_specification_len(url);
+ char* handler = xmalloc(len + 1);
+ handler[len] = 0;
+ strncpy(handler, url, len);
+ transport_helper_init(ret, handler);
}
return ret;
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 7/8] Support remote archive from external protocol helpers
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Helpers which support invoke/connect also should support remote archive
snapshot (or at least there's only one way to attempt it). So support
remote snapshotting for protocol helpers.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
builtin-archive.c | 17 ++++++++++-------
transport-helper.c | 19 +++++++++++++++++++
transport.c | 21 +++++++++++++++++++++
transport.h | 5 +++++
4 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/builtin-archive.c b/builtin-archive.c
index 12351e9..d34b3fd 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -5,6 +5,7 @@
#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "transport.h"
#include "parse-options.h"
#include "pkt-line.h"
#include "sideband.h"
@@ -25,12 +26,16 @@ static void create_output_file(const char *output_file)
static int run_remote_archiver(int argc, const char **argv,
const char *remote, const char *exec)
{
- char *url, buf[LARGE_PACKET_MAX];
+ char buf[LARGE_PACKET_MAX];
int fd[2], i, len, rv;
- struct child_process *conn;
+ struct transport *transport;
+ struct remote *_remote;
- url = xstrdup(remote);
- conn = git_connect(fd, url, exec, 0);
+ _remote = remote_get(remote);
+ if (!_remote->url[0])
+ die("git archive: Remote with no URL");
+ transport = transport_get(_remote, _remote->url[0]);
+ transport_connect(transport, "git-upload-archive", exec, fd);
for (i = 1; i < argc; i++)
packet_write(fd[1], "argument %s\n", argv[i]);
@@ -53,9 +58,7 @@ static int run_remote_archiver(int argc, const char **argv,
/* Now, start reading from fd[0] and spit it out to stdout */
rv = recv_sideband("archive", fd[0], 1);
- close(fd[0]);
- close(fd[1]);
- rv |= finish_connect(conn);
+ rv |= transport_disconnect(transport);
return !!rv;
}
diff --git a/transport-helper.c b/transport-helper.c
index e0254bc..a49be55 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -451,6 +451,24 @@ static int process_connect(struct transport* transport,
return _process_connect(transport, name, exec);
}
+static int connect_helper(struct transport *transport, const char *name,
+ const char *exec, int fd[2])
+{
+ struct helper_data *data = transport->data;
+
+ /* Get_helper so connect is inited. */
+ get_helper(transport);
+ if (!data->connect)
+ die("Operation not supported by protocol.");
+
+ if (!_process_connect(transport, name, exec))
+ die("Can't connect to subservice %s.", name);
+
+ fd[0] = data->helper->out;
+ fd[1] = data->helper->in;
+ return 0;
+}
+
static int fetch(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
@@ -694,6 +712,7 @@ int transport_helper_init(struct transport *transport, const char *name)
transport->fetch = fetch;
transport->push_refs = push_refs;
transport->disconnect = release_helper;
+ transport->connect = connect_helper;
transport->disown = helper_disown;
transport->smart_options = &(data->gitoptions);
return 0;
diff --git a/transport.c b/transport.c
index e9802e3..b418889 100644
--- a/transport.c
+++ b/transport.c
@@ -756,6 +756,17 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
return ret;
}
+static int connect_git(struct transport *transport, const char* name,
+ const char* executable, int fd[2])
+{
+ struct git_transport_data *data = transport->data;
+ data->conn = git_connect(data->fd, transport->url,
+ executable, 0);
+ fd[0] = data->fd[0];
+ fd[1] = data->fd[1];
+ return 0;
+}
+
static int disconnect_git(struct transport *transport)
{
struct git_transport_data *data = transport->data;
@@ -917,6 +928,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->get_refs_list = get_refs_via_connect;
ret->fetch = fetch_refs_via_pack;
ret->push_refs = git_transport_push;
+ ret->connect = connect_git;
ret->disconnect = disconnect_git;
ret->smart_options = &(data->options);
ret->disown = NULL;
@@ -1078,6 +1090,15 @@ void transport_unlock_pack(struct transport *transport)
}
}
+int transport_connect(struct transport *transport, const char *name,
+ const char* exec, int fd[2])
+{
+ if (transport->connect)
+ return transport->connect(transport, name, exec, fd);
+ else
+ die("Operation not supported by protocol");
+}
+
int transport_disconnect(struct transport *transport)
{
int ret = 0;
diff --git a/transport.h b/transport.h
index 499962d..d702e31 100644
--- a/transport.h
+++ b/transport.h
@@ -64,6 +64,8 @@ struct transport {
**/
int (*push_refs)(struct transport *transport, struct ref *refs, int flags);
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
+ int (*connect)(struct transport *connection, const char* name,
+ const char* executable, int fd[2]);
/**
* Disown the transport helper. Releases all resources used
@@ -139,6 +141,9 @@ int transport_disconnect(struct transport *transport);
char *transport_anonymize_url(const char *url);
void transport_take_over(struct transport *transport);
+int transport_connect(struct transport *transport, const char *name,
+ const char* exec, int fd[2]);
+
/* Transport methods defined outside transport.c */
int transport_helper_init(struct transport *transport, const char *name);
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 5/8] Support taking over transports
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
Add support for taking over transports that turn out to be smart.
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
transport-helper.c | 28 ++++++++++++++++++++++++-
transport.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++----
transport.h | 10 +++++++++
3 files changed, 89 insertions(+), 6 deletions(-)
diff --git a/transport-helper.c b/transport-helper.c
index 95aaa02..3d99fe1 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -22,6 +22,7 @@ struct helper_data
/* These go from remote name (as in "list") to private name */
struct refspec *refspecs;
int refspec_nr;
+ struct git_transport_options gitoptions;
};
static void sendline(struct helper_data *helper, struct strbuf *buffer)
@@ -63,6 +64,15 @@ static void write_constant(int fd, const char *str)
die_errno("Full write to remote helper failed");
}
+static struct child_process* helper_disown(struct transport *transport)
+{
+ struct helper_data *data = transport->data;
+ struct child_process *child = data->helper;
+ fclose(data->out);
+ free(data);
+ return child;
+}
+
const char* remove_ext_force(const char* url)
{
const char* url2 = url;
@@ -91,6 +101,7 @@ static struct child_process *get_helper(struct transport *transport)
const char **refspecs = NULL;
int refspec_nr = 0;
int refspec_alloc = 0;
+ int duped;
if (data->helper)
return data->helper;
@@ -109,9 +120,21 @@ static struct child_process *get_helper(struct transport *transport)
die("Unable to run helper: git %s", helper->argv[0]);
data->helper = helper;
+ /* Open the output as FILE* so strbuf_getline() can be used.
+ Do this with duped fd because fclose() will close the fd,
+ and stuff like disowning will require the fd to remain.
+
+ Set the stream to unbuffered because some reads are critical
+ in sense that any overreading will cause deadlocks.
+ */
+ duped = dup(helper->out);
+ if (duped < 0)
+ die_errno("Can't dup helper output fd");
+ data->out = xfdopen(duped, "r");
+ setvbuf(data->out, NULL, _IONBF, 0);
+
write_constant(helper->in, "capabilities\n");
- data->out = xfdopen(helper->out, "r");
while (1) {
const char* capname;
int mandatory = 0;
@@ -171,6 +194,7 @@ static int disconnect_helper(struct transport *transport)
strbuf_addf(&buf, "\n");
sendline(data, &buf);
close(data->helper->in);
+ close(data->helper->out);
fclose(data->out);
finish_command(data->helper);
free((char *)data->helper->argv[0]);
@@ -590,5 +614,7 @@ int transport_helper_init(struct transport *transport, const char *name)
transport->fetch = fetch;
transport->push_refs = push_refs;
transport->disconnect = release_helper;
+ transport->disown = helper_disown;
+ transport->smart_options = &(data->gitoptions);
return 0;
}
diff --git a/transport.c b/transport.c
index deaf983..e9802e3 100644
--- a/transport.c
+++ b/transport.c
@@ -398,6 +398,7 @@ struct git_transport_data {
struct git_transport_options options;
struct child_process *conn;
int fd[2];
+ unsigned got_remote_heads : 1;
struct extra_have_objects extra_have;
};
@@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts,
static int connect_setup(struct transport *transport, int for_push, int verbose)
{
struct git_transport_data *data = transport->data;
+
+ if (data->conn)
+ return 0;
+
data->conn = git_connect(data->fd, transport->url,
for_push ? data->options.receivepack :
data->options.uploadpack,
verbose ? CONNECT_VERBOSE : 0);
+
return 0;
}
@@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
connect_setup(transport, for_push, 0);
get_remote_heads(data->fd[0], &refs, 0, NULL,
for_push ? REF_NORMAL : 0, &data->extra_have);
+ data->got_remote_heads = 1;
return refs;
}
@@ -477,9 +484,10 @@ static int fetch_refs_via_pack(struct transport *transport,
for (i = 0; i < nr_heads; i++)
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
- if (!data->conn) {
+ if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
+ data->got_remote_heads = 1;
}
refs = fetch_pack(&args, data->fd, data->conn,
@@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport,
if (finish_connect(data->conn))
refs = NULL;
data->conn = NULL;
+ data->got_remote_heads = 0;
free_refs(refs_tmp);
@@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
struct send_pack_args args;
int ret;
- if (!data->conn) {
+ if (!data->got_remote_heads) {
struct ref *tmp_refs;
connect_setup(transport, 1, 0);
get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
NULL);
+ data->got_remote_heads = 1;
}
memset(&args, 0, sizeof(args));
@@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
close(data->fd[0]);
ret |= finish_connect(data->conn);
data->conn = NULL;
+ data->got_remote_heads = 0;
return ret;
}
@@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport)
{
struct git_transport_data *data = transport->data;
if (data->conn) {
- packet_flush(data->fd[1]);
+ if (data->got_remote_heads)
+ packet_flush(data->fd[1]);
close(data->fd[0]);
close(data->fd[1]);
finish_connect(data->conn);
@@ -759,6 +771,35 @@ static int disconnect_git(struct transport *transport)
return 0;
}
+void transport_take_over(struct transport *transport)
+{
+ struct git_transport_data *data;
+
+ if (!transport->disown)
+ die("Bug detected: Taking over transport requires non-NULL "
+ "disown method.");
+ if (!transport->smart_options)
+ die("Bug detected: Taking over transport requires non-NULL "
+ "smart_options field.");
+
+ data = xcalloc(1, sizeof(*data));
+ data->options = *transport->smart_options;
+ data->conn = transport->disown(transport);
+ data->fd[0] = data->conn->out;
+ data->fd[1] = data->conn->in;
+ data->got_remote_heads = 0;
+ transport->data = data;
+
+ transport->set_option = NULL;
+ transport->get_refs_list = get_refs_via_connect;
+ transport->fetch = fetch_refs_via_pack;
+ transport->push = NULL;
+ transport->push_refs = git_transport_push;
+ transport->disconnect = disconnect_git;
+ transport->smart_options = &(data->options);
+ transport->disown = NULL;
+}
+
static int is_local(const char *url)
{
const char *colon = strchr(url, ':');
@@ -854,6 +895,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->fetch = fetch_objs_via_rsync;
ret->push = rsync_transport_push;
ret->smart_options = NULL;
+ ret->disown = NULL;
} else if (is_local(url) && is_file(url)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
@@ -861,6 +903,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->fetch = fetch_refs_from_bundle;
ret->disconnect = close_bundle;
ret->smart_options = NULL;
+ ret->disown = NULL;
} else if (!is_url(url)
|| !prefixcmp(url, "file://")
|| !prefixcmp(url, "git://")
@@ -876,8 +919,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->push_refs = git_transport_push;
ret->disconnect = disconnect_git;
ret->smart_options = &(data->options);
+ ret->disown = NULL;
data->conn = NULL;
+ data->got_remote_heads = 0;
} else if (!prefixcmp(url, "http://")
|| !prefixcmp(url, "https://")
|| !prefixcmp(url, "ftp://")) {
@@ -938,9 +983,9 @@ int transport_push(struct transport *transport,
*nonfastforward = 0;
verify_remote_names(refspec_nr, refspec);
- if (transport->push)
+ if (transport->push) {
return transport->push(transport, refspec_nr, refspec, flags);
- if (transport->push_refs) {
+ } else if (transport->push_refs) {
struct ref *remote_refs =
transport->get_refs_list(transport, 1);
struct ref *local_refs = get_local_heads();
@@ -984,6 +1029,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
{
if (!transport->remote_refs)
transport->remote_refs = transport->get_refs_list(transport, 0);
+
return transport->remote_refs;
}
@@ -1018,6 +1064,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
}
rc = transport->fetch(transport, nr_heads, heads);
+
free(heads);
return rc;
}
diff --git a/transport.h b/transport.h
index d0192f9..499962d 100644
--- a/transport.h
+++ b/transport.h
@@ -65,6 +65,15 @@ struct transport {
int (*push_refs)(struct transport *transport, struct ref *refs, int flags);
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
+ /**
+ * Disown the transport helper. Releases all resources used
+ * by field pointed by member data, except that the child
+ * process is not released but returned and whatever is pointed
+ * by smart transport options structure is not freed (but the
+ * smart transport options structure itself is).
+ **/
+ struct child_process* (*disown)(struct transport* connection);
+
/** get_refs_list(), fetch(), and push_refs() can keep
* resources (such as a connection) reserved for futher
* use. disconnect() releases these resources.
@@ -128,6 +137,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs);
void transport_unlock_pack(struct transport *transport);
int transport_disconnect(struct transport *transport);
char *transport_anonymize_url(const char *url);
+void transport_take_over(struct transport *transport);
/* Transport methods defined outside transport.c */
int transport_helper_init(struct transport *transport, const char *name);
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* [RFC PATCH v3 8/8] Remove special casing of http, https and ftp
From: Ilari Liusvaara @ 2009-12-06 16:28 UTC (permalink / raw)
To: git
In-Reply-To: <1260116931-16549-1-git-send-email-ilari.liusvaara@elisanet.fi>
HTTP, HTTPS and FTP are no longer special to transport code. Also
add support for FTPS (curl supports it so it is easy).
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
.gitignore | 4 ++++
Makefile | 24 ++++++++++++++++++++++--
transport.c | 8 --------
3 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7cc54b4..7c79f97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,6 +107,10 @@
/git-relink
/git-remote
/git-remote-curl
+/git-remote-http
+/git-remote-https
+/git-remote-ftp
+/git-remote-ftps
/git-repack
/git-replace
/git-repo-config
diff --git a/Makefile b/Makefile
index 42744a4..1332225 100644
--- a/Makefile
+++ b/Makefile
@@ -424,6 +424,13 @@ BUILT_INS += git-stage$X
BUILT_INS += git-status$X
BUILT_INS += git-whatchanged$X
+#ifdef NO_CURL
+REMOTE_CURL_NAMES =
+#else
+# Yes, this is missing git-remote-http intentionally!
+REMOTE_CURL_NAMES = git-remote-https git-remote-ftp git-remote-ftps
+#endif
+
# what 'all' will build and 'install' will install in gitexecdir,
# excluding programs for built-in commands
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -1097,7 +1104,7 @@ else
else
CURL_LIBCURL = -lcurl
endif
- PROGRAMS += git-remote-curl$X git-http-fetch$X
+ PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-remote-ftps$X git-http-fetch$X
curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
ifeq "$(curl_check)" "070908"
ifndef NO_EXPAT
@@ -1676,7 +1683,13 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS)
+$(REMOTE_CURL_NAMES): git-remote-http$X
+ $(QUIET_LNCP)$(RM) $@ && \
+ ln $< $@ 2>/dev/null || \
+ ln -s $< $@ 2>/dev/null || \
+ cp $< $@
+
+git-remote-http$X: remote-curl.o http.o http-walker.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
@@ -1853,6 +1866,7 @@ endif
ifneq (,$X)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
endif
+
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ test "$$bindir/" = "$$execdir/" || \
@@ -1866,6 +1880,12 @@ endif
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
done; } && \
+ { for p in $(REMOTE_CURL_NAMES); do \
+ $(RM) "$$execdir/$$p" && \
+ ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+ ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
+ done; } && \
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
install-doc:
diff --git a/transport.c b/transport.c
index b418889..c6684ac 100644
--- a/transport.c
+++ b/transport.c
@@ -935,14 +935,6 @@ struct transport *transport_get(struct remote *remote, const char *url)
data->conn = NULL;
data->got_remote_heads = 0;
- } else if (!prefixcmp(url, "http://")
- || !prefixcmp(url, "https://")
- || !prefixcmp(url, "ftp://")) {
- /* These three are just plain special. */
- transport_helper_init(ret, "curl");
-#ifdef NO_CURL
- error("git was compiled without libcurl support.");
-#endif
} else {
/* Unknown protocol in URL. Pass to external handler. */
int len = external_specification_len(url);
--
1.6.6.rc1.300.gfbc27
^ permalink raw reply related
* Re: git-svn breakage on repository rename
From: Guido Stevens @ 2009-12-06 16:24 UTC (permalink / raw)
To: Eric Wong; +Cc: git, George Kuk, clark.alex, wichert, admins
In-Reply-To: <20091205222251.GA2120@dcvr.yhbt.net>
Eric, thanks!
Plone admins: I can now confirm it was not a svn corruption. Adding the
"--no-follow-parent" switch to git svn clone makes it possible to check
out the Plone svn into git -- at least the commits since the rename.
That one might be relevant for anybody who wants to contribute to the
Plone code base from a git-centered workflow.
Thanks everybody for helping to solve this problem! I can now integrate
the analysis of Products.CMFPlone into the overall Plone ecosystem
analysis, and it would have been very awkward not to be able to do that
because of this renaming issue. Again: thanks.
:*CU#
Eric Wong wrote:
> Guido Stevens <guido.stevens@cosent.net> wrote:
>> ----------------------------------------------------
>> To reconstruct this error:
>> ----------------------------------------------------
>>
>> $ git svn init https://svn-mirror.plone.org/svn/plone/Plone/trunk Plone
>> $ cd Plone
>> $ git svn fetch
>
> Since Plone appears to use a standard trunk/branches/tags layout
> recommended by SVN developers, can you try this instead?:
>
> git svn clone -s http://svn-mirror.plone.org/svn/plone/Plone
That one breaks completely, silently.
>
> If you don't care about branches/tags at all, you can also try
>
> git svn clone --no-follow-parent \
> https://svn-mirror.plone.org/svn/plone/Plone/trunk Plone
Yep, that one does the trick.
It does what it says though: it stops at the rename boundary
22715->22716. Luckily I can do other checkouts on the other names that
this package has had and complete my analysis anyway.
:*CU#
--
*** Guido A.J. Stevens *** tel: +31.43.3618933 ***
*** guido.stevens@cosent.nl *** Postbus 619 ***
*** http://www.cosent.nl *** 6200 AP Maastricht ***
s h a r i n g m a k e s s e n s e
^ permalink raw reply
* Approach for collaborative branches
From: Gary Pickrell @ 2009-12-06 16:57 UTC (permalink / raw)
To: git
My apologies if this is the wrong place to ask my question.
I've setup a git remote repository and placed the source for a windows
program there. I'm working on getting it to compile on Ubuntu. The
compilers are different so the code needs to be tweeked to make sure it
compiles fine in Ubuntu without breaking anything in Windows. Great!
This is a situation that calls for git branches, I thought. Did the
following:
1) Clone the repository on Ubuntu
2) Made an Ubuntu branch
3) Made my changes to the code. Added files...ect
4) Used git push origin Ubuntu to push the changes to the repository
I'm unable to see my Ubuntu changes on my windows machine. How should I
proceed?
Thanks in advance.
-Gary
^ permalink raw reply
* Re: Approach for collaborative branches
From: Matthieu Moy @ 2009-12-06 17:15 UTC (permalink / raw)
To: Gary Pickrell; +Cc: git
In-Reply-To: <4B1BE266.2000208@pickrell.com>
Gary Pickrell <gary@pickrell.com> writes:
> 1) Clone the repository on Ubuntu
> 2) Made an Ubuntu branch
> 3) Made my changes to the code. Added files...ect
> 4) Used git push origin Ubuntu to push the changes to the repository
>
> I'm unable to see my Ubuntu changes on my windows machine. How should
> I proceed?
On the windows machine, you should do first
git fetch
this will tell you about the new branch if you didn't fetch it
already. If it's called Ubuntu remotely, it's probably called
origin/Ubuntu on your local repository after doing a fetch. Therefore,
you can now do
git merge origin/Ubuntu
Now, you probably also want your local branch to be named the same way
on both machines. One way to do that is to create a branch "foo" on
the repository, then on both sides, fetch it and do
git checkout --track origin/foo
this will create a local branch foo, and tell git that further "pull"
should take their changes from origin/foo.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply
* Re: svn svn returning 'fatal: Not a valid object name' on sourceforge svn repo
From: Stephen Bannasch @ 2009-12-06 17:49 UTC (permalink / raw)
To: Eric Wong; +Cc: git
In-Reply-To: <20091205224950.GC2120@dcvr.yhbt.net>
At 2:49 PM -0800 12/5/09, Eric Wong wrote:
>Stephen Bannasch <stephen.bannasch@deanbrook.org> wrote:
>> I use git svn often and normally it works fine.
>>
>> I getting a fatal error trying to clone the asciimathm svn repo at sourceforge:
>>
>> $ git svn clone --trunk=trunk --branches=branches http://asciimathml.svn.sourceforge.net/svnroot/asciimathml asciimathml-svn-git
>> fatal: Not a valid object name
> > ls-tree -z ./: command returned error: 128
>
>Passing the "-r4:HEAD" parameter to "git svn clone" should work. It
>looks like the repository was initially miscreated and "trunk" was a
>symlink (and not a directory) in r1.
Thanks Eric, your suggestion worked.
How could you tell the first svn commit was a symlink?
^ permalink raw reply
* [PATCH 1/2] Documentation: 'git add --all' can remove files
From: Björn Gustavsson @ 2009-12-06 18:07 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Document that 'git add --all' can remove files no longer present
in the working tree from the index. Also mention why it is useful,
and insert a cross-reference in the 'git rm' documentation to
'git add --all'.
Signed-off-by: Björn Gustavsson <bgustavsson@gmail.com>
---
Documentation/git-add.txt | 13 +++++++++----
Documentation/git-rm.txt | 4 ++++
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index e93e606..b7e8aa2 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -16,6 +16,8 @@ DESCRIPTION
-----------
This command adds the current content of new or modified files to the
index, thus staging that content for inclusion in the next commit.
+(Given the `--all` option, the `git add` command will also remove files
+from the index that are no longer present in the working tree.)
The "index" holds a snapshot of the content of the working tree, and it
is this snapshot that is taken as the contents of the next commit. Thus
@@ -102,10 +104,13 @@ apply.
-A::
--all::
- Update files that git already knows about (same as '\--update')
- and add all untracked files that are not ignored by '.gitignore'
- mechanism.
-
+ Update files that git already knows about (same as '\--update'),
+ add all untracked files that are not ignored by '.gitignore'
+ mechanism and remove files from the index that are no longer
+ present in the working tree.
++
+This option is especially useful after running the `rsync` command with
+the working tree as the target to sync the index with the working tree.
-N::
--intent-to-add::
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 5afb1e7..b4dff5b 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -81,6 +81,10 @@ two directories `d` and `d2`, there is a difference between
using `git rm \'d\*\'` and `git rm \'d/\*\'`, as the former will
also remove all of directory `d2`.
+To automatically remove all files from the index that are no longer
+present in the working tree, see the `--all` option for
+linkgit:git-add[1].
+
EXAMPLES
--------
git rm Documentation/\\*.txt::
--
1.6.6.rc1.31.g1a56b
^ permalink raw reply related
* [PATCH 2/2] git-add/rm doc: Consistently back-quote
From: Björn Gustavsson @ 2009-12-06 18:07 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Consistently back-quote commands, options and file names.
Signed-off-by: Björn Gustavsson <bgustavsson@gmail.com>
---
Documentation/git-add.txt | 30 +++++++++++++++---------------
Documentation/git-rm.txt | 6 +++---
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index b7e8aa2..cf75738 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -22,22 +22,22 @@ from the index that are no longer present in the working tree.)
The "index" holds a snapshot of the content of the working tree, and it
is this snapshot that is taken as the contents of the next commit. Thus
after making any changes to the working directory, and before running
-the commit command, you must use the 'add' command to add any new or
+the commit command, you must use the `add` command to add any new or
modified files to the index.
This command can be performed multiple times before a commit. It only
adds the content of the specified file(s) at the time the add command is
run; if you want subsequent changes included in the next commit, then
-you must run 'git add' again to add the new content to the index.
+you must run `git add` again to add the new content to the index.
-The 'git status' command can be used to obtain a summary of which
+The `git status` command can be used to obtain a summary of which
files have changes that are staged for the next commit.
-The 'git add' command will not add ignored files by default. If any
-ignored files were explicitly specified on the command line, 'git add'
+The `git add` command will not add ignored files by default. If any
+ignored files were explicitly specified on the command line, `git add`
will fail with a list of ignored files. Ignored files reached by
directory recursion or filename globbing performed by Git (quote your
-globs before the shell) will be silently ignored. The 'add' command can
+globs before the shell) will be silently ignored. The `add` command can
be used to add ignored files with the `-f` (force) option.
Please see linkgit:git-commit[1] for alternative ways to add content to a
@@ -97,15 +97,15 @@ apply.
Update only files that git already knows about, staging modified
content for commit and marking deleted files for removal. This
is similar
- to what "git commit -a" does in preparation for making a commit,
+ to what `git commit -a` does in preparation for making a commit,
except that the update is limited to paths specified on the
command line. If no paths are specified, all tracked files in the
current directory and its subdirectories are updated.
-A::
--all::
- Update files that git already knows about (same as '\--update'),
- add all untracked files that are not ignored by '.gitignore'
+ Update files that git already knows about (same as `\--update`),
+ add all untracked files that are not ignored by `.gitignore`
mechanism and remove files from the index that are no longer
present in the working tree.
+
@@ -117,8 +117,8 @@ the working tree as the target to sync the index with the working tree.
Record only the fact that the path will be added later. An entry
for the path is placed in the index with no content. This is
useful for, among other things, showing the unstaged content of
- such files with 'git diff' and committing them with 'git commit
- -a'.
+ such files with `git diff` and committing them with `git commit
+ -a`.
--refresh::
Don't add the file(s), but only refresh their stat()
@@ -138,7 +138,7 @@ the working tree as the target to sync the index with the working tree.
Configuration
-------------
-The optional configuration variable 'core.excludesfile' indicates a path to a
+The optional configuration variable `core.excludesfile` indicates a path to a
file containing patterns of file names to exclude from git-add, similar to
$GIT_DIR/info/exclude. Patterns in the exclude file are used in addition to
those in info/exclude. See linkgit:gitrepository-layout[5].
@@ -186,7 +186,7 @@ and type return, like this:
What now> 1
------------
-You also could say "s" or "sta" or "status" above as long as the
+You also could say `s` or `sta` or `status` above as long as the
choice is unique.
The main command loop has 6 subcommands (plus help and quit).
@@ -194,9 +194,9 @@ The main command loop has 6 subcommands (plus help and quit).
status::
This shows the change between HEAD and index (i.e. what will be
- committed if you say "git commit"), and between index and
+ committed if you say `git commit`), and between index and
working tree files (i.e. what you could stage further before
- "git commit" using "git-add") for each path. A sample output
+ `git commit` using `git add`) for each path. A sample output
looks like this:
+
------------
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index b4dff5b..2803266 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -12,13 +12,13 @@ SYNOPSIS
DESCRIPTION
-----------
Remove files from the index, or from the working tree and the index.
-'git-rm' will not remove a file from just your working directory.
+`git rm` will not remove a file from just your working directory.
(There is no option to remove a file only from the work tree
and yet keep it in the index; use `/bin/rm` if you want to do that.)
The files being removed have to be identical to the tip of the branch,
and no updates to their contents can be staged in the index,
though that default behavior can be overridden with the `-f` option.
-When '--cached' is given, the staged content has to
+When `--cached` is given, the staged content has to
match either the tip of the branch or the file on disk,
allowing the file to be removed from just the index.
@@ -64,7 +64,7 @@ OPTIONS
-q::
--quiet::
- 'git-rm' normally outputs one line (in the form of an "rm" command)
+ `git rm` normally outputs one line (in the form of an `rm` command)
for each file removed. This option suppresses that output.
--
1.6.6.rc1.31.g1a56b
^ permalink raw reply related
* Re: Speedlimit at "git clone"
From: Daniel Stenberg @ 2009-12-06 18:13 UTC (permalink / raw)
To: Jeff King; +Cc: git
In-Reply-To: <20091206144322.GB26440@coredump.intra.peff.net>
On Sun, 6 Dec 2009, Jeff King wrote:
>>> how can i limit the download speed at "git clone"?
>>>
>> no one any idea?
>
> Git has no internal support for doing this.
libcurl provides such a feature so if the clone is done over HTTP it would be
easy to offer, but I figure it would also be weird to only provide it over a
single particular transfer method...
--
/ daniel.haxx.se
^ 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