From 35ee69c0f6c77f293b66125d334467d9692ef866 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Thu, 30 May 2013 00:51:49 +0530 Subject: [PATCH 1/3] push: factor out the detached HEAD error message With push.default set to upstream or simple, and a detached HEAD, git push prints the following error: $ git push fatal: You are not currently on a branch. To push the history leading to the current (detached HEAD) state now, use git push ram HEAD: This error is not unique to upstream or simple: current cannot push with a detached HEAD either. So, factor out the error string in preparation for using it in current. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- builtin/push.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/builtin/push.c b/builtin/push.c index 909c34dfda..ef3aa970ce 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -113,17 +113,19 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote remote->name, branch->name, advice_maybe); } +static const char message_detached_head_die[] = + N_("You are not currently on a branch.\n" + "To push the history leading to the current (detached HEAD)\n" + "state now, use\n" + "\n" + " git push %s HEAD:\n"); + static void setup_push_upstream(struct remote *remote, int simple) { struct strbuf refspec = STRBUF_INIT; struct branch *branch = branch_get(NULL); if (!branch) - die(_("You are not currently on a branch.\n" - "To push the history leading to the current (detached HEAD)\n" - "state now, use\n" - "\n" - " git push %s HEAD:\n"), - remote->name); + die(_(message_detached_head_die), remote->name); if (!branch->merge_nr || !branch->merge || !branch->remote_name) die(_("The current branch %s has no upstream branch.\n" "To push the current branch and set the remote as upstream, use\n" From 7b2ecd81084adeba701c60da81eec6be478910b8 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Thu, 30 May 2013 00:51:50 +0530 Subject: [PATCH 2/3] push: fail early with detached HEAD and current Setting push.default to current adds the refspec "HEAD" for the transport layer to handle. If "HEAD" doesn't resolve to a branch (and since no refspec rhs is specified), the push fails after some time with a cryptic error message: $ git push error: unable to push to unqualified destination: HEAD The destination refspec neither matches an existing ref on the remote nor begins with refs/, and we are unable to guess a prefix based on the source ref. error: failed to push some refs to 'git@github.com:artagnon/git' Fail early with a nicer error message: $ git push fatal: You are not currently on a branch. To push the history leading to the current (detached HEAD) state now, use git push ram HEAD: Just like in the upstream and simple cases. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- builtin/push.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin/push.c b/builtin/push.c index ef3aa970ce..ba2bd56ebc 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -175,6 +175,8 @@ static void warn_unspecified_push_default_configuration(void) static void setup_default_push_refspecs(struct remote *remote) { + struct branch *branch; + switch (push_default) { default: case PUSH_DEFAULT_UNSPECIFIED: @@ -194,6 +196,9 @@ static void setup_default_push_refspecs(struct remote *remote) break; case PUSH_DEFAULT_CURRENT: + branch = branch_get(NULL); + if (!branch) + die(_(message_detached_head_die), remote->name); add_refspec("HEAD"); break; From 0f075b220862e729eb3873a1c1496b923d17c2d4 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Thu, 30 May 2013 00:51:51 +0530 Subject: [PATCH 3/3] push: make push.default = current use resolved HEAD With this change, the output of the push (with push.default set to current) changes subtly from: $ git push ... * [new branch] HEAD -> push-current-head to: $ git push ... * [new branch] push-current-head -> push-current-head This patch was written with a different motivation. There is a problem unique to push.default = current: # on branch push-current-head $ git push # on another terminal $ git checkout master # return to the first terminal # the push tried to push master! This happens because the 'git checkout' on the second terminal races with the 'git push' on the first terminal. Although this patch does not solve the core problem (there is still no guarantee that 'git push' on the first terminal will resolve HEAD before 'git checkout' changes HEAD on the second), it works in practice. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- builtin/push.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/push.c b/builtin/push.c index ba2bd56ebc..2d84d10720 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -199,7 +199,7 @@ static void setup_default_push_refspecs(struct remote *remote) branch = branch_get(NULL); if (!branch) die(_(message_detached_head_die), remote->name); - add_refspec("HEAD"); + add_refspec(branch->name); break; case PUSH_DEFAULT_NOTHING: