git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3]: add git push --current and remote.*.pushHeadOnly
@ 2009-07-13 23:07 Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 1/3] push: add --current Paolo Bonzini
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Paolo Bonzini @ 2009-07-13 23:07 UTC (permalink / raw)
  To: git

This second series is gets rid of the most annoying part
(IMHO) of push.default = tracking, i.e. the fact that its
behavior cannot be achieved using git's ordinary tools.
While autosetuppush is enough to set the refspecs correctly,
push.tracking does not push _all_ tracked branches, but
only the current one (because it implicitly adds only
one refspec, while autosetuppush places them all in the
configuration).

What I introduce here is "git push --current" and a companion
remote.*.pushHeadOnly option to make it the default.  The
difference between "git push HEAD" and "git push --current"
is that the latter will still walk the remote.*.push refspecs,
but honor only the one matching HEAD.

Together with autosetuppush, this more or less achieves the
same result as push.tracking, at least for newly created
remotes.  A subsequent series will handle the transition.

Patch 1 is the meat of the implementation.  Patch 2 touches
one detail about how to handle "git push --current" when
the remote does not have a corresponding push refspec.
Patch 3 adds remote.*.pushHeadOnly.

Paolo Bonzini (3):
 push: add --current
 change default push refspec when --current is given
 push: add remote.*.pushHeadOnly configuration

 Documentation/config.txt   |    6 ++++
 Documentation/git-push.txt |   15 +++++++++-
 builtin-push.c             |   15 ++++++++--
 http-push.c                |   27 ++++++++++++++----
 remote.c                   |   42 ++++++++++++++++++++++++-----
 remote.h                   |    3 ++
 t/t5516-fetch-push.sh      |   64 ++++++++++++++++++++++++++++++++++++++++++++
 transport.c                |   22 ++++++++++++++-
 transport.h                |    1 +
 9 files changed, 177 insertions(+), 18 deletions(-)

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

* [PATCH 1/3] push: add --current
  2009-07-13 23:07 [PATCH 0/3]: add git push --current and remote.*.pushHeadOnly Paolo Bonzini
@ 2009-07-13 23:07 ` Paolo Bonzini
  2009-07-19 21:32   ` Nanako Shiraishi
  2009-07-13 23:07 ` [PATCH 2/3] change default push refspec when --current is given Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 3/3] push: add remote.*.pushHeadOnly configuration Paolo Bonzini
  2 siblings, 1 reply; 6+ messages in thread
From: Paolo Bonzini @ 2009-07-13 23:07 UTC (permalink / raw)
  To: git

This patch adds the --current option to git-push.  The option restricts
pushing to the current HEAD, even in the presence of wildcard refspecs
in the configuration.  This achieves an effect similar to the "tracking"
value of push.default, in that git push only pushes a subset of the
entire push possibilities (the difference, of course, is that these
are implicitly taken from remote.*.merge in the case of push.default =
tracking).

The option does not make sense, and is thus disabled, if explicit refspecs
are given on the command line.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
	If some of the tests seem dubious, please consider patch 2
	first.  Patch 2 changes some of the semantics to something
	that I consider more intuitive, and adjusts the tests
	correspondingly.

 Documentation/git-push.txt |   11 ++++++++-
 builtin-push.c             |    5 +++-
 http-push.c                |   27 +++++++++++++++++-----
 remote.c                   |   40 +++++++++++++++++++++++++++------
 remote.h                   |    2 +
 t/t5516-fetch-push.sh      |   52 ++++++++++++++++++++++++++++++++++++++++++++
 transport.c                |   22 +++++++++++++++++-
 transport.h                |    1 +
 8 files changed, 144 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 2653388..0d6fcaa 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
 SYNOPSIS
 --------
 [verse]
-'git push' [--all | --mirror | --tags] [--dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --mirror | --tags] [--current] [--dry-run] [--receive-pack=<git-receive-pack>]
 	   [--repo=<repository>] [-f | --force] [-v | --verbose]
 	   [<repository> <refspec>...]
 
@@ -71,6 +71,15 @@ nor in any Push line of the corresponding remotes file---see below).
 	Instead of naming each ref to push, specifies that all
 	refs under `$GIT_DIR/refs/heads/` be pushed.
 
+--current::
+	Independent of the other options, restrict pushing to the current
+	HEAD.
+
+	Refspecs given in the configuration is still used to find the
+	destination name of the current branch.  However, this option
+	cannot be specified if an explicit refspec is given on the
+	command line, because it would be useless and possibly confusing.
+
 --mirror::
 	Instead of naming each ref to push, specifies that all
 	refs under `$GIT_DIR/refs/` (which includes but is not
diff --git a/builtin-push.c b/builtin-push.c
index 0a0297f..8921d53 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-	"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
+	"git push [--all | --mirror] [--current] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
 	NULL,
 };
 
@@ -199,6 +199,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
 			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
+		OPT_BIT( 0 , "current", &flags, "push current HEAD only", TRANSPORT_PUSH_CURRENT),
 		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 		OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
 		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
@@ -210,6 +211,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 
+	if ((argc > 1 || tags) && (flags & TRANSPORT_PUSH_CURRENT))
+		return error ("Cannot give --current together with --tags or a refspec.");
 	if (tags)
 		add_refspec("refs/tags/*");
 
diff --git a/http-push.c b/http-push.c
index 00e83dc..9c93e91 100644
--- a/http-push.c
+++ b/http-push.c
@@ -14,7 +14,7 @@
 #include <expat.h>
 
 static const char http_push_usage[] =
-"git http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
+"git http-push [--all] [--current] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
 
 #ifndef XML_STATUS_OK
 enum XML_Status {
@@ -75,7 +75,7 @@ static int aborted;
 static signed char remote_dir_exists[256];
 
 static int push_verbosely;
-static int push_all = MATCH_REFS_NONE;
+static int match_flags = MATCH_REFS_NONE;
 static int force_all;
 static int dry_run;
 
@@ -1802,7 +1802,11 @@ int main(int argc, char **argv)
 
 		if (*arg == '-') {
 			if (!strcmp(arg, "--all")) {
-				push_all = MATCH_REFS_ALL;
+				match_flags |= MATCH_REFS_ALL;
+				continue;
+			}
+			if (!strcmp(arg, "--current")) {
+				match_flags |= MATCH_REFS_HEAD_ONLY;
 				continue;
 			}
 			if (!strcmp(arg, "--force")) {
@@ -1904,7 +1908,17 @@ int main(int argc, char **argv)
 		fetch_indices();
 
 	/* Get a list of all local and remote heads to validate refspecs */
-	local_refs = get_local_heads();
+	if (match_flags && MATCH_REFS_HEAD_ONLY) {
+		local_refs = get_current_head();
+		if (!local_refs) {
+			fprintf(stderr, "--current specified with no current branch.\n");
+			rc = -1;
+			goto cleanup;
+		}
+	}
+	else
+		local_refs = get_local_heads();
+
 	fprintf(stderr, "Fetching remote heads...\n");
 	get_dav_remote_heads();
 	run_request_queue();
@@ -1919,7 +1933,7 @@ int main(int argc, char **argv)
 
 	/* match them up */
 	if (match_refs(local_refs, &remote_refs,
-		       nr_refspec, (const char **) refspec, push_all)) {
+		       nr_refspec, (const char **) refspec, match_flags)) {
 		rc = -1;
 		goto cleanup;
 	}
@@ -2005,7 +2019,8 @@ int main(int argc, char **argv)
 		old_sha1_hex = NULL;
 		commit_argv[1] = "--objects";
 		commit_argv[2] = new_sha1_hex;
-		if (!push_all && !is_null_sha1(ref->old_sha1)) {
+		if (!(match_flags & MATCH_REFS_ALL)
+		    && !is_null_sha1(ref->old_sha1)) {
 			old_sha1_hex = xmalloc(42);
 			sprintf(old_sha1_hex, "^%s",
 				sha1_to_hex(ref->old_sha1));
diff --git a/remote.c b/remote.c
index c3ada2d..b5bf9a6 100644
--- a/remote.c
+++ b/remote.c
@@ -990,7 +990,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 
 static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
-			  struct refspec *rs)
+			  struct refspec *rs, int head_only)
 {
 	struct ref *matched_src, *matched_dst;
 	int copy_src;
@@ -1007,14 +1007,26 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		copy_src = 1;
 		break;
 	case 0:
-		/* The source could be in the get_sha1() format
+		/*
+		 * The source could be in the get_sha1() format
 		 * not a reference name.  :refs/other is a
 		 * way to delete 'other' ref at the remote end.
+		 * This case however could cause unwanted references
+		 * to be stored in matched_dst->peer_ref for --current.
+		 * In that case, all we can/want handle is HEAD.
 		 */
-		matched_src = try_explicit_object_name(rs->src);
+		if (head_only) {
+			assert (!src->next);
+			if (strcmp(rs->src, "HEAD"))
+				return 0;
+			matched_src = src;
+			copy_src = 1;
+		} else {
+			matched_src = try_explicit_object_name(rs->src);
+			copy_src = 0;
+		}
 		if (!matched_src)
 			return error("src refspec %s does not match any.", rs->src);
-		copy_src = 0;
 		break;
 	default:
 		return error("src refspec %s matches more than one.", rs->src);
@@ -1068,11 +1080,11 @@ static int match_explicit(struct ref *src, struct ref *dst,
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
 			       struct ref ***dst_tail, struct refspec *rs,
-			       int rs_nr)
+			       int rs_nr, int head_only)
 {
 	int i, errs;
 	for (i = errs = 0; i < rs_nr; i++)
-		errs += match_explicit(src, dst, dst_tail, &rs[i]);
+		errs += match_explicit(src, dst, dst_tail, &rs[i], head_only);
 	return errs;
 }
 
@@ -1118,6 +1130,7 @@ int match_refs(struct ref *src, struct ref **dst,
 	struct refspec *rs;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
+	int head_only = flags & MATCH_REFS_HEAD_ONLY;
 	int errs;
 	static const char *default_refspec[] = { ":", NULL };
 	struct ref **dst_tail = tail_ref(dst);
@@ -1127,7 +1140,8 @@ int match_refs(struct ref *src, struct ref **dst,
 		refspec = default_refspec;
 	}
 	rs = parse_push_refspec(nr_refspec, (const char **) refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
+	errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec,
+				   head_only);
 
 	/* pick the remainder */
 	for ( ; src; src = src->next) {
@@ -1527,6 +1541,18 @@ struct ref *get_local_heads(void)
 	return local_refs;
 }
 
+struct ref *get_current_head(void)
+{
+	struct ref *local_refs = NULL, **local_tail = &local_refs;
+	struct branch *branch = branch_get(NULL);
+	unsigned char sha1[20];
+	if (branch) {
+		get_sha1(branch->refname, sha1);
+		one_local_ref(branch->refname, sha1, 0, &local_tail);
+	}
+	return local_refs;
+}
+
 struct ref *guess_remote_head(const struct ref *head,
 			      const struct ref *refs,
 			      int all)
diff --git a/remote.h b/remote.h
index 5db8420..8e5d5b4 100644
--- a/remote.h
+++ b/remote.h
@@ -137,6 +137,7 @@ enum match_refs_flags {
 	MATCH_REFS_NONE		= 0,
 	MATCH_REFS_ALL 		= (1 << 0),
 	MATCH_REFS_MIRROR	= (1 << 1),
+	MATCH_REFS_HEAD_ONLY	= (1 << 2),
 };
 
 /* Reporting of tracking info */
@@ -144,6 +145,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);
 int format_tracking_info(struct branch *branch, struct strbuf *sb);
 
 struct ref *get_local_heads(void);
+struct ref *get_current_head(void);
 /*
  * Find refs from a list which are likely to be pointed to by the given HEAD
  * ref. If 'all' is false, returns the most likely ref; otherwise, returns a
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 2d2633f..3333ce9 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -586,4 +586,56 @@ test_expect_success 'push with branches containing #' '
 	git checkout master
 '
 
+test_expect_success 'push --current fails on empty repository' '
+	git init &&
+	mkdir b.git &&
+	(cd b.git && git init --bare) &&
+	echo a > b &&
+	git add b &&
+	git commit -m a &&
+	git checkout -b branch &&
+	echo bb > b &&
+	git add b &&
+	git commit -m branch &&
+	git checkout master &&
+	! git push --current b.git
+'
+
+test_expect_success 'push --current succeeds when push is configured' '
+	git config remote.bremote.url b.git &&
+	git config remote.bremote.push refs/heads/master:refs/heads/master &&
+	git push --current bremote &&
+	test `git rev-parse master` = `cd b.git && git rev-parse master`
+'
+
+test_expect_success 'push --current does nothing when current branch does not exist' '
+	git checkout branch &&
+	git push --current b.git 2>&1 | grep "Everything up-to-date" &&
+	git push b.git branch
+'
+
+test_expect_success 'push --current does not push other branches' '
+	git checkout master &&
+	echo aa > b &&
+	git commit -m master2 b &&
+	git checkout branch &&
+	git push --current b.git 2>&1 | grep "Everything up-to-date" &&
+	test `git rev-parse master^` = `cd b.git && git rev-parse master`
+'
+
+test_expect_success 'push --current does update the current branches' '
+	echo cc > b &&
+	git commit -m branch2 b &&
+	git checkout master &&
+	git push --current b.git &&
+	test `git rev-parse master` = `cd b.git && git rev-parse master` &&
+	test `git rev-parse branch^` = `cd b.git && git rev-parse branch`
+'
+
+test_expect_success 'push --current respects configuration' '
+	git checkout branch &&
+	git push --current bremote 2>&1 | grep "Everything up-to-date" &&
+	test `git rev-parse branch^` = `cd b.git && git rev-parse branch`
+'
+
 test_done
diff --git a/transport.c b/transport.c
index de0d587..c7b6aaa 100644
--- a/transport.c
+++ b/transport.c
@@ -327,6 +327,11 @@ static int rsync_transport_push(struct transport *transport,
 	if (flags & TRANSPORT_PUSH_ALL) {
 		if (for_each_ref(write_one_ref, &temp_dir))
 			return -1;
+	} else if (flags & TRANSPORT_PUSH_CURRENT) {
+		struct branch *branch = branch_get(NULL);
+		unsigned char sha1[20];
+		get_sha1(branch->name, sha1);
+		write_one_ref(branch->name, sha1, 0, &temp_dir);
 	} else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec))
 		return -1;
 
@@ -406,6 +411,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
 	argc = 1;
 	if (flags & TRANSPORT_PUSH_ALL)
 		argv[argc++] = "--all";
+	if (flags & TRANSPORT_PUSH_CURRENT)
+		argv[argc++] = "--current";
 	if (flags & TRANSPORT_PUSH_FORCE)
 		argv[argc++] = "--force";
 	if (flags & TRANSPORT_PUSH_DRY_RUN)
@@ -1001,12 +1008,19 @@ int transport_push(struct transport *transport,
 {
 	verify_remote_names(refspec_nr, refspec);
 
+	if (flags & TRANSPORT_PUSH_CURRENT) {
+		struct branch *branch = branch_get(NULL);
+		if (!branch)
+			return error("Tried to push current branch, but there "
+				     "is no current branch!");
+	}
+
 	if (transport->push)
 		return transport->push(transport, refspec_nr, refspec, flags);
 	if (transport->push_refs) {
 		struct ref *remote_refs =
 			transport->get_refs_list(transport, 1);
-		struct ref *local_refs = get_local_heads();
+		struct ref *local_refs;
 		int match_flags = MATCH_REFS_NONE;
 		int verbose = flags & TRANSPORT_PUSH_VERBOSE;
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
@@ -1017,6 +1031,12 @@ int transport_push(struct transport *transport,
 		if (flags & TRANSPORT_PUSH_MIRROR)
 			match_flags |= MATCH_REFS_MIRROR;
 
+		if (flags & TRANSPORT_PUSH_CURRENT) {
+			local_refs = get_current_head();
+			match_flags |= MATCH_REFS_HEAD_ONLY;
+		} else
+			local_refs = get_local_heads();
+
 		if (match_refs(local_refs, &remote_refs,
 			       refspec_nr, refspec, match_flags)) {
 			return -1;
diff --git a/transport.h b/transport.h
index 51b5397..62aa243 100644
--- a/transport.h
+++ b/transport.h
@@ -36,6 +36,7 @@ struct transport {
 #define TRANSPORT_PUSH_MIRROR 8
 #define TRANSPORT_PUSH_VERBOSE 16
 #define TRANSPORT_PUSH_PORCELAIN 32
+#define TRANSPORT_PUSH_CURRENT 64
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
-- 
1.6.2.5

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

* [PATCH 2/3] change default push refspec when --current is given
  2009-07-13 23:07 [PATCH 0/3]: add git push --current and remote.*.pushHeadOnly Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 1/3] push: add --current Paolo Bonzini
@ 2009-07-13 23:07 ` Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 3/3] push: add remote.*.pushHeadOnly configuration Paolo Bonzini
  2 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2009-07-13 23:07 UTC (permalink / raw)
  To: git

This patch is separate because I find it a little more controversial.
Actually, after writing the tests I am pretty sure that it results
in a more intuitive behavior, but keeping it separate also makes it
clearer to see the effect of the patch (from the changes to the
testsuite).

With this patch, if there is no push.default specified I make the
default push refspec "HEAD".  This conforms to the idea of pushing
the current branch only.

The main effect of the patch is that, in a normal configuration,
"git push --current FOO" will *not* give an error when pushing to
an empty destination.  Instead, it will obviously push the current
branch to the destination, with the same name.  I find this quite
intuitive.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
	Actually, I'm pretty sure that the behavior after patch 1 is
	more or less "wrong".

	The reason why I split this patch is that I'm undecided whether
	to do something even more Draconian: when --current is used,
	*always* use a default refspec of HEAD, even when push.default
	is set.  I somehow felt this was more correct, yet I didn't do it
	for three reasons.  Together, these were enough to discourage
	me:

	1) it would have been more complicated to document, even though
	easier to code;

	2) this only affects one case, i.e. pushing a new branch;

	3) I want to implement "git remote add
	--push={matching,current,tracking}" as the next step; this will
	automatically a remote.*.push=HEAD line when appropriate.

	This means that in practice nobody will see the difference
	assuming I get to (3) before 1.6.5 or something like that.

 Documentation/git-push.txt |    6 +++++-
 builtin-push.c             |    8 ++++++--
 t/t5516-fetch-push.sh      |   20 +++++++++-----------
 3 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 0d6fcaa..ce6133e 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -75,11 +75,15 @@ nor in any Push line of the corresponding remotes file---see below).
 	Independent of the other options, restrict pushing to the current
 	HEAD.
 
-	Refspecs given in the configuration is still used to find the
+	Refspecs given in the configuration are still used to find the
 	destination name of the current branch.  However, this option
 	cannot be specified if an explicit refspec is given on the
 	command line, because it would be useless and possibly confusing.
 
+	Additionally, if there is no refspec in the configuration and no
+	`push.default` configuration either, with this option git will
+	use a default refspec of `HEAD` rather than `:`.
+
 --mirror::
 	Instead of naming each ref to push, specifies that all
 	refs under `$GIT_DIR/refs/` (which includes but is not
diff --git a/builtin-push.c b/builtin-push.c
index 8921d53..2911513 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -88,7 +88,6 @@ static void warn_unconfigured_push(void)
 
 static void setup_default_push_refspecs(void)
 {
-	git_config(git_default_config, NULL);
 	switch (push_default) {
 	case PUSH_DEFAULT_UNSPECIFIED:
 		warn_unconfigured_push();
@@ -150,8 +149,13 @@ static int do_push(const char *repo, int flags)
 		if (remote->push_refspec_nr) {
 			refspec = remote->push_refspec;
 			refspec_nr = remote->push_refspec_nr;
-		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
+		} else if (!(flags & TRANSPORT_PUSH_MIRROR)) {
+			push_default = (flags & TRANSPORT_PUSH_CURRENT
+					? PUSH_DEFAULT_CURRENT
+					: PUSH_DEFAULT_UNSPECIFIED);
+			git_config(git_default_config, NULL);
 			setup_default_push_refspecs();
+		}
 	}
 	errs = 0;
 	if (remote->pushurl_nr) {
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 3333ce9..bdc98ec 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -586,7 +586,7 @@ test_expect_success 'push with branches containing #' '
 	git checkout master
 '
 
-test_expect_success 'push --current fails on empty repository' '
+test_expect_success 'push --current succeeds on empty repository' '
 	git init &&
 	mkdir b.git &&
 	(cd b.git && git init --bare) &&
@@ -598,20 +598,14 @@ test_expect_success 'push --current succeeds on empty repository' '
 	git add b &&
 	git commit -m branch &&
 	git checkout master &&
-	! git push --current b.git
-'
-
-test_expect_success 'push --current succeeds when push is configured' '
-	git config remote.bremote.url b.git &&
-	git config remote.bremote.push refs/heads/master:refs/heads/master &&
-	git push --current bremote &&
+	git push --current b.git
 	test `git rev-parse master` = `cd b.git && git rev-parse master`
 '
 
-test_expect_success 'push --current does nothing when current branch does not exist' '
+test_expect_success 'push --current always creates current branch' '
 	git checkout branch &&
-	git push --current b.git 2>&1 | grep "Everything up-to-date" &&
-	git push b.git branch
+	git push --current b.git &&
+	test `git rev-parse branch` = `cd b.git && git rev-parse branch`
 '
 
 test_expect_success 'push --current does not push other branches' '
@@ -633,6 +627,10 @@ test_expect_success 'push --current does update the current branches' '
 '
 
 test_expect_success 'push --current respects configuration' '
+	git config remote.bremote.url b.git &&
+	git config remote.bremote.push refs/heads/master:refs/heads/master2 &&
+	git push --current bremote &&
+	test `git rev-parse master` = `cd b.git && git rev-parse master2`
 	git checkout branch &&
 	git push --current bremote 2>&1 | grep "Everything up-to-date" &&
 	test `git rev-parse branch^` = `cd b.git && git rev-parse branch`
-- 
1.6.2.5

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

* [PATCH 3/3] push: add remote.*.pushHeadOnly configuration
  2009-07-13 23:07 [PATCH 0/3]: add git push --current and remote.*.pushHeadOnly Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 1/3] push: add --current Paolo Bonzini
  2009-07-13 23:07 ` [PATCH 2/3] change default push refspec when --current is given Paolo Bonzini
@ 2009-07-13 23:07 ` Paolo Bonzini
  2 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2009-07-13 23:07 UTC (permalink / raw)
  To: git

This patch adds a remote.*.pushHeadOnly configuration that automatically
enables (when possible) the --current option to git push.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 Documentation/config.txt |    6 ++++++
 builtin-push.c           |    2 ++
 remote.c                 |    2 ++
 remote.h                 |    1 +
 t/t5516-fetch-push.sh    |   16 +++++++++++++++-
 5 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index cb6832b..4ab5593 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1359,6 +1359,12 @@ remote.<name>.uploadpack::
 	The default program to execute on the remote side when fetching.  See
 	option \--upload-pack of linkgit:git-fetch-pack[1].
 
+remote.<name>.pushHeadOnly::
+	If true, whenever `git push` is invoked without a refspec and
+	it will try pushing to this remote, `git push` will automatically
+	behave as if the `\--current` option was given on the command line.
+	In other words, only the current branch is pushed to the remote.
+
 remote.<name>.tagopt::
 	Setting this value to \--no-tags disables automatic tag following when
 	fetching from remote <name>
diff --git a/builtin-push.c b/builtin-push.c
index 2911513..fcecd14 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -127,6 +127,8 @@ static int do_push(const char *repo, int flags)
 
 	if (remote->mirror)
 		flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
+	if (remote->push_head_only && !refspec_nr)
+		flags |= TRANSPORT_PUSH_CURRENT;
 
 	if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
 		if (!strcmp(*refspec, "refs/tags/*"))
diff --git a/remote.c b/remote.c
index b5bf9a6..d46dc0d 100644
--- a/remote.c
+++ b/remote.c
@@ -379,6 +379,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 		remote->mirror = git_config_bool(key, value);
 	else if (!strcmp(subkey, ".skipdefaultupdate"))
 		remote->skip_default_update = git_config_bool(key, value);
+	else if (!strcmp(subkey, ".pushheadonly"))
+		remote->push_head_only = git_config_bool(key, value);
 
 	else if (!strcmp(subkey, ".url")) {
 		const char *v;
diff --git a/remote.h b/remote.h
index 8e5d5b4..b1e3e99 100644
--- a/remote.h
+++ b/remote.h
@@ -36,6 +36,7 @@ struct remote {
 	 * 2 to always fetch tags
 	 */
 	int fetch_tags;
+	int push_head_only;
 	int skip_default_update;
 	int mirror;
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index bdc98ec..eee9e00 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -631,9 +631,23 @@ test_expect_success 'push --current respects configuration' '
 	git config remote.bremote.push refs/heads/master:refs/heads/master2 &&
 	git push --current bremote &&
 	test `git rev-parse master` = `cd b.git && git rev-parse master2`
+'
+
+test_expect_success 'remote.*.pushHeadOnly respects configuration' '
+	echo xx > b &&
+	git commit -mmaster3 b &&
+	git config remote.bremote.pushHeadOnly true &&
 	git checkout branch &&
-	git push --current bremote 2>&1 | grep "Everything up-to-date" &&
+	git push bremote &&
+	test `git rev-parse master^` = `cd b.git && git rev-parse master` &&
 	test `git rev-parse branch^` = `cd b.git && git rev-parse branch`
 '
 
+test_expect_success 'remote.*.pushHeadOnly works' '
+	git config --unset remote.bremote.push &&
+	git push bremote &&
+	test `git rev-parse master^` = `cd b.git && git rev-parse master` &&
+	test `git rev-parse branch` = `cd b.git && git rev-parse branch`
+'
+
 test_done
-- 
1.6.2.5

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

* Re: [PATCH 1/3] push: add --current
  2009-07-13 23:07 ` [PATCH 1/3] push: add --current Paolo Bonzini
@ 2009-07-19 21:32   ` Nanako Shiraishi
  2009-07-19 21:46     ` Paolo Bonzini
  0 siblings, 1 reply; 6+ messages in thread
From: Nanako Shiraishi @ 2009-07-19 21:32 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: git

Quoting Paolo Bonzini <bonzini@gnu.org>:

> diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
> index 2653388..0d6fcaa 100644
> --- a/Documentation/git-push.txt
> +++ b/Documentation/git-push.txt
> @@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
>  SYNOPSIS
>  --------
>  [verse]
> -'git push' [--all | --mirror | --tags] [--dry-run] [--receive-pack=<git-receive-pack>]
> +'git push' [--all | --mirror | --tags] [--current] [--dry-run] [--receive-pack=<git-receive-pack>]

Shouldn't this be "[--all | --mirror | --tags | --current]" instead? In other words, does it make sense to say "git push --all --current"?

> @@ -71,6 +71,15 @@ nor in any Push line of the corresponding remotes file---see below).
>  	Instead of naming each ref to push, specifies that all
>  	refs under `$GIT_DIR/refs/heads/` be pushed.
>  
> +--current::
> +	Independent of the other options, restrict pushing to the current
> +	HEAD.
> +
> +	Refspecs given in the configuration is still used to find the
> +	destination name of the current branch.  However, this option
> +	cannot be specified if an explicit refspec is given on the
> +	command line, because it would be useless and possibly confusing.
> +

The second and subsequent paragraphs must be dedented, and the blank line between paragraphs should be replaced by a single line with '+' on it. You can find examples in the same file (e.g. description of <refspec>).

Instead of correcting a grammatical error you made here in patch 1/3 with a later patch 2/3, please fix it here.

> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
> index 2d2633f..3333ce9 100755
> --- a/t/t5516-fetch-push.sh
> +++ b/t/t5516-fetch-push.sh
> @@ -586,4 +586,56 @@ test_expect_success 'push with branches containing #' '
>  	git checkout master
>  '
>  
> +test_expect_success 'push --current fails on empty repository' '
> +	git init &&
> +	mkdir b.git &&
> +	(cd b.git && git init --bare) &&
> +	echo a > b &&
> +	git add b &&
> +	git commit -m a &&
> +	git checkout -b branch &&
> +	echo bb > b &&
> +	git add b &&
> +	git commit -m branch &&
> +	git checkout master &&
> +	! git push --current b.git
> +'

If your final belief (which I happen to agree) is that

% git push --current
% git push --current origin
% git push --current over.there.example.com:project.git

should work as expected (that is, they should push the current branch to the same name) from a repository without any special configuration, don't say "push --current fails" on the title as if you think it is the right thing to do.

Instead, mark clearly that the code after this patch is still broken, like this:

	test_expect_failure 'push --current into an empty repository' '
		...
                git push --current b.git
	'

and change expect_failure to expect_success in the later patch that fixes the breakage.

> +test_expect_success 'push --current succeeds when push is configured' '
> +	git config remote.bremote.url b.git &&
> +	git config remote.bremote.push refs/heads/master:refs/heads/master &&
> +	git push --current bremote &&
> +	test `git rev-parse master` = `cd b.git && git rev-parse master`
> +'

The style of the existing tests in the script isn't

	test `git rev-parse master` = `cd b.git && git rev-parse master`

but is

	test "$(git rev-parse master)" = "$(cd b.git && git rev-parse master)"

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

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

* Re: [PATCH 1/3] push: add --current
  2009-07-19 21:32   ` Nanako Shiraishi
@ 2009-07-19 21:46     ` Paolo Bonzini
  0 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2009-07-19 21:46 UTC (permalink / raw)
  To: Nanako Shiraishi; +Cc: git

Thanks for the review!

> If your final belief (which I happen to agree) is that
> 
> % git push --current
> % git push --current origin
> % git push --current over.there.example.com:project.git
> 
> should work as expected [...] mark clearly that the code after this patch is still broken

Okay, will do.  I just wanted to present both possibilities and thought
that (succeeding) tests were the best way to illustrate the difference.
 For the final submission, now that I had a second opinion, I'll
probably just squash 1/3 and 2/3 together.

> The style of the existing tests in the script isn't
> 
> 	test `git rev-parse master` = `cd b.git && git rev-parse master`
> 
> but is
> 
> 	test "$(git rev-parse master)" = "$(cd b.git && git rev-parse master)"

Will do.

Paolo

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

end of thread, other threads:[~2009-07-19 21:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-13 23:07 [PATCH 0/3]: add git push --current and remote.*.pushHeadOnly Paolo Bonzini
2009-07-13 23:07 ` [PATCH 1/3] push: add --current Paolo Bonzini
2009-07-19 21:32   ` Nanako Shiraishi
2009-07-19 21:46     ` Paolo Bonzini
2009-07-13 23:07 ` [PATCH 2/3] change default push refspec when --current is given Paolo Bonzini
2009-07-13 23:07 ` [PATCH 3/3] push: add remote.*.pushHeadOnly configuration Paolo Bonzini

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 NNTP newsgroup(s).