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:
parent
1f73566af5
commit
e9fcd1e212
@ -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
|
||||||
|
@ -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
69
t/t5523-push-upstream.sh
Executable 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
|
56
transport.c
56
transport.c
@ -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)
|
||||||
|
@ -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 *);
|
||||||
|
Loading…
Reference in New Issue
Block a user