Re: [PATCH 5/5] implement @{publish} shorthand

2014-02-18 Thread Johan Herland
On Tue, Feb 18, 2014 at 9:52 AM, Jeff King p...@peff.net wrote:
 On Sat, Feb 15, 2014 at 11:50:10AM -, Philip Oakley wrote:
  This patch introduces the branch@{publish} shorthand (or
  @{pu} to be even shorter).

 Just to say that I'm not sure that publish is the best word for
 this concept.
 [...]

 I would much rather have a name that describes what the thing _is_, then
 how it is meant to be used. The concept of @{publish} is a shorthand for
 where would I push if I typed git push on this branch. In a
 non-triangular workflow, that means sharing your commits with others on
 the main branch. In a triangular workflow, it means sharing your commits
 with a publishing point so that others can see them. If your default
 push goes to a backup repo, it does not mean publishing at all, but
 rather syncing the backup.

 So I do not think any one word can describe all of those use cases; they
 are orthogonal to each other, and it depends on your workflow.

 In that sense, publish is not the best word, either, as it describes
 only the first two, but not the third case (and those are just examples;
 there may be other setups beyond that, even).

 Perhaps @{push} would be the most direct word.

I agree that we want a more general (i.e. workflow-agnostic) term to
differentiate between where we pull from, and where we push to. As
such, @{push} should have a corresponding @{pull} (which I believe
should function as an alias of @{upstream}). [1]


...Johan

[1]: I don't think there is a reason not to reuse the push/pull
terminology for these concepts, but if there is, I guess we could
instead call them @{source}/@{destination}, @{src}/@{dst}, or
@{from}/@{to}, or somesuch...

-- 
Johan Herland, jo...@herland.net
www.herland.net
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-02-18 Thread Junio C Hamano
Jeff King p...@peff.net writes:

 In that sense, publish is not the best word, either, as it describes
 only the first two, but not the third case (and those are just examples;
 there may be other setups beyond that, even).

 Perhaps @{push} would be the most direct word.

Hmph, then the other one would be @{pull}.

Which does not sound too bad, IMHO.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-24 Thread Jeff King
On Thu, Jan 23, 2014 at 04:16:06PM -0800, Junio C Hamano wrote:

 Jeff King p...@peff.net writes:
 
  In a triangular workflow, you may have a distinct
  @{upstream} that you pull changes from, but publish by
  default (if you typed git push) to a different remote (or
  a different branch on the remote). It may sometimes be
  useful to be able to quickly refer to that publishing point
  (e.g., to see which changes you have that have not yet been
  published).
 
  This patch introduces the branch@{publish} shorthand (or
  @{pu} to be even shorter). It refers to the tracking
  branch of the remote branch to which you would push if you
  were to push the named branch. That's a mouthful to explain,
  so here's an example:
 
$ git checkout -b foo origin/master
$ git config remote.pushdefault github
$ git push
 
  Signed-off-by: Jeff King p...@peff.net
  ---
 
 As there is no @{pu} in publish_mark() as far as I can see, and also
 I found it is a bit unclear what the example in the last paragraph
 wants to illustrate, I'll reword the above as the following before
 merging it to 'next'.

Yeah, I think the @{pu} was just a silly omission from the code, though
I agree after our discussion that we should just stick with @{publish}
for now.

I am not sure why I said git push at the end. I would have thought
that:

  $ git rev-parse --symbolic-full-name @{publish}
  refs/remotes/github/foo

would have been the right command to demonstrate. The text you suggested
is fine, though I think you can simply drop the git push, as it does
not add anything.

As far as merging it to 'next', I had not really intended it to go that
far. :) It was more for Ram to use as a base. I find some of the
refactoring questionable, including:

  1. The meaning of branch-pushremote is subtly different from that of
 branch-remote. Ram's followup refactoring did a better job of
 that (but he is missing the patches on top to finish out the
 feature).

  2. We are duplicating the where to push logic here. That should
 probably be factored out so that git push and @{publish} use
 the same logic.

And of course there are no tests or documentation. It might work,
though.

I don't mind if you want to merge it and do more work in-tree, but I do
not think it should graduate as-is. And you may want check from Ram that
he is not in the middle of his own version based on the patches he sent
earlier, as reworking them on top of mine would probably just be
needless extra work.

Are you planning on having request-pull use @{publish} as a default? I
saw you cc'd me on that thread, but I didn't have any opinion besides
sounds like you could use it here.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-24 Thread Ramkumar Ramachandra
Jeff King wrote:
 As far as merging it to 'next', I had not really intended it to go that
 far. :) It was more for Ram to use as a base.

Sorry about not having posted a follow-up yet; I'm adjusting to a new
timezone and environment.

 I find some of the
 refactoring questionable, including:

   1. The meaning of branch-pushremote is subtly different from that of
  branch-remote. Ram's followup refactoring did a better job of
  that (but he is missing the patches on top to finish out the
  feature).

   2. We are duplicating the where to push logic here. That should
  probably be factored out so that git push and @{publish} use
  the same logic.

 And of course there are no tests or documentation. It might work,
 though.

Actually, task (2) is somewhat involved: I still haven't figured out
how to share code with 'git push'.

 I don't mind if you want to merge it and do more work in-tree, but I do
 not think it should graduate as-is. And you may want check from Ram that
 he is not in the middle of his own version based on the patches he sent
 earlier, as reworking them on top of mine would probably just be
 needless extra work.

On that note, can you hold off graduating
jk/branch-at-publish-rebased, Junio? Hopefully, I'll come up with a
replacement over the weekend.

Thanks.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-24 Thread Junio C Hamano
Ramkumar Ramachandra artag...@gmail.com writes:

 On that note, can you hold off graduating
 jk/branch-at-publish-rebased, Junio? Hopefully, I'll come up with a
 replacement over the weekend.

Sure.

This close to the feature freeze, I'd rather see all contributors,
not limited to you, not rush on new and shiny things, but instead
spend time looking at bugs and fixes proposed for the upcoming
release in the codepaths they were involved.

The send-email SSL issue $gmane/240479 is one of the things I'd like
to see your sanity-checking ;-)
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-23 Thread Junio C Hamano
Jeff King p...@peff.net writes:

 In a triangular workflow, you may have a distinct
 @{upstream} that you pull changes from, but publish by
 default (if you typed git push) to a different remote (or
 a different branch on the remote). It may sometimes be
 useful to be able to quickly refer to that publishing point
 (e.g., to see which changes you have that have not yet been
 published).

 This patch introduces the branch@{publish} shorthand (or
 @{pu} to be even shorter). It refers to the tracking
 branch of the remote branch to which you would push if you
 were to push the named branch. That's a mouthful to explain,
 so here's an example:

   $ git checkout -b foo origin/master
   $ git config remote.pushdefault github
   $ git push

 Signed-off-by: Jeff King p...@peff.net
 ---

As there is no @{pu} in publish_mark() as far as I can see, and also
I found it is a bit unclear what the example in the last paragraph
wants to illustrate, I'll reword the above as the following before
merging it to 'next'.

This patch introduces the branch@{publish} shorthand that
refers to the tracking branch of the remote branch to which
you would push if you were to push the named branch.

That's a mouthful to explain, so here's an example:

  $ git checkout -b foo origin/master
  $ git config remote.pushdefault github
  $ git push

With this, foo@{upstream} and foo@{publish} would be origin/master
and github/foo, respectively (assuming that git fetch github is
configured to use refs/remotes/github/* remote-tracking branches).

 The implementation feels weird, like the where do we push to code
 should be factored out from somewhere else. I think what we're doing
 here is not _wrong_, but I don't like repeating what git push is doing
 elsewhere. And I just punt on simple as a result. :)

I think we can polish that in-tree.

Thanks.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-09 Thread Philip Oakley

From: Jeff King p...@peff.net
Sent: Wednesday, January 08, 2014 9:37 AM

In a triangular workflow, you may have a distinct
@{upstream} that you pull changes from, but publish by
default (if you typed git push) to a different remote (or
a different branch on the remote).


One of the broader issues is the lack of _documenation_ about what the 
'normal' naming convention is for the uspstream remote. Especially the 
implicit convention used within our documentation (and workflow).


This is especially true for github users who will normally fork a repo 
of interest and then clone it from their own copy/fork. This means that 
the 'origin' remote is _not_ the upstream. See 
https://help.github.com/articles/fork-a-repo In my case 'origin' is my 
publish repo (as suggested by Github) while 'junio' is the upstream (as 
do some others). There are similar results from the likes of 
Stackoverflow.


Much of the earlier discussion did appear to be as much a confusion over 
terminology as that of coding a suitable solution ro Ram's original 
forked-from issue.


I know it's been an issue I've had for some while 
http://thread.gmane.org/gmane.comp.version-control.git/194175/focus=195385


Philip




--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-09 Thread Jeff King
On Wed, Jan 08, 2014 at 03:42:09PM -0800, Junio C Hamano wrote:

  This patch introduces the branch@{publish} shorthand (or
  @{pu} to be even shorter). It refers to the tracking
 
 If @{u} can already be used for upstream, why not allow @{p} but
 require two letters @{pu}?  Just being curious---I am not advocating
 strongly for a shorter short-hand.
 
 Or is @{p} already taken by something and my memory is not
 functioning well?

It is my brain that was not functioning well. I somehow thought well,
@{u} is already taken, so we must use @{pu}. Which of course makes no
sense, unless you are middle-endian. :)

We may want to be cautious about giving up a short-and-sweet
single-letter, though, until the feature has proved itself. We could
also teach upstream_mark and friends to match unambiguous prefixes (so
@{u}, @{up}, @{upst}, etc). That means @{p} would work
immediately, but scripts should use @{publish} for future-proofing.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-09 Thread Junio C Hamano
Jeff King p...@peff.net writes:

 Or is @{p} already taken by something and my memory is not
 functioning well?

 It is my brain that was not functioning well. I somehow thought well,
 @{u} is already taken, so we must use @{pu}. Which of course makes no
 sense, unless you are middle-endian. :)

 We may want to be cautious about giving up a short-and-sweet
 single-letter, though, until the feature has proved itself. We could
 also teach upstream_mark and friends to match unambiguous prefixes (so
 @{u}, @{up}, @{upst}, etc). That means @{p} would work
 immediately, but scripts should use @{publish} for future-proofing.

I recall we wanted to start only with @{upstream} without @{u};
justification being if the concept is solid and useful enough, the
latter will come later as a natural user-desire, during the
discussion that ended up introducing them.

I am OK with the unambigous prefix string.

Thanks for sanity-checking.


--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-09 Thread Jeff King
On Thu, Jan 09, 2014 at 08:39:44AM -, Philip Oakley wrote:

 From: Jeff King p...@peff.net
 Sent: Wednesday, January 08, 2014 9:37 AM
 In a triangular workflow, you may have a distinct
 @{upstream} that you pull changes from, but publish by
 default (if you typed git push) to a different remote (or
 a different branch on the remote).
 
 One of the broader issues is the lack of _documenation_ about what
 the 'normal' naming convention is for the uspstream remote.
 Especially the implicit convention used within our documentation (and
 workflow).
 
 This is especially true for github users who will normally fork a
 repo of interest and then clone it from their own copy/fork. This
 means that the 'origin' remote is _not_ the upstream. See
 https://help.github.com/articles/fork-a-repo In my case 'origin' is
 my publish repo (as suggested by Github) while 'junio' is the
 upstream (as do some others). There are similar results from the
 likes of Stackoverflow.

Sure, and I have done the same thing (though I tend to clone from the
other person as origin, and only fork my own repo when I am ready to
push). But it shouldn't matter, should it? The whole point of the
upstream config is that git checkout -b topic junio/master does the
right thing, without caring about your naming convention.

So I'm not sure what you think should be said (or where). Telling me in
patch form is preferred. :)

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-09 Thread Junio C Hamano
Philip Oakley philipoak...@iee.org writes:

 From: Jeff King p...@peff.net
 Sent: Wednesday, January 08, 2014 9:37 AM
 In a triangular workflow, you may have a distinct
 @{upstream} that you pull changes from, but publish by
 default (if you typed git push) to a different remote (or
 a different branch on the remote).

 One of the broader issues is the lack of _documenation_ about what the
 normal' naming convention is for the uspstream remote. Especially the
 implicit convention used within our documentation (and workflow).

Sure, let's start trying to come up with what the eventual
documentation patch may want to say.

 * The upstream is the place the updates by the project-as-a-whole
   (including others' work but also your previous work) come from.
   It is what you use git pull [--rebase] to integrate the work on
   your current branch with in order to keep it in sync with the
   outside world.  Such a repository (often called origin, and
   git clone sets it up for you) may be called upstream
   repository.

   Each of your branch would often have a single branch in that
   repository (e.g. master, which you locally use the
   origin/master remote-tracking branch to keep track of its most
   recently observed state).  In the simplest case, you clone from
   your origin, you get your own master branch, which is set to
   integrate with the master branch at the origin.  Their
   master (i.e. what you view as origin/master) would be the
   upstream branch for your master branch.

   For a branch B, B@{upstream} names the remote-tracking branch
   used for the upstream branch of B.  For example, to fork a new
   branch 'foo' that has the same upstream branch as your branch
   'master' does, git checkout -t -b foo master@{upstream} can be
   used.

 * If you and others are using the same repository to advance the
   project, the repository you cloned from, i.e. your upstream
   repository, is the same repository you push your changes back
   to.  There is no other repository you have to worry about.

   In such a centralized setting, it is likely that you may want
   to update one of three possible branches at the upstream
   repository when you push your changes back, if your local branch
   is named differently from its upstream branch.  Either:

   (1) You started working on a topic (e.g. your fix-bug-2431
   branch) based on an integration branch (e.g. master at the
   upstream, i.e. origin/master to you), and you want to
   publish it so that others can take a look at it and help you
   polish it while it is still not suitable for the integration
   branch.  As long as you gave a name to that topic branch that
   is descriptive and good enough for public consumption, you
   would want it to go to the same name (e.g. you would want to
   push to fix-bug-2431 branch at the upstream repository from
   your fix-bug-2431 branch); or

   (2) You are working on your copy (e.g. your master branch) of
   an integration branch (e.g. origin/master to you), and you
   want to update the master branch at the upstream
   repository.

   (3) There is another possibilty, in which you are working on a
   topic forked from an integration branch (as in (1)), and are
   done with the topic and want to push the result out directly
   to the integration branch.  Your fix-bug-2431 branch may
   have started from origin/master and git pull [--rebase]
   on the branch would integrate with master branch at the
   upstream repository, and your git push on the
   fix-bug-2431 branch will update that master branch at the
   upstream repository, which makes it look symmetric.

The default in Git 2.0 will allow you to do (2) without any
further set-up, and you can start living in the future by
setting push.default to simple.  Your current branch, when you
run git push, and its upstream branch must share the same
name.

If you want to do (1), you would want to set push.default to
current.  Your current branch, when you run git push may not
have an explicit upstream branch (hence git pull without any
other argument may fail), but the work on your branch will be
pushed to the branch of the same name at the upstream
repository.

For (3), you would set push.default to upstream.  Your current
branch, when you run git push, must have an explicit upstream
branch specified and you must be pushing to the upstream
repository for this to work for obvious reasons.

 * If you originally clone from somewhere you cannot (or do not want
   to even if you could) push to, you would want your git push to
   go to a repository that is different from your upstream.  In
   such a triangular setting, the result of your work is published
   to your own repository (we'd call it publish), and others
   interested in your work would pull from there to integrate it to
   their work.  Among these other people there may be 

[PATCH 5/5] implement @{publish} shorthand

2014-01-08 Thread Jeff King
In a triangular workflow, you may have a distinct
@{upstream} that you pull changes from, but publish by
default (if you typed git push) to a different remote (or
a different branch on the remote). It may sometimes be
useful to be able to quickly refer to that publishing point
(e.g., to see which changes you have that have not yet been
published).

This patch introduces the branch@{publish} shorthand (or
@{pu} to be even shorter). It refers to the tracking
branch of the remote branch to which you would push if you
were to push the named branch. That's a mouthful to explain,
so here's an example:

  $ git checkout -b foo origin/master
  $ git config remote.pushdefault github
  $ git push

Signed-off-by: Jeff King p...@peff.net
---
The implementation feels weird, like the where do we push to code
should be factored out from somewhere else. I think what we're doing
here is not _wrong_, but I don't like repeating what git push is doing
elsewhere. And I just punt on simple as a result. :)

 sha1_name.c | 76 -
 1 file changed, 75 insertions(+), 1 deletion(-)

diff --git a/sha1_name.c b/sha1_name.c
index 50df5d4..59ffa93 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -435,6 +435,12 @@ static inline int upstream_mark(const char *string, int 
len)
return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 }
 
+static inline int publish_mark(const char *string, int len)
+{
+   const char *suffix[] = { @{publish} };
+   return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned 
lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf);
 
@@ -481,7 +487,8 @@ static int get_sha1_basic(const char *str, int len, 
unsigned char *sha1)
nth_prior = 1;
continue;
}
-   if (!upstream_mark(str + at, len - at)) {
+   if (!upstream_mark(str + at, len - at) 
+   !publish_mark(str + at, len - at)) {
reflog_len = (len-1) - (at+2);
len = at;
}
@@ -1100,6 +1107,69 @@ static int interpret_upstream_mark(const char *name, int 
namelen,
return len + at;
 }
 
+static const char *get_publish_branch(const char *name_buf, int len)
+{
+   char *name = xstrndup(name_buf, len);
+   struct branch *b = branch_get(*name ? name : NULL);
+   struct remote *remote = b-pushremote;
+   const char *dst;
+   const char *track;
+
+   free(name);
+
+   if (!remote)
+   die(_(branch '%s' has no remote for pushing), b-name);
+
+   /* Figure out what we would call it on the remote side... */
+   if (remote-push_refspec_nr)
+   dst = apply_refspecs(remote-push, remote-push_refspec_nr,
+b-refname);
+   else
+   dst = b-refname;
+   if (!dst)
+   die(_(unable to figure out how '%s' would be pushed),
+   b-name);
+
+   /* ...and then figure out what we would call that remote here */
+   track = apply_refspecs(remote-fetch, remote-fetch_refspec_nr, dst);
+   if (!track)
+   die(_(%s@{publish} has no tracking branch for '%s'),
+   b-name, dst);
+
+   return track;
+}
+
+static int interpret_publish_mark(const char *name, int namelen,
+ int at, struct strbuf *buf)
+{
+   int len;
+
+   len = publish_mark(name + at, namelen - at);
+   if (!len)
+   return -1;
+
+   switch (push_default) {
+   case PUSH_DEFAULT_NOTHING:
+   die(_(cannot use @{publish} with push.default of 'nothing'));
+
+   case PUSH_DEFAULT_UNSPECIFIED:
+   case PUSH_DEFAULT_MATCHING:
+   case PUSH_DEFAULT_CURRENT:
+   set_shortened_ref(buf, get_publish_branch(name, at));
+   break;
+
+   case PUSH_DEFAULT_UPSTREAM:
+   set_shortened_ref(buf, get_upstream_branch(name, at));
+   break;
+
+   case PUSH_DEFAULT_SIMPLE:
+   /* ??? */
+   die(@{publish} with simple unimplemented);
+   }
+
+   return at + len;
+}
+
 /*
  * This reads short-hand syntax that not only evaluates to a commit
  * object name, but also can act as if the end user spelled the name
@@ -1150,6 +1220,10 @@ int interpret_branch_name(const char *name, int namelen, 
struct strbuf *buf)
if (len  0)
return len;
 
+   len = interpret_publish_mark(name, namelen, cp - name, buf);
+   if (len  0)
+   return len;
+
return -1;
 }
 
-- 
1.8.5.2.500.g8060133
--
To unsubscribe from this list: send the line unsubscribe git in
the body of 

Re: [PATCH 5/5] implement @{publish} shorthand

2014-01-08 Thread Junio C Hamano
Jeff King p...@peff.net writes:

 In a triangular workflow, you may have a distinct
 @{upstream} that you pull changes from, but publish by
 default (if you typed git push) to a different remote (or
 a different branch on the remote). It may sometimes be
 useful to be able to quickly refer to that publishing point
 (e.g., to see which changes you have that have not yet been
 published).

 This patch introduces the branch@{publish} shorthand (or
 @{pu} to be even shorter). It refers to the tracking

If @{u} can already be used for upstream, why not allow @{p} but
require two letters @{pu}?  Just being curious---I am not advocating
strongly for a shorter short-hand.

Or is @{p} already taken by something and my memory is not
functioning well?

 branch of the remote branch to which you would push if you
 were to push the named branch. That's a mouthful to explain,
 so here's an example:

   $ git checkout -b foo origin/master
   $ git config remote.pushdefault github
   $ git push

 Signed-off-by: Jeff King p...@peff.net
 ---
 The implementation feels weird, like the where do we push to code
 should be factored out from somewhere else. I think what we're doing
 here is not _wrong_, but I don't like repeating what git push is doing
 elsewhere. And I just punt on simple as a result. :)

  sha1_name.c | 76 
 -
  1 file changed, 75 insertions(+), 1 deletion(-)

 diff --git a/sha1_name.c b/sha1_name.c
 index 50df5d4..59ffa93 100644
 --- a/sha1_name.c
 +++ b/sha1_name.c
 @@ -435,6 +435,12 @@ static inline int upstream_mark(const char *string, int 
 len)
   return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
  }
  
 +static inline int publish_mark(const char *string, int len)
 +{
 + const char *suffix[] = { @{publish} };
 + return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 +}
 +
  static int get_sha1_1(const char *name, int len, unsigned char *sha1, 
 unsigned lookup_flags);
  static int interpret_nth_prior_checkout(const char *name, struct strbuf 
 *buf);
  
 @@ -481,7 +487,8 @@ static int get_sha1_basic(const char *str, int len, 
 unsigned char *sha1)
   nth_prior = 1;
   continue;
   }
 - if (!upstream_mark(str + at, len - at)) {
 + if (!upstream_mark(str + at, len - at) 
 + !publish_mark(str + at, len - at)) {
   reflog_len = (len-1) - (at+2);
   len = at;
   }
 @@ -1100,6 +1107,69 @@ static int interpret_upstream_mark(const char *name, 
 int namelen,
   return len + at;
  }
  
 +static const char *get_publish_branch(const char *name_buf, int len)
 +{
 + char *name = xstrndup(name_buf, len);
 + struct branch *b = branch_get(*name ? name : NULL);
 + struct remote *remote = b-pushremote;
 + const char *dst;
 + const char *track;
 +
 + free(name);
 +
 + if (!remote)
 + die(_(branch '%s' has no remote for pushing), b-name);
 +
 + /* Figure out what we would call it on the remote side... */
 + if (remote-push_refspec_nr)
 + dst = apply_refspecs(remote-push, remote-push_refspec_nr,
 +  b-refname);
 + else
 + dst = b-refname;
 + if (!dst)
 + die(_(unable to figure out how '%s' would be pushed),
 + b-name);
 +
 + /* ...and then figure out what we would call that remote here */
 + track = apply_refspecs(remote-fetch, remote-fetch_refspec_nr, dst);
 + if (!track)
 + die(_(%s@{publish} has no tracking branch for '%s'),
 + b-name, dst);
 +
 + return track;
 +}
 +
 +static int interpret_publish_mark(const char *name, int namelen,
 +   int at, struct strbuf *buf)
 +{
 + int len;
 +
 + len = publish_mark(name + at, namelen - at);
 + if (!len)
 + return -1;
 +
 + switch (push_default) {
 + case PUSH_DEFAULT_NOTHING:
 + die(_(cannot use @{publish} with push.default of 'nothing'));
 +
 + case PUSH_DEFAULT_UNSPECIFIED:
 + case PUSH_DEFAULT_MATCHING:
 + case PUSH_DEFAULT_CURRENT:
 + set_shortened_ref(buf, get_publish_branch(name, at));
 + break;
 +
 + case PUSH_DEFAULT_UPSTREAM:
 + set_shortened_ref(buf, get_upstream_branch(name, at));
 + break;
 +
 + case PUSH_DEFAULT_SIMPLE:
 + /* ??? */
 + die(@{publish} with simple unimplemented);
 + }
 +
 + return at + len;
 +}
 +
  /*
   * This reads short-hand syntax that not only evaluates to a commit
   * object name, but also can act as if the end user spelled the name
 @@ -1150,6 +1220,10 @@ int interpret_branch_name(const char *name, int 
 namelen, struct strbuf