Add push --set-upstream

Frequent complaint is lack of easy way to set up upstream (tracking)
references for git pull to work as part of push command. So add switch
--set-upstream (-u) to do just that.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ilari Liusvaara 2010-01-16 23:45:31 +02:00 committed by Junio C Hamano
parent 1f73566af5
commit e9fcd1e212
5 changed files with 136 additions and 1 deletions

View file

@ -10,7 +10,7 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>] 'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-v | --verbose] [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
[<repository> <refspec>...] [<repository> <refspec>...]
DESCRIPTION DESCRIPTION
@ -122,6 +122,13 @@ nor in any Push line of the corresponding remotes file---see below).
the name "origin" is used. For this latter case, this option the name "origin" is used. For this latter case, this option
can be used to override the name "origin". In other words, can be used to override the name "origin". In other words,
the difference between these two commands the difference between these two commands
-u::
--set-upstream::
For every branch that is up to date or successfully pushed, add
upstream (tracking) reference, used by argument-less
linkgit:git-pull[1] and other commands. For more information,
see 'branch.<name>.merge' in linkgit:git-config[1].
+ +
-------------------------- --------------------------
git push public #1 git push public #1

View file

@ -218,6 +218,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"), OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
TRANSPORT_PUSH_SET_UPSTREAM),
OPT_END() OPT_END()
}; };

69
t/t5523-push-upstream.sh Executable file
View file

@ -0,0 +1,69 @@
#!/bin/sh
test_description='push with --set-upstream'
. ./test-lib.sh
test_expect_success 'setup bare parent' '
git init --bare parent &&
git remote add upstream parent
'
test_expect_success 'setup local commit' '
echo content >file &&
git add file &&
git commit -m one
'
check_config() {
(echo $2; echo $3) >expect.$1
(git config branch.$1.remote
git config branch.$1.merge) >actual.$1
test_cmp expect.$1 actual.$1
}
test_expect_success 'push -u master:master' '
git push -u upstream master:master &&
check_config master upstream refs/heads/master
'
test_expect_success 'push -u master:other' '
git push -u upstream master:other &&
check_config master upstream refs/heads/other
'
test_expect_success 'push -u --dry-run master:otherX' '
git push -u --dry-run upstream master:otherX &&
check_config master upstream refs/heads/other
'
test_expect_success 'push -u master2:master2' '
git branch master2 &&
git push -u upstream master2:master2 &&
check_config master2 upstream refs/heads/master2
'
test_expect_success 'push -u master2:other2' '
git push -u upstream master2:other2 &&
check_config master2 upstream refs/heads/other2
'
test_expect_success 'push -u :master2' '
git push -u upstream :master2 &&
check_config master2 upstream refs/heads/other2
'
test_expect_success 'push -u --all' '
git branch all1 &&
git branch all2 &&
git push -u --all &&
check_config all1 upstream refs/heads/all1 &&
check_config all2 upstream refs/heads/all2
'
test_expect_success 'push -u HEAD' '
git checkout -b headbranch &&
git push -u upstream HEAD &&
check_config headbranch upstream refs/heads/headbranch
'
test_done

View file

@ -8,6 +8,7 @@
#include "bundle.h" #include "bundle.h"
#include "dir.h" #include "dir.h"
#include "refs.h" #include "refs.h"
#include "branch.h"
/* rsync support */ /* rsync support */
@ -135,6 +136,53 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
} }
} }
static void set_upstreams(struct transport *transport, struct ref *refs,
int pretend)
{
struct ref *ref;
for (ref = refs; ref; ref = ref->next) {
const char *localname;
const char *tmp;
const char *remotename;
unsigned char sha[20];
int flag = 0;
/*
* Check suitability for tracking. Must be successful /
* already up-to-date ref create/modify (not delete).
*/
if (ref->status != REF_STATUS_OK &&
ref->status != REF_STATUS_UPTODATE)
continue;
if (!ref->peer_ref)
continue;
if (!ref->new_sha1 || is_null_sha1(ref->new_sha1))
continue;
/* Follow symbolic refs (mainly for HEAD). */
localname = ref->peer_ref->name;
remotename = ref->name;
tmp = resolve_ref(localname, sha, 1, &flag);
if (tmp && flag & REF_ISSYMREF &&
!prefixcmp(tmp, "refs/heads/"))
localname = tmp;
/* Both source and destination must be local branches. */
if (!localname || prefixcmp(localname, "refs/heads/"))
continue;
if (!remotename || prefixcmp(remotename, "refs/heads/"))
continue;
if (!pretend)
install_branch_config(BRANCH_CONFIG_VERBOSE,
localname + 11, transport->remote->name,
remotename);
else
printf("Would set upstream of '%s' to '%s' of '%s'\n",
localname + 11, remotename + 11,
transport->remote->name);
}
}
static const char *rsync_url(const char *url) static const char *rsync_url(const char *url)
{ {
return prefixcmp(url, "rsync://") ? skip_prefix(url, "rsync:") : url; return prefixcmp(url, "rsync://") ? skip_prefix(url, "rsync:") : url;
@ -974,6 +1022,10 @@ int transport_push(struct transport *transport,
verify_remote_names(refspec_nr, refspec); verify_remote_names(refspec_nr, refspec);
if (transport->push) { if (transport->push) {
/* Maybe FIXME. But no important transport uses this case. */
if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
die("This transport does not support using --set-upstream");
return transport->push(transport, refspec_nr, refspec, flags); return transport->push(transport, refspec_nr, refspec, flags);
} else if (transport->push_refs) { } else if (transport->push_refs) {
struct ref *remote_refs = struct ref *remote_refs =
@ -983,6 +1035,7 @@ int transport_push(struct transport *transport,
int verbose = flags & TRANSPORT_PUSH_VERBOSE; int verbose = flags & TRANSPORT_PUSH_VERBOSE;
int quiet = flags & TRANSPORT_PUSH_QUIET; int quiet = flags & TRANSPORT_PUSH_QUIET;
int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
int ret; int ret;
if (flags & TRANSPORT_PUSH_ALL) if (flags & TRANSPORT_PUSH_ALL)
@ -1002,6 +1055,9 @@ int transport_push(struct transport *transport,
verbose | porcelain, porcelain, verbose | porcelain, porcelain,
nonfastforward); nonfastforward);
if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
set_upstreams(transport, remote_refs, pretend);
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
struct ref *ref; struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next) for (ref = remote_refs; ref; ref = ref->next)

View file

@ -91,6 +91,7 @@ struct transport {
#define TRANSPORT_PUSH_VERBOSE 16 #define TRANSPORT_PUSH_VERBOSE 16
#define TRANSPORT_PUSH_PORCELAIN 32 #define TRANSPORT_PUSH_PORCELAIN 32
#define TRANSPORT_PUSH_QUIET 64 #define TRANSPORT_PUSH_QUIET 64
#define TRANSPORT_PUSH_SET_UPSTREAM 128
/* Returns a transport suitable for the url */ /* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *); struct transport *transport_get(struct remote *, const char *);