git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/5] Builtin "git remote"
@ 2008-02-29  1:44 Johannes Schindelin
  2008-02-29  1:44 ` [PATCH 1/5] path-list: add functions to work with unsorted lists Johannes Schindelin
                   ` (5 more replies)
  0 siblings, 6 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:44 UTC (permalink / raw)
  To: git, gitster


This patch series puts a few building blocks in place (the first three
patches), builds in "git remote", and fixes the current behaviour of
"git remote prune" when the remote was initialized with --mirror.

It incorporates Hannes Sixt's comments about checking remote_nr.

Oh, and in contrast to the earlier series, I removed the DWIM "git add
remote" patch.

It also demonstrates that format-patch --cover-letter should default to -M
for the diffstat (search for "git-remote.perl"...).

Johannes Schindelin (5):
      path-list: add functions to work with unsorted lists
      parseopt: add flag to stop on first non option
      Test "git remote show" and "git remote prune"
      Make git-remote a builtin
      builtin-remote: prune remotes correctly that were added with --mirror

 Makefile                         |    3 +-
 builtin-remote.c                 |  557 ++++++++++++++++++++++++++++++++++++++
 builtin.h                        |    1 +
 contrib/examples/git-remote.perl |  477 ++++++++++++++++++++++++++++++++
 git-remote.perl                  |  477 --------------------------------
 git.c                            |    1 +
 parse-options.c                  |    2 +
 parse-options.h                  |    1 +
 path-list.c                      |   30 ++
 path-list.h                      |    8 +-
 remote.c                         |    3 +-
 remote.h                         |    1 +
 t/t5505-remote.sh                |   50 ++++
 13 files changed, 1131 insertions(+), 480 deletions(-)
 create mode 100644 builtin-remote.c
 create mode 100755 contrib/examples/git-remote.perl
 delete mode 100755 git-remote.perl


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

* [PATCH 1/5] path-list: add functions to work with unsorted lists
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
@ 2008-02-29  1:44 ` Johannes Schindelin
  2008-02-29  2:04   ` Junio C Hamano
  2008-02-29  1:45 ` [PATCH 2/5] parseopt: add flag to stop on first non option Johannes Schindelin
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:44 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>
---

	This is probably useful to a number of existing non-users of
	path_list.

 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.4.3.431.g066fa



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

* [PATCH 2/5] parseopt: add flag to stop on first non option
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
  2008-02-29  1:44 ` [PATCH 1/5] path-list: add functions to work with unsorted lists Johannes Schindelin
@ 2008-02-29  1:45 ` Johannes Schindelin
  2008-02-29  1:45 ` [PATCH 3/5] Test "git remote show" and "git remote prune" Johannes Schindelin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:45 UTC (permalink / raw)
  To: git, gitster


Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 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 d9562ba..be35785 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -249,6 +249,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.4.3.431.g066fa



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

* [PATCH 3/5] Test "git remote show" and "git remote prune"
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
  2008-02-29  1:44 ` [PATCH 1/5] path-list: add functions to work with unsorted lists Johannes Schindelin
  2008-02-29  1:45 ` [PATCH 2/5] parseopt: add flag to stop on first non option Johannes Schindelin
@ 2008-02-29  1:45 ` Johannes Schindelin
  2008-02-29  1:45 ` [PATCH 4/5] Make git-remote a builtin Johannes Schindelin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:45 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 4fc62f5..e1e0a18 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -94,4 +94,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.4.3.431.g066fa



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

* [PATCH 4/5] Make git-remote a builtin
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
                   ` (2 preceding siblings ...)
  2008-02-29  1:45 ` [PATCH 3/5] Test "git remote show" and "git remote prune" Johannes Schindelin
@ 2008-02-29  1:45 ` Johannes Schindelin
  2008-02-29  1:46 ` [PATCH 5/5] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
  2008-02-29  1:56 ` [PATCH 0/5] Builtin "git remote" Junio C Hamano
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:45 UTC (permalink / raw)
  To: git, gitster


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

	Relative to my patch series of December, this fixes a nasty bug
	in "git remote rm": do not call anything that invalidates the
	cached refs from the callback function passed to for_each_ref().

	Such as delete_ref()...

	Instead, build the list of refs-to-delete, and _then_ delete them.
	Junio, this should solve the problems that you encountered (I
	valgrinded it).

	This includes the fix to guard remote->url accesses by checking
	remote->url_nr, as suggested by Johannes Sixt.

 Makefile                                           |    3 +-
 builtin-remote.c                                   |  547 ++++++++++++++++++++
 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, 556 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 8d8fc17..759074a 100644
--- a/Makefile
+++ b/Makefile
@@ -243,7 +243,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)) \
@@ -380,6 +380,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..d229919
--- /dev/null
+++ b/builtin-remote.c
@@ -0,0 +1,547 @@
+#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;
+}
+
+struct branches_for_remote {
+	const char *prefix;
+	struct path_list *branches;
+};
+
+static int add_branch_for_removal(const char *refname,
+	const unsigned char *sha1, int flags, void *cb_data)
+{
+	struct branches_for_remote *branches = cb_data;
+
+	if (!prefixcmp(refname, branches->prefix)) {
+		struct path_list_item *item;
+		item = path_list_append(refname, branches->branches);
+		item->util = xmalloc(20);
+		hashcpy(item->util, sha1);
+	}
+
+	return 0;
+}
+
+static int remove_branches(struct path_list *branches)
+{
+	int i, result = 0;
+	for (i = 0; i < branches->nr; i++) {
+		struct path_list_item *item = branches->items + i;
+		const char *refname = item->path;
+		unsigned char *sha1 = item->util;
+
+		if (delete_ref(refname, sha1))
+			result |= error("Could not remove branch %s", refname);
+	}
+	return result;
+}
+
+static int rm(int argc, const char **argv)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct remote *remote;
+	struct strbuf buf;
+	struct path_list branches = { NULL, 0, 0, 1 };
+	struct branches_for_remote cb_data = { NULL, &branches };
+	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;
+				}
+			}
+		}
+	}
+
+	/*
+	 * We cannot just pass a function to for_each_ref() which deletes
+	 * the branches one by one, since for_each_ref() relies on cached
+	 * refs, which are invalidated when deleting a branch.
+	 */
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
+	cb_data.prefix = buf.buf;
+	i = for_each_ref(add_branch_for_removal, &cb_data);
+	strbuf_release(&buf);
+
+	if (!i)
+		i = remove_branches(&branches);
+	path_list_clear(&branches, 1);
+
+	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_nr > 0 ?
+			states.remote->url[0] : NULL);
+		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_nr > 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 = 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;
+}
+
+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 674c8a1..95126fd 100644
--- a/builtin.h
+++ b/builtin.h
@@ -67,6 +67,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 9cca81a..1e3eb10 100644
--- a/git.c
+++ b/git.c
@@ -334,6 +334,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 7e19372..f3f7375 100644
--- a/remote.c
+++ b/remote.c
@@ -357,7 +357,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 0f6033f..f1dedf1 100644
--- a/remote.h
+++ b/remote.h
@@ -25,6 +25,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 e1e0a18..5986982 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -97,9 +97,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.4.3.431.g066fa



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

* [PATCH 5/5] builtin-remote: prune remotes correctly that were added with --mirror
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
                   ` (3 preceding siblings ...)
  2008-02-29  1:45 ` [PATCH 4/5] Make git-remote a builtin Johannes Schindelin
@ 2008-02-29  1:46 ` Johannes Schindelin
  2008-02-29  1:56 ` [PATCH 0/5] Builtin "git remote" Junio C Hamano
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  1:46 UTC (permalink / raw)
  To: git, gitster


This adds special handling for mirror remotes.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 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 d229919..3954926 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -396,12 +396,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 5986982..0a25c8b 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -128,4 +128,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.4.3.431.g066fa



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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
                   ` (4 preceding siblings ...)
  2008-02-29  1:46 ` [PATCH 5/5] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
@ 2008-02-29  1:56 ` Junio C Hamano
  2008-02-29  2:13   ` Johannes Schindelin
  2008-02-29  2:17   ` Daniel Barkalow
  5 siblings, 2 replies; 29+ messages in thread
From: Junio C Hamano @ 2008-02-29  1:56 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Daniel Barkalow

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> It also demonstrates that format-patch --cover-letter should default to -M
> for the diffstat (search for "git-remote.perl"...).

It probably should inherit the settings for the primary part.
You did generate the series with -M, especially [PATCH 4/5],
didn't you?

> Johannes Schindelin (5):
>       path-list: add functions to work with unsorted lists
>       parseopt: add flag to stop on first non option
>       Test "git remote show" and "git remote prune"
>       Make git-remote a builtin
>       builtin-remote: prune remotes correctly that were added with --mirror

Also I wish the default indentation were not that deep, and also
line-wrapped at around 72-76 columns.

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

* Re: [PATCH 1/5] path-list: add functions to work with unsorted lists
  2008-02-29  1:44 ` [PATCH 1/5] path-list: add functions to work with unsorted lists Johannes Schindelin
@ 2008-02-29  2:04   ` Junio C Hamano
  2008-02-29  2:15     ` Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Junio C Hamano @ 2008-02-29  2:04 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> 	This is probably useful to a number of existing non-users of
> 	path_list.

I suspect most of the non-users will stay non-users, until the
thing is renamed to something more sensible.

The name gives a false impression that this is a special-purpose
data structure that is meant to handle pathnames very well
(e.g. canonicalizing "foo//../bar" to "bar" before doing
comparsion) but in reality it does not do anything like that,
and is a general purpose "table keyed with string" mechanism.

The wholesale renaming, if we were to do so, should happen when
things are quiet, and this is probably not a good time for it.



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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-02-29  1:56 ` [PATCH 0/5] Builtin "git remote" Junio C Hamano
@ 2008-02-29  2:13   ` Johannes Schindelin
  2008-02-29  2:17   ` Daniel Barkalow
  1 sibling, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  2:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Daniel Barkalow

Hi,

On Thu, 28 Feb 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > It also demonstrates that format-patch --cover-letter should default 
> > to -M for the diffstat (search for "git-remote.perl"...).
> 
> It probably should inherit the settings for the primary part.
> You did generate the series with -M, especially [PATCH 4/5],
> didn't you?

Yes, I did.

> > Johannes Schindelin (5):
> >       path-list: add functions to work with unsorted lists
> >       parseopt: add flag to stop on first non option
> >       Test "git remote show" and "git remote prune"
> >       Make git-remote a builtin
> >       builtin-remote: prune remotes correctly that were added with --mirror
> 
> Also I wish the default indentation were not that deep, and also
> line-wrapped at around 72-76 columns.

Right.

I still have a few patches in my personal tree to implement "git-fmt", and 
I think that it should be easy to rework them into something usable for 
this purpose (4-character indent for the first line, 8-character for every 
subsequent one).

Also, it might be a good idea to teach "git log" to use these wrapping 
functions, as there are still regular contributors, even to Git itself, 
who seem to be unwilling to use <=76 characters/line.

Ciao,
Dscho


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

* Re: [PATCH 1/5] path-list: add functions to work with unsorted lists
  2008-02-29  2:04   ` Junio C Hamano
@ 2008-02-29  2:15     ` Johannes Schindelin
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29  2:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hi,

On Thu, 28 Feb 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > 	This is probably useful to a number of existing non-users of
> > 	path_list.
> 
> I suspect most of the non-users will stay non-users, until the
> thing is renamed to something more sensible.
> 
> The wholesale renaming, if we were to do so, should happen when things 
> are quiet, and this is probably not a good time for it.

Right.  Will try to think of a patch when the right time has come.  Just 
to make sure: "string_list"?

Ciao,
Dscho


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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-02-29  1:56 ` [PATCH 0/5] Builtin "git remote" Junio C Hamano
  2008-02-29  2:13   ` Johannes Schindelin
@ 2008-02-29  2:17   ` Daniel Barkalow
  2008-02-29 11:21     ` Johannes Schindelin
  1 sibling, 1 reply; 29+ messages in thread
From: Daniel Barkalow @ 2008-02-29  2:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git

On Thu, 28 Feb 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > It also demonstrates that format-patch --cover-letter should default to -M
> > for the diffstat (search for "git-remote.perl"...).
> 
> It probably should inherit the settings for the primary part.
> You did generate the series with -M, especially [PATCH 4/5],
> didn't you?

Obviously not the output_format, but everything else, I assume? Easy 
enough to pass the main diff options into make_cover_letter() and use them 
to initialize the diff options there.

> > Johannes Schindelin (5):
> >       path-list: add functions to work with unsorted lists
> >       parseopt: add flag to stop on first non option
> >       Test "git remote show" and "git remote prune"
> >       Make git-remote a builtin
> >       builtin-remote: prune remotes correctly that were added with --mirror
> 
> Also I wish the default indentation were not that deep, and also
> line-wrapped at around 72-76 columns.

Only for the cover letter, and not shortlog in general, I assume? It 
should be easy to set the struct shortlog fields to whatever suits your 
taste. Making it configurable (without getting tangled in other option 
parsing) is trickier, though.

	-Daniel
*This .sig left intentionally blank*

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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-02-29  2:17   ` Daniel Barkalow
@ 2008-02-29 11:21     ` Johannes Schindelin
  2008-03-02 15:15       ` Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-02-29 11:21 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git

Hi,

On Thu, 28 Feb 2008, Daniel Barkalow wrote:

> On Thu, 28 Feb 2008, Junio C Hamano wrote:
> 
> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> > 
> > > It also demonstrates that format-patch --cover-letter should default to -M
> > > for the diffstat (search for "git-remote.perl"...).
> > 
> > It probably should inherit the settings for the primary part.
> > You did generate the series with -M, especially [PATCH 4/5],
> > didn't you?
> 
> Obviously not the output_format, but everything else, I assume? Easy 
> enough to pass the main diff options into make_cover_letter() and use 
> them to initialize the diff options there.

Nice.

> > > Johannes Schindelin (5):
> > >       path-list: add functions to work with unsorted lists
> > >       parseopt: add flag to stop on first non option
> > >       Test "git remote show" and "git remote prune"
> > >       Make git-remote a builtin
> > >       builtin-remote: prune remotes correctly that were added with --mirror
> > 
> > Also I wish the default indentation were not that deep, and also
> > line-wrapped at around 72-76 columns.
> 
> Only for the cover letter, and not shortlog in general, I assume? It 
> should be easy to set the struct shortlog fields to whatever suits your 
> taste. Making it configurable (without getting tangled in other option 
> parsing) is trickier, though.

It is not really well documented, but with -w, you _can_ drive shortlog to 
do that.  In the API, you have to set the members wrap_lines = 1, in1 = 
first_indent, in2 = indent, wrap = width in struct shortlog.

I suggest the values 4,8,76, respectively.

Ciao,
Dscho


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

* [PATCH 0/6] Builtin remote, v2
  2008-02-29  2:15     ` Johannes Schindelin
@ 2008-03-01 13:14       ` Johannes Schindelin
  2008-03-01 13:15         ` [PATCH 1/6] Rename path_list to string_list Johannes Schindelin
                           ` (5 more replies)
  0 siblings, 6 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


(Yes, I know, it is not v2, but I lost track...)

The only change is that path_list was renamed to string_list.  This is the
first patch, and pretty intrusive (even if the changes are all straight
forward...).

On Fri, 29 Feb 2008, Johannes Schindelin wrote:

> On Thu, 28 Feb 2008, Junio C Hamano wrote:
> 
> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> > 
> > > This is probably useful to a number of existing non-users of 
> > > path_list.
> > 
> > I suspect most of the non-users will stay non-users, until the thing 
> > is renamed to something more sensible.
> > 
> > The wholesale renaming, if we were to do so, should happen when things 
> > are quiet, and this is probably not a good time for it.
> 
> Right.  Will try to think of a patch when the right time has come.  Just 
> to make sure: "string_list"?

Just in case, I did it.  I have no problems resending it later, too, just 
wanted to let you know that I have the patches ready.

Johannes Schindelin (6):
      Rename path_list to string_list
      string-list: add functions to work with unsorted lists
      parseopt: add flag to stop on first non option
      Test "git remote show" and "git remote prune"
      Make git-remote a builtin
      builtin-remote: prune remotes correctly that were added with --mirror

 Documentation/CodingGuidelines            |    5 +-
 Documentation/technical/api-path-list.txt |    4 +-
 Makefile                                  |    7 +-
 builtin-blame.c                           |    4 +-
 builtin-commit.c                          |   20 +-
 builtin-fast-export.c                     |   14 +-
 builtin-fetch.c                           |   16 +-
 builtin-mailsplit.c                       |   12 +-
 builtin-merge-recursive.c                 |   96 +++---
 builtin-mv.c                              |   39 +-
 builtin-remote.c                          |  558 +++++++++++++++++++++++++++++
 builtin-rerere.c                          |   48 ++--
 builtin-shortlog.c                        |   42 ++--
 builtin-show-ref.c                        |   10 +-
 builtin.h                                 |    1 +
 contrib/examples/git-remote.perl          |  477 ++++++++++++++++++++++++
 diff-lib.c                                |   22 +-
 git-remote.perl                           |  477 ------------------------
 git.c                                     |    1 +
 mailmap.c                                 |   12 +-
 mailmap.h                                 |    4 +-
 parse-options.c                           |    2 +
 parse-options.h                           |    1 +
 path-list.c                               |  104 ------
 path-list.h                               |   22 --
 reflog-walk.c                             |   10 +-
 remote.c                                  |    3 +-
 remote.h                                  |    1 +
 shortlog.h                                |    6 +-
 string-list.c                             |  134 +++++++
 string-list.h                             |   28 ++
 t/t5505-remote.sh                         |   50 +++
 32 files changed, 1442 insertions(+), 788 deletions(-)
 create mode 100644 builtin-remote.c
 create mode 100755 contrib/examples/git-remote.perl
 delete mode 100755 git-remote.perl
 delete mode 100644 path-list.c
 delete mode 100644 path-list.h
 create mode 100644 string-list.c
 create mode 100644 string-list.h


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

* [PATCH 1/6] Rename path_list to string_list
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
@ 2008-03-01 13:15         ` Johannes Schindelin
  2008-03-11 16:20           ` David Kågedal
  2008-03-01 13:15         ` [PATCH 2/6] string-list: add functions to work with unsorted lists Johannes Schindelin
                           ` (4 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


The name path_list was correct for the first usage of that data structure,
but it really is a general-purpose string list.

$ perl -i -pe 's/path-list/string-list/g' $(git grep -l path-list)
$ perl -i -pe 's/path_list/string_list/g' $(git grep -l path_list)
$ git mv path-list.h string-list.h
$ git mv path-list.c string-list.c
$ perl -i -pe 's/has_path/has_string/g' $(git grep -l has_path)
$ perl -i -pe 's/path/string/g' string-list.[ch]

... and then fix all users of string-list to access the member "string"
instead of "path"...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/CodingGuidelines            |    2 +-
 Documentation/technical/api-path-list.txt |    4 +-
 Makefile                                  |    4 +-
 builtin-blame.c                           |    4 +-
 builtin-commit.c                          |   20 +++---
 builtin-fast-export.c                     |   14 ++--
 builtin-fetch.c                           |   16 +++---
 builtin-mailsplit.c                       |   12 ++--
 builtin-merge-recursive.c                 |   96 ++++++++++++++--------------
 builtin-mv.c                              |   39 ++++++------
 builtin-rerere.c                          |   48 +++++++-------
 builtin-shortlog.c                        |   42 ++++++------
 builtin-show-ref.c                        |   10 ++--
 diff-lib.c                                |   22 +++---
 mailmap.c                                 |   12 ++--
 mailmap.h                                 |    4 +-
 path-list.h                               |   22 -------
 reflog-walk.c                             |   10 ++--
 shortlog.h                                |    6 +-
 path-list.c => string-list.c              |   41 ++++++------
 string-list.h                             |   22 +++++++
 21 files changed, 226 insertions(+), 224 deletions(-)
 delete mode 100644 path-list.h
 rename path-list.c => string-list.c (53%)
 create mode 100644 string-list.h

diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 3b042db..fe7c74b 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -91,7 +91,7 @@ For C programs:
 
  - Use the API.  No, really.  We have a strbuf (variable length
    string), several arrays with the ALLOC_GROW() macro, a
-   path_list for sorted string lists, a hash map (mapping struct
+   string_list for sorted string lists, a hash map (mapping struct
    objects) named "struct decorate", amongst other things.
 
  - When you come up with an API, document it.
diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt
index d077683..8892cf0 100644
--- a/Documentation/technical/api-path-list.txt
+++ b/Documentation/technical/api-path-list.txt
@@ -1,7 +1,7 @@
-path-list API
+string-list API
 =============
 
-Talk about <path-list.h>, things like
+Talk about <string-list.h>, things like
 
 * it is not just paths but strings in general;
 * the calling sequence.
diff --git a/Makefile b/Makefile
index 88f1c7e..ad214d3 100644
--- a/Makefile
+++ b/Makefile
@@ -302,7 +302,7 @@ LIB_H = \
 	archive.h blob.h cache.h cache-tree.h commit.h csum-file.h delta.h grep.h \
 	diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
 	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
-	tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
+	tree-walk.h log-tree.h dir.h string-list.h unpack-trees.h builtin.h \
 	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
 	mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h ll-merge.h
 
@@ -324,7 +324,7 @@ LIB_OBJS = \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
 	revision.o pager.o tree-walk.o xdiff-interface.o \
 	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) \
+	alloc.o merge-file.o string-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 remote.o \
 	transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o \
diff --git a/builtin-blame.c b/builtin-blame.c
index bfd562d..25c7996 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -16,7 +16,7 @@
 #include "quote.h"
 #include "xdiff-interface.h"
 #include "cache-tree.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "mailmap.h"
 
 static char blame_usage[] =
@@ -47,7 +47,7 @@ static int blank_boundary;
 static int incremental;
 static int cmd_is_annotate;
 static int xdl_opts = XDF_NEED_MINIMAL;
-static struct path_list mailmap;
+static struct string_list mailmap;
 
 #ifndef DEBUG
 #define DEBUG 0
diff --git a/builtin-commit.c b/builtin-commit.c
index f49c22e..380dcdc 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -21,7 +21,7 @@
 #include "strbuf.h"
 #include "utf8.h"
 #include "parse-options.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "unpack-trees.h"
 
 static const char * const builtin_commit_usage[] = {
@@ -146,7 +146,7 @@ static int commit_index_files(void)
  * Take a union of paths in the index and the named tree (typically, "HEAD"),
  * and return the paths that match the given pattern in list.
  */
-static int list_paths(struct path_list *list, const char *with_tree,
+static int list_paths(struct string_list *list, const char *with_tree,
 		      const char *prefix, const char **pattern)
 {
 	int i;
@@ -165,21 +165,21 @@ static int list_paths(struct path_list *list, const char *with_tree,
 			continue;
 		if (!pathspec_match(pattern, m, ce->name, 0))
 			continue;
-		path_list_insert(ce->name, list);
+		string_list_insert(ce->name, list);
 	}
 
 	return report_path_error(m, pattern, prefix ? strlen(prefix) : 0);
 }
 
-static void add_remove_files(struct path_list *list)
+static void add_remove_files(struct string_list *list)
 {
 	int i;
 	for (i = 0; i < list->nr; i++) {
-		struct path_list_item *p = &(list->items[i]);
-		if (file_exists(p->path))
-			add_file_to_cache(p->path, 0);
+		struct string_list_item *p = &(list->items[i]);
+		if (file_exists(p->string))
+			add_file_to_cache(p->string, 0);
 		else
-			remove_file_from_cache(p->path);
+			remove_file_from_cache(p->string);
 	}
 }
 
@@ -212,7 +212,7 @@ static void create_base_index(void)
 static char *prepare_index(int argc, const char **argv, const char *prefix)
 {
 	int fd;
-	struct path_list partial;
+	struct string_list partial;
 	const char **pathspec = NULL;
 
 	if (interactive) {
@@ -294,7 +294,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
 		die("cannot do a partial commit during a merge.");
 
 	memset(&partial, 0, sizeof(partial));
-	partial.strdup_paths = 1;
+	partial.strdup_strings = 1;
 	if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec))
 		exit(1);
 
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index e1c5630..a705029 100755
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -13,7 +13,7 @@
 #include "log-tree.h"
 #include "revision.h"
 #include "decorate.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "utf8.h"
 #include "parse-options.h"
 
@@ -286,7 +286,7 @@ static void handle_tag(const char *name, struct tag *tag)
 }
 
 static void get_tags_and_duplicates(struct object_array *pending,
-				    struct path_list *extra_refs)
+				    struct string_list *extra_refs)
 {
 	struct tag *tag;
 	int i;
@@ -307,7 +307,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		case OBJ_TAG:
 			tag = (struct tag *)e->item;
 			while (tag && tag->object.type == OBJ_TAG) {
-				path_list_insert(full_name, extra_refs)->util = tag;
+				string_list_insert(full_name, extra_refs)->util = tag;
 				tag = (struct tag *)tag->tagged;
 			}
 			if (!tag)
@@ -327,19 +327,19 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		}
 		if (commit->util)
 			/* more than one name for the same object */
-			path_list_insert(full_name, extra_refs)->util = commit;
+			string_list_insert(full_name, extra_refs)->util = commit;
 		else
 			commit->util = full_name;
 	}
 }
 
-static void handle_tags_and_duplicates(struct path_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *extra_refs)
 {
 	struct commit *commit;
 	int i;
 
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
-		const char *name = extra_refs->items[i].path;
+		const char *name = extra_refs->items[i].string;
 		struct object *object = extra_refs->items[i].util;
 		switch (object->type) {
 		case OBJ_TAG:
@@ -360,7 +360,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
 	struct object_array commits = { 0, 0, NULL };
-	struct path_list extra_refs = { NULL, 0, 0, 0 };
+	struct string_list extra_refs = { NULL, 0, 0, 0 };
 	struct commit *commit;
 	struct option options[] = {
 		OPT_INTEGER(0, "progress", &progress,
diff --git a/builtin-fetch.c b/builtin-fetch.c
index ac335f2..94e3e74 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -5,7 +5,7 @@
 #include "refs.h"
 #include "commit.h"
 #include "builtin.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "remote.h"
 #include "transport.h"
 #include "run-command.h"
@@ -447,16 +447,16 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 static int add_existing(const char *refname, const unsigned char *sha1,
 			int flag, void *cbdata)
 {
-	struct path_list *list = (struct path_list *)cbdata;
-	path_list_insert(refname, list);
+	struct string_list *list = (struct string_list *)cbdata;
+	string_list_insert(refname, list);
 	return 0;
 }
 
 static struct ref *find_non_local_tags(struct transport *transport,
 				       struct ref *fetch_map)
 {
-	static struct path_list existing_refs = { NULL, 0, 0, 0 };
-	struct path_list new_refs = { NULL, 0, 0, 1 };
+	static struct string_list existing_refs = { NULL, 0, 0, 0 };
+	struct string_list new_refs = { NULL, 0, 0, 1 };
 	char *ref_name;
 	int ref_name_len;
 	const unsigned char *ref_sha1;
@@ -487,10 +487,10 @@ static struct ref *find_non_local_tags(struct transport *transport,
 			}
 		}
 
-		if (!path_list_has_path(&existing_refs, ref_name) &&
-		    !path_list_has_path(&new_refs, ref_name) &&
+		if (!string_list_has_string(&existing_refs, ref_name) &&
+		    !string_list_has_string(&new_refs, ref_name) &&
 		    has_sha1_file(ref->old_sha1)) {
-			path_list_insert(ref_name, &new_refs);
+			string_list_insert(ref_name, &new_refs);
 
 			rm = alloc_ref(strlen(ref_name) + 1);
 			strcpy(rm->name, ref_name);
diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c
index 46b27cd..29df10f 100644
--- a/builtin-mailsplit.c
+++ b/builtin-mailsplit.c
@@ -6,7 +6,7 @@
  */
 #include "cache.h"
 #include "builtin.h"
-#include "path-list.h"
+#include "string-list.h"
 
 static const char git_mailsplit_usage[] =
 "git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>|<Maildir>...";
@@ -97,7 +97,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
 	exit(1);
 }
 
-static int populate_maildir_list(struct path_list *list, const char *path)
+static int populate_maildir_list(struct string_list *list, const char *path)
 {
 	DIR *dir;
 	struct dirent *dent;
@@ -118,7 +118,7 @@ static int populate_maildir_list(struct path_list *list, const char *path)
 			if (dent->d_name[0] == '.')
 				continue;
 			snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name);
-			path_list_insert(name, list);
+			string_list_insert(name, list);
 		}
 
 		closedir(dir);
@@ -134,14 +134,14 @@ static int split_maildir(const char *maildir, const char *dir,
 	char name[PATH_MAX];
 	int ret = -1;
 	int i;
-	struct path_list list = {NULL, 0, 0, 1};
+	struct string_list list = {NULL, 0, 0, 1};
 
 	if (populate_maildir_list(&list, maildir) < 0)
 		goto out;
 
 	for (i = 0; i < list.nr; i++) {
 		FILE *f;
-		snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path);
+		snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].string);
 		f = fopen(file, "r");
 		if (!f) {
 			error("cannot open mail %s (%s)", file, strerror(errno));
@@ -161,7 +161,7 @@ static int split_maildir(const char *maildir, const char *dir,
 
 	ret = skip;
 out:
-	path_list_clear(&list, 1);
+	string_list_clear(&list, 1);
 	return ret;
 }
 
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 5a0a7b5..8e77e8b 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -13,7 +13,7 @@
 #include "diffcore.h"
 #include "tag.h"
 #include "unpack-trees.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "xdiff-interface.h"
 #include "ll-merge.h"
 #include "interpolate.h"
@@ -87,8 +87,8 @@ struct stage_data
 	unsigned processed:1;
 };
 
-static struct path_list current_file_set = {NULL, 0, 0, 1};
-static struct path_list current_directory_set = {NULL, 0, 0, 1};
+static struct string_list current_file_set = {NULL, 0, 0, 1};
+static struct string_list current_directory_set = {NULL, 0, 0, 1};
 
 static int call_depth = 0;
 static int verbosity = 2;
@@ -262,9 +262,9 @@ static int save_files_dirs(const unsigned char *sha1,
 	newpath[baselen + len] = '\0';
 
 	if (S_ISDIR(mode))
-		path_list_insert(newpath, &current_directory_set);
+		string_list_insert(newpath, &current_directory_set);
 	else
-		path_list_insert(newpath, &current_file_set);
+		string_list_insert(newpath, &current_file_set);
 	free(newpath);
 
 	return READ_TREE_RECURSIVE;
@@ -285,9 +285,9 @@ static int get_files_dirs(struct tree *tree)
  */
 static struct stage_data *insert_stage_data(const char *path,
 		struct tree *o, struct tree *a, struct tree *b,
-		struct path_list *entries)
+		struct string_list *entries)
 {
-	struct path_list_item *item;
+	struct string_list_item *item;
 	struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
 	get_tree_entry(o->object.sha1, path,
 			e->stages[1].sha, &e->stages[1].mode);
@@ -295,7 +295,7 @@ static struct stage_data *insert_stage_data(const char *path,
 			e->stages[2].sha, &e->stages[2].mode);
 	get_tree_entry(b->object.sha1, path,
 			e->stages[3].sha, &e->stages[3].mode);
-	item = path_list_insert(path, entries);
+	item = string_list_insert(path, entries);
 	item->util = e;
 	return e;
 }
@@ -304,23 +304,23 @@ static struct stage_data *insert_stage_data(const char *path,
  * Create a dictionary mapping file names to stage_data objects. The
  * dictionary contains one entry for every path with a non-zero stage entry.
  */
-static struct path_list *get_unmerged(void)
+static struct string_list *get_unmerged(void)
 {
-	struct path_list *unmerged = xcalloc(1, sizeof(struct path_list));
+	struct string_list *unmerged = xcalloc(1, sizeof(struct string_list));
 	int i;
 
-	unmerged->strdup_paths = 1;
+	unmerged->strdup_strings = 1;
 
 	for (i = 0; i < active_nr; i++) {
-		struct path_list_item *item;
+		struct string_list_item *item;
 		struct stage_data *e;
 		struct cache_entry *ce = active_cache[i];
 		if (!ce_stage(ce))
 			continue;
 
-		item = path_list_lookup(ce->name, unmerged);
+		item = string_list_lookup(ce->name, unmerged);
 		if (!item) {
-			item = path_list_insert(ce->name, unmerged);
+			item = string_list_insert(ce->name, unmerged);
 			item->util = xcalloc(1, sizeof(struct stage_data));
 		}
 		e = item->util;
@@ -345,17 +345,17 @@ struct rename
  * 'b_tree') to be able to associate the correct cache entries with
  * the rename information. 'tree' is always equal to either a_tree or b_tree.
  */
-static struct path_list *get_renames(struct tree *tree,
+static struct string_list *get_renames(struct tree *tree,
 					struct tree *o_tree,
 					struct tree *a_tree,
 					struct tree *b_tree,
-					struct path_list *entries)
+					struct string_list *entries)
 {
 	int i;
-	struct path_list *renames;
+	struct string_list *renames;
 	struct diff_options opts;
 
-	renames = xcalloc(1, sizeof(struct path_list));
+	renames = xcalloc(1, sizeof(struct string_list));
 	diff_setup(&opts);
 	DIFF_OPT_SET(&opts, RECURSIVE);
 	opts.detect_rename = DIFF_DETECT_RENAME;
@@ -366,7 +366,7 @@ static struct path_list *get_renames(struct tree *tree,
 	diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
 	diffcore_std(&opts);
 	for (i = 0; i < diff_queued_diff.nr; ++i) {
-		struct path_list_item *item;
+		struct string_list_item *item;
 		struct rename *re;
 		struct diff_filepair *pair = diff_queued_diff.queue[i];
 		if (pair->status != 'R') {
@@ -376,20 +376,20 @@ static struct path_list *get_renames(struct tree *tree,
 		re = xmalloc(sizeof(*re));
 		re->processed = 0;
 		re->pair = pair;
-		item = path_list_lookup(re->pair->one->path, entries);
+		item = string_list_lookup(re->pair->one->path, entries);
 		if (!item)
 			re->src_entry = insert_stage_data(re->pair->one->path,
 					o_tree, a_tree, b_tree, entries);
 		else
 			re->src_entry = item->util;
 
-		item = path_list_lookup(re->pair->two->path, entries);
+		item = string_list_lookup(re->pair->two->path, entries);
 		if (!item)
 			re->dst_entry = insert_stage_data(re->pair->two->path,
 					o_tree, a_tree, b_tree, entries);
 		else
 			re->dst_entry = item->util;
-		item = path_list_insert(pair->one->path, renames);
+		item = string_list_insert(pair->one->path, renames);
 		item->util = re;
 	}
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -466,12 +466,12 @@ static char *unique_path(const char *path, const char *branch)
 	for (; *p; ++p)
 		if ('/' == *p)
 			*p = '_';
-	while (path_list_has_path(&current_file_set, newpath) ||
-	       path_list_has_path(&current_directory_set, newpath) ||
+	while (string_list_has_string(&current_file_set, newpath) ||
+	       string_list_has_string(&current_directory_set, newpath) ||
 	       lstat(newpath, &st) == 0)
 		sprintf(p, "_%d", suffix++);
 
-	path_list_insert(newpath, &current_file_set);
+	string_list_insert(newpath, &current_file_set);
 	return newpath;
 }
 
@@ -716,13 +716,13 @@ static void conflict_rename_rename(struct rename *ren1,
 	const char *ren2_dst = ren2->pair->two->path;
 	const char *dst_name1 = ren1_dst;
 	const char *dst_name2 = ren2_dst;
-	if (path_list_has_path(&current_directory_set, ren1_dst)) {
+	if (string_list_has_string(&current_directory_set, ren1_dst)) {
 		dst_name1 = del[delp++] = unique_path(ren1_dst, branch1);
 		output(1, "%s is a directory in %s added as %s instead",
 		       ren1_dst, branch2, dst_name1);
 		remove_file(0, ren1_dst, 0);
 	}
-	if (path_list_has_path(&current_directory_set, ren2_dst)) {
+	if (string_list_has_string(&current_directory_set, ren2_dst)) {
 		dst_name2 = del[delp++] = unique_path(ren2_dst, branch2);
 		output(1, "%s is a directory in %s added as %s instead",
 		       ren2_dst, branch1, dst_name2);
@@ -772,30 +772,30 @@ static void conflict_rename_rename_2(struct rename *ren1,
 	free(new_path1);
 }
 
-static int process_renames(struct path_list *a_renames,
-			   struct path_list *b_renames,
+static int process_renames(struct string_list *a_renames,
+			   struct string_list *b_renames,
 			   const char *a_branch,
 			   const char *b_branch)
 {
 	int clean_merge = 1, i, j;
-	struct path_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0};
+	struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0};
 	const struct rename *sre;
 
 	for (i = 0; i < a_renames->nr; i++) {
 		sre = a_renames->items[i].util;
-		path_list_insert(sre->pair->two->path, &a_by_dst)->util
+		string_list_insert(sre->pair->two->path, &a_by_dst)->util
 			= sre->dst_entry;
 	}
 	for (i = 0; i < b_renames->nr; i++) {
 		sre = b_renames->items[i].util;
-		path_list_insert(sre->pair->two->path, &b_by_dst)->util
+		string_list_insert(sre->pair->two->path, &b_by_dst)->util
 			= sre->dst_entry;
 	}
 
 	for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
 		int compare;
 		char *src;
-		struct path_list *renames1, *renames2, *renames2Dst;
+		struct string_list *renames1, *renames2, *renames2Dst;
 		struct rename *ren1 = NULL, *ren2 = NULL;
 		const char *branch1, *branch2;
 		const char *ren1_src, *ren1_dst;
@@ -807,8 +807,8 @@ static int process_renames(struct path_list *a_renames,
 			compare = -1;
 			ren1 = a_renames->items[i++].util;
 		} else {
-			compare = strcmp(a_renames->items[i].path,
-					b_renames->items[j].path);
+			compare = strcmp(a_renames->items[i].string,
+					b_renames->items[j].string);
 			if (compare <= 0)
 				ren1 = a_renames->items[i++].util;
 			if (compare >= 0)
@@ -897,7 +897,7 @@ static int process_renames(struct path_list *a_renames,
 			}
 		} else {
 			/* Renamed in 1, maybe changed in 2 */
-			struct path_list_item *item;
+			struct string_list_item *item;
 			/* we only use sha1 and mode of these */
 			struct diff_filespec src_other, dst_other;
 			int try_merge, stage = a_renames == renames1 ? 3: 2;
@@ -911,7 +911,7 @@ static int process_renames(struct path_list *a_renames,
 
 			try_merge = 0;
 
-			if (path_list_has_path(&current_directory_set, ren1_dst)) {
+			if (string_list_has_string(&current_directory_set, ren1_dst)) {
 				clean_merge = 0;
 				output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s "
 				       " directory %s added in %s",
@@ -936,7 +936,7 @@ static int process_renames(struct path_list *a_renames,
 				new_path = unique_path(ren1_dst, branch2);
 				output(1, "Added as %s instead", new_path);
 				update_file(0, dst_other.sha1, dst_other.mode, new_path);
-			} else if ((item = path_list_lookup(ren1_dst, renames2Dst))) {
+			} else if ((item = string_list_lookup(ren1_dst, renames2Dst))) {
 				ren2 = item->util;
 				clean_merge = 0;
 				ren2->processed = 1;
@@ -992,8 +992,8 @@ static int process_renames(struct path_list *a_renames,
 			}
 		}
 	}
-	path_list_clear(&a_by_dst, 0);
-	path_list_clear(&b_by_dst, 0);
+	string_list_clear(&a_by_dst, 0);
+	string_list_clear(&b_by_dst, 0);
 
 	return clean_merge;
 }
@@ -1071,7 +1071,7 @@ static int process_entry(const char *path, struct stage_data *entry,
 			sha = b_sha;
 			conf = "directory/file";
 		}
-		if (path_list_has_path(&current_directory_set, path)) {
+		if (string_list_has_string(&current_directory_set, path)) {
 			const char *new_path = unique_path(path, add_branch);
 			clean_merge = 0;
 			output(1, "CONFLICT (%s): There is a directory with name %s in %s. "
@@ -1162,10 +1162,10 @@ int merge_trees(struct tree *head,
 		    sha1_to_hex(merge->object.sha1));
 
 	if (unmerged_cache()) {
-		struct path_list *entries, *re_head, *re_merge;
+		struct string_list *entries, *re_head, *re_merge;
 		int i;
-		path_list_clear(&current_file_set, 1);
-		path_list_clear(&current_directory_set, 1);
+		string_list_clear(&current_file_set, 1);
+		string_list_clear(&current_directory_set, 1);
 		get_files_dirs(head);
 		get_files_dirs(merge);
 
@@ -1175,16 +1175,16 @@ int merge_trees(struct tree *head,
 		clean = process_renames(re_head, re_merge,
 				branch1, branch2);
 		for (i = 0; i < entries->nr; i++) {
-			const char *path = entries->items[i].path;
+			const char *path = entries->items[i].string;
 			struct stage_data *e = entries->items[i].util;
 			if (!e->processed
 				&& !process_entry(path, e, branch1, branch2))
 				clean = 0;
 		}
 
-		path_list_clear(re_merge, 0);
-		path_list_clear(re_head, 0);
-		path_list_clear(entries, 1);
+		string_list_clear(re_merge, 0);
+		string_list_clear(re_head, 0);
+		string_list_clear(entries, 1);
 
 	}
 	else
diff --git a/builtin-mv.c b/builtin-mv.c
index 68aa2a6..6d22106 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -7,7 +7,7 @@
 #include "builtin.h"
 #include "dir.h"
 #include "cache-tree.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "parse-options.h"
 
 static const char * const builtin_mv_usage[] = {
@@ -40,13 +40,14 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
 	return result;
 }
 
-static void show_list(const char *label, struct path_list *list)
+static void show_list(const char *label, struct string_list *list)
 {
 	if (list->nr > 0) {
 		int i;
 		printf("%s", label);
 		for (i = 0; i < list->nr; i++)
-			printf("%s%s", i > 0 ? ", " : "", list->items[i].path);
+			printf("%s%s", i > 0 ? ", " : "",
+					list->items[i].string);
 		putchar('\n');
 	}
 }
@@ -79,11 +80,11 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	const char **source, **destination, **dest_path;
 	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
 	struct stat st;
-	struct path_list overwritten = {NULL, 0, 0, 0};
-	struct path_list src_for_dst = {NULL, 0, 0, 0};
-	struct path_list added = {NULL, 0, 0, 0};
-	struct path_list deleted = {NULL, 0, 0, 0};
-	struct path_list changed = {NULL, 0, 0, 0};
+	struct string_list overwritten = {NULL, 0, 0, 0};
+	struct string_list src_for_dst = {NULL, 0, 0, 0};
+	struct string_list added = {NULL, 0, 0, 0};
+	struct string_list deleted = {NULL, 0, 0, 0};
+	struct string_list changed = {NULL, 0, 0, 0};
 
 	git_config(git_default_config);
 
@@ -193,16 +194,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 							" will overwrite!\n",
 							bad);
 					bad = NULL;
-					path_list_insert(dst, &overwritten);
+					string_list_insert(dst, &overwritten);
 				} else
 					bad = "Cannot overwrite";
 			}
 		} else if (cache_name_pos(src, length) < 0)
 			bad = "not under version control";
-		else if (path_list_has_path(&src_for_dst, dst))
+		else if (string_list_has_string(&src_for_dst, dst))
 			bad = "multiple sources for the same target";
 		else
-			path_list_insert(dst, &src_for_dst);
+			string_list_insert(dst, &src_for_dst);
 
 		if (bad) {
 			if (ignore_errors) {
@@ -232,15 +233,15 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 			continue;
 
 		if (cache_name_pos(src, strlen(src)) >= 0) {
-			path_list_insert(src, &deleted);
+			string_list_insert(src, &deleted);
 
 			/* destination can be a directory with 1 file inside */
-			if (path_list_has_path(&overwritten, dst))
-				path_list_insert(dst, &changed);
+			if (string_list_has_string(&overwritten, dst))
+				string_list_insert(dst, &changed);
 			else
-				path_list_insert(dst, &added);
+				string_list_insert(dst, &added);
 		} else
-			path_list_insert(dst, &added);
+			string_list_insert(dst, &added);
 	}
 
 	if (show_only) {
@@ -249,7 +250,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		show_list("Deleting : ", &deleted);
 	} else {
 		for (i = 0; i < changed.nr; i++) {
-			const char *path = changed.items[i].path;
+			const char *path = changed.items[i].string;
 			int j = cache_name_pos(path, strlen(path));
 			struct cache_entry *ce = active_cache[j];
 
@@ -259,12 +260,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		}
 
 		for (i = 0; i < added.nr; i++) {
-			const char *path = added.items[i].path;
+			const char *path = added.items[i].string;
 			add_file_to_cache(path, verbose);
 		}
 
 		for (i = 0; i < deleted.nr; i++)
-			remove_file_from_cache(deleted.items[i].path);
+			remove_file_from_cache(deleted.items[i].string);
 
 		if (active_cache_changed) {
 			if (write_cache(newfd, active_cache, active_nr) ||
diff --git a/builtin-rerere.c b/builtin-rerere.c
index c607aad..963b19e 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -1,6 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "xdiff/xdiff.h"
 #include "xdiff-interface.h"
 
@@ -23,7 +23,7 @@ static const char *rr_path(const char *name, const char *file)
 	return git_path("rr-cache/%s/%s", name, file);
 }
 
-static void read_rr(struct path_list *rr)
+static void read_rr(struct string_list *rr)
 {
 	unsigned char sha1[20];
 	char buf[PATH_MAX];
@@ -43,18 +43,18 @@ static void read_rr(struct path_list *rr)
 			; /* do nothing */
 		if (i == sizeof(buf))
 			die("filename too long");
-		path_list_insert(buf, rr)->util = xstrdup(name);
+		string_list_insert(buf, rr)->util = xstrdup(name);
 	}
 	fclose(in);
 }
 
 static struct lock_file write_lock;
 
-static int write_rr(struct path_list *rr, int out_fd)
+static int write_rr(struct string_list *rr, int out_fd)
 {
 	int i;
 	for (i = 0; i < rr->nr; i++) {
-		const char *path = rr->items[i].path;
+		const char *path = rr->items[i].string;
 		int length = strlen(path) + 1;
 		if (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||
 		    write_in_full(out_fd, "\t", 1) != 1 ||
@@ -138,7 +138,7 @@ static int handle_file(const char *path,
 	return hunk_no;
 }
 
-static int find_conflict(struct path_list *conflict)
+static int find_conflict(struct string_list *conflict)
 {
 	int i;
 	if (read_cache() < 0)
@@ -151,7 +151,7 @@ static int find_conflict(struct path_list *conflict)
 		    ce_same_name(e2, e3) &&
 		    S_ISREG(e2->ce_mode) &&
 		    S_ISREG(e3->ce_mode)) {
-			path_list_insert((const char *)e2->name, conflict);
+			string_list_insert((const char *)e2->name, conflict);
 			i++; /* skip over both #2 and #3 */
 		}
 	}
@@ -198,9 +198,9 @@ static void unlink_rr_item(const char *name)
 	rmdir(git_path("rr-cache/%s", name));
 }
 
-static void garbage_collect(struct path_list *rr)
+static void garbage_collect(struct string_list *rr)
 {
-	struct path_list to_remove = { NULL, 0, 0, 1 };
+	struct string_list to_remove = { NULL, 0, 0, 1 };
 	char buf[1024];
 	DIR *dir;
 	struct dirent *e;
@@ -226,12 +226,12 @@ static void garbage_collect(struct path_list *rr)
 		cutoff = stat(buf, &st) ? cutoff_noresolve : cutoff_resolve;
 		if (then < now - cutoff * 86400) {
 			buf[len + i] = '\0';
-			path_list_insert(xstrdup(name), &to_remove);
+			string_list_insert(xstrdup(name), &to_remove);
 		}
 	}
 	for (i = 0; i < to_remove.nr; i++)
-		unlink_rr_item(to_remove.items[i].path);
-	path_list_clear(&to_remove, 0);
+		unlink_rr_item(to_remove.items[i].string);
+	string_list_clear(&to_remove, 0);
 }
 
 static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
@@ -267,9 +267,9 @@ static int diff_two(const char *file1, const char *label1,
 	return 0;
 }
 
-static int do_plain_rerere(struct path_list *rr, int fd)
+static int do_plain_rerere(struct string_list *rr, int fd)
 {
-	struct path_list conflict = { NULL, 0, 0, 1 };
+	struct string_list conflict = { NULL, 0, 0, 1 };
 	int i;
 
 	find_conflict(&conflict);
@@ -282,8 +282,8 @@ static int do_plain_rerere(struct path_list *rr, int fd)
 	 */
 
 	for (i = 0; i < conflict.nr; i++) {
-		const char *path = conflict.items[i].path;
-		if (!path_list_has_path(rr, path)) {
+		const char *path = conflict.items[i].string;
+		if (!string_list_has_string(rr, path)) {
 			unsigned char sha1[20];
 			char *hex;
 			int ret;
@@ -291,7 +291,7 @@ static int do_plain_rerere(struct path_list *rr, int fd)
 			if (ret < 1)
 				continue;
 			hex = xstrdup(sha1_to_hex(sha1));
-			path_list_insert(path, rr)->util = hex;
+			string_list_insert(path, rr)->util = hex;
 			if (mkdir(git_path("rr-cache/%s", hex), 0755))
 				continue;;
 			handle_file(path, NULL, rr_path(hex, "preimage"));
@@ -308,7 +308,7 @@ static int do_plain_rerere(struct path_list *rr, int fd)
 	for (i = 0; i < rr->nr; i++) {
 		struct stat st;
 		int ret;
-		const char *path = rr->items[i].path;
+		const char *path = rr->items[i].string;
 		const char *name = (const char *)rr->items[i].util;
 
 		if (!stat(rr_path(name, "preimage"), &st) &&
@@ -372,7 +372,7 @@ static int is_rerere_enabled(void)
 	return 1;
 }
 
-static int setup_rerere(struct path_list *merge_rr)
+static int setup_rerere(struct string_list *merge_rr)
 {
 	int fd;
 
@@ -388,7 +388,7 @@ static int setup_rerere(struct path_list *merge_rr)
 
 int rerere(void)
 {
-	struct path_list merge_rr = { NULL, 0, 0, 1 };
+	struct string_list merge_rr = { NULL, 0, 0, 1 };
 	int fd;
 
 	fd = setup_rerere(&merge_rr);
@@ -399,7 +399,7 @@ int rerere(void)
 
 int cmd_rerere(int argc, const char **argv, const char *prefix)
 {
-	struct path_list merge_rr = { NULL, 0, 0, 1 };
+	struct string_list merge_rr = { NULL, 0, 0, 1 };
 	int i, fd;
 
 	fd = setup_rerere(&merge_rr);
@@ -422,16 +422,16 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		garbage_collect(&merge_rr);
 	else if (!strcmp(argv[1], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
-			printf("%s\n", merge_rr.items[i].path);
+			printf("%s\n", merge_rr.items[i].string);
 	else if (!strcmp(argv[1], "diff"))
 		for (i = 0; i < merge_rr.nr; i++) {
-			const char *path = merge_rr.items[i].path;
+			const char *path = merge_rr.items[i].string;
 			const char *name = (const char *)merge_rr.items[i].util;
 			diff_two(rr_path(name, "preimage"), path, path, path);
 		}
 	else
 		usage(git_rerere_usage);
 
-	path_list_clear(&merge_rr, 1);
+	string_list_clear(&merge_rr, 1);
 	return 0;
 }
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index af31aba..fe37515 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -2,7 +2,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "diff.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "revision.h"
 #include "utf8.h"
 #include "mailmap.h"
@@ -13,8 +13,8 @@ static const char shortlog_usage[] =
 
 static int compare_by_number(const void *a1, const void *a2)
 {
-	const struct path_list_item *i1 = a1, *i2 = a2;
-	const struct path_list *l1 = i1->util, *l2 = i2->util;
+	const struct string_list_item *i1 = a1, *i2 = a2;
+	const struct string_list *l1 = i1->util, *l2 = i2->util;
 
 	if (l1->nr < l2->nr)
 		return 1;
@@ -30,8 +30,8 @@ static void insert_one_record(struct shortlog *log,
 {
 	const char *dot3 = log->common_repo_prefix;
 	char *buffer, *p;
-	struct path_list_item *item;
-	struct path_list *onelines;
+	struct string_list_item *item;
+	struct string_list *onelines;
 	char namebuf[1024];
 	size_t len;
 	const char *eol;
@@ -64,9 +64,9 @@ static void insert_one_record(struct shortlog *log,
 	}
 
 	buffer = xstrdup(namebuf);
-	item = path_list_insert(buffer, &log->list);
+	item = string_list_insert(buffer, &log->list);
 	if (item->util == NULL)
-		item->util = xcalloc(1, sizeof(struct path_list));
+		item->util = xcalloc(1, sizeof(struct string_list));
 	else
 		free(buffer);
 
@@ -103,11 +103,11 @@ static void insert_one_record(struct shortlog *log,
 		onelines->alloc = alloc_nr(onelines->nr);
 		onelines->items = xrealloc(onelines->items,
 				onelines->alloc
-				* sizeof(struct path_list_item));
+				* sizeof(struct string_list_item));
 	}
 
 	onelines->items[onelines->nr].util = NULL;
-	onelines->items[onelines->nr++].path = buffer;
+	onelines->items[onelines->nr++].string = buffer;
 }
 
 static void read_from_stdin(struct shortlog *log)
@@ -218,7 +218,7 @@ void shortlog_init(struct shortlog *log)
 
 	read_mailmap(&log->mailmap, ".mailmap", &log->common_repo_prefix);
 
-	log->list.strdup_paths = 1;
+	log->list.strdup_strings = 1;
 	log->wrap = DEFAULT_WRAPLEN;
 	log->in1 = DEFAULT_INDENT1;
 	log->in2 = DEFAULT_INDENT2;
@@ -274,17 +274,17 @@ void shortlog_output(struct shortlog *log)
 {
 	int i, j;
 	if (log->sort_by_number)
-		qsort(log->list.items, log->list.nr, sizeof(struct path_list_item),
+		qsort(log->list.items, log->list.nr, sizeof(struct string_list_item),
 			compare_by_number);
 	for (i = 0; i < log->list.nr; i++) {
-		struct path_list *onelines = log->list.items[i].util;
+		struct string_list *onelines = log->list.items[i].util;
 
 		if (log->summary) {
-			printf("%6d\t%s\n", onelines->nr, log->list.items[i].path);
+			printf("%6d\t%s\n", onelines->nr, log->list.items[i].string);
 		} else {
-			printf("%s (%d):\n", log->list.items[i].path, onelines->nr);
+			printf("%s (%d):\n", log->list.items[i].string, onelines->nr);
 			for (j = onelines->nr - 1; j >= 0; j--) {
-				const char *msg = onelines->items[j].path;
+				const char *msg = onelines->items[j].string;
 
 				if (log->wrap_lines) {
 					int col = print_wrapped_text(msg, log->in1, log->in2, log->wrap);
@@ -297,14 +297,14 @@ void shortlog_output(struct shortlog *log)
 			putchar('\n');
 		}
 
-		onelines->strdup_paths = 1;
-		path_list_clear(onelines, 1);
+		onelines->strdup_strings = 1;
+		string_list_clear(onelines, 1);
 		free(onelines);
 		log->list.items[i].util = NULL;
 	}
 
-	log->list.strdup_paths = 1;
-	path_list_clear(&log->list, 1);
-	log->mailmap.strdup_paths = 1;
-	path_list_clear(&log->mailmap, 1);
+	log->list.strdup_strings = 1;
+	string_list_clear(&log->list, 1);
+	log->mailmap.strdup_strings = 1;
+	string_list_clear(&log->mailmap, 1);
 }
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index a323633..add1600 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -3,7 +3,7 @@
 #include "refs.h"
 #include "object.h"
 #include "tag.h"
-#include "path-list.h"
+#include "string-list.h"
 
 static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
 
@@ -98,8 +98,8 @@ match:
 
 static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
 {
-	struct path_list *list = (struct path_list *)cbdata;
-	path_list_insert(refname, list);
+	struct string_list *list = (struct string_list *)cbdata;
+	string_list_insert(refname, list);
 	return 0;
 }
 
@@ -114,7 +114,7 @@ static int add_existing(const char *refname, const unsigned char *sha1, int flag
  */
 static int exclude_existing(const char *match)
 {
-	static struct path_list existing_refs = { NULL, 0, 0, 0 };
+	static struct string_list existing_refs = { NULL, 0, 0, 0 };
 	char buf[1024];
 	int matchlen = match ? strlen(match) : 0;
 
@@ -143,7 +143,7 @@ static int exclude_existing(const char *match)
 			fprintf(stderr, "warning: ref '%s' ignored\n", ref);
 			continue;
 		}
-		if (!path_list_has_path(&existing_refs, ref)) {
+		if (!string_list_has_string(&existing_refs, ref)) {
 			printf("%s\n", buf);
 		}
 	}
diff --git a/diff-lib.c b/diff-lib.c
index 94b150e..42e012f 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -8,14 +8,14 @@
 #include "diffcore.h"
 #include "revision.h"
 #include "cache-tree.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "unpack-trees.h"
 
 /*
  * diff-files
  */
 
-static int read_directory(const char *path, struct path_list *list)
+static int read_directory(const char *path, struct string_list *list)
 {
 	DIR *dir;
 	struct dirent *e;
@@ -25,7 +25,7 @@ static int read_directory(const char *path, struct path_list *list)
 
 	while ((e = readdir(dir)))
 		if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
-			path_list_insert(e->d_name, list);
+			string_list_insert(e->d_name, list);
 
 	closedir(dir);
 	return 0;
@@ -59,13 +59,13 @@ static int queue_diff(struct diff_options *o,
 
 	if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
 		char buffer1[PATH_MAX], buffer2[PATH_MAX];
-		struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
+		struct string_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
 		int len1 = 0, len2 = 0, i1, i2, ret = 0;
 
 		if (name1 && read_directory(name1, &p1))
 			return -1;
 		if (name2 && read_directory(name2, &p2)) {
-			path_list_clear(&p1, 0);
+			string_list_clear(&p1, 0);
 			return -1;
 		}
 
@@ -94,14 +94,14 @@ static int queue_diff(struct diff_options *o,
 			else if (i2 == p2.nr)
 				comp = -1;
 			else
-				comp = strcmp(p1.items[i1].path,
-					p2.items[i2].path);
+				comp = strcmp(p1.items[i1].string,
+					p2.items[i2].string);
 
 			if (comp > 0)
 				n1 = NULL;
 			else {
 				n1 = buffer1;
-				strncpy(buffer1 + len1, p1.items[i1++].path,
+				strncpy(buffer1 + len1, p1.items[i1++].string,
 						PATH_MAX - len1);
 			}
 
@@ -109,14 +109,14 @@ static int queue_diff(struct diff_options *o,
 				n2 = NULL;
 			else {
 				n2 = buffer2;
-				strncpy(buffer2 + len2, p2.items[i2++].path,
+				strncpy(buffer2 + len2, p2.items[i2++].string,
 						PATH_MAX - len2);
 			}
 
 			ret = queue_diff(o, n1, n2);
 		}
-		path_list_clear(&p1, 0);
-		path_list_clear(&p2, 0);
+		string_list_clear(&p1, 0);
+		string_list_clear(&p2, 0);
 
 		return ret;
 	} else {
diff --git a/mailmap.c b/mailmap.c
index f017255..88fc6f3 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,8 +1,8 @@
 #include "cache.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "mailmap.h"
 
-int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev)
+int read_mailmap(struct string_list *map, const char *filename, char **repo_abbrev)
 {
 	char buffer[1024];
 	FILE *f = fopen(filename, "r");
@@ -54,16 +54,16 @@ int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev
 		for (i = 0; i < right_bracket - left_bracket - 1; i++)
 			email[i] = tolower(left_bracket[i + 1]);
 		email[right_bracket - left_bracket - 1] = '\0';
-		path_list_insert(email, map)->util = name;
+		string_list_insert(email, map)->util = name;
 	}
 	fclose(f);
 	return 0;
 }
 
-int map_email(struct path_list *map, const char *email, char *name, int maxlen)
+int map_email(struct string_list *map, const char *email, char *name, int maxlen)
 {
 	char *p;
-	struct path_list_item *item;
+	struct string_list_item *item;
 	char buf[1024], *mailbuf;
 	int i;
 
@@ -80,7 +80,7 @@ int map_email(struct path_list *map, const char *email, char *name, int maxlen)
 	for (i = 0; i < p - email; i++)
 		mailbuf[i] = tolower(email[i]);
 	mailbuf[i] = 0;
-	item = path_list_lookup(mailbuf, map);
+	item = string_list_lookup(mailbuf, map);
 	if (mailbuf != buf)
 		free(mailbuf);
 	if (item != NULL) {
diff --git a/mailmap.h b/mailmap.h
index 3503fd2..6e48f83 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -1,7 +1,7 @@
 #ifndef MAILMAP_H
 #define MAILMAP_H
 
-int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev);
-int map_email(struct path_list *mailmap, const char *email, char *name, int maxlen);
+int read_mailmap(struct string_list *map, const char *filename, char **repo_abbrev);
+int map_email(struct string_list *mailmap, const char *email, char *name, int maxlen);
 
 #endif
diff --git a/path-list.h b/path-list.h
deleted file mode 100644
index 5931e2c..0000000
--- a/path-list.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef PATH_LIST_H
-#define PATH_LIST_H
-
-struct path_list_item {
-	char *path;
-	void *util;
-};
-struct path_list
-{
-	struct path_list_item *items;
-	unsigned int nr, alloc;
-	unsigned int strdup_paths:1;
-};
-
-void print_path_list(const char *text, const struct path_list *p);
-
-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);
-
-#endif /* PATH_LIST_H */
diff --git a/reflog-walk.c b/reflog-walk.c
index ee1456b..f751fdc 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -3,7 +3,7 @@
 #include "refs.h"
 #include "diff.h"
 #include "revision.h"
-#include "path-list.h"
+#include "string-list.h"
 #include "reflog-walk.h"
 
 struct complete_reflogs {
@@ -127,7 +127,7 @@ struct commit_reflog {
 
 struct reflog_walk_info {
 	struct commit_info_lifo reflogs;
-	struct path_list complete_reflogs;
+	struct string_list complete_reflogs;
 	struct commit_reflog *last_commit_reflog;
 };
 
@@ -141,7 +141,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 {
 	unsigned long timestamp = 0;
 	int recno = -1;
-	struct path_list_item *item;
+	struct string_list_item *item;
 	struct complete_reflogs *reflogs;
 	char *branch, *at = strchr(name, '@');
 	struct commit_reflog *commit_reflog;
@@ -161,7 +161,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 	} else
 		recno = 0;
 
-	item = path_list_lookup(branch, &info->complete_reflogs);
+	item = string_list_lookup(branch, &info->complete_reflogs);
 	if (item)
 		reflogs = item->util;
 	else {
@@ -189,7 +189,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 		}
 		if (!reflogs || reflogs->nr == 0)
 			return -1;
-		path_list_insert(branch, &info->complete_reflogs)->util
+		string_list_insert(branch, &info->complete_reflogs)->util
 			= reflogs;
 	}
 
diff --git a/shortlog.h b/shortlog.h
index 31ff491..46a0991 100644
--- a/shortlog.h
+++ b/shortlog.h
@@ -1,10 +1,10 @@
 #ifndef SHORTLOG_H
 #define SHORTLOG_H
 
-#include "path-list.h"
+#include "string-list.h"
 
 struct shortlog {
-	struct path_list list;
+	struct string_list list;
 	int summary;
 	int wrap_lines;
 	int sort_by_number;
@@ -14,7 +14,7 @@ struct shortlog {
 
 	char *common_repo_prefix;
 	int email;
-	struct path_list mailmap;
+	struct string_list mailmap;
 };
 
 void shortlog_init(struct shortlog *log);
diff --git a/path-list.c b/string-list.c
similarity index 53%
rename from path-list.c
rename to string-list.c
index 3d83b7b..699e754 100644
--- a/path-list.c
+++ b/string-list.c
@@ -1,16 +1,16 @@
 #include "cache.h"
-#include "path-list.h"
+#include "string-list.h"
 
 /* if there is no exact match, point to the index where the entry could be
  * inserted */
-static int get_entry_index(const struct path_list *list, const char *path,
+static int get_entry_index(const struct string_list *list, const char *string,
 		int *exact_match)
 {
 	int left = -1, right = list->nr;
 
 	while (left + 1 < right) {
 		int middle = (left + right) / 2;
-		int compare = strcmp(path, list->items[middle].path);
+		int compare = strcmp(string, list->items[middle].string);
 		if (compare < 0)
 			right = middle;
 		else if (compare > 0)
@@ -26,10 +26,10 @@ static int get_entry_index(const struct path_list *list, const char *path,
 }
 
 /* returns -1-index if already exists */
-static int add_entry(struct path_list *list, const char *path)
+static int add_entry(struct string_list *list, const char *string)
 {
 	int exact_match;
-	int index = get_entry_index(list, path, &exact_match);
+	int index = get_entry_index(list, string, &exact_match);
 
 	if (exact_match)
 		return -1 - index;
@@ -37,23 +37,23 @@ static int add_entry(struct path_list *list, const char *path)
 	if (list->nr + 1 >= list->alloc) {
 		list->alloc += 32;
 		list->items = xrealloc(list->items, list->alloc
-				* sizeof(struct path_list_item));
+				* sizeof(struct string_list_item));
 	}
 	if (index < list->nr)
 		memmove(list->items + index + 1, list->items + index,
 				(list->nr - index)
-				* sizeof(struct path_list_item));
-	list->items[index].path = list->strdup_paths ?
-		xstrdup(path) : (char *)path;
+				* sizeof(struct string_list_item));
+	list->items[index].string = list->strdup_strings ?
+		xstrdup(string) : (char *)string;
 	list->items[index].util = NULL;
 	list->nr++;
 
 	return index;
 }
 
-struct path_list_item *path_list_insert(const char *path, struct path_list *list)
+struct string_list_item *string_list_insert(const char *string, struct string_list *list)
 {
-	int index = add_entry(list, path);
+	int index = add_entry(list, string);
 
 	if (index < 0)
 		index = -1 - index;
@@ -61,28 +61,28 @@ struct path_list_item *path_list_insert(const char *path, struct path_list *list
 	return list->items + index;
 }
 
-int path_list_has_path(const struct path_list *list, const char *path)
+int string_list_has_string(const struct string_list *list, const char *string)
 {
 	int exact_match;
-	get_entry_index(list, path, &exact_match);
+	get_entry_index(list, string, &exact_match);
 	return exact_match;
 }
 
-struct path_list_item *path_list_lookup(const char *path, struct path_list *list)
+struct string_list_item *string_list_lookup(const char *string, struct string_list *list)
 {
-	int exact_match, i = get_entry_index(list, path, &exact_match);
+	int exact_match, i = get_entry_index(list, string, &exact_match);
 	if (!exact_match)
 		return NULL;
 	return list->items + i;
 }
 
-void path_list_clear(struct path_list *list, int free_util)
+void string_list_clear(struct string_list *list, int free_util)
 {
 	if (list->items) {
 		int i;
-		if (list->strdup_paths) {
+		if (list->strdup_strings) {
 			for (i = 0; i < list->nr; i++)
-				free(list->items[i].path);
+				free(list->items[i].string);
 		}
 		if (free_util) {
 			for (i = 0; i < list->nr; i++)
@@ -94,11 +94,12 @@ void path_list_clear(struct path_list *list, int free_util)
 	list->nr = list->alloc = 0;
 }
 
-void print_path_list(const char *text, const struct path_list *p)
+void print_string_list(const char *text, const struct string_list *p)
 {
 	int i;
 	if ( text )
 		printf("%s\n", text);
 	for (i = 0; i < p->nr; i++)
-		printf("%s:%p\n", p->items[i].path, p->items[i].util);
+		printf("%s:%p\n", p->items[i].string, p->items[i].util);
 }
+
diff --git a/string-list.h b/string-list.h
new file mode 100644
index 0000000..6195791
--- /dev/null
+++ b/string-list.h
@@ -0,0 +1,22 @@
+#ifndef PATH_LIST_H
+#define PATH_LIST_H
+
+struct string_list_item {
+	char *string;
+	void *util;
+};
+struct string_list
+{
+	struct string_list_item *items;
+	unsigned int nr, alloc;
+	unsigned int strdup_strings:1;
+};
+
+void print_string_list(const char *text, const struct string_list *p);
+
+int string_list_has_string(const struct string_list *list, const char *string);
+void string_list_clear(struct string_list *list, int free_util);
+struct string_list_item *string_list_insert(const char *string, struct string_list *list);
+struct string_list_item *string_list_lookup(const char *string, struct string_list *list);
+
+#endif /* PATH_LIST_H */
-- 
1.5.4.3.446.gbe8932



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

* [PATCH 2/6] string-list: add functions to work with unsorted lists
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
  2008-03-01 13:15         ` [PATCH 1/6] Rename path_list to string_list Johannes Schindelin
@ 2008-03-01 13:15         ` Johannes Schindelin
  2008-03-01 13:16         ` [PATCH 3/6] parseopt: add flag to stop on first non option Johannes Schindelin
                           ` (3 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


Up to now, string-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 string_list_append() and sort_string_list() to allow that.

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

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/CodingGuidelines |    5 +++--
 string-list.c                  |   29 +++++++++++++++++++++++++++++
 string-list.h                  |    8 +++++++-
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index fe7c74b..7507053 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -91,8 +91,9 @@ For C programs:
 
  - Use the API.  No, really.  We have a strbuf (variable length
    string), several arrays with the ALLOC_GROW() macro, a
-   string_list for sorted string lists, a hash map (mapping struct
-   objects) named "struct decorate", amongst other things.
+   string_list for sorted and unsorted string lists, a hash map
+   (mapping struct objects) named "struct decorate", amongst other
+   things.
 
  - When you come up with an API, document it.
 
diff --git a/string-list.c b/string-list.c
index 699e754..ddd83c8 100644
--- a/string-list.c
+++ b/string-list.c
@@ -103,3 +103,32 @@ void print_string_list(const char *text, const struct string_list *p)
 		printf("%s:%p\n", p->items[i].string, p->items[i].util);
 }
 
+struct string_list_item *string_list_append(const char *string, struct string_list *list)
+{
+	ALLOC_GROW(list->items, list->nr + 1, list->alloc);
+	list->items[list->nr].string =
+		list->strdup_strings ? xstrdup(string) : (char *)string;
+	return list->items + list->nr++;
+}
+
+static int cmp_items(const void *a, const void *b)
+{
+	const struct string_list_item *one = a;
+	const struct string_list_item *two = b;
+	return strcmp(one->string, two->string);
+}
+
+void sort_string_list(struct string_list *list)
+{
+	qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
+}
+
+int unsorted_string_list_has_string(struct string_list *list, const char *string)
+{
+	int i;
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(string, list->items[i].string))
+			return 1;
+	return 0;
+}
+
diff --git a/string-list.h b/string-list.h
index 6195791..4d6a705 100644
--- a/string-list.h
+++ b/string-list.h
@@ -13,10 +13,16 @@ struct string_list
 };
 
 void print_string_list(const char *text, const struct string_list *p);
+void string_list_clear(struct string_list *list, int free_util);
 
+/* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
-void string_list_clear(struct string_list *list, int free_util);
 struct string_list_item *string_list_insert(const char *string, struct string_list *list);
 struct string_list_item *string_list_lookup(const char *string, struct string_list *list);
 
+/* Use these functions only on unsorted lists: */
+struct string_list_item *string_list_append(const char *string, struct string_list *list);
+void sort_string_list(struct string_list *list);
+int unsorted_string_list_has_string(struct string_list *list, const char *string);
+
 #endif /* PATH_LIST_H */
-- 
1.5.4.3.446.gbe8932



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

* [PATCH 3/6] parseopt: add flag to stop on first non option
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
  2008-03-01 13:15         ` [PATCH 1/6] Rename path_list to string_list Johannes Schindelin
  2008-03-01 13:15         ` [PATCH 2/6] string-list: add functions to work with unsorted lists Johannes Schindelin
@ 2008-03-01 13:16         ` Johannes Schindelin
  2008-03-01 13:16         ` [PATCH 4/6] Test "git remote show" and "git remote prune" Johannes Schindelin
                           ` (2 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 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 d9562ba..be35785 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -249,6 +249,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.4.3.446.gbe8932



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

* [PATCH 4/6] Test "git remote show" and "git remote prune"
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
                           ` (2 preceding siblings ...)
  2008-03-01 13:16         ` [PATCH 3/6] parseopt: add flag to stop on first non option Johannes Schindelin
@ 2008-03-01 13:16         ` Johannes Schindelin
  2008-03-01 13:16         ` [PATCH 5/6] Make git-remote a builtin Johannes Schindelin
  2008-03-01 13:17         ` [PATCH 6/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


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 4fc62f5..e1e0a18 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -94,4 +94,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.4.3.446.gbe8932



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

* [PATCH 5/6] Make git-remote a builtin
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
                           ` (3 preceding siblings ...)
  2008-03-01 13:16         ` [PATCH 4/6] Test "git remote show" and "git remote prune" Johannes Schindelin
@ 2008-03-01 13:16         ` Johannes Schindelin
  2008-03-01 13:17         ` [PATCH 6/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


This includes the fix to guard remote->url accesses by checking
remote->url_nr, as suggested by Johannes Sixt.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                                           |    3 +-
 builtin-remote.c                                   |  547 ++++++++++++++++++++
 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, 556 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 ad214d3..8847bbe 100644
--- a/Makefile
+++ b/Makefile
@@ -243,7 +243,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)) \
@@ -380,6 +380,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..2c10df3
--- /dev/null
+++ b/builtin-remote.c
@@ -0,0 +1,547 @@
+#include "cache.h"
+#include "parse-options.h"
+#include "transport.h"
+#include "remote.h"
+#include "string-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 string_list *list = opt->value;
+	if (not)
+		string_list_clear(list, 0);
+	else
+		string_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 string_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)
+		string_list_append("*", &track);
+	for (i = 0; i < track.nr; i++) {
+		struct string_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->string, item->string);
+		else
+			strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
+					item->string, name, item->string);
+		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);
+	string_list_clear(&track, 0);
+
+	return 0;
+}
+
+struct branch_info {
+	char *remote;
+	struct string_list merge;
+};
+
+static struct string_list branch_list;
+
+static int config_read_branches(const char *key, const char *value)
+{
+	if (!prefixcmp(key, "branch.")) {
+		char *name;
+		struct string_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 = string_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);
+				string_list_append(merge, &info->merge);
+				value = skip_prefix(space + 1, "refs/heads/");
+				space = strchr(value, ' ');
+			}
+			string_list_append(xstrdup(value), &info->merge);
+		}
+	}
+	return 0;
+}
+
+static void read_branches()
+{
+	if (branch_list.nr)
+		return;
+	git_config(config_read_branches);
+	sort_string_list(&branch_list);
+}
+
+struct ref_states {
+	struct remote *remote;
+	struct strbuf remote_prefix;
+	struct string_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 string_list_item *item;
+		const char *name = skip_prefix(refspec.src, "refs/heads/");
+		if (unsorted_string_list_has_string(&states->tracked, name) ||
+				unsorted_string_list_has_string(&states->new,
+					name))
+			return 0;
+		item = string_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_strings = states->tracked.strdup_strings = 1;
+	for (ref = fetch_map; ref; ref = ref->next) {
+		struct string_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;
+		}
+		string_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_string_list(&states->stale);
+
+	return 0;
+}
+
+struct branches_for_remote {
+	const char *prefix;
+	struct string_list *branches;
+};
+
+static int add_branch_for_removal(const char *refname,
+	const unsigned char *sha1, int flags, void *cb_data)
+{
+	struct branches_for_remote *branches = cb_data;
+
+	if (!prefixcmp(refname, branches->prefix)) {
+		struct string_list_item *item;
+		item = string_list_append(refname, branches->branches);
+		item->util = xmalloc(20);
+		hashcpy(item->util, sha1);
+	}
+
+	return 0;
+}
+
+static int remove_branches(struct string_list *branches)
+{
+	int i, result = 0;
+	for (i = 0; i < branches->nr; i++) {
+		struct string_list_item *item = branches->items + i;
+		const char *refname = item->string;
+		unsigned char *sha1 = item->util;
+
+		if (delete_ref(refname, sha1))
+			result |= error("Could not remove branch %s", refname);
+	}
+	return result;
+}
+
+static int rm(int argc, const char **argv)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct remote *remote;
+	struct strbuf buf;
+	struct string_list branches = { NULL, 0, 0, 1 };
+	struct branches_for_remote cb_data = { NULL, &branches };
+	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 string_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->string, *k);
+				if (git_config_set(buf.buf, NULL)) {
+					strbuf_release(&buf);
+					return -1;
+				}
+			}
+		}
+	}
+
+	/*
+	 * We cannot just pass a function to for_each_ref() which deletes
+	 * the branches one by one, since for_each_ref() relies on cached
+	 * refs, which are invalidated when deleting a branch.
+	 */
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
+	cb_data.prefix = buf.buf;
+	i = for_each_ref(add_branch_for_removal, &cb_data);
+	strbuf_release(&buf);
+
+	if (!i)
+		i = remove_branches(&branches);
+	string_list_clear(&branches, 1);
+
+	return i;
+}
+
+static void show_list(const char *title, struct string_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].string);
+	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_nr > 0 ?
+			states.remote->url[0] : NULL);
+		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].string);
+				result |= delete_ref(buf.buf, NULL);
+			}
+
+			strbuf_release(&buf);
+			goto cleanup_states;
+		}
+
+		printf("* remote %s\n  URL: %s\n", *argv,
+			states.remote->url_nr > 0 ?
+				states.remote->url[0] : "(no URL)");
+
+		for (i = 0; i < branch_list.nr; i++) {
+			struct string_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->string);
+			for (j = 0; j < info->merge.nr; j++)
+				printf(" %s", info->merge.items[j].string);
+			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 */
+		string_list_clear(&states.new, 0);
+		string_list_clear(&states.stale, 0);
+		string_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 string_list *list = priv;
+
+	string_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;
+}
+
+static int show_all()
+{
+	struct string_list list = { NULL, 0, 0 };
+	int result = for_each_remote(get_one_entry, &list);
+
+	if (!result) {
+		int i;
+
+		sort_string_list(&list);
+		for (i = 0; i < list.nr; i++) {
+			struct string_list_item *item = list.items + i;
+			printf("%s%s%s\n", item->string,
+				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 674c8a1..95126fd 100644
--- a/builtin.h
+++ b/builtin.h
@@ -67,6 +67,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 9cca81a..1e3eb10 100644
--- a/git.c
+++ b/git.c
@@ -334,6 +334,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 7e19372..f3f7375 100644
--- a/remote.c
+++ b/remote.c
@@ -357,7 +357,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 0f6033f..f1dedf1 100644
--- a/remote.h
+++ b/remote.h
@@ -25,6 +25,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 e1e0a18..5986982 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -97,9 +97,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.4.3.446.gbe8932



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

* [PATCH 6/6] builtin-remote: prune remotes correctly that were added with --mirror
  2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
                           ` (4 preceding siblings ...)
  2008-03-01 13:16         ` [PATCH 5/6] Make git-remote a builtin Johannes Schindelin
@ 2008-03-01 13:17         ` Johannes Schindelin
  5 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-01 13:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


This adds special handling for mirror remotes.

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

diff --git a/builtin-remote.c b/builtin-remote.c
index 2c10df3..221d2d6 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -396,11 +396,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,
+				strbuf_setlen(&buf, prefix_len);
+				strbuf_addstr(&buf,
 						states.stale.items[i].string);
 				result |= delete_ref(buf.buf, NULL);
 			}
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 5986982..0a25c8b 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -128,4 +128,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.4.3.446.gbe8932



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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-02-29 11:21     ` Johannes Schindelin
@ 2008-03-02 15:15       ` Johannes Schindelin
  2008-03-02 15:40         ` Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 15:15 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git

[PATCH] format-patch: use the diff options for the cover letter, too

Earlier, when you called "git format-patch --cover-letter -M", the
diffstat in the cover letter would not inherit the "-M".  Now it does.

While at it, add a few "|| break" statements in the test's loops;
otherwise, breakages inside the loops would not be caught.

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

	On Fri, 29 Feb 2008, Johannes Schindelin wrote:

	> On Thu, 28 Feb 2008, Daniel Barkalow wrote:
	> 
	> > On Thu, 28 Feb 2008, Junio C Hamano wrote:
	> > 
	> > > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
	> > > 
	> > > > It also demonstrates that format-patch --cover-letter 
	> > > > should default to -M for the diffstat (search for 
	> > > > "git-remote.perl"...).
	> > > 
	> > > It probably should inherit the settings for the primary 
	> > > part. You did generate the series with -M, especially [PATCH 
	> > > 4/5], didn't you?
	> > 
	> > Obviously not the output_format, but everything else, I 
	> > assume? Easy enough to pass the main diff options into 
	> > make_cover_letter() and use them to initialize the diff 
	> > options there.

	Voila.

	I thought that the changes in the for loops do not merit an own
	patch, but if you think otherwise, let me know, and I'll resend.

 builtin-log.c           |    2 +-
 t/t4014-format-patch.sh |   18 ++++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index bbadbc0..17e491b 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -694,7 +694,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 	if (!origin)
 		return;
 
-	diff_setup(&opts);
+	memcpy(&opts, &rev->diffopt, sizeof(opts));
 	opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
 
 	diff_setup_done(&opts);
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 16aa99d..6d86b7d 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -147,7 +147,7 @@ test_expect_success 'thread' '
 	for i in patches/0002-* patches/0003-*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -160,7 +160,7 @@ test_expect_success 'thread in-reply-to' '
 	for i in patches/*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -173,7 +173,7 @@ test_expect_success 'thread cover-letter' '
 	for i in patches/0001-* patches/0002-* patches/0003-* 
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -186,7 +186,7 @@ test_expect_success 'thread cover-letter in-reply-to' '
 	for i in patches/*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -201,4 +201,14 @@ test_expect_success 'excessive subject' '
 	ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
 '
 
+test_expect_success 'cover-letter inherits diff options' '
+
+	git mv file foo &&
+	git commit -m foo &&
+	git format-patch --cover-letter -1 &&
+	! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
+	git format-patch --cover-letter -1 -M &&
+	grep "file => foo .* 0 *$" 0000-cover-letter.patch
+
+'
 test_done
-- 
1.5.4.3.510.g7cdd


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

* Re: [PATCH 0/5] Builtin "git remote"
  2008-03-02 15:15       ` Johannes Schindelin
@ 2008-03-02 15:40         ` Johannes Schindelin
  2008-03-02 15:52           ` [PATCH 0/2] format-patch --cover-letter improvements Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 15:40 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git

Hi,

On Sun, 2 Mar 2008, Johannes Schindelin wrote:

> diff --git a/builtin-log.c b/builtin-log.c
> index bbadbc0..17e491b 100644
> --- a/builtin-log.c
> +++ b/builtin-log.c
> @@ -694,7 +694,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
>  	if (!origin)
>  		return;
>  
> -	diff_setup(&opts);
> +	memcpy(&opts, &rev->diffopt, sizeof(opts));
>  	opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
>  
>  	diff_setup_done(&opts);

Ooops, I forgot to "make test"!  And sure enough, t4013 breaks, because 
the "|=" was bogus to begin with.

Will resend, together with a patch to wrap the shortlog nicely.

... after "make test" ;-)

Ciao,
Dscho


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

* [PATCH 0/2] format-patch --cover-letter improvements
  2008-03-02 15:40         ` Johannes Schindelin
@ 2008-03-02 15:52           ` Johannes Schindelin
  2008-03-02 15:53             ` [PATCH 1/2] format-patch: use the diff options for the cover letter, too Johannes Schindelin
  2008-03-02 15:53             ` [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly Johannes Schindelin
  0 siblings, 2 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 15:52 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git


This patch pair brings two improvements to the cover letter:

	- when calling format-patch with a diff option, this options
	  will be heeded by the cover-letter's diffstat, and

	- the onelines in the shortlog are wrapped around, just like
	  in Junio's "What's in ..." messages.


Johannes Schindelin (2):
  format-patch: use the diff options for the cover letter, too
  format-patch: wrap cover-letter's shortlog sensibly

 builtin-log.c                                      |    8 +++-
 ...tch_--stdout_--cover-letter_-n_initial..master^ |    4 +-
 t/t4014-format-patch.sh                            |   37 +++++++++++++++++--
 3 files changed, 41 insertions(+), 8 deletions(-)



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

* [PATCH 1/2] format-patch: use the diff options for the cover letter, too
  2008-03-02 15:52           ` [PATCH 0/2] format-patch --cover-letter improvements Johannes Schindelin
@ 2008-03-02 15:53             ` Johannes Schindelin
  2008-03-02 15:53             ` [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly Johannes Schindelin
  1 sibling, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 15:53 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git


Earlier, when you called "git format-patch --cover-letter -M", the
diffstat in the cover letter would not inherit the "-M".  Now it does.

While at it, add a few "|| break" statements in the test's loops;
otherwise, breakages inside the loops would not be caught.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-log.c           |    4 ++--
 t/t4014-format-patch.sh |   18 ++++++++++++++----
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index bbadbc0..fd9b3ae 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -694,8 +694,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 	if (!origin)
 		return;
 
-	diff_setup(&opts);
-	opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+	memcpy(&opts, &rev->diffopt, sizeof(opts));
+	opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
 
 	diff_setup_done(&opts);
 
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 16aa99d..6d86b7d 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -147,7 +147,7 @@ test_expect_success 'thread' '
 	for i in patches/0002-* patches/0003-*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -160,7 +160,7 @@ test_expect_success 'thread in-reply-to' '
 	for i in patches/*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -173,7 +173,7 @@ test_expect_success 'thread cover-letter' '
 	for i in patches/0001-* patches/0002-* patches/0003-* 
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -186,7 +186,7 @@ test_expect_success 'thread cover-letter in-reply-to' '
 	for i in patches/*
 	do
 	  grep "References: $FIRST_MID" $i &&
-	  grep "In-Reply-To: $FIRST_MID" $i
+	  grep "In-Reply-To: $FIRST_MID" $i || break
 	done
 '
 
@@ -201,4 +201,14 @@ test_expect_success 'excessive subject' '
 	ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
 '
 
+test_expect_success 'cover-letter inherits diff options' '
+
+	git mv file foo &&
+	git commit -m foo &&
+	git format-patch --cover-letter -1 &&
+	! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
+	git format-patch --cover-letter -1 -M &&
+	grep "file => foo .* 0 *$" 0000-cover-letter.patch
+
+'
 test_done
-- 
1.5.4.3.510.g7cdd



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

* [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly
  2008-03-02 15:52           ` [PATCH 0/2] format-patch --cover-letter improvements Johannes Schindelin
  2008-03-02 15:53             ` [PATCH 1/2] format-patch: use the diff options for the cover letter, too Johannes Schindelin
@ 2008-03-02 15:53             ` Johannes Schindelin
  2008-03-02 17:05               ` Junio C Hamano
  1 sibling, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 15:53 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git


Earlier, overly-long onelines would not be wrapped at all, and indented
with 6 spaces.

Instead, we now wrap around at 72 characters, with a first-line indent
of 2 spaces, and the rest with 4 spaces (like the "What's in" messages
of Junio).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-log.c                                      |    4 ++++
 ...tch_--stdout_--cover-letter_-n_initial..master^ |    4 ++--
 t/t4014-format-patch.sh                            |   19 +++++++++++++++++++
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index fd9b3ae..fe8fc6f 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -683,6 +683,10 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 	strbuf_release(&sb);
 
 	shortlog_init(&log);
+	log.wrap_lines = 1;
+	log.wrap = 72;
+	log.in1 = 2;
+	log.in2 = 4;
 	for (i = 0; i < nr; i++)
 		shortlog_add_commit(&log, list[i]);
 
diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 0151453..8dab4bf 100644
--- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -7,8 +7,8 @@ Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***
 *** BLURB HERE ***
 
 A U Thor (2):
-      Second
-      Third
+  Second
+  Third
 
  dir/sub |    4 ++++
  file0   |    3 +++
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 6d86b7d..b2b7a8d 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -211,4 +211,23 @@ test_expect_success 'cover-letter inherits diff options' '
 	grep "file => foo .* 0 *$" 0000-cover-letter.patch
 
 '
+
+cat > expect << EOF
+  This is an excessively long subject line for a message due to the
+    habit some projects have of not having a short, one-line subject at
+    the start of the commit message, but rather sticking a whole
+    paragraph right at the start as the only thing in the commit
+    message. It had better not become the filename for the patch.
+  foo
+
+EOF
+
+test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
+
+	git format-patch --cover-letter -2 &&
+	sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
+	git diff expect output
+
+'
+
 test_done
-- 
1.5.4.3.510.g7cdd



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

* Re: [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly
  2008-03-02 15:53             ` [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly Johannes Schindelin
@ 2008-03-02 17:05               ` Junio C Hamano
  2008-03-02 17:38                 ` Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: Junio C Hamano @ 2008-03-02 17:05 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Daniel Barkalow, git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> Earlier, overly-long onelines would not be wrapped at all, and indented
> with 6 spaces.
>
> Instead, we now wrap around at 72 characters, with a first-line indent
> of 2 spaces, and the rest with 4 spaces (like the "What's in" messages
> of Junio).

Heh, I seem to personally use 76,2,4 but otherwise I think this makes it
easier to read.  Thanks.

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

* Re: [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly
  2008-03-02 17:05               ` Junio C Hamano
@ 2008-03-02 17:38                 ` Johannes Schindelin
  0 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-02 17:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Daniel Barkalow, git

Hi,

On Sun, 2 Mar 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > Earlier, overly-long onelines would not be wrapped at all, and indented
> > with 6 spaces.
> >
> > Instead, we now wrap around at 72 characters, with a first-line indent 
> > of 2 spaces, and the rest with 4 spaces (like the "What's in" messages 
> > of Junio).
> 
> Heh, I seem to personally use 76,2,4 but otherwise I think this makes it 
> easier to read.  Thanks.

Oh?  My first patch was 76,4,8, but then I was unsure, and went to your 
todo branch, and found this:

$ git grep -e -w.*7
Summary:git shortlog -w72,2,4 --no-merges $bottom..$top
WI:     git shortlog -w76,2,4 --no-merges "$@"

Obviously, I missed the second one, and took the first one.

Ciao,
Dscho


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

* Re: [PATCH 1/6] Rename path_list to string_list
  2008-03-01 13:15         ` [PATCH 1/6] Rename path_list to string_list Johannes Schindelin
@ 2008-03-11 16:20           ` David Kågedal
  2008-03-11 16:26             ` Johannes Schindelin
  0 siblings, 1 reply; 29+ messages in thread
From: David Kågedal @ 2008-03-11 16:20 UTC (permalink / raw)
  To: git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt
> index d077683..8892cf0 100644
> --- a/Documentation/technical/api-path-list.txt
> +++ b/Documentation/technical/api-path-list.txt
> @@ -1,7 +1,7 @@
> -path-list API
> +string-list API
>  =============

Looks like you'll want to add two = here.

-- 
David Kågedal

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

* Re: [PATCH 1/6] Rename path_list to string_list
  2008-03-11 16:20           ` David Kågedal
@ 2008-03-11 16:26             ` Johannes Schindelin
  2008-03-11 16:44               ` David Kågedal
  0 siblings, 1 reply; 29+ messages in thread
From: Johannes Schindelin @ 2008-03-11 16:26 UTC (permalink / raw)
  To: David Kågedal; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 666 bytes --]

Hi,

On Tue, 11 Mar 2008, David Kågedal wrote:

> The following message is a courtesy copy of an article
> that has been posted to gmane.comp.version-control.git as well.

I hate having to readd the Cc: to the list.

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt
> > index d077683..8892cf0 100644
> > --- a/Documentation/technical/api-path-list.txt
> > +++ b/Documentation/technical/api-path-list.txt
> > @@ -1,7 +1,7 @@
> > -path-list API
> > +string-list API
> >  =============
> 
> Looks like you'll want to add two = here.

Yes.

Ciao,
Dscho

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

* Re: [PATCH 1/6] Rename path_list to string_list
  2008-03-11 16:26             ` Johannes Schindelin
@ 2008-03-11 16:44               ` David Kågedal
  0 siblings, 0 replies; 29+ messages in thread
From: David Kågedal @ 2008-03-11 16:44 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> Hi,
>
> On Tue, 11 Mar 2008, David Kågedal wrote:
>
>> The following message is a courtesy copy of an article
>> that has been posted to gmane.comp.version-control.git as well.
>
> I hate having to readd the Cc: to the list.

Sorry about that.

-- 
David Kågedal

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

end of thread, other threads:[~2008-03-11 16:44 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-29  1:44 [PATCH 0/5] Builtin "git remote" Johannes Schindelin
2008-02-29  1:44 ` [PATCH 1/5] path-list: add functions to work with unsorted lists Johannes Schindelin
2008-02-29  2:04   ` Junio C Hamano
2008-02-29  2:15     ` Johannes Schindelin
2008-03-01 13:14       ` [PATCH 0/6] Builtin remote, v2 Johannes Schindelin
2008-03-01 13:15         ` [PATCH 1/6] Rename path_list to string_list Johannes Schindelin
2008-03-11 16:20           ` David Kågedal
2008-03-11 16:26             ` Johannes Schindelin
2008-03-11 16:44               ` David Kågedal
2008-03-01 13:15         ` [PATCH 2/6] string-list: add functions to work with unsorted lists Johannes Schindelin
2008-03-01 13:16         ` [PATCH 3/6] parseopt: add flag to stop on first non option Johannes Schindelin
2008-03-01 13:16         ` [PATCH 4/6] Test "git remote show" and "git remote prune" Johannes Schindelin
2008-03-01 13:16         ` [PATCH 5/6] Make git-remote a builtin Johannes Schindelin
2008-03-01 13:17         ` [PATCH 6/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
2008-02-29  1:45 ` [PATCH 2/5] parseopt: add flag to stop on first non option Johannes Schindelin
2008-02-29  1:45 ` [PATCH 3/5] Test "git remote show" and "git remote prune" Johannes Schindelin
2008-02-29  1:45 ` [PATCH 4/5] Make git-remote a builtin Johannes Schindelin
2008-02-29  1:46 ` [PATCH 5/5] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin
2008-02-29  1:56 ` [PATCH 0/5] Builtin "git remote" Junio C Hamano
2008-02-29  2:13   ` Johannes Schindelin
2008-02-29  2:17   ` Daniel Barkalow
2008-02-29 11:21     ` Johannes Schindelin
2008-03-02 15:15       ` Johannes Schindelin
2008-03-02 15:40         ` Johannes Schindelin
2008-03-02 15:52           ` [PATCH 0/2] format-patch --cover-letter improvements Johannes Schindelin
2008-03-02 15:53             ` [PATCH 1/2] format-patch: use the diff options for the cover letter, too Johannes Schindelin
2008-03-02 15:53             ` [PATCH 2/2] format-patch: wrap cover-letter's shortlog sensibly Johannes Schindelin
2008-03-02 17:05               ` Junio C Hamano
2008-03-02 17:38                 ` 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).