Second round of support for cloning submodules

33 messages, 5 authors, 2016-06-15 · open the first message on its own page

Second round of support for cloning submodules

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This patch series implements a mechanism for cloning submodules.
Each submodule is specified by a 'submodule.<submodule>.url'
configuration option, e.g.,

bash-3.00$ ./git-config --remote=http://www.liacs.nl/~sverdool/isa.git --get-regexp 'submodule\..*\.url' 
submodule.cloog.url /home/sverdool/public_html/cloog.git
submodule.cloog.url http://www.liacs.nl/~sverdool/cloog.git

git-clone will use the first url that works.
E.g., a

git clone --submodules ssh://liacs/~/public_html/isa.git

(which only works for me), will use the first url, while a

git clone --submodules http://www.liacs.nl/~sverdool/isa.git

will use the second.

The cloning of submodules is now handled inside git-fetch.

skimo

[PATCH 04/16] git-config: read remote config files over HTTP

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 Makefile           |    7 ++++++-
 builtin-config.c   |    8 ++++++--
 config.c           |   16 +++++++++++++++-
 http.c             |   10 ++++++----
 http.h             |    2 +-
 http_config.h      |    1 +
 http_config_curl.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 http_config_none.c |    6 ++++++
 8 files changed, 93 insertions(+), 9 deletions(-)
 create mode 100644 http_config.h
 create mode 100644 http_config_curl.c
 create mode 100644 http_config_none.c
diff --git a/Makefile b/Makefile
index 37eb861..bce8514 100644
--- a/Makefile
+++ b/Makefile
@@ -319,7 +319,8 @@ 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 symlinks.o
+	convert.o attr.o decorate.o progress.o mailmap.o symlinks.o \
+	$(HTTP_CONFIG_OBJ)
 
 BUILTIN_OBJS = \
 	builtin-add.o \
@@ -526,6 +527,10 @@ ifndef NO_CURL
 	ifndef NO_EXPAT
 		EXPAT_LIBEXPAT = -lexpat
 	endif
+	HTTP_CONFIG_OBJ = http_config_curl.o http.o
+	EXTLIBS += $(CURL_LIBCURL)
+else
+	HTTP_CONFIG_OBJ = http_config_none.o
 endif
 
 ifndef NO_OPENSSL
diff --git a/builtin-config.c b/builtin-config.c
index 3a1e86c..7e18f73 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -147,8 +147,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			type = T_INT;
 		else if (!strcmp(argv[1], "--bool"))
 			type = T_BOOL;
-		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
-			return git_config(show_all_config);
+		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
+			if (dest)
+				return git_config_from_remote(show_all_config, dest);
+			else
+				return git_config(show_all_config);
+		}
 		else if (!strcmp(argv[1], "--global")) {
 			char *home = getenv("HOME");
 			if (home) {
diff --git a/config.c b/config.c
index dbfae3f..fc2162b 100644
--- a/config.c
+++ b/config.c
@@ -7,6 +7,7 @@
  */
 #include "cache.h"
 #include "pkt-line.h"
+#include "http_config.h"
 
 #define MAXNAME (256)
 
@@ -406,6 +407,16 @@ int git_config_from_file(config_fn_t fn, const char *filename)
 	return ret;
 }
 
+static int config_from_http(config_fn_t fn, char *dest)
+{
+	char config_temp[50];
+	if (git_http_fetch_config(dest, config_temp, sizeof(config_temp)))
+		return 1;
+	git_config_from_file(fn, config_temp);
+	unlink(config_temp);
+	return 0;
+}
+
 int git_config_from_remote(config_fn_t fn, char *dest)
 {
 	int ret;
@@ -414,7 +425,10 @@ int git_config_from_remote(config_fn_t fn, char *dest)
 	static char var[MAXNAME];
 	static char value[1024];
 
-	pid = git_connect(fd, dest, dumpconfig);
+	if (!prefixcmp(dest, "http://"))
+		return config_from_http(fn, dest);
+
+	pid = git_connect(fd, dest, dumpconfig, 0);
 	if (pid < 0)
 		return 1;
 	ret = 0;
diff --git a/http.c b/http.c
index ae27e0c..c8237cb 100644
--- a/http.c
+++ b/http.c
@@ -25,6 +25,8 @@ long curl_low_speed_limit = -1;
 long curl_low_speed_time = -1;
 int curl_ftp_no_epsv = 0;
 
+void (*fill_active_slots)(void) = NULL;
+
 struct curl_slist *pragma_header;
 
 struct active_request_slot *active_queue_head = NULL;
@@ -394,7 +396,8 @@ void step_active_slots(void)
 	} while (curlm_result == CURLM_CALL_MULTI_PERFORM);
 	if (num_transfers < active_requests) {
 		process_curl_messages();
-		fill_active_slots();
+		if (fill_active_slots)
+			fill_active_slots();
 	}
 }
 #endif
@@ -458,9 +461,8 @@ void release_active_slot(struct active_request_slot *slot)
 		curl_easy_cleanup(slot->curl);
 		slot->curl = NULL;
 	}
-#ifdef USE_CURL_MULTI
-	fill_active_slots();
-#endif
+	if (fill_active_slots)
+		fill_active_slots();
 }
 
 static void finish_active_slot(struct active_request_slot *slot)
diff --git a/http.h b/http.h
index 7a41cde..7f29ff8 100644
--- a/http.h
+++ b/http.h
@@ -68,8 +68,8 @@ extern void run_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
 extern void release_active_slot(struct active_request_slot *slot);
 
-#ifdef USE_CURL_MULTI
 extern void (*fill_active_slots)(void);
+#ifdef USE_CURL_MULTI
 extern void step_active_slots(void);
 #endif
 
diff --git a/http_config.h b/http_config.h
new file mode 100644
index 0000000..25f5c19
--- /dev/null
+++ b/http_config.h
@@ -0,0 +1 @@
+int git_http_fetch_config(const char *repo, char *config_file, int len);
diff --git a/http_config_curl.c b/http_config_curl.c
new file mode 100644
index 0000000..88317cf
--- /dev/null
+++ b/http_config_curl.c
@@ -0,0 +1,52 @@
+#include "http_config.h"
+#include "http.h"
+
+int git_http_fetch_config(const char *repo, char *config, int config_len)
+{
+	char url[PATH_MAX];
+	int len = strlen(repo);
+
+	int fd;
+	FILE *configfile;
+	struct active_request_slot *slot;
+	struct slot_results results;
+
+	strcpy(url, repo);
+	while (len > 0 && url[len-1] == '/')
+		--len;
+	snprintf(url+len, sizeof(url)-len, "/config");
+
+	fd = git_mkstemp(config, config_len, ".config_XXXXXX");
+	if (fd >= 0)
+		configfile = fdopen(fd, "w");
+	if (fd < 0 || !configfile)
+		return error("Unable to open local file %s for config",
+			     config);
+
+	http_init();
+
+	slot = get_active_slot();
+	slot->results = &results;
+	curl_easy_setopt(slot->curl, CURLOPT_FILE, configfile);
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
+	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+	slot->local = configfile;
+
+	if (start_active_slot(slot)) {
+		run_active_slot(slot);
+		if (results.curl_result != CURLE_OK) {
+			fclose(configfile);
+			warning("Unable to get config %s\n%s", url,
+				 curl_errorstr);
+		}
+	} else {
+		fclose(configfile);
+		return error("Unable to start request");
+	}
+
+	http_cleanup();
+
+	fclose(configfile);
+
+	return 0;
+}
diff --git a/http_config_none.c b/http_config_none.c
new file mode 100644
index 0000000..860ae84
--- /dev/null
+++ b/http_config_none.c
@@ -0,0 +1,6 @@
+#include "http_config.h"
+
+int git_http_fetch_config(const char *repo, char *config_file, int len)
+{
+	return error("Reading http config files not supported");
+}
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 01/16] Add dump-config

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This command dumps the config of a repository and will be used
to read config options from a remote site.

Signed-off-by: Sven Verdoolaege <redacted>
---
 .gitignore                        |    1 +
 Documentation/cmd-list.perl       |    1 +
 Documentation/git-dump-config.txt |   37 +++++++++++++++++++++++++++++++++++++
 Makefile                          |    1 +
 daemon.c                          |    7 +++++++
 dump-config.c                     |   29 +++++++++++++++++++++++++++++
 6 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/git-dump-config.txt
 create mode 100644 dump-config.c
diff --git a/.gitignore b/.gitignore
index 4dc0c39..d4e5492 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ git-diff-files
 git-diff-index
 git-diff-tree
 git-describe
+git-dump-config
 git-fast-import
 git-fetch
 git-fetch--tool
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 443802a..fa04615 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -103,6 +103,7 @@ git-diff-files                          plumbinginterrogators
 git-diff-index                          plumbinginterrogators
 git-diff                                mainporcelain
 git-diff-tree                           plumbinginterrogators
+git-dump-config                         synchelpers
 git-fast-import				ancillarymanipulators
 git-fetch                               mainporcelain
 git-fetch-pack                          synchingrepositories
diff --git a/Documentation/git-dump-config.txt b/Documentation/git-dump-config.txt
new file mode 100644
index 0000000..370781c
--- /dev/null
+++ b/Documentation/git-dump-config.txt
@@ -0,0 +1,37 @@
+git-dump-config(1)
+====================
+
+NAME
+----
+git-dump-config - Dump config options
+
+
+SYNOPSIS
+--------
+'git-dump-config' <directory>
+
+DESCRIPTION
+-----------
+Invoked by 'git-config --remote' and dumps the config file to the
+other end over the git protocol.
+
+This command is usually not invoked directly by the end user.  The UI
+for the protocol is on the 'git-config' side, where it is used to get
+options from a remote repository.
+
+OPTIONS
+-------
+<directory>::
+	The repository to get the config options from.
+
+Author
+------
+Written by Sven Verdoolaege.
+
+Documentation
+--------------
+Documentation by Sven Verdoolaege.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Makefile b/Makefile
index 29243c6..37eb861 100644
--- a/Makefile
+++ b/Makefile
@@ -240,6 +240,7 @@ PROGRAMS = \
 	git-fast-import$X \
 	git-merge-base$X \
 	git-daemon$X \
+	git-dump-config$X \
 	git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
 	git-peek-remote$X git-receive-pack$X \
 	git-send-pack$X git-shell$X \
diff --git a/daemon.c b/daemon.c
index e74ecac..3e5ebf3 100644
--- a/daemon.c
+++ b/daemon.c
@@ -378,10 +378,17 @@ static int receive_pack(void)
 	return -1;
 }
 
+static int dump_config(void)
+{
+	execl_git_cmd("dump-config", ".", NULL);
+	return -1;
+}
+
 static struct daemon_service daemon_service[] = {
 	{ "upload-archive", "uploadarch", upload_archive, 0, 1 },
 	{ "upload-pack", "uploadpack", upload_pack, 1, 1 },
 	{ "receive-pack", "receivepack", receive_pack, 0, 1 },
+	{ "dump-config", "dumpconfig", dump_config, 0, 1 },
 };
 
 static void enable_service(const char *name, int ena) {
diff --git a/dump-config.c b/dump-config.c
new file mode 100644
index 0000000..355920d
--- /dev/null
+++ b/dump-config.c
@@ -0,0 +1,29 @@
+#include "git-compat-util.h"
+#include "cache.h"
+#include "pkt-line.h"
+
+static const char dump_config_usage[] = "git-dump-config <dir>";
+
+static int dump_config(const char *var, const char *value)
+{
+	packet_write(1, "%s", var);
+	packet_write(1, "%s", value);
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	char *dir;
+
+	if (argc != 2)
+		usage(dump_config_usage);
+
+	dir = argv[1];
+	if (!enter_repo(dir, 0))
+		die("'%s': unable to chdir or not a git archive", dir);
+
+	git_config(dump_config);
+	packet_flush(1);
+
+	return 0;
+}
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 02/16] git-config: add --remote option for reading config from remote repo

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 Documentation/git-config.txt |   33 +++++++++++++++++++++---------
 builtin-config.c             |   44 ++++++++++++++++++++++++++++++++---------
 cache.h                      |    1 +
 config.c                     |   26 ++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 280ef20..76398ab 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -9,16 +9,25 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git-config' [--system | --global] [type] name [value [value_regex]]
-'git-config' [--system | --global] [type] --add name value
-'git-config' [--system | --global] [type] --replace-all name [value [value_regex]]
-'git-config' [--system | --global] [type] --get name [value_regex]
-'git-config' [--system | --global] [type] --get-all name [value_regex]
-'git-config' [--system | --global] [type] --unset name [value_regex]
-'git-config' [--system | --global] [type] --unset-all name [value_regex]
-'git-config' [--system | --global] [type] --rename-section old_name new_name
-'git-config' [--system | --global] [type] --remove-section name
-'git-config' [--system | --global] -l | --list
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] name [value [value_regex]]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --add name value
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --replace-all name [value [value_regex]]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --get name [value_regex]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --get-all name [value_regex]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --unset name [value_regex]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --unset-all name [value_regex]
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --rename-section old_name new_name
+'git-config' [--system | --global | --remote=[<host>:]<directory ]
+	     [type] --remove-section name
+'git-config' [--system | --global | --remote=[<host>:]<directory ] -l | --list
 
 DESCRIPTION
 -----------
@@ -80,6 +89,10 @@ OPTIONS
 	Use system-wide $(prefix)/etc/gitconfig rather than the repository
 	.git/config.
 
+--remote=[<host>:]<directory
+	Use remote config instead of the repository .git/config.
+	Only available for reading options.
+
 --remove-section::
 	Remove the given section from the configuration file.
 
diff --git a/builtin-config.c b/builtin-config.c
index b2515f7..3a1e86c 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -2,8 +2,10 @@
 #include "cache.h"
 
 static const char git_config_set_usage[] =
-"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
+"git-config [ --global | --system | --remote=[<host>:]<directory ] "
+"[ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
 
+static char *dest;
 static char *key;
 static regex_t *key_regexp;
 static regex_t *regexp;
@@ -104,15 +106,19 @@ static int get_value(const char* key_, const char* regex_)
 		}
 	}
 
-	if (do_all && system_wide)
-		git_config_from_file(show_config, system_wide);
-	if (do_all && global)
-		git_config_from_file(show_config, global);
-	git_config_from_file(show_config, local);
-	if (!do_all && !seen && global)
-		git_config_from_file(show_config, global);
-	if (!do_all && !seen && system_wide)
-		git_config_from_file(show_config, system_wide);
+	if (dest)
+		git_config_from_remote(show_config, dest);
+	else {
+		if (do_all && system_wide)
+			git_config_from_file(show_config, system_wide);
+		if (do_all && global)
+			git_config_from_file(show_config, global);
+		git_config_from_file(show_config, local);
+		if (!do_all && !seen && global)
+			git_config_from_file(show_config, global);
+		if (!do_all && !seen && system_wide)
+			git_config_from_file(show_config, system_wide);
+	}
 
 	free(key);
 	if (regexp) {
@@ -155,8 +161,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		}
 		else if (!strcmp(argv[1], "--system"))
 			setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
+		else if (!prefixcmp(argv[1], "--remote="))
+			dest = xstrdup(argv[1]+9);
 		else if (!strcmp(argv[1], "--rename-section")) {
 			int ret;
+			if (dest) {
+				fprintf(stderr, "Cannot rename on remote\n");
+				return 1;
+			}
 			if (argc != 4)
 				usage(git_config_set_usage);
 			ret = git_config_rename_section(argv[2], argv[3]);
@@ -170,6 +182,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		}
 		else if (!strcmp(argv[1], "--remove-section")) {
 			int ret;
+			if (dest) {
+				fprintf(stderr, "Cannot remove on remote\n");
+				return 1;
+			}
 			if (argc != 3)
 				usage(git_config_set_usage);
 			ret = git_config_rename_section(argv[2], NULL);
@@ -191,6 +207,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	case 2:
 		return get_value(argv[1], NULL);
 	case 3:
+		if (dest && prefixcmp(argv[1], "--get")) {
+			fprintf(stderr, "Cannot (un)set on remote\n");
+			return 1;
+		}
 		if (!strcmp(argv[1], "--unset"))
 			return git_config_set(argv[2], NULL);
 		else if (!strcmp(argv[1], "--unset-all"))
@@ -209,6 +229,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 
 			return git_config_set(argv[1], argv[2]);
 	case 4:
+		if (dest && prefixcmp(argv[1], "--get")) {
+			fprintf(stderr, "Cannot (un)set on remote\n");
+			return 1;
+		}
 		if (!strcmp(argv[1], "--unset"))
 			return git_config_set_multivar(argv[2], NULL, argv[3], 0);
 		else if (!strcmp(argv[1], "--unset-all"))
diff --git a/cache.h b/cache.h
index e34958b..6acc330 100644
--- a/cache.h
+++ b/cache.h
@@ -501,6 +501,7 @@ extern int update_server_info(int);
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
 extern int git_config_from_file(config_fn_t fn, const char *);
+extern int git_config_from_remote(config_fn_t fn, char *dest);
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
diff --git a/config.c b/config.c
index 0614c2b..dbfae3f 100644
--- a/config.c
+++ b/config.c
@@ -6,9 +6,12 @@
  *
  */
 #include "cache.h"
+#include "pkt-line.h"
 
 #define MAXNAME (256)
 
+static const char *dumpconfig = "git-dump-config";
+
 static FILE *config_file;
 static const char *config_file_name;
 static int config_linenr;
@@ -403,6 +406,29 @@ int git_config_from_file(config_fn_t fn, const char *filename)
 	return ret;
 }
 
+int git_config_from_remote(config_fn_t fn, char *dest)
+{
+	int ret;
+	int fd[2];
+	pid_t pid;
+	static char var[MAXNAME];
+	static char value[1024];
+
+	pid = git_connect(fd, dest, dumpconfig);
+	if (pid < 0)
+		return 1;
+	ret = 0;
+	while (packet_read_line(fd[0], var, sizeof(var))) {
+		if (!packet_read_line(fd[0], value, sizeof(value)))
+			die("Missing value");
+		fn(var, value);
+	}
+	close(fd[0]);
+	close(fd[1]);
+	ret |= finish_connect(pid);
+	return !!ret;
+}
+
 int git_config(config_fn_t fn)
 {
 	int ret = 0;
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 10/16] git-checkout: pass --submodules option to git-read-tree

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 git-checkout.sh |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/git-checkout.sh b/git-checkout.sh
index 6b6facf..cbb1f00 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+USAGE='[-q] [-f] [--submodules] [--no-submodules] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
@@ -16,6 +16,7 @@ track=
 newbranch=
 newbranch_log=
 merge=
+submodules=
 quiet=
 v=-v
 LF='
@@ -46,6 +47,15 @@ while [ "$#" != "0" ]; do
 	-m)
 		merge=1
 		;;
+	*,--su|*,--sub|*,--subm|*,--submo|*,--submod|*,--submodu|*,--submodul|\
+	*,--submodule|*,--submodules)
+		submodules="--submodules"
+		;;
+	*,--no-su|*,--no-sub|*,--no-subm|*,--no-submo|*,--no-submod|\
+	*,--no-submodu|*,--no-submodul|\
+	*,--no-submodule|*,--no-submodules)
+		submodules="--no-submodules"
+		;;
 	"-q")
 		quiet=1
 		v=
@@ -199,10 +209,10 @@ fi
 
 if [ "$force" ]
 then
-    git-read-tree $v --reset -u $new
+    git-read-tree $v $submodules --reset -u $new
 else
     git-update-index --refresh >/dev/null
-    merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
+    merge_error=$(git-read-tree $submodules -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
 	case "$merge" in
 	'')
 		echo >&2 "$merge_error"
@@ -212,7 +222,7 @@ else
 	# Match the index to the working tree, and do a three-way.
     	git diff-files --name-only | git update-index --remove --stdin &&
 	work=`git write-tree` &&
-	git read-tree $v --reset -u $new || exit
+	git read-tree $v $submodules --reset -u $new || exit
 
 	eval GITHEAD_$new='${new_name:-${branch:-$new}}' &&
 	eval GITHEAD_$work=local &&
@@ -223,7 +233,7 @@ else
 	# this is not a real merge before committing, but just carrying
 	# the working tree changes along.
 	unmerged=`git ls-files -u`
-	git read-tree $v --reset $new
+	git read-tree $v $submodules --reset $new
 	case "$unmerged" in
 	'')	;;
 	*)
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 12/16] builtin-fetch--tool: extend "native-store" for use in cloning

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 builtin-fetch--tool.c |   48 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index ed4d5de..3441a4a 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -207,6 +207,32 @@ static void remove_keep_on_signal(int signo)
 	raise(signo);
 }
 
+static char *construct_local_name(const char *remote_ref, const char *remote_nick,
+				  int use_separate_remote)
+{
+	static char local_ref[PATH_MAX];
+	int len = strlen(remote_ref);
+
+	if (len >= 3 && !memcmp(remote_ref+len-3, "^{}", 3))
+		return NULL;
+	if (!strcmp(remote_ref, "HEAD"))
+		return "REMOTE_HEAD";
+	if (!prefixcmp(remote_ref, "refs/heads/")) {
+		if (snprintf(local_ref, sizeof(local_ref), "refs/%s%s/%s",
+			    use_separate_remote ? "remotes/" : "heads",
+			    use_separate_remote ? remote_nick : "",
+			    remote_ref+11) > sizeof(local_ref))
+			die("Local branchname too long");
+	} else if (!prefixcmp(remote_ref, "refs/tags/")) {
+		if (snprintf(local_ref, sizeof(local_ref), "refs/tags/%s",
+			    remote_ref+10) > sizeof(local_ref))
+			die("Local branchname too long");
+	} else
+		return NULL;
+
+	return local_ref;
+}
+
 static char *find_local_name(const char *remote_name, const char *refs,
 			     int *force_p, int *not_for_merge_p)
 {
@@ -261,7 +287,8 @@ static int fetch_native_store(FILE *fp,
 			      const char *remote,
 			      const char *remote_nick,
 			      const char *refs,
-			      int verbose, int force)
+			      int verbose, int force,
+			      int all, int use_separate_remote)
 {
 	char buffer[1024];
 	int err = 0;
@@ -294,8 +321,12 @@ static int fetch_native_store(FILE *fp,
 			continue;
 		}
 
-		local_name = find_local_name(cp, refs,
-					     &single_force, &not_for_merge);
+		if (all)
+			local_name = construct_local_name(cp, remote_nick,
+							  use_separate_remote);
+		else
+			local_name = find_local_name(cp, refs,
+						     &single_force, &not_for_merge);
 		if (!local_name)
 			continue;
 		err |= append_fetch_head(fp,
@@ -514,6 +545,8 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 	int verbose = 0;
 	int force = 0;
 	int sopt = 0;
+	int all = 0;
+	int use_separate_remote = 1;
 
 	while (1 < argc) {
 		const char *arg = argv[1];
@@ -523,6 +556,12 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 			force = 1;
 		else if (!strcmp("-s", arg))
 			sopt = 1;
+		else if (!strcmp("--all", arg))
+			all = 1;
+		else if (!strcmp("--use-separate-remote", arg))
+			use_separate_remote = 1;
+		else if (!strcmp("--no-separate-remote", arg))
+			use_separate_remote = 0;
 		else
 			break;
 		argc--;
@@ -554,7 +593,8 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 			return error("fetch-native-store takes 3 args");
 		fp = fopen(git_path("FETCH_HEAD"), "a");
 		result = fetch_native_store(fp, argv[2], argv[3], argv[4],
-					    verbose, force);
+					    verbose, force, all,
+					    use_separate_remote);
 		fclose(fp);
 		return result;
 	}
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 07/16] git-read-tree: take --submodules option

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This option currently has no effect.

Signed-off-by: Sven Verdoolaege <redacted>
---
 builtin-read-tree.c |   25 ++++++++++++++++++++++---
 cache.h             |    3 ++-
 unpack-trees.c      |    1 +
 unpack-trees.h      |    1 +
 4 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 316fb0f..929dd95 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -87,14 +87,23 @@ static void prime_cache_tree(void)
 static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
 
 static struct lock_file lock_file;
+static struct unpack_trees_options opts;
+
+static int git_read_tree_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "core.submodules")) {
+		opts.submodules = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value);
+}
 
 int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 {
 	int i, newfd, stage = 0;
 	unsigned char sha1[20];
-	struct unpack_trees_options opts;
 
-	memset(&opts, 0, sizeof(opts));
 	opts.head_idx = -1;
 
 	setup_git_directory();
@@ -102,7 +111,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 
 	newfd = hold_locked_index(&lock_file, 1);
 
-	git_config(git_default_config);
+	git_config(git_read_tree_config);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
@@ -172,6 +181,16 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 			continue;
 		}
 
+		if (!strcmp(arg, "--no-submodules")) {
+			opts.submodules = 0;
+			continue;
+		}
+
+		if (!strcmp(arg, "--submodules")) {
+			opts.submodules = 1;
+			continue;
+		}
+
 		/* "-m" stands for "merge", meaning we start in stage 1 */
 		if (!strcmp(arg, "-m")) {
 			if (stage || opts.merge || opts.prefix)
diff --git a/cache.h b/cache.h
index 6acc330..42a275e 100644
--- a/cache.h
+++ b/cache.h
@@ -406,7 +406,8 @@ struct checkout {
 	unsigned force:1,
 		 quiet:1,
 		 not_new:1,
-		 refresh_cache:1;
+		 refresh_cache:1,
+		 submodules:1;
 };
 
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
diff --git a/unpack-trees.c b/unpack-trees.c
index 3dac150..5fa637a 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -352,6 +352,7 @@ int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
 	state.force = 1;
 	state.quiet = 1;
 	state.refresh_cache = 1;
+	state.submodules = o->submodules;
 
 	o->merge_size = len;
 
diff --git a/unpack-trees.h b/unpack-trees.h
index fee7da4..21005d9 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -15,6 +15,7 @@ struct unpack_trees_options {
 	int trivial_merges_only;
 	int verbose_update;
 	int aggressive;
+	int submodules;
 	const char *prefix;
 	int pos;
 	struct dir_struct *dir;
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 09/16] entry.c: optionally checkout submodules

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 entry.c |   42 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/entry.c b/entry.c
index 82bf725..96a4a60 100644
--- a/entry.c
+++ b/entry.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "blob.h"
+#include "run-command.h"
 
 static void create_directories(const char *path, const struct checkout *state)
 {
@@ -163,6 +164,44 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
 	return 0;
 }
 
+static int checkout_submodule(const char *path, struct cache_entry *ce, const struct checkout *state)
+{
+	static char cwd[PATH_MAX];
+	const char *gitdirenv;
+	const char *args[10];
+	int argc;
+	int err;
+
+	if (!state->submodules)
+		return 0;
+
+	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+		die("Unable to read current working directory");
+
+	if (chdir(path))
+		die("Cannot move to '%s'", path);
+
+	argc = 0;
+	args[argc++] = "checkout";
+	if (state->force)
+	    args[argc++] = "-f";
+	args[argc++] = sha1_to_hex(ce->sha1);
+	args[argc] = NULL;
+
+	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	unsetenv(GIT_DIR_ENVIRONMENT);
+	err = run_command_v_opt(args, RUN_GIT_CMD);
+	setenv(GIT_DIR_ENVIRONMENT, gitdirenv, 1);
+
+	if (chdir(cwd))
+		die("Cannot come back to cwd");
+
+	if (err)
+		return error("failed to run git-checkout in submodule '%s'", path);
+
+	return 0;
+}
+
 int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
 {
 	static char path[PATH_MAX + 1];
@@ -193,9 +232,8 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
 		 */
 		unlink(path);
 		if (S_ISDIR(st.st_mode)) {
-			/* If it is a gitlink, leave it alone! */
 			if (S_ISDIRLNK(ntohl(ce->ce_mode)))
-				return 0;
+				return checkout_submodule(path, ce, state);
 			if (!state->force)
 				return error("%s is a directory", path);
 			remove_subtree(path);
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 08/16] unpack-trees.c: assume submodules are clean

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

If the submodules are not clean, then we will get an error
when we actally do the checkout.

Signed-off-by: Sven Verdoolaege <redacted>
---
 unpack-trees.c |   43 ++++++++++++++++++++++++++++++++++---------
 1 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index 5fa637a..e979bc5 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -5,6 +5,7 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "progress.h"
+#include "refs.h"
 
 #define DBRT_DEBUG 1
 
@@ -426,11 +427,24 @@ static void invalidate_ce_path(struct cache_entry *ce)
 		cache_tree_invalidate_path(active_cache_tree, ce->name);
 }
 
-static int verify_clean_subdirectory(const char *path, const char *action,
+/* Check that checking out ce->sha1 in subdir ce->name is not
+ * going to overwrite any working files.
+ *
+ * FIXME: implement this function, so we can detect problems
+ *        early, rather than waiting until we actually try to checkout
+ *        the submodules.
+ */
+static int verify_clean_submodule(struct cache_entry *ce, const char *action,
+				      struct unpack_trees_options *o)
+{
+	return 0;
+}
+
+static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
 				      struct unpack_trees_options *o)
 {
 	/*
-	 * we are about to extract "path"; we would not want to lose
+	 * we are about to extract "ce->name"; we would not want to lose
 	 * anything in the existing directory there.
 	 */
 	int namelen;
@@ -438,13 +452,24 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 	struct dir_struct d;
 	char *pathbuf;
 	int cnt = 0;
+	unsigned char sha1[20];
+
+	if (S_ISDIRLNK(ntohl(ce->ce_mode)) &&
+	    resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
+		/* If we are not going to update the submodule, then
+		 * we don't care.
+		 */
+		if (!o->submodules || !hashcmp(sha1, ce->sha1))
+			return 0;
+		verify_clean_submodule(ce, action, o);
+	}
 
 	/*
 	 * First let's make sure we do not have a local modification
 	 * in that directory.
 	 */
-	namelen = strlen(path);
-	pos = cache_name_pos(path, namelen);
+	namelen = strlen(ce->name);
+	pos = cache_name_pos(ce->name, namelen);
 	if (0 <= pos)
 		return cnt; /* we have it as nondirectory */
 	pos = -pos - 1;
@@ -452,7 +477,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 		struct cache_entry *ce = active_cache[i];
 		int len = ce_namelen(ce);
 		if (len < namelen ||
-		    strncmp(path, ce->name, namelen) ||
+		    strncmp(ce->name, ce->name, namelen) ||
 		    ce->name[namelen] != '/')
 			break;
 		/*
@@ -470,16 +495,16 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 	 * present file that is not ignored.
 	 */
 	pathbuf = xmalloc(namelen + 2);
-	memcpy(pathbuf, path, namelen);
+	memcpy(pathbuf, ce->name, namelen);
 	strcpy(pathbuf+namelen, "/");
 
 	memset(&d, 0, sizeof(d));
 	if (o->dir)
 		d.exclude_per_dir = o->dir->exclude_per_dir;
-	i = read_directory(&d, path, pathbuf, namelen+1, NULL);
+	i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
 	if (i)
 		die("Updating '%s' would lose untracked files in it",
-		    path);
+		    ce->name);
 	free(pathbuf);
 	return cnt;
 }
@@ -513,7 +538,7 @@ static void verify_absent(struct cache_entry *ce, const char *action,
 			 * files that are in "foo/" we would lose
 			 * it.
 			 */
-			cnt = verify_clean_subdirectory(ce->name, action, o);
+			cnt = verify_clean_subdirectory(ce, action, o);
 
 			/*
 			 * If this removed entries from the index,
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 03/16] http.h: make fill_active_slots a function pointer

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This allows us to use the methods provided by http.c
from within libgit, in particular config.c.

Signed-off-by: Sven Verdoolaege <redacted>
---
 http-fetch.c |    5 ++++-
 http-push.c  |    5 ++++-
 http.h       |    2 +-
 3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/http-fetch.c b/http-fetch.c
index 09baedc..53fb2a9 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -317,7 +317,7 @@ static void release_object_request(struct object_request *obj_req)
 }
 
 #ifdef USE_CURL_MULTI
-void fill_active_slots(void)
+static void fetch_fill_active_slots(void)
 {
 	struct object_request *obj_req = object_queue_head;
 	struct active_request_slot *slot = active_queue_head;
@@ -1031,6 +1031,9 @@ int main(int argc, const char **argv)
 	}
 	url = argv[arg];
 
+#ifdef USE_CURL_MULTI
+	fill_active_slots = fetch_fill_active_slots;
+#endif
 	http_init();
 
 	no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
diff --git a/http-push.c b/http-push.c
index e3f7675..d4c850b 100644
--- a/http-push.c
+++ b/http-push.c
@@ -794,7 +794,7 @@ static void finish_request(struct transfer_request *request)
 }
 
 #ifdef USE_CURL_MULTI
-void fill_active_slots(void)
+static void push_fill_active_slots(void)
 {
 	struct transfer_request *request = request_queue_head;
 	struct transfer_request *next;
@@ -2355,6 +2355,9 @@ int main(int argc, char **argv)
 
 	memset(remote_dir_exists, -1, 256);
 
+#ifdef USE_CURL_MULTI
+	fill_active_slots = push_fill_active_slots;
+#endif
 	http_init();
 
 	no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
diff --git a/http.h b/http.h
index 69b6b66..7a41cde 100644
--- a/http.h
+++ b/http.h
@@ -69,7 +69,7 @@ extern void finish_all_active_slots(void);
 extern void release_active_slot(struct active_request_slot *slot);
 
 #ifdef USE_CURL_MULTI
-extern void fill_active_slots(void);
+extern void (*fill_active_slots)(void);
 extern void step_active_slots(void);
 #endif
 
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 13/16] git-clone: rely on git-fetch for fetching for most protocols

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 git-clone.sh |   20 ++++++++++++--------
 git-fetch.sh |   28 ++++++++++++++++++++++------
 2 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/git-clone.sh b/git-clone.sh
index fdd354f..44127c5 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -159,6 +159,11 @@ then
 	no_checkout=yes
 	use_separate_remote=
 fi
+if test t = "$use_separate_remote"; then
+	separate_remote_flag="--use-separate-remote"
+else
+	separate_remote_flag="--no-separate-remote"
+fi
 
 if test -z "$origin"
 then
@@ -219,6 +224,10 @@ then
 	fi
 fi
 
+# Write out $origin URL
+GIT_CONFIG="$GIT_DIR/config"
+git-config remote."$origin".url "$repo" || exit
+
 rm -f "$GIT_DIR/CLONE_HEAD"
 
 # We do local magic only when the user tells us to.
@@ -299,11 +308,9 @@ yes,yes)
 		fi
 		;;
 	*)
-		case "$upload_pack" in
-		'') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
-		*) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress "$repo" ;;
-		esac >"$GIT_DIR/CLONE_HEAD" ||
-			die "fetch-pack from '$repo' failed."
+		git-fetch --all -k $quiet "$upload_pack" $depth \
+			$separate_remote_flag "$origin" ||
+			die "fetch from '$repo' failed."
 		;;
 	esac
 	;;
@@ -387,9 +394,6 @@ then
 		origin_track="$remote_top/$head_points_at" &&
 		git-update-ref HEAD "$head_sha1" &&
 
-		# Upstream URL
-		git-config remote."$origin".url "$repo" &&
-
 		# Set up the mappings to track the remote branches.
 		git-config remote."$origin".fetch \
 			"+refs/heads/*:$remote_top/*" '^$' &&
diff --git a/git-fetch.sh b/git-fetch.sh
index dbeca14..e169848 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -15,6 +15,7 @@ LF='
 '
 IFS="$LF"
 
+all=
 no_tags=
 tags=
 append=
@@ -25,6 +26,7 @@ exec=
 keep=
 shallow_depth=
 no_progress=
+use_separate_remote=
 test -t 1 || no_progress=--no-progress
 quiet=
 while case "$#" in 0) break ;; esac
@@ -33,6 +35,9 @@ do
 	-a|--a|--ap|--app|--appe|--appen|--append)
 		append=t
 		;;
+	--al|--all)
+		all=--all
+		;;
 	--upl|--uplo|--uploa|--upload|--upload-|--upload-p|\
 	--upload-pa|--upload-pac|--upload-pack)
 		shift
@@ -63,6 +68,12 @@ do
 	-v|--verbose)
 		verbose=Yes
 		;;
+	--use-separate-remote)
+		use_separate_remote="--use-separate-remote"
+		;;
+	--no-separate-remote)
+		use_separate_remote="--no-separate-remote"
+		;;
 	-k|--k|--ke|--kee|--keep)
 		keep='-k -k'
 		;;
@@ -143,7 +154,9 @@ esac
 # branches file, and just fetch those and refspecs explicitly given.
 # Otherwise we do what we always did.
 
-reflist=$(get_remote_refs_for_fetch "$@")
+if test -z "$all"; then
+	reflist=$(get_remote_refs_for_fetch "$@")
+fi
 if test "$tags"
 then
 	taglist=`IFS='	' &&
@@ -165,8 +178,10 @@ fi
 
 fetch_all_at_once () {
 
-  eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
-  eval "$eval"
+    if test -z "$all"; then
+	eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
+	eval "$eval"
+    fi
 
     ( : subshell because we muck with IFS
       IFS=" 	$LF"
@@ -179,7 +194,8 @@ fetch_all_at_once () {
 	    git-bundle unbundle "$remote" $rref ||
 	    echo failed "$remote"
 	else
-		if	test -d "$remote" &&
+		if	test -z "$all" &&
+			test -d "$remote" &&
 
 			# The remote might be our alternate.  With
 			# this optimization we will bypass fetch-pack
@@ -203,7 +219,7 @@ fetch_all_at_once () {
 			echo "$ls_remote_result" | \
 				git-fetch--tool pick-rref "$rref" "-"
 		else
-			git-fetch-pack --thin $exec $keep $shallow_depth \
+			git-fetch-pack --thin $all $exec $keep $shallow_depth \
 				$quiet $no_progress "$remote" $rref ||
 			echo failed "$remote"
 		fi
@@ -214,7 +230,7 @@ fetch_all_at_once () {
 	test -n "$verbose" && flags="$flags -v"
 	test -n "$force" && flags="$flags -f"
 	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
-		git-fetch--tool $flags native-store \
+		git-fetch--tool $flags $all $use_separate_remote native-store \
 			"$remote" "$remote_nick" "$refs"
       )
     ) || exit
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 06/16] unpack-trees.c: pass cache_entry * to verify_absent rather than just the name

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

We will need the full cache_entry later to figure out if we are dealing
with a submodule.

Signed-off-by: Sven Verdoolaege <redacted>
---
 unpack-trees.c |   32 ++++++++++++++++----------------
 1 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index cac2411..3dac150 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -487,7 +487,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
  */
-static void verify_absent(const char *path, const char *action,
+static void verify_absent(struct cache_entry *ce, const char *action,
 		struct unpack_trees_options *o)
 {
 	struct stat st;
@@ -495,12 +495,12 @@ static void verify_absent(const char *path, const char *action,
 	if (o->index_only || o->reset || !o->update)
 		return;
 
-	if (!lstat(path, &st)) {
+	if (!lstat(ce->name, &st)) {
 		int cnt;
 
-		if (o->dir && excluded(o->dir, path))
+		if (o->dir && excluded(o->dir, ce->name))
 			/*
-			 * path is explicitly excluded, so it is Ok to
+			 * ce->name is explicitly excluded, so it is Ok to
 			 * overwrite it.
 			 */
 			return;
@@ -512,7 +512,7 @@ static void verify_absent(const char *path, const char *action,
 			 * files that are in "foo/" we would lose
 			 * it.
 			 */
-			cnt = verify_clean_subdirectory(path, action, o);
+			cnt = verify_clean_subdirectory(ce->name, action, o);
 
 			/*
 			 * If this removed entries from the index,
@@ -540,7 +540,7 @@ static void verify_absent(const char *path, const char *action,
 		 * delete this path, which is in a subdirectory that
 		 * is being replaced with a blob.
 		 */
-		cnt = cache_name_pos(path, strlen(path));
+		cnt = cache_name_pos(ce->name, strlen(ce->name));
 		if (0 <= cnt) {
 			struct cache_entry *ce = active_cache[cnt];
 			if (!ce_stage(ce) && !ce->ce_mode)
@@ -548,7 +548,7 @@ static void verify_absent(const char *path, const char *action,
 		}
 
 		die("Untracked working tree file '%s' "
-		    "would be %s by merge.", path, action);
+		    "would be %s by merge.", ce->name, action);
 	}
 }
 
@@ -572,7 +572,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 		}
 	}
 	else {
-		verify_absent(merge->name, "overwritten", o);
+		verify_absent(merge, "overwritten", o);
 		invalidate_ce_path(merge);
 	}
 
@@ -587,7 +587,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
 	if (old)
 		verify_uptodate(old, o);
 	else
-		verify_absent(ce->name, "removed", o);
+		verify_absent(ce, "removed", o);
 	ce->ce_mode = 0;
 	add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 	invalidate_ce_path(ce);
@@ -704,18 +704,18 @@ int threeway_merge(struct cache_entry **stages,
 	if (o->aggressive) {
 		int head_deleted = !head && !df_conflict_head;
 		int remote_deleted = !remote && !df_conflict_remote;
-		const char *path = NULL;
+		struct cache_entry *ce = NULL;
 
 		if (index)
-			path = index->name;
+			ce = index;
 		else if (head)
-			path = head->name;
+			ce = head;
 		else if (remote)
-			path = remote->name;
+			ce = remote;
 		else {
 			for (i = 1; i < o->head_idx; i++) {
 				if (stages[i] && stages[i] != o->df_conflict_entry) {
-					path = stages[i]->name;
+					ce = stages[i];
 					break;
 				}
 			}
@@ -730,8 +730,8 @@ int threeway_merge(struct cache_entry **stages,
 		    (remote_deleted && head && head_match)) {
 			if (index)
 				return deleted_entry(index, index, o);
-			else if (path && !head_deleted)
-				verify_absent(path, "removed", o);
+			else if (ce && !head_deleted)
+				verify_absent(ce, "removed", o);
 			return 0;
 		}
 		/*
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 05/16] unpack-trees.c: verify_uptodate: remove dead code

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This code was killed by commit fcc387db9bc453dc7e07a262873481af2ee9e5c8.

Signed-off-by: Sven Verdoolaege <redacted>
---
 unpack-trees.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index 906ce69..cac2411 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -414,10 +414,6 @@ static void verify_uptodate(struct cache_entry *ce,
 			return;
 		errno = 0;
 	}
-	if (o->reset) {
-		ce->ce_flags |= htons(CE_UPDATE);
-		return;
-	}
 	if (errno == ENOENT)
 		return;
 	die("Entry '%s' not uptodate. Cannot merge.", ce->name);
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 11/16] git-fetch: skip empty arguments

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

This makes it easier for scripts to call git-fetch with options
that may or may not be set.

Signed-off-by: Sven Verdoolaege <redacted>
---
 git-fetch.sh |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/git-fetch.sh b/git-fetch.sh
index 0e05cf1..dbeca14 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -76,6 +76,8 @@ do
 	-*)
 		usage
 		;;
+	'')
+		;;
 	*)
 		break
 		;;
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 16/16] git-clone: add --submodules for cloning submodules

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

When the --submodules option is specified, git-clone will search
for submodule.<submodule>.url options in the remote configuration
and clone each submodule using the first url that it can use from
the local site.

Signed-off-by: Sven Verdoolaege <redacted>
---
 Documentation/config.txt    |    7 +++
 Documentation/git-clone.txt |    6 ++-
 git-clone.sh                |   18 +++++++-
 git-fetch.sh                |   90 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ee1c35e..cee9e40 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -256,6 +256,10 @@ You probably do not need to adjust this value.
 +
 Common unit suffixes of 'k', 'm', or 'g' are supported.
 
+core.submodules
+	If true, gitlink:git-checkout[1] also checks out submodules.
+	False by default.
+
 alias.*::
 	Command aliases for the gitlink:git[1] command wrapper - e.g.
 	after defining "alias.last = cat-file commit HEAD", the invocation
@@ -606,6 +610,9 @@ showbranch.default::
 	The default set of branches for gitlink:git-show-branch[1].
 	See gitlink:git-show-branch[1].
 
+submodule.<submodule>.url
+	The URL of a submodule.  See gitlink:git-clone[1].
+
 tar.umask::
 	By default, gitlink:git-tar-tree[1] sets file and directories modes
 	to 0666 or 0777. While this is both useful and acceptable for projects
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 644bf12..565155b 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
 	  [-o <name>] [-u <upload-pack>] [--reference <repository>]
-	  [--depth <depth>] <repository> [<directory>]
+	  [--depth <depth>] [--submodules] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -105,6 +105,10 @@ OPTIONS
 	with a long history, and would want to send in a fixes
 	as patches.
 
+--submodules::
+	Clone submodules specified in (remote) configuration parameters
+	submodule.<submodule>.url.
+
 <repository>::
 	The (possibly remote) repository to clone from.  It can
 	be any URL git-fetch supports.
diff --git a/git-clone.sh b/git-clone.sh
index 44387f4..f5a3548 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -14,7 +14,7 @@ die() {
 }
 
 usage() {
-	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
+	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--submodules] <repo> [<dir>]"
 }
 
 get_repo_base() {
@@ -88,6 +88,7 @@ origin_override=
 use_separate_remote=t
 depth=
 no_progress=
+submodules=
 test -t 1 || no_progress=--no-progress
 while
 	case "$#,$1" in
@@ -138,6 +139,8 @@ while
 	*,--depth)
 		shift
 		depth="--depth=$1";;
+	*,--su|*,--sub|*,--subm|*,--submo|*,--submod|*,--submodu|*,--submodul|\
+	*,--submodule|*,--submodules) submodules="--submodules" ;;
 	*,-*) usage ;;
 	*) break ;;
 	esac
@@ -156,6 +159,10 @@ then
 	then
 		die '--bare and --origin $origin options are incompatible.'
 	fi
+	if test -n "$submodules"
+	then
+		die '--bare and --submodules origin options are incompatible.'
+	fi
 	no_checkout=yes
 	use_separate_remote=
 fi
@@ -309,7 +316,7 @@ yes,yes)
 		;;
 	*)
 		git-fetch --all -k $quiet "$upload_pack" $depth \
-			$separate_remote_flag "$origin" ||
+			$separate_remote_flag $submodules "$origin" ||
 			die "fetch from '$repo' failed."
 		;;
 	esac
@@ -405,10 +412,15 @@ then
 		git-config branch."$head_points_at".merge "refs/heads/$head_points_at"
 	esac
 
+	if test -n "$submodules"
+	then
+		git-config core.submodules true
+	fi
+
 	case "$no_checkout" in
 	'')
 		test "z$quiet" = z -a "z$no_progress" = z && v=-v || v=
-		git-read-tree -m -u $v HEAD HEAD
+		git-read-tree -m -u $v $submodules HEAD HEAD
 	esac
 fi
 rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
diff --git a/git-fetch.sh b/git-fetch.sh
index 84c2523..b7ef0c3 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -15,6 +15,70 @@ LF='
 '
 IFS="$LF"
 
+local_URL() {
+	# tranforms a "URL" on the remote to a URL that works on the local machine
+	# $1 - remote, $2 - URL on remote
+	echo "$1 $2" >&2
+	case "$1" in
+	https://*|http://*|ftp://*)
+		case "$2" in
+		https://*|http://*|ftp://*)
+			echo $2
+		esac
+		;;
+	ssh://*)
+		case "$2" in
+		https://*|http://*|ftp://*)
+			echo $2
+			;;
+		/*)
+			echo $(echo $1 | sed -e 's/\(ssh:\/\/[^\/]*\)\/.*/\1/')$2
+		esac
+		;;
+	/*)
+		echo $2
+		;;
+	*)
+		case "$2" in
+		https://*|http://*|ftp://*)
+			echo $2
+		esac
+	esac
+}
+
+clone_submodules () {
+	# $1 - remote
+	remote=$1
+	( : subshell because we muck with IFS
+        IFS=" 	$LF"
+	cd "$GIT_DIR/.."
+	git-config --remote="$remote" --get-regexp 'submodule\..*\.url' | \
+	sed -e 's/^submodule\.//' -e 's/\.url / /' |
+	while read submodule URL
+	do
+		previous=$(git-config "submodule.$submodule.url")
+		if test -n "$previous"
+		then
+			continue;
+		fi
+		URL=$(local_URL "$remote" "$URL")
+		if test -z "$URL"
+		then
+			continue;
+		fi
+		# At this point, we don't know if the submodule
+		# appears in the HEAD of the supermodule, so clone it
+		# without a checkout and overwrite HEAD so that a subsequent
+		# checkout won't assume the submodule has already been
+		# checked out.
+		git-clone --submodules -n "$URL" "$submodule"
+		z40=0000000000000000000000000000000000000000
+		GIT_DIR="$submodule/.git" git-update-ref --no-deref HEAD $z40
+		git-config "submodule.$submodule.url" "$URL"
+	done
+	)
+}
+
 all=
 no_tags=
 tags=
@@ -27,6 +91,7 @@ keep=
 shallow_depth=
 no_progress=
 use_separate_remote=
+submodules=
 test -t 1 || no_progress=--no-progress
 quiet=
 while case "$#" in 0) break ;; esac
@@ -84,6 +149,15 @@ do
 		shift
 		shallow_depth="--depth=$1"
 		;;
+	--su|--sub|--subm|--submo|--submod|--submodu|--submodul|\
+	--submodule|--submodules)
+		submodules="yes"
+		;;
+	--no-su|--no-sub|--no-subm|--no-submo|--no-submod|\
+	--no-submodu|--no-submodul|\
+	--no-submodule|--no-submodules)
+		submodules="no"
+		;;
 	-*)
 		usage
 		;;
@@ -149,6 +223,18 @@ case "$tags$no_tags" in
 	esac
 esac
 
+case "$submodules" in
+'')
+	case "$(git-config --bool core.submodules)" in
+	true)
+		submodues=yes
+		;;
+	*)
+		submodules=no
+		;;
+	esac
+esac
+
 # If --tags (and later --heads or --all) is specified, then we are
 # not talking about defaults stored in Pull: line of remotes or
 # branches file, and just fetch those and refspecs explicitly given.
@@ -407,3 +493,7 @@ case "$orig_head" in
 	fi
 	;;
 esac
+
+if test "$submodules" = yes; then
+	clone_submodules "$remote"
+fi
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 14/16] git-clone: rely on git-fetch for non-bare fetching over http

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 git-clone.sh |    6 +++---
 git-fetch.sh |   20 ++++++++++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/git-clone.sh b/git-clone.sh
index 44127c5..44387f4 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -262,8 +262,8 @@ yes,yes)
 	git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
 	;;
 *)
-	case "$repo" in
-	rsync://*)
+	case "$bare,$repo" in
+	*,rsync://*)
 		case "$depth" in
 		"") ;;
 		*) die "shallow over rsync not supported" ;;
@@ -295,7 +295,7 @@ yes,yes)
 		fi
 		git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
 		;;
-	https://*|http://*|ftp://*)
+	yes,https://*|yes,http://*|yes,ftp://*)
 		case "$depth" in
 		"") ;;
 		*) die "shallow over http or ftp not supported" ;;
diff --git a/git-fetch.sh b/git-fetch.sh
index e169848..84c2523 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -237,11 +237,31 @@ fetch_all_at_once () {
 
 }
 
+http_fetch () {
+	if [ -n "$GIT_SSL_NO_VERIFY" ]; then
+		curl_extra_args="-k"
+	fi
+	if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
+		"`git-config --bool http.noEPSV`" = true ]; then
+		curl_extra_args="${curl_extra_args} --disable-epsv"
+	fi
+
+	# $1 = Remote, $2 = Local
+	curl -nsfL $curl_extra_args "$1" >"$2"
+}
+
 fetch_per_ref () {
   reflist="$1"
   refs=
   rref=
 
+    if test -n "$all"; then
+	reflist=$(canon_refs_list_for_fetch -d "$remote_nick" \
+			"+refs/heads/*:refs/remotes/$remote_nick/*")
+	http_fetch "$remote/HEAD" "$GIT_DIR/REMOTE_HEAD" ||
+	rm -f "$GIT_DIR/REMOTE_HEAD"
+    fi
+
   for ref in $reflist
   do
       refs="$refs$LF$ref"
-- 
1.5.2.rc3.783.gc7476-dirty

[PATCH 15/16] git-read-tree: treat null commit as empty tree

From: <hidden>
Date: 2016-06-15 22:43:11

From: Sven Verdoolaege <redacted>

---
 builtin-read-tree.c |    9 ++++++---
 unpack-trees.c      |    3 +++
 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 929dd95..b9fcff7 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -17,9 +17,12 @@ static struct object_list *trees;
 
 static int list_tree(unsigned char *sha1)
 {
-	struct tree *tree = parse_tree_indirect(sha1);
-	if (!tree)
-		return -1;
+	struct tree *tree = NULL;
+	if (!is_null_sha1(sha1)) {
+		tree = parse_tree_indirect(sha1);
+		if (!tree)
+			return -1;
+	}
 	object_list_append(&tree->object, &trees);
 	return 0;
 }
diff --git a/unpack-trees.c b/unpack-trees.c
index e979bc5..30c2a49 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -26,6 +26,9 @@ static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
 	struct tree_entry_list *ret = NULL;
 	struct tree_entry_list **list_p = &ret;
 
+	if (!tree)
+		return ret;
+
 	if (!tree->object.parsed)
 		parse_tree(tree);
 
-- 
1.5.2.rc3.783.gc7476-dirty

Re: Second round of support for cloning submodules

From: Sven Verdoolaege <hidden>
Date: 2016-06-15 22:43:11

I forgot to mention that these changes go on top of next
(v1.5.2-rc3-762-g77e153b).

skimo

Re: [PATCH 07/16] git-read-tree: take --submodules option

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl, Fri, May 18, 2007 21:24:56 +0200:
This option currently has no effect.
Can we have this option (and corresponding support in the following
patches, of course) first? It is enough to have subprojects working
locally, and people can start using them immediately: anyone can clone
the subprojects manually if he wishes so.

Cloning of subprojects is still unclear, and frankly I'm not sure it
should be done at all. Not even with an option which is off by
default.

Re: [PATCH 09/16] entry.c: optionally checkout submodules

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl, Fri, May 18, 2007 21:24:58 +0200:
+	if (err)
+		return error("failed to run git-checkout in submodule '%s'", path);
We may need an option to ignore these failures. Maybe even active by
default. Imagine a superproject with _optional_ submodules, where it
is just nice to know that some submodules weren't checked out. BTW,
doesn't git-checkout already prints an error?

Re: [PATCH 09/16] entry.c: optionally checkout submodules

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl, Fri, May 18, 2007 21:24:58 +0200:
+	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+		die("Unable to read current working directory");
+
+	if (chdir(path))
+		die("Cannot move to '%s'", path);
+
How about modifying run_command to chdir after fork?

You'd save the hassle of save/restoring cwd and don't mess up process'
context (which is always a good idea to preserve). The code'd be
simplier, too.

Re: [PATCH 09/16] entry.c: optionally checkout submodules

From: Sven Verdoolaege <hidden>
Date: 2016-06-15 22:43:11

On Fri, May 18, 2007 at 11:56:42PM +0200, Alex Riesen wrote:
skimo@liacs.nl, Fri, May 18, 2007 21:24:58 +0200:
quoted
+	if (err)
+		return error("failed to run git-checkout in submodule '%s'", path);
We may need an option to ignore these failures. Maybe even active by
default. Imagine a superproject with _optional_ submodules, where it
is just nice to know that some submodules weren't checked out. BTW,
doesn't git-checkout already prints an error?
Probably.  You probably noticed that I haven't written any tests yet...

Still, the error that git-checkout prints may not give enough of a clue
that something was wrong with a submodule.

skimo

Re: [PATCH 07/16] git-read-tree: take --submodules option

From: Sven Verdoolaege <hidden>
Date: 2016-06-15 22:43:11

I noticed there's a whole thread about subprojects that I haven't read yet,
so this may have been addressed already ....

On Fri, May 18, 2007 at 11:53:12PM +0200, Alex Riesen wrote:
Can we have this option (and corresponding support in the following
patches, of course) first?
That's why the clone thing comes last.
It is enough to have subprojects working
locally, and people can start using them immediately: anyone can clone
the subprojects manually if he wishes so.
Anyone can run git-write-tree and git-commit-tree is she wishes so...
Cloning of subprojects is still unclear, and frankly I'm not sure it
should be done at all. Not even with an option which is off by
default.
Then don't use it.

The reason for not putting this in shouldn't be that someone doesn't
think it is useful; the reason should be that my code is crap.

skimo

[PATCH] Add run_command_v_opt_cd: chdir into a directory before exec

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

It can make code simplier (no need to preserve cwd) and safer
(no chance the cwd of the current process is accidentally forgotten).

Signed-off-by: Alex Riesen <redacted>
---
Alex Riesen, Sat, May 19, 2007 00:00:14 +0200:
skimo@liacs.nl, Fri, May 18, 2007 21:24:58 +0200:
quoted
+	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+		die("Unable to read current working directory");
+
+	if (chdir(path))
+		die("Cannot move to '%s'", path);
+
How about modifying run_command to chdir after fork?

You'd save the hassle of save/restoring cwd and don't mess up process'
context (which is always a good idea to preserve). The code'd be
simplier, too.
something like this

 run-command.c |   27 ++++++++++++++++++++++-----
 run-command.h |    2 ++
 2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/run-command.c b/run-command.c
index eff523e..043b570 100644
--- a/run-command.c
+++ b/run-command.c
@@ -73,6 +73,9 @@ int start_command(struct child_process *cmd)
 			close(cmd->out);
 		}
 
+		if (cmd->dir && chdir(cmd->dir))
+			die("exec %s: cd to %s failed (%s)", cmd->argv[0],
+			    cmd->dir, strerror(errno));
 		if (cmd->git_cmd) {
 			execv_git_cmd(cmd->argv);
 		} else {
@@ -133,13 +136,27 @@ int run_command(struct child_process *cmd)
 	return finish_command(cmd);
 }
 
+static void prepare_run_command_v_opt(struct child_process *cmd,
+				      const char **argv, int opt)
+{
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->argv = argv;
+	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+	cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
+	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+}
+
 int run_command_v_opt(const char **argv, int opt)
 {
 	struct child_process cmd;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.argv = argv;
-	cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-	cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
-	cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+	prepare_run_command_v_opt(&cmd, argv, opt);
+	return run_command(&cmd);
+}
+
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir)
+{
+	struct child_process cmd;
+	prepare_run_command_v_opt(&cmd, argv, opt);
+	cmd.dir = dir;
 	return run_command(&cmd);
 }
diff --git a/run-command.h b/run-command.h
index 3680ef9..cbd7484 100644
--- a/run-command.h
+++ b/run-command.h
@@ -16,6 +16,7 @@ struct child_process {
 	pid_t pid;
 	int in;
 	int out;
+	const char *dir;
 	unsigned close_in:1;
 	unsigned close_out:1;
 	unsigned no_stdin:1;
@@ -32,5 +33,6 @@ int run_command(struct child_process *);
 #define RUN_GIT_CMD	     2	/*If this is to be git sub-command */
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 int run_command_v_opt(const char **argv, int opt);
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir);
 
 #endif
-- 
1.5.2.rc3.83.gbbb0

Re: [PATCH 11/16] git-fetch: skip empty arguments

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl writes:
From: Sven Verdoolaege <redacted>

This makes it easier for scripts to call git-fetch with options
that may or may not be set.
For git-fetch it does not matter as I do not think there is any
valid case to pass an empty string as a parameter to it (even
"fetch from our own repository" requires a single dot).  But
from discipline point of view, I am not happy about this.

If you are talking about shell scripts, the standard way to do
that is to say ${1+"$1"}.

Re: [PATCH 05/16] unpack-trees.c: verify_uptodate: remove dead code

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl writes:
quoted hunk
From: Sven Verdoolaege <redacted>

This code was killed by commit fcc387db9bc453dc7e07a262873481af2ee9e5c8.

Signed-off-by: Sven Verdoolaege <redacted>
---
 unpack-trees.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index 906ce69..cac2411 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -414,10 +414,6 @@ static void verify_uptodate(struct cache_entry *ce,
 			return;
 		errno = 0;
 	}
-	if (o->reset) {
-		ce->ce_flags |= htons(CE_UPDATE);
-		return;
-	}
 	if (errno == ENOENT)
 		return;
 	die("Entry '%s' not uptodate. Cannot merge.", ce->name);
-- 
1.5.2.rc3.783.gc7476-dirty
Hmmm.

I am not absolutely sure if the fcc387db change was correct
anymore, but in any case, this removal of dead code should not
break anything.

But this does not belong to your series either.

Perhaps I should apply this to 'master' regardless of the rest
of the series.

Re: [PATCH 09/16] entry.c: optionally checkout submodules

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

Sven Verdoolaege, Sat, May 19, 2007 00:03:23 +0200:
On Fri, May 18, 2007 at 11:56:42PM +0200, Alex Riesen wrote:
quoted
skimo@liacs.nl, Fri, May 18, 2007 21:24:58 +0200:
quoted
+	if (err)
+		return error("failed to run git-checkout in submodule '%s'", path);
We may need an option to ignore these failures. Maybe even active by
default. Imagine a superproject with _optional_ submodules, where it
is just nice to know that some submodules weren't checked out. BTW,
doesn't git-checkout already prints an error?
Probably.  You probably noticed that I haven't written any tests yet...
I see. It was a very ... provocative patch series :)
Still, the error that git-checkout prints may not give enough of a clue
that something was wrong with a submodule.
Like, for example, it failed because the directory is not a git repo
yet, because the previous git-checkout was called _without_
--submodule and the directories created are just empty.

Anyway, just a "failed to run git-checkout" is not very helpful
either. Come to think about it, there is not very much you can tell
out of super-project context. git-checkout will always know better.

Re: [PATCH 07/16] git-read-tree: take --submodules option

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

Sven Verdoolaege, Sat, May 19, 2007 00:08:26 +0200:
I noticed there's a whole thread about subprojects that I haven't read yet,
so this may have been addressed already ....
Not the checkout, which is strange. It's mostly about cloning.
On Fri, May 18, 2007 at 11:53:12PM +0200, Alex Riesen wrote:
quoted
Can we have this option (and corresponding support in the following
patches, of course) first?
That's why the clone thing comes last.
quoted
It is enough to have subprojects working
locally, and people can start using them immediately: anyone can clone
the subprojects manually if he wishes so.
Anyone can run git-write-tree and git-commit-tree is she wishes so...
It is much more tedious. It have to be done recursively, and with
right SHA and you have to cd into right direcotry first and it is
git-read-tree and git-checkout-index, BTW.

IOW, it is hard.
The reason for not putting this in shouldn't be that someone doesn't
think it is useful; the reason should be that my code is crap.
The code is not a problem. It can be also discarded because you
implemented something no one wants.

I just meant to say, that even if no one wants your subproject cloning
code, _I_ support your checkout effort and I am asking for it to be
put in.

"First", as the cloning discussion does not seem to be finished (and,
as I said, I am not interested in cloning anyway).

[PATCH] Use run_command_v_opt_cd when checking out a submodule

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

Signed-off-by: Alex Riesen <redacted>
---
 entry.c |   12 +-----------
 1 files changed, 1 insertions(+), 11 deletions(-)
diff --git a/entry.c b/entry.c
index 96a4a60..0316c74 100644
--- a/entry.c
+++ b/entry.c
@@ -166,7 +166,6 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
 
 static int checkout_submodule(const char *path, struct cache_entry *ce, const struct checkout *state)
 {
-	static char cwd[PATH_MAX];
 	const char *gitdirenv;
 	const char *args[10];
 	int argc;
@@ -175,12 +174,6 @@ static int checkout_submodule(const char *path, struct cache_entry *ce, const st
 	if (!state->submodules)
 		return 0;
 
-	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
-		die("Unable to read current working directory");
-
-	if (chdir(path))
-		die("Cannot move to '%s'", path);
-
 	argc = 0;
 	args[argc++] = "checkout";
 	if (state->force)
@@ -190,12 +183,9 @@ static int checkout_submodule(const char *path, struct cache_entry *ce, const st
 
 	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
 	unsetenv(GIT_DIR_ENVIRONMENT);
-	err = run_command_v_opt(args, RUN_GIT_CMD);
+	err = run_command_v_opt_cd(args, RUN_GIT_CMD, path);
 	setenv(GIT_DIR_ENVIRONMENT, gitdirenv, 1);
 
-	if (chdir(cwd))
-		die("Cannot come back to cwd");
-
 	if (err)
 		return error("failed to run git-checkout in submodule '%s'", path);
 
-- 
1.5.2.rc3.83.gbbb0

Re: [PATCH 12/16] builtin-fetch--tool: extend "native-store" for use in cloning

From: Alex Riesen <hidden>
Date: 2016-06-15 22:43:11

skimo@liacs.nl, Fri, May 18, 2007 21:25:01 +0200:
quoted hunk
@@ -261,7 +287,8 @@ static int fetch_native_store(FILE *fp,
 			      const char *remote,
 			      const char *remote_nick,
 			      const char *refs,
-			      int verbose, int force)
+			      int verbose, int force,
+			      int all, int use_separate_remote)
 {
 	char buffer[1024];
 	int err = 0;
@@ -294,8 +321,12 @@ static int fetch_native_store(FILE *fp,
 			continue;
 		}
 
-		local_name = find_local_name(cp, refs,
-					     &single_force, &not_for_merge);
+		if (all)
+			local_name = construct_local_name(cp, remote_nick,
+							  use_separate_remote);
+		else
+			local_name = find_local_name(cp, refs,
+						     &single_force, &not_for_merge);
This code produces warning about possible uninitialized used of
single_force and not_for_merge. I used the patch below, but didn't
look into what the "all" does.

---
 builtin-fetch--tool.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index 12adb38..ebb49d9 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -273,7 +273,7 @@ static int fetch_native_store(FILE *fp,
 		int len;
 		char *cp;
 		char *local_name;
-		int single_force, not_for_merge;
+		int single_force = force, not_for_merge = 0;
 
 		for (cp = buffer; *cp && !isspace(*cp); cp++)
 			;
@@ -301,7 +301,7 @@ static int fetch_native_store(FILE *fp,
 		err |= append_fetch_head(fp,
 					 buffer, remote, cp, remote_nick,
 					 local_name, not_for_merge,
-					 verbose, force || single_force);
+					 verbose, single_force);
 	}
 	return err;
 }
-- 
1.5.2.rc3.83.gbbb0

Re: [PATCH 07/16] git-read-tree: take --submodules option

From: Petr Baudis <hidden>
Date: 2016-06-15 22:43:11

On Fri, May 18, 2007 at 09:24:56PM CEST, skimo@liacs.nl wrote:
From: Sven Verdoolaege <redacted>

This option currently has no effect.

Signed-off-by: Sven Verdoolaege <redacted>
Nacked-by: Petr Baudis [off-list ref]

Please do not add more undocumented parameters - include documentation
in the patch adding the parameter.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Ever try. Ever fail. No matter. // Try again. Fail again. Fail better.
		-- Samuel Beckett

Re: [PATCH 10/16] git-checkout: pass --submodules option to git-read-tree

From: Petr Baudis <hidden>
Date: 2016-06-15 22:43:11

On Fri, May 18, 2007 at 09:24:59PM CEST, skimo@liacs.nl wrote:
quoted hunk
From: Sven Verdoolaege <redacted>

Signed-off-by: Sven Verdoolaege <redacted>
---
 git-checkout.sh |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/git-checkout.sh b/git-checkout.sh
index 6b6facf..cbb1f00 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+USAGE='[-q] [-f] [--submodules] [--no-submodules] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
Thus Documentation/git-checkout.txt needs to be updated as well.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Ever try. Ever fail. No matter. // Try again. Fail again. Fail better.
		-- Samuel Beckett

Re: [PATCH 12/16] builtin-fetch--tool: extend "native-store" for use in cloning

From: Sven Verdoolaege <hidden>
Date: 2016-06-15 22:43:11

On Sat, May 19, 2007 at 12:52:34AM +0200, Alex Riesen wrote:
This code produces warning about possible uninitialized used of
single_force and not_for_merge. I used the patch below, but didn't
look into what the "all" does.
Sorry for being sloppy.  It is assumed that "all" is only used
for cloning and then the other two flags don't really matter,
but I should've set some defaults.
Yours look fine, thanks.

A fixed-up version is available in the "submodules" branch
of http://www.liacs.nl/~sverdool/git.git or
www.liacs.nl/~sverdool/gitweb.cgi?p=git.git;a=shortlog;h=submodules

skimo
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help