git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/6] builtin-remote
@ 2007-12-05 19:00 Johannes Schindelin
  2007-12-05 19:00 ` (unknown) Johannes Schindelin
                   ` (5 more replies)
  0 siblings, 6 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:00 UTC (permalink / raw)
  To: git, gitster

Hi,

this series introduces remote as a builtin, and fixes a long-standing bug 
(if you created a remote with --mirror, prune would not do the right 
thing).

I know it is pretty late in the game for 1.5.4, but then, I do not expect 
this to go into that version...

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

* (unknown)
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
@ 2007-12-05 19:00 ` Johannes Schindelin
  2007-12-05 19:01   ` your mail Johannes Schindelin
  2007-12-05 19:05   ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin
  2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:00 UTC (permalink / raw)
  To: git, gitster

[PATCH 1/6] path-list: add functions to work with unsorted lists

Up to now, path-lists were sorted at all times.  But sometimes it
is much more convenient to build the list and sort it at the end,
or sort it not at all.

Add path_list_append() and sort_path_list() to allow that.

Also, add the unsorted_path_list_has_path() function, to do a linear
search.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	I should have done this much earlier...

 path-list.c |   30 ++++++++++++++++++++++++++++++
 path-list.h |    8 +++++++-
 2 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/path-list.c b/path-list.c
index 3d83b7b..92e5cf2 100644
--- a/path-list.c
+++ b/path-list.c
@@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p)
 	for (i = 0; i < p->nr; i++)
 		printf("%s:%p\n", p->items[i].path, p->items[i].util);
 }
+
+struct path_list_item *path_list_append(const char *path, struct path_list *list)
+{
+	ALLOC_GROW(list->items, list->nr + 1, list->alloc);
+	list->items[list->nr].path =
+		list->strdup_paths ? xstrdup(path) : (char *)path;
+	return list->items + list->nr++;
+}
+
+static int cmp_items(const void *a, const void *b)
+{
+	const struct path_list_item *one = a;
+	const struct path_list_item *two = b;
+	return strcmp(one->path, two->path);
+}
+
+void sort_path_list(struct path_list *list)
+{
+	qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
+}
+
+int unsorted_path_list_has_path(struct path_list *list, const char *path)
+{
+	int i;
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(path, list->items[i].path))
+			return 1;
+	return 0;
+}
+
diff --git a/path-list.h b/path-list.h
index 5931e2c..ca2cbba 100644
--- a/path-list.h
+++ b/path-list.h
@@ -13,10 +13,16 @@ struct path_list
 };
 
 void print_path_list(const char *text, const struct path_list *p);
+void path_list_clear(struct path_list *list, int free_util);
 
+/* Use these functions only on sorted lists: */
 int path_list_has_path(const struct path_list *list, const char *path);
-void path_list_clear(struct path_list *list, int free_util);
 struct path_list_item *path_list_insert(const char *path, struct path_list *list);
 struct path_list_item *path_list_lookup(const char *path, struct path_list *list);
 
+/* Use these functions only on unsorted lists: */
+struct path_list_item *path_list_append(const char *path, struct path_list *list);
+void sort_path_list(struct path_list *list);
+int unsorted_path_list_has_path(struct path_list *list, const char *path);
+
 #endif /* PATH_LIST_H */
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/6] parseopt: add flag to stop on first non option
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
  2007-12-05 19:00 ` (unknown) Johannes Schindelin
@ 2007-12-05 19:01 ` Johannes Schindelin
  2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:01 UTC (permalink / raw)
  To: git, gitster


Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	This allows "git remote --option command --command-option".

 parse-options.c |    2 ++
 parse-options.h |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index e12b428..6df1230 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -229,6 +229,8 @@ int parse_options(int argc, const char **argv, const struct option *options,
 		const char *arg = args.argv[0];
 
 		if (*arg != '-' || !arg[1]) {
+			if (flags & PARSE_OPT_STOP_AT_NON_OPTION)
+				break;
 			argv[j++] = args.argv[0];
 			continue;
 		}
diff --git a/parse-options.h b/parse-options.h
index 102ac31..0d40cd2 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -18,6 +18,7 @@ enum parse_opt_type {
 
 enum parse_opt_flags {
 	PARSE_OPT_KEEP_DASHDASH = 1,
+	PARSE_OPT_STOP_AT_NON_OPTION = 2,
 };
 
 enum parse_opt_option_flags {
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: your mail
  2007-12-05 19:00 ` (unknown) Johannes Schindelin
@ 2007-12-05 19:01   ` Johannes Schindelin
  2007-12-05 19:05   ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin
  1 sibling, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:01 UTC (permalink / raw)
  To: git, gitster

Hi,

On Wed, 5 Dec 2007, Johannes Schindelin wrote:

> [PATCH 1/6] path-list: add functions to work with unsorted lists

Ooops.

Sorry,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/6] Test "git remote show" and "git remote prune"
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
  2007-12-05 19:00 ` (unknown) Johannes Schindelin
  2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin
@ 2007-12-05 19:02 ` Johannes Schindelin
  2007-12-05 21:59   ` René Scharfe
  2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw)
  To: git, gitster


While at it, also fix a few instances where a cd was done outside of a
subshell.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 636aec2..c7d7242 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -97,4 +97,38 @@ test_expect_success 'remove remote' '
 )
 '
 
+cat > test/expect << EOF
+* remote origin
+  URL: $(pwd)/one/.git
+  Remote branch(es) merged with 'git pull' while on branch master
+    master
+  New remote branches (next fetch will store in remotes/origin)
+    master
+  Tracked remote branches
+    side master
+EOF
+
+test_expect_success 'show' '
+	(cd test &&
+	 git config --add remote.origin.fetch \
+		refs/heads/master:refs/heads/upstream &&
+	 git fetch &&
+	 git branch -d -r origin/master &&
+	 (cd ../one &&
+	  echo 1 > file &&
+	  git commit -m update file) &&
+	 git remote show origin > output &&
+	 git diff expect output)
+'
+
+test_expect_success 'prune' '
+	(cd one &&
+	 git branch -m side side2) &&
+	(cd test &&
+	 git fetch origin &&
+	 git remote prune origin &&
+	 git rev-parse refs/remotes/origin/side2 &&
+	 ! git rev-parse refs/remotes/origin/side)
+'
+
 test_done
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/6] Make git-remote a builtin
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
                   ` (2 preceding siblings ...)
  2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin
@ 2007-12-05 19:02 ` Johannes Schindelin
  2007-12-05 21:40   ` [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check Johannes Schindelin
  2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
  2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin
  5 siblings, 1 reply; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw)
  To: git, gitster


Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                                           |    3 +-
 builtin-remote.c                                   |  517 ++++++++++++++++++++
 builtin.h                                          |    1 +
 .../examples/git-remote.perl                       |    0 
 git.c                                              |    1 +
 remote.c                                           |    3 +-
 remote.h                                           |    1 +
 t/t5505-remote.sh                                  |    4 +-
 8 files changed, 526 insertions(+), 4 deletions(-)
 create mode 100644 builtin-remote.c
 rename git-remote.perl => contrib/examples/git-remote.perl (100%)

diff --git a/Makefile b/Makefile
index 233bb5f..e840ca3 100644
--- a/Makefile
+++ b/Makefile
@@ -228,7 +228,7 @@ SCRIPT_SH = \
 SCRIPT_PERL = \
 	git-add--interactive.perl \
 	git-archimport.perl git-cvsimport.perl git-relink.perl \
-	git-cvsserver.perl git-remote.perl git-cvsexportcommit.perl \
+	git-cvsserver.perl git-cvsexportcommit.perl \
 	git-send-email.perl git-svn.perl
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
@@ -362,6 +362,7 @@ BUILTIN_OBJS = \
 	builtin-push.o \
 	builtin-read-tree.o \
 	builtin-reflog.o \
+	builtin-remote.o \
 	builtin-send-pack.o \
 	builtin-config.o \
 	builtin-rerere.o \
diff --git a/builtin-remote.c b/builtin-remote.c
new file mode 100644
index 0000000..41ac4a1
--- /dev/null
+++ b/builtin-remote.c
@@ -0,0 +1,517 @@
+#include "cache.h"
+#include "parse-options.h"
+#include "transport.h"
+#include "remote.h"
+#include "path-list.h"
+#include "strbuf.h"
+#include "run-command.h"
+#include "refs.h"
+
+static const char * const builtin_remote_usage[] = {
+	"git remote",
+        "git remote add <name> <url>",
+        "git remote rm <name>",
+        "git remote show <name>",
+        "git remote prune <name>",
+        "git remote update [group]",
+	NULL
+};
+
+static int verbose;
+
+static inline int postfixcmp(const char *string, const char *postfix)
+{
+	int len1 = strlen(string), len2 = strlen(postfix);
+	if (len1 < len2)
+		return 1;
+	return strcmp(string + len1 - len2, postfix);
+}
+
+static inline const char *skip_prefix(const char *name, const char *prefix)
+{
+	return !name ? "" :
+		prefixcmp(name, prefix) ?  name : name + strlen(prefix);
+}
+
+static int opt_parse_track(const struct option *opt, const char *arg, int not)
+{
+	struct path_list *list = opt->value;
+	if (not)
+		path_list_clear(list, 0);
+	else
+		path_list_append(arg, list);
+	return 0;
+}
+
+static int fetch_remote(const char *name)
+{
+	const char *argv[] = { "fetch", name, NULL };
+	if (run_command_v_opt(argv, RUN_GIT_CMD))
+		return error ("Could not fetch %s", name);
+	return 0;
+}
+
+static int add(int argc, const char **argv)
+{
+	int fetch = 0, mirror = 0;
+	struct path_list track = { NULL, 0, 0 };
+	const char *master = NULL;
+	struct remote *remote;
+	struct strbuf buf, buf2;
+	const char *name, *url;
+	int i;
+
+	struct option options[] = {
+		OPT_GROUP("add specific options"),
+		OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"),
+		OPT_CALLBACK('t', "track", &track, "branch",
+			"branch(es) to track", opt_parse_track),
+		OPT_STRING('m', "master", &master, "branch", "master branch"),
+		OPT_BOOLEAN(0, "mirror", &mirror, "no separate remotes"),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
+
+	if (argc < 2)
+		usage_with_options(builtin_remote_usage, options);
+
+	name = argv[0];
+	url = argv[1];
+
+	remote = remote_get(name);
+	if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
+			remote->fetch_refspec_nr))
+		die ("remote %s already exists.", name);
+
+	strbuf_init(&buf, 0);
+	strbuf_init(&buf2, 0);
+
+	strbuf_addf(&buf, "remote.%s.url", name);
+	if (git_config_set(buf.buf, url))
+		return 1;
+
+	if (track.nr == 0)
+		path_list_append("*", &track);
+	for (i = 0; i < track.nr; i++) {
+		struct path_list_item *item = track.items + i;
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.fetch", name);
+
+		strbuf_reset(&buf2);
+		if (mirror)
+			strbuf_addf(&buf2, "refs/%s:refs/%s",
+					item->path, item->path);
+		else
+			strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
+					item->path, name, item->path);
+		if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
+			return 1;
+	}
+
+	if (fetch && fetch_remote(name))
+		return 1;
+
+	if (master) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/remotes/%s/HEAD", name);
+
+		strbuf_reset(&buf2);
+		strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
+
+		if (create_symref(buf.buf, buf2.buf, "remote add"))
+			return error ("Could not setup master '%s'", master);
+	}
+
+	strbuf_release(&buf);
+	strbuf_release(&buf2);
+	path_list_clear(&track, 0);
+
+	return 0;
+}
+
+struct branch_info {
+	char *remote;
+	struct path_list merge;
+};
+
+static struct path_list branch_list;
+
+static int config_read_branches(const char *key, const char *value)
+{
+	if (!prefixcmp(key, "branch.")) {
+		char *name;
+		struct path_list_item *item;
+		struct branch_info *info;
+		enum { REMOTE, MERGE } type;
+
+		key += 7;
+		if (!postfixcmp(key, ".remote")) {
+			name = xstrndup(key, strlen(key) - 7);
+			type = REMOTE;
+		} else if (!postfixcmp(key, ".merge")) {
+			name = xstrndup(key, strlen(key) - 6);
+			type = MERGE;
+		} else
+			return 0;
+
+		item = path_list_insert(name, &branch_list);
+
+		if (!item->util)
+			item->util = xcalloc(sizeof(struct branch_info), 1);
+		info = item->util;
+		if (type == REMOTE) {
+			if (info->remote)
+				warning ("more than one branch.%s", key);
+			info->remote = xstrdup(value);
+		} else {
+			char *space = strchr(value, ' ');
+			value = skip_prefix(value, "refs/heads/");
+			while (space) {
+				char *merge;
+				merge = xstrndup(value, space - value);
+				path_list_append(merge, &info->merge);
+				value = skip_prefix(space + 1, "refs/heads/");
+				space = strchr(value, ' ');
+			}
+			path_list_append(xstrdup(value), &info->merge);
+		}
+	}
+	return 0;
+}
+
+static void read_branches()
+{
+	if (branch_list.nr)
+		return;
+	git_config(config_read_branches);
+	sort_path_list(&branch_list);
+}
+
+struct ref_states {
+	struct remote *remote;
+	struct strbuf remote_prefix;
+	struct path_list new, stale, tracked;
+};
+
+static int handle_one_branch(const char *refname,
+	const unsigned char *sha1, int flags, void *cb_data)
+{
+	struct ref_states *states = cb_data;
+	struct refspec refspec;
+
+	memset(&refspec, 0, sizeof(refspec));
+	refspec.dst = (char *)refname;
+	if (!remote_find_tracking(states->remote, &refspec)) {
+		struct path_list_item *item;
+		const char *name = skip_prefix(refspec.src, "refs/heads/");
+		if (unsorted_path_list_has_path(&states->tracked, name) ||
+				unsorted_path_list_has_path(&states->new,
+					name))
+			return 0;
+		item = path_list_append(name, &states->stale);
+		item->util = xstrdup(refname);
+	}
+	return 0;
+}
+
+static int get_ref_states(const struct ref *ref, struct ref_states *states)
+{
+	struct ref *fetch_map = NULL, **tail = &fetch_map;
+	int i;
+
+	for (i = 0; i < states->remote->fetch_refspec_nr; i++)
+		if (get_fetch_map(ref, states->remote->fetch +i, &tail, 1))
+			die ("Could not get fetch map for refspec %s",
+				states->remote->fetch_refspec[i]);
+
+	states->new.strdup_paths = states->tracked.strdup_paths = 1;
+	for (ref = fetch_map; ref; ref = ref->next) {
+		struct path_list *target = &states->tracked;
+		unsigned char sha1[20];
+		void *util = NULL;
+
+		if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
+			target = &states->new;
+		else {
+			target = &states->tracked;
+			if (hashcmp(sha1, ref->new_sha1))
+				util = &states;
+		}
+		path_list_append(skip_prefix(ref->name, "refs/heads/"),
+				target)->util = util;
+	}
+	free_refs(fetch_map);
+
+	strbuf_addf(&states->remote_prefix,
+		"refs/remotes/%s/", states->remote->name);
+	for_each_ref(handle_one_branch, states);
+	sort_path_list(&states->stale);
+
+	return 0;
+}
+
+static int remove_tracking_branch(const char *refname,
+	const unsigned char *sha1, int flags, void *cb_data)
+{
+	const char *remote_prefix = cb_data;
+
+	if (!prefixcmp(refname, remote_prefix) &&
+			delete_ref(refname, sha1))
+		return error("Could not remove branch %s", refname);
+	return 0;
+}
+
+static int rm(int argc, const char **argv)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct remote *remote;
+	struct strbuf buf;
+	int i;
+
+	if (argc != 2)
+		usage_with_options(builtin_remote_usage, options);
+
+	remote = remote_get(argv[1]);
+	if (!remote)
+		die ("No such remote: %s", argv[1]);
+
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "remote.%s", remote->name);
+	if (git_config_rename_section(buf.buf, NULL) < 1)
+		return error("Could not remove config section '%s'", buf.buf);
+
+	read_branches();
+	for (i = 0; i < branch_list.nr; i++) {
+		struct path_list_item *item = branch_list.items +i;
+		struct branch_info *info = item->util;
+		if (info->remote && !strcmp(info->remote, remote->name)) {
+			const char *keys[] = { "remote", "merge", NULL }, **k;
+			for (k = keys; *k; k++) {
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "branch.%s.%s",
+						item->path, *k);
+				if (git_config_set(buf.buf, NULL)) {
+					strbuf_release(&buf);
+					return -1;
+				}
+			}
+		}
+	}
+
+	/*
+	 * NEEDSTHOUGHT: this could check something like
+	 * !remote_find_tracking(remote, &refspec) to know if the
+	 * branch was really tracked.  But then we'll have to make
+	 * sure that no other remote writes into that branch.
+	 * Probably not worth it.
+	 */
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
+	i = for_each_ref(remove_tracking_branch, buf.buf);
+	strbuf_release(&buf);
+
+	return i;
+}
+
+static void show_list(const char *title, struct path_list *list)
+{
+	int i;
+
+	if (!list->nr)
+		return;
+
+	printf(title, list->nr > 1 ? "es" : "");
+	printf("\n    ");
+	for (i = 0; i < list->nr; i++)
+		printf("%s%s", i ? " " : "", list->items[i].path);
+	printf("\n");
+}
+
+static int show_or_prune(int argc, const char **argv, int prune)
+{
+	int dry_run = 0, result = 0;
+	struct option options[] = {
+		OPT_GROUP("show specific options"),
+		OPT__DRY_RUN(&dry_run),
+		OPT_END()
+	};
+	struct ref_states states;
+
+	argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
+
+	if (argc < 1)
+		usage_with_options(builtin_remote_usage, options);
+
+	memset(&states, 0, sizeof(states));
+	for (; argc; argc--, argv++) {
+		struct transport *transport;
+		const struct ref *ref;
+		struct strbuf buf;
+		int i, got_states;
+
+		states.remote = remote_get(*argv);
+		if (!states.remote)
+			return error("No such remote: %s", *argv);
+		transport = transport_get(NULL, states.remote->url[0]);
+		ref = transport_get_remote_refs(transport);
+
+		read_branches();
+		got_states = get_ref_states(ref, &states);
+		if (got_states)
+			result = error("Error getting local info for '%s'",
+					states.remote->name);
+
+		if (prune) {
+			struct strbuf buf;
+
+			strbuf_init(&buf, 0);
+			for (i = 0; i < states.stale.nr; i++) {
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "refs/remotes/%s/%s", *argv,
+						states.stale.items[i].path);
+				result |= delete_ref(buf.buf, NULL);
+			}
+
+			strbuf_release(&buf);
+			goto cleanup_states;
+		}
+
+		printf("* remote %s\n  URL: %s\n", *argv,
+			states.remote->url[0] ?
+				states.remote->url[0] : "(no URL)");
+
+		for (i = 0; i < branch_list.nr; i++) {
+			struct path_list_item *branch = branch_list.items + i;
+			struct branch_info *info = branch->util;
+			int j;
+
+			if (!info->merge.nr || strcmp(*argv, info->remote))
+				continue;
+			printf("  Remote branch%s merged with 'git pull' "
+				"while on branch %s\n   ",
+				info->merge.nr > 1 ? "es" : "",
+				branch->path);
+			for (j = 0; j < info->merge.nr; j++)
+				printf(" %s", info->merge.items[j].path);
+			printf("\n");
+		}
+
+		if (got_states)
+			continue;
+		strbuf_init(&buf, 0);
+		strbuf_addf(&buf, "  New remote branch%%s (next fetch will "
+			"store in remotes/%s)", states.remote->name);
+		show_list(buf.buf, &states.new);
+		strbuf_release(&buf);
+		show_list("  Stale tracking branch%s (use 'git remote prune')",
+				&states.stale);
+		show_list("  Tracked remote branch%s",
+				&states.tracked);
+
+		if (states.remote->push_refspec_nr) {
+			printf("  Local branch%s pushed with 'git push'\n   ",
+				states.remote->push_refspec_nr > 1 ?
+					"es" : "");
+			for (i = 0; i < states.remote->push_refspec_nr; i++) {
+				struct refspec *spec = states.remote->push + i;
+				printf(" %s%s%s%s", spec->force ? "+" : "",
+					skip_prefix(spec->src, "refs/heads/"),
+					spec->dst ? ":" : "",
+					skip_prefix(spec->dst, "refs/heads/"));
+			}
+		}
+cleanup_states:
+		/* NEEDSWORK: free remote */
+		path_list_clear(&states.new, 0);
+		path_list_clear(&states.stale, 0);
+		path_list_clear(&states.tracked, 0);
+	}
+
+	return result;
+}
+
+static int update_one(struct remote *remote, void *priv)
+{
+	if (!remote->skip_default_update)
+		return fetch_remote(remote->name);
+	return 0;
+}
+
+static int update(int argc, const char **argv)
+{
+	int i;
+
+	if (argc < 2)
+		return for_each_remote(update_one, NULL);
+
+	for (i = 1; i < argc; i++)
+		if (fetch_remote(argv[i]))
+			return 1;
+	return 0;
+}
+
+static int get_one_entry(struct remote *remote, void *priv)
+{
+	struct path_list *list = priv;
+
+	path_list_append(remote->name, list)->util = (void *)remote->url[0];
+	if (remote->url[0] && remote->url[1])
+		warning ("Remote %s has more than one URL", remote->name);
+
+	return 0;
+}
+
+static int show_all()
+{
+	struct path_list list = { NULL, 0, 0 };
+	int result = for_each_remote(get_one_entry, &list);
+
+	if (!result) {
+		int i;
+
+		sort_path_list(&list);
+		for (i = 0; i < list.nr; i++) {
+			struct path_list_item *item = list.items + i;
+			printf("%s%s%s\n", item->path,
+				verbose ? "\t" : "",
+				verbose && item->util ?
+					(const char *)item->util : "");
+		}
+	}
+	return result;
+}
+
+int cmd_remote(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT__VERBOSE(&verbose),
+		OPT_END()
+	};
+	int result;
+
+	argc = parse_options(argc, argv, options, builtin_remote_usage,
+		PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc < 1)
+		result = show_all();
+	else if (!strcmp(argv[0], "add"))
+		result = add(argc, argv);
+	else if (!strcmp(argv[0], "rm"))
+		result = rm(argc, argv);
+	else if (!strcmp(argv[0], "show"))
+		result = show_or_prune(argc, argv, 0);
+	else if (!strcmp(argv[0], "prune"))
+		result = show_or_prune(argc, argv, 1);
+	else if (!strcmp(argv[0], "update"))
+		result = update(argc, argv);
+	else {
+		error ("Unknown subcommand: %s", argv[0]);
+		usage_with_options(builtin_remote_usage, options);
+	}
+
+	return result ? 1 : 0;
+}
diff --git a/builtin.h b/builtin.h
index cb675c4..20b6e75 100644
--- a/builtin.h
+++ b/builtin.h
@@ -66,6 +66,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
 extern int cmd_push(int argc, const char **argv, const char *prefix);
 extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_reflog(int argc, const char **argv, const char *prefix);
+extern int cmd_remote(int argc, const char **argv, const char *prefix);
 extern int cmd_config(int argc, const char **argv, const char *prefix);
 extern int cmd_rerere(int argc, const char **argv, const char *prefix);
 extern int cmd_reset(int argc, const char **argv, const char *prefix);
diff --git a/git-remote.perl b/contrib/examples/git-remote.perl
similarity index 100%
rename from git-remote.perl
rename to contrib/examples/git-remote.perl
diff --git a/git.c b/git.c
index c8b7e74..80e9082 100644
--- a/git.c
+++ b/git.c
@@ -349,6 +349,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "push", cmd_push, RUN_SETUP },
 		{ "read-tree", cmd_read_tree, RUN_SETUP },
 		{ "reflog", cmd_reflog, RUN_SETUP },
+		{ "remote", cmd_remote, RUN_SETUP },
 		{ "repo-config", cmd_config },
 		{ "rerere", cmd_rerere, RUN_SETUP },
 		{ "reset", cmd_reset, RUN_SETUP },
diff --git a/remote.c b/remote.c
index 3fb0f99..ae7abe4 100644
--- a/remote.c
+++ b/remote.c
@@ -280,7 +280,8 @@ static int handle_config(const char *key, const char *value)
 			remote->fetch_tags = -1;
 	} else if (!strcmp(subkey, ".proxy")) {
 		remote->http_proxy = xstrdup(value);
-	}
+	} else if (!strcmp(subkey, ".skipdefaultupdate"))
+		remote->skip_default_update = 1;
 	return 0;
 }
 
diff --git a/remote.h b/remote.h
index 86e036d..bb26d3c 100644
--- a/remote.h
+++ b/remote.h
@@ -22,6 +22,7 @@ struct remote {
 	 * 2 to always fetch tags
 	 */
 	int fetch_tags;
+	int skip_default_update;
 
 	const char *receivepack;
 	const char *uploadpack;
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index c7d7242..d343a96 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -100,9 +100,9 @@ test_expect_success 'remove remote' '
 cat > test/expect << EOF
 * remote origin
   URL: $(pwd)/one/.git
-  Remote branch(es) merged with 'git pull' while on branch master
+  Remote branch merged with 'git pull' while on branch master
     master
-  New remote branches (next fetch will store in remotes/origin)
+  New remote branch (next fetch will store in remotes/origin)
     master
   Tracked remote branches
     side master
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
                   ` (3 preceding siblings ...)
  2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin
@ 2007-12-05 19:02 ` Johannes Schindelin
  2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin
  5 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw)
  To: git, gitster


This adds special handling for mirror remotes.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	This fixes a real bug in git-remote, which I tried to fix in the
	perl script, failing.

 builtin-remote.c  |   16 +++++++++++++---
 t/t5505-remote.sh |   16 ++++++++++++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/builtin-remote.c b/builtin-remote.c
index 41ac4a1..142eb97 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -367,12 +367,22 @@ static int show_or_prune(int argc, const char **argv, int prune)
 
 		if (prune) {
 			struct strbuf buf;
+			int prefix_len;
 
 			strbuf_init(&buf, 0);
+			if (states.remote->fetch_refspec_nr == 1 &&
+					states.remote->fetch->pattern &&
+					!strcmp(states.remote->fetch->src,
+						states.remote->fetch->dst))
+				/* handle --mirror remote */
+				strbuf_addstr(&buf, "refs/heads/");
+			else
+				strbuf_addf(&buf, "refs/remotes/%s/", *argv);
+			prefix_len = buf.len;
+
 			for (i = 0; i < states.stale.nr; i++) {
-				strbuf_reset(&buf);
-				strbuf_addf(&buf, "refs/remotes/%s/%s", *argv,
-						states.stale.items[i].path);
+				strbuf_setlen(&buf, prefix_len);
+				strbuf_addstr(&buf, states.stale.items[i].path);
 				result |= delete_ref(buf.buf, NULL);
 			}
 
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index d343a96..2376e0a 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -131,4 +131,20 @@ test_expect_success 'prune' '
 	 ! git rev-parse refs/remotes/origin/side)
 '
 
+test_expect_success 'add --mirror && prune' '
+	(mkdir mirror &&
+	 cd mirror &&
+	 git init &&
+	 git remote add --mirror -f origin ../one) &&
+	(cd one &&
+	 git branch -m side2 side) &&
+	(cd mirror &&
+	 git rev-parse --verify refs/heads/side2 &&
+	 ! git rev-parse --verify refs/heads/side &&
+	 git fetch origin &&
+	 git remote prune origin &&
+	 ! git rev-parse --verify refs/heads/side2 &&
+	 git rev-parse --verify refs/heads/side)
+'
+
 test_done
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/6] DWIM "git add remote ..."
  2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
                   ` (4 preceding siblings ...)
  2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
@ 2007-12-05 19:03 ` Johannes Schindelin
  2007-12-05 19:34   ` Linus Torvalds
  5 siblings, 1 reply; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:03 UTC (permalink / raw)
  To: git, gitster


It is wrong to divert to "git remote add" when you typed the
(more English) "git add remote".  But is it also pretty convenient.

So implement it, but do not document it ;-)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-add.c     |    7 +++++++
 t/t5505-remote.sh |    6 ++++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 5c29cc2..b5b4c2f 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -196,6 +196,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	const char **pathspec;
 	struct dir_struct dir;
 
+	if (argc > 1 && !strcmp(argv[1], "remote") &&
+			access("remote", F_OK)) {
+		argv[1] = argv[0];
+		argv[0] = "remote";
+		return cmd_remote(argc, argv, prefix);
+	}
+
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
 	if (patch_interactive)
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 2376e0a..83ed70c 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -147,4 +147,10 @@ test_expect_success 'add --mirror && prune' '
 	 git rev-parse --verify refs/heads/side)
 '
 
+test_expect_success 'add remote' '
+	(cd test &&
+	 git add remote -f another-one ../one &&
+	 git diff master remotes/another-one/master)
+'
+
 test_done
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 1/6] path-list: add functions to work with unsorted lists
  2007-12-05 19:00 ` (unknown) Johannes Schindelin
  2007-12-05 19:01   ` your mail Johannes Schindelin
@ 2007-12-05 19:05   ` Johannes Schindelin
  1 sibling, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:05 UTC (permalink / raw)
  To: git, gitster


Up to now, path-lists were sorted at all times.  But sometimes it
is much more convenient to build the list and sort it at the end,
or sort it not at all.

Add path_list_append() and sort_path_list() to allow that.

Also, add the unsorted_path_list_has_path() function, to do a linear
search.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	I should have done that long ago.

 path-list.c |   30 ++++++++++++++++++++++++++++++
 path-list.h |    8 +++++++-
 2 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/path-list.c b/path-list.c
index 3d83b7b..92e5cf2 100644
--- a/path-list.c
+++ b/path-list.c
@@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p)
 	for (i = 0; i < p->nr; i++)
 		printf("%s:%p\n", p->items[i].path, p->items[i].util);
 }
+
+struct path_list_item *path_list_append(const char *path, struct path_list *list)
+{
+	ALLOC_GROW(list->items, list->nr + 1, list->alloc);
+	list->items[list->nr].path =
+		list->strdup_paths ? xstrdup(path) : (char *)path;
+	return list->items + list->nr++;
+}
+
+static int cmp_items(const void *a, const void *b)
+{
+	const struct path_list_item *one = a;
+	const struct path_list_item *two = b;
+	return strcmp(one->path, two->path);
+}
+
+void sort_path_list(struct path_list *list)
+{
+	qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
+}
+
+int unsorted_path_list_has_path(struct path_list *list, const char *path)
+{
+	int i;
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(path, list->items[i].path))
+			return 1;
+	return 0;
+}
+
diff --git a/path-list.h b/path-list.h
index 5931e2c..ca2cbba 100644
--- a/path-list.h
+++ b/path-list.h
@@ -13,10 +13,16 @@ struct path_list
 };
 
 void print_path_list(const char *text, const struct path_list *p);
+void path_list_clear(struct path_list *list, int free_util);
 
+/* Use these functions only on sorted lists: */
 int path_list_has_path(const struct path_list *list, const char *path);
-void path_list_clear(struct path_list *list, int free_util);
 struct path_list_item *path_list_insert(const char *path, struct path_list *list);
 struct path_list_item *path_list_lookup(const char *path, struct path_list *list);
 
+/* Use these functions only on unsorted lists: */
+struct path_list_item *path_list_append(const char *path, struct path_list *list);
+void sort_path_list(struct path_list *list);
+int unsorted_path_list_has_path(struct path_list *list, const char *path);
+
 #endif /* PATH_LIST_H */
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/6] DWIM "git add remote ..."
  2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin
@ 2007-12-05 19:34   ` Linus Torvalds
  2007-12-05 19:47     ` Johannes Schindelin
  0 siblings, 1 reply; 14+ messages in thread
From: Linus Torvalds @ 2007-12-05 19:34 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster



On Wed, 5 Dec 2007, Johannes Schindelin wrote:
> 
> It is wrong to divert to "git remote add" when you typed the
> (more English) "git add remote".  But is it also pretty convenient.

Please don't do cute things like this. Suddenly "git add remote" has two 
different meanings depending on whether you have a file called "remote" or 
not. That is *not* ok.

Not to mention the fact that your patch is also a horrible piece of 
bug-infested shit, to put it less-than-politely. Namely, you now broke 
"git add remote" when "remote" is a symbolic link pointing to hyperspace.

But even if you fix that bug, it only goes to show just how misguided 
things like these are. It's a *lot* more important to make sense and not 
have surprising special cases, than to try to make git command lines act 
as if they were free-form English.

		Linus

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/6] DWIM "git add remote ..."
  2007-12-05 19:34   ` Linus Torvalds
@ 2007-12-05 19:47     ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 19:47 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git, gitster

Hi,

On Wed, 5 Dec 2007, Linus Torvalds wrote:

> On Wed, 5 Dec 2007, Johannes Schindelin wrote:
> > 
> > It is wrong to divert to "git remote add" when you typed the (more 
> > English) "git add remote".  But is it also pretty convenient.
> 
> Please don't do cute things like this. Suddenly "git add remote" has two 
> different meanings depending on whether you have a file called "remote" 
> or not. That is *not* ok.
> 
> Not to mention the fact that your patch is also a horrible piece of 
> bug-infested shit, to put it less-than-politely. Namely, you now broke 
> "git add remote" when "remote" is a symbolic link pointing to 
> hyperspace.
> 
> But even if you fix that bug, it only goes to show just how misguided 
> things like these are. It's a *lot* more important to make sense and not 
> have surprising special cases, than to try to make git command lines act 
> as if they were free-form English.

Hehe.  You're right, of course.  But I could not resist showing off that 
patch which I wrote after I mixed up the command line of "remote add" for 
the 926th time.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check
  2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin
@ 2007-12-05 21:40   ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 21:40 UTC (permalink / raw)
  To: git, gitster; +Cc: Johannes Sixt


struct remote's url member is not a NULL terminated list.  Instead, we
have to check url_nr before accessing it.

Noticed by Johannes Sixt.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	For your viewing pleasure, this is not a resend, but an amend.  
	Feel free to squash with 4/6, or to bug me to do it.

 builtin-remote.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/builtin-remote.c b/builtin-remote.c
index 142eb97..ea323e2 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -356,7 +356,8 @@ static int show_or_prune(int argc, const char **argv, int prune)
 		states.remote = remote_get(*argv);
 		if (!states.remote)
 			return error("No such remote: %s", *argv);
-		transport = transport_get(NULL, states.remote->url[0]);
+		transport = transport_get(NULL, states.remote->url_nr > 0 ?
+			states.remote->url[0] : NULL);
 		ref = transport_get_remote_refs(transport);
 
 		read_branches();
@@ -391,7 +392,7 @@ static int show_or_prune(int argc, const char **argv, int prune)
 		}
 
 		printf("* remote %s\n  URL: %s\n", *argv,
-			states.remote->url[0] ?
+			states.remote->url_nr > 0 ?
 				states.remote->url[0] : "(no URL)");
 
 		for (i = 0; i < branch_list.nr; i++) {
@@ -468,8 +469,9 @@ static int get_one_entry(struct remote *remote, void *priv)
 {
 	struct path_list *list = priv;
 
-	path_list_append(remote->name, list)->util = (void *)remote->url[0];
-	if (remote->url[0] && remote->url[1])
+	path_list_append(remote->name, list)->util = remote->url_nr ?
+		(void *)remote->url[0] : NULL;
+	if (remote->url_nr > 1)
 		warning ("Remote %s has more than one URL", remote->name);
 
 	return 0;
-- 
1.5.3.7.2157.g9598e

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/6] Test "git remote show" and "git remote prune"
  2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin
@ 2007-12-05 21:59   ` René Scharfe
  2007-12-05 22:38     ` Johannes Schindelin
  0 siblings, 1 reply; 14+ messages in thread
From: René Scharfe @ 2007-12-05 21:59 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

Johannes Schindelin schrieb:
> While at it, also fix a few instances where a cd was done outside of a
> subshell.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++
>  1 files changed, 34 insertions(+), 0 deletions(-)

It seems to me the patch only adds tests, but doesn't fix existing ones.
 And looking at t5505-remote.sh, every call of cd is already done inside
of a subshell, so there doesn't seem to be anything to fix either. :-?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/6] Test "git remote show" and "git remote prune"
  2007-12-05 21:59   ` René Scharfe
@ 2007-12-05 22:38     ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2007-12-05 22:38 UTC (permalink / raw)
  To: René Scharfe; +Cc: git, gitster

Hi,

On Wed, 5 Dec 2007, Ren? Scharfe wrote:

> Johannes Schindelin schrieb:
> > While at it, also fix a few instances where a cd was done outside of a 
> > subshell.
> > 
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++
> >  1 files changed, 34 insertions(+), 0 deletions(-)
> 
> It seems to me the patch only adds tests, but doesn't fix existing ones. 
> And looking at t5505-remote.sh, every call of cd is already done inside 
> of a subshell, so there doesn't seem to be anything to fix either. :-?

Right.  This comment is from a long time ago, back when I had my own 
(incomplete) t5505-remote.sh.  It was funny to me that Junio chose exactly 
the same name... but his implementation was different ;-)

I agree that this comment is obsolete.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-12-05 22:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin
2007-12-05 19:00 ` (unknown) Johannes Schindelin
2007-12-05 19:01   ` your mail Johannes Schindelin
2007-12-05 19:05   ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin
2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin
2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin
2007-12-05 21:59   ` René Scharfe
2007-12-05 22:38     ` Johannes Schindelin
2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin
2007-12-05 21:40   ` [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check Johannes Schindelin
2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin
2007-12-05 19:34   ` Linus Torvalds
2007-12-05 19:47     ` Johannes Schindelin

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).