From 0ecfcb3b700e7e3097a55f015894ad75f1097090 Mon Sep 17 00:00:00 2001
From: Olivier Marin <dkr@freesurf.fr>
Date: Tue, 10 Jun 2008 16:51:08 +0200
Subject: [PATCH 1/5] remote show: fix the -n option

The perl version accepted a -n flag, to show local informations only
without querying remote heads, that seems to have been lost in the C
revrite.

This restores the older behaviour and add a test case.

Signed-off-by: Olivier Marin <dkr@freesurf.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-remote.txt |  2 +-
 builtin-remote.c             | 44 +++++++++++++++++++-----------------
 t/t5505-remote.sh            | 17 ++++++++++++++
 3 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 782b0554cf..7bd024eeba 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -12,7 +12,7 @@ SYNOPSIS
 'git-remote' [-v | --verbose]
 'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
 'git-remote' rm <name>
-'git-remote' show <name>
+'git-remote' show [-n] <name>
 'git-remote' prune <name>
 'git-remote' update [group]
 
diff --git a/builtin-remote.c b/builtin-remote.c
index c49f00f58b..efe74c7d5d 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -421,10 +421,10 @@ static void show_list(const char *title, struct path_list *list)
 
 static int show_or_prune(int argc, const char **argv, int prune)
 {
-	int dry_run = 0, result = 0;
+	int no_query = 0, result = 0;
 	struct option options[] = {
 		OPT_GROUP("show specific options"),
-		OPT__DRY_RUN(&dry_run),
+		OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
 		OPT_END()
 	};
 	struct ref_states states;
@@ -442,21 +442,23 @@ static int show_or_prune(int argc, const char **argv, int prune)
 		struct transport *transport;
 		const struct ref *ref;
 		struct strbuf buf;
-		int i, got_states;
+		int i;
 
 		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);
-		transport_disconnect(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 (!no_query) {
+			transport = transport_get(NULL,
+				states.remote->url_nr > 0 ?
+				states.remote->url[0] : NULL);
+			ref = transport_get_remote_refs(transport);
+			transport_disconnect(transport);
+
+			get_ref_states(ref, &states);
+		}
 
 		if (prune) {
 			for (i = 0; i < states.stale.nr; i++) {
@@ -486,17 +488,17 @@ static int show_or_prune(int argc, const char **argv, int prune)
 			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",
+		if (!no_query) {
+			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   ",
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 0d7ed1f99b..c6a7bfb448 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -138,6 +138,23 @@ test_expect_success 'show' '
 	 test_cmp expect output)
 '
 
+cat > test/expect << EOF
+* remote origin
+  URL: $(pwd)/one/.git
+  Remote branch merged with 'git pull' while on branch master
+    master
+  Local branches pushed with 'git push'
+    master:upstream +refs/tags/lastbackup
+EOF
+
+test_expect_success 'show -n' '
+	(mv one one.unreachable &&
+	 cd test &&
+	 git remote show -n origin > output &&
+	 mv ../one.unreachable ../one &&
+	 test_cmp expect output)
+'
+
 test_expect_success 'prune' '
 	(cd one &&
 	 git branch -m side side2) &&

From 67a7e2d07162dc470f7e3ae1889aad146e5b7917 Mon Sep 17 00:00:00 2001
From: Olivier Marin <dkr@freesurf.fr>
Date: Tue, 10 Jun 2008 16:51:21 +0200
Subject: [PATCH 2/5] builtin-remote: split show_or_prune() in two separate
 functions

This allow us to add different features to each of them and keep the
code simple at the same time. Also create a get_remote_ref_states()
to avoid duplicated code.

Signed-off-by: Olivier Marin <dkr@freesurf.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-remote.c | 101 +++++++++++++++++++++++++++++++----------------
 1 file changed, 67 insertions(+), 34 deletions(-)

diff --git a/builtin-remote.c b/builtin-remote.c
index efe74c7d5d..745a4ee6c5 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -419,7 +419,32 @@ static void show_list(const char *title, struct path_list *list)
 	printf("\n");
 }
 
-static int show_or_prune(int argc, const char **argv, int prune)
+static int get_remote_ref_states(const char *name,
+				 struct ref_states *states,
+				 int query)
+{
+	struct transport *transport;
+	const struct ref *ref;
+
+	states->remote = remote_get(name);
+	if (!states->remote)
+		return error("No such remote: %s", name);
+
+	read_branches();
+
+	if (query) {
+		transport = transport_get(NULL, states->remote->url_nr > 0 ?
+			states->remote->url[0] : NULL);
+		ref = transport_get_remote_refs(transport);
+		transport_disconnect(transport);
+
+		get_ref_states(ref, states);
+	}
+
+	return 0;
+}
+
+static int show(int argc, const char **argv)
 {
 	int no_query = 0, result = 0;
 	struct option options[] = {
@@ -431,42 +456,15 @@ static int show_or_prune(int argc, const char **argv, int prune)
 
 	argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
 
-	if (argc < 1) {
-		if (!prune)
-			return show_all();
-		usage_with_options(builtin_remote_usage, options);
-	}
+	if (argc < 1)
+		return show_all();
 
 	memset(&states, 0, sizeof(states));
 	for (; argc; argc--, argv++) {
-		struct transport *transport;
-		const struct ref *ref;
 		struct strbuf buf;
 		int i;
 
-		states.remote = remote_get(*argv);
-		if (!states.remote)
-			return error("No such remote: %s", *argv);
-
-		read_branches();
-
-		if (!no_query) {
-			transport = transport_get(NULL,
-				states.remote->url_nr > 0 ?
-				states.remote->url[0] : NULL);
-			ref = transport_get_remote_refs(transport);
-			transport_disconnect(transport);
-
-			get_ref_states(ref, &states);
-		}
-
-		if (prune) {
-			for (i = 0; i < states.stale.nr; i++) {
-				const char *refname = states.stale.items[i].util;
-				result |= delete_ref(refname, NULL);
-			}
-			goto cleanup_states;
-		}
+		get_remote_ref_states(*argv, &states, !no_query);
 
 		printf("* remote %s\n  URL: %s\n", *argv,
 			states.remote->url_nr > 0 ?
@@ -513,7 +511,42 @@ static int show_or_prune(int argc, const char **argv, int prune)
 			}
 			printf("\n");
 		}
-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 prune(int argc, const char **argv)
+{
+	int no_query = 0, result = 0;
+	struct option options[] = {
+		OPT_GROUP("prune specific options"),
+		OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
+		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++) {
+		int i;
+
+		get_remote_ref_states(*argv, &states, !no_query);
+
+		for (i = 0; i < states.stale.nr; i++) {
+			const char *refname = states.stale.items[i].util;
+			result |= delete_ref(refname, NULL);
+		}
+
 		/* NEEDSWORK: free remote */
 		path_list_clear(&states.new, 0);
 		path_list_clear(&states.stale, 0);
@@ -634,9 +667,9 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
 	else if (!strcmp(argv[0], "rm"))
 		result = rm(argc, argv);
 	else if (!strcmp(argv[0], "show"))
-		result = show_or_prune(argc, argv, 0);
+		result = show(argc, argv);
 	else if (!strcmp(argv[0], "prune"))
-		result = show_or_prune(argc, argv, 1);
+		result = prune(argc, argv);
 	else if (!strcmp(argv[0], "update"))
 		result = update(argc, argv);
 	else {

From 8d7679276af861b44e307c9879f6c4774f4944fc Mon Sep 17 00:00:00 2001
From: Olivier Marin <dkr@freesurf.fr>
Date: Tue, 10 Jun 2008 16:51:35 +0200
Subject: [PATCH 3/5] remote prune: print the list of pruned branches

This command is really too quiet which make it unconfortable to use.

Also implement a --dry-run option, in place of the original -n one, to
list stale tracking branches that will be pruned, but do not actually
prune them.

Add a test case for --dry-run.

Signed-off-by: Olivier Marin <dkr@freesurf.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-remote.txt |  7 +++----
 builtin-remote.c             | 20 ++++++++++++++++----
 t/t5505-remote.sh            | 18 ++++++++++++++++++
 3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 7bd024eeba..345943a264 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
 'git-remote' rm <name>
 'git-remote' show [-n] <name>
-'git-remote' prune <name>
+'git-remote' prune [-n | --dry-run] <name>
 'git-remote' update [group]
 
 DESCRIPTION
@@ -80,9 +80,8 @@ These stale branches have already been removed from the remote repository
 referenced by <name>, but are still locally available in
 "remotes/<name>".
 +
-With `-n` option, the remote heads are not confirmed first with `git
-ls-remote <name>`; cached information is used instead.  Use with
-caution.
+With `--dry-run` option, report what branches will be pruned, but do no
+actually prune them.
 
 'update'::
 
diff --git a/builtin-remote.c b/builtin-remote.c
index 745a4ee6c5..6bce55cd53 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -523,10 +523,10 @@ static int show(int argc, const char **argv)
 
 static int prune(int argc, const char **argv)
 {
-	int no_query = 0, result = 0;
+	int dry_run = 0, result = 0;
 	struct option options[] = {
 		OPT_GROUP("prune specific options"),
-		OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
+		OPT__DRY_RUN(&dry_run),
 		OPT_END()
 	};
 	struct ref_states states;
@@ -540,11 +540,23 @@ static int prune(int argc, const char **argv)
 	for (; argc; argc--, argv++) {
 		int i;
 
-		get_remote_ref_states(*argv, &states, !no_query);
+		get_remote_ref_states(*argv, &states, 1);
+
+		printf("Pruning %s\n", *argv);
+		if (states.stale.nr)
+			printf("URL: %s\n",
+			       states.remote->url_nr
+			       ? states.remote->url[0]
+			       : "(no URL)");
 
 		for (i = 0; i < states.stale.nr; i++) {
 			const char *refname = states.stale.items[i].util;
-			result |= delete_ref(refname, NULL);
+
+			if (!dry_run)
+				result |= delete_ref(refname, NULL);
+
+			printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
+			       skip_prefix(refname, "refs/remotes/"));
 		}
 
 		/* NEEDSWORK: free remote */
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index c6a7bfb448..c17d9dcc74 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -165,6 +165,24 @@ test_expect_success 'prune' '
 	 ! git rev-parse refs/remotes/origin/side)
 '
 
+cat > test/expect << EOF
+Pruning origin
+URL: $(pwd)/one/.git
+ * [would prune] origin/side2
+EOF
+
+test_expect_success 'prune --dry-run' '
+	(cd one &&
+	 git branch -m side2 side) &&
+	(cd test &&
+	 git remote prune --dry-run origin > output &&
+	 git rev-parse refs/remotes/origin/side2 &&
+	 ! git rev-parse refs/remotes/origin/side &&
+	(cd ../one &&
+	 git branch -m side side2) &&
+	 test_cmp expect output)
+'
+
 test_expect_success 'add --mirror && prune' '
 	(mkdir mirror &&
 	 cd mirror &&

From e7d5a97d5e131925ccae48db94f2069631a8aa41 Mon Sep 17 00:00:00 2001
From: Olivier Marin <dkr@freesurf.fr>
Date: Wed, 11 Jun 2008 00:54:49 +0200
Subject: [PATCH 4/5] remote show: list tracked remote branches with -n

Signed-off-by: Olivier Marin <dkr@freesurf.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-remote.c  | 22 ++++++++++++++++++++--
 t/t5505-remote.sh |  2 ++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/builtin-remote.c b/builtin-remote.c
index 6bce55cd53..4b00cf9258 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -444,6 +444,22 @@ static int get_remote_ref_states(const char *name,
 	return 0;
 }
 
+static int append_ref_to_tracked_list(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)) {
+		path_list_append(skip_prefix(refspec.src, "refs/heads/"),
+			&states->tracked);
+	}
+
+	return 0;
+}
+
 static int show(int argc, const char **argv)
 {
 	int no_query = 0, result = 0;
@@ -494,10 +510,12 @@ static int show(int argc, const char **argv)
 			strbuf_release(&buf);
 			show_list("  Stale tracking branch%s (use 'git remote "
 				"prune')", &states.stale);
-			show_list("  Tracked remote branch%s",
-				&states.tracked);
 		}
 
+		if (no_query)
+			for_each_ref(append_ref_to_tracked_list, &states);
+		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 ?
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index c17d9dcc74..1e192a2207 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -143,6 +143,8 @@ cat > test/expect << EOF
   URL: $(pwd)/one/.git
   Remote branch merged with 'git pull' while on branch master
     master
+  Tracked remote branches
+    master side
   Local branches pushed with 'git push'
     master:upstream +refs/tags/lastbackup
 EOF

From 8b7d4e738ee5489fecb5c4a55d14884b09e0dc6d Mon Sep 17 00:00:00 2001
From: Junio C Hamano <gitster@pobox.com>
Date: Wed, 11 Jun 2008 23:43:25 -0700
Subject: [PATCH 5/5] "remote prune": be quiet when there is nothing to prune

The previous commit made it always say "Pruning $remote" but reported the
URL only when there is something to prune.  Make it consistent by not
saying anything at all when there is nothing to prune.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-remote.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/builtin-remote.c b/builtin-remote.c
index 4b00cf9258..145dd8568c 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -560,12 +560,13 @@ static int prune(int argc, const char **argv)
 
 		get_remote_ref_states(*argv, &states, 1);
 
-		printf("Pruning %s\n", *argv);
-		if (states.stale.nr)
+		if (states.stale.nr) {
+			printf("Pruning %s\n", *argv);
 			printf("URL: %s\n",
 			       states.remote->url_nr
 			       ? states.remote->url[0]
 			       : "(no URL)");
+		}
 
 		for (i = 0; i < states.stale.nr; i++) {
 			const char *refname = states.stale.items[i].util;