#define MAX_URI (16)
-static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
+static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
-static int all = 0, tags = 0, force = 0, thin = 1;
-static const char *execute = NULL;
+static int all, tags, force, thin = 1, verbose;
+static const char *execute;
#define BUF_SIZE (2084)
static char buffer[BUF_SIZE];
-static const char **refspec = NULL;
-static int refspec_nr = 0;
+static const char **refspec;
+static int refspec_nr;
static void add_refspec(const char *ref)
{
refspec_nr = nr;
}
-static int expand_one_ref(const char *ref, const unsigned char *sha1)
+static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
{
/* Ignore the "refs/" at the beginning of the refname */
ref += 5;
- if (strncmp(ref, "tags/", 5))
- return 0;
-
- add_refspec(strdup(ref));
+ if (!strncmp(ref, "tags/", 5))
+ add_refspec(xstrdup(ref));
return 0;
}
}
if (!tags)
return;
- for_each_ref(expand_one_ref);
+ for_each_ref(expand_one_ref, NULL);
}
static void set_refspecs(const char **refs, int nr)
{
if (nr) {
- size_t bytes = nr * sizeof(char *);
-
- refspec = xrealloc(refspec, bytes);
- memcpy(refspec, refs, bytes);
- refspec_nr = nr;
+ int pass;
+ for (pass = 0; pass < 2; pass++) {
+ /* pass 0 counts and allocates, pass 1 fills */
+ int i, cnt;
+ for (i = cnt = 0; i < nr; i++) {
+ if (!strcmp("tag", refs[i])) {
+ int len;
+ char *tag;
+ if (nr <= ++i)
+ die("tag <tag> shorthand without <tag>");
+ if (pass) {
+ len = strlen(refs[i]) + 11;
+ tag = xmalloc(len);
+ strcpy(tag, "refs/tags/");
+ strcat(tag, refs[i]);
+ refspec[cnt] = tag;
+ }
+ cnt++;
+ continue;
+ }
+ if (pass)
+ refspec[cnt] = refs[i];
+ cnt++;
+ }
+ if (!pass) {
+ size_t bytes = cnt * sizeof(char *);
+ refspec_nr = cnt;
+ refspec = xrealloc(refspec, bytes);
+ }
+ }
}
expand_refspecs();
}
{
int n = 0;
FILE *f = fopen(git_path("remotes/%s", repo), "r");
+ int has_explicit_refspec = refspec_nr || all || tags;
if (!f)
return -1;
while (fgets(buffer, BUF_SIZE, f)) {
+ int is_refspec;
char *s, *p;
- if (strncmp("URL: ", buffer, 5))
+ if (!strncmp("URL:", buffer, 4)) {
+ is_refspec = 0;
+ s = buffer + 4;
+ } else if (!strncmp("Push:", buffer, 5)) {
+ is_refspec = 1;
+ s = buffer + 5;
+ } else
continue;
- s = buffer + 5;
/* Remove whitespace at the head.. */
while (isspace(*s))
while (isspace(p[-1]))
*--p = 0;
- uri[n++] = strdup(s);
- if (n == MAX_URI)
- break;
+ if (!is_refspec) {
+ if (n < MAX_URI)
+ uri[n++] = xstrdup(s);
+ else
+ error("more than %d URL's specified, ignoring the rest", MAX_URI);
+ }
+ else if (is_refspec && !has_explicit_refspec)
+ add_refspec(xstrdup(s));
}
fclose(f);
if (!n)
return n;
}
+static const char **config_uri;
+static const char *config_repo;
+static int config_repo_len;
+static int config_current_uri;
+static int config_get_refspecs;
+
+static int get_remote_config(const char* key, const char* value)
+{
+ if (!strncmp(key, "remote.", 7) &&
+ !strncmp(key + 7, config_repo, config_repo_len)) {
+ if (!strcmp(key + 7 + config_repo_len, ".url")) {
+ if (config_current_uri < MAX_URI)
+ config_uri[config_current_uri++] = xstrdup(value);
+ else
+ error("more than %d URL's specified, ignoring the rest", MAX_URI);
+ }
+ else if (config_get_refspecs &&
+ !strcmp(key + 7 + config_repo_len, ".push"))
+ add_refspec(xstrdup(value));
+ }
+ return 0;
+}
+
+static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+ config_repo_len = strlen(repo);
+ config_repo = repo;
+ config_current_uri = 0;
+ config_uri = uri;
+ config_get_refspecs = !(refspec_nr || all || tags);
+
+ git_config(get_remote_config);
+ return config_current_uri;
+}
+
static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
{
const char *slash = strchr(repo, '/');
return 1;
}
-static int get_uri(const char *repo, const char *uri[MAX_URI])
+/*
+ * Read remotes and branches file, fill the push target URI
+ * list. If there is no command line refspecs, read Push: lines
+ * to set up the *refspec list as well.
+ * return the number of push target URIs
+ */
+static int read_config(const char *repo, const char *uri[MAX_URI])
{
int n;
if (n > 0)
return n;
+ n = get_config_remotes_uri(repo, uri);
+ if (n > 0)
+ return n;
+
n = get_branches_uri(repo, uri);
if (n > 0)
return n;
static int do_push(const char *repo)
{
const char *uri[MAX_URI];
- int i, n = get_uri(repo, uri);
- int remote;
+ int i, n;
+ int common_argc;
const char **argv;
int argc;
- n = get_uri(repo, uri);
+ n = read_config(repo, uri);
if (n <= 0)
die("bad repository '%s'", repo);
argv[argc++] = "--force";
if (execute)
argv[argc++] = execute;
- if (thin)
- argv[argc++] = "--thin";
- remote = argc;
- argv[argc++] = "dummy-remote";
- while (refspec_nr--)
- argv[argc++] = *refspec++;
- argv[argc] = NULL;
+ common_argc = argc;
for (i = 0; i < n; i++) {
- int error;
+ int err;
+ int dest_argc = common_argc;
+ int dest_refspec_nr = refspec_nr;
+ const char **dest_refspec = refspec;
const char *dest = uri[i];
const char *sender = "git-send-pack";
if (!strncmp(dest, "http://", 7) ||
!strncmp(dest, "https://", 8))
sender = "git-http-push";
+ else if (thin)
+ argv[dest_argc++] = "--thin";
argv[0] = sender;
- argv[remote] = dest;
- error = run_command_v(argc, argv);
- if (!error)
+ argv[dest_argc++] = dest;
+ while (dest_refspec_nr--)
+ argv[dest_argc++] = *dest_refspec++;
+ argv[dest_argc] = NULL;
+ if (verbose)
+ fprintf(stderr, "Pushing to %s\n", dest);
+ err = run_command_v(argv);
+ if (!err)
continue;
- switch (error) {
+ switch (err) {
case -ERR_RUN_COMMAND_FORK:
die("unable to fork for %s", sender);
case -ERR_RUN_COMMAND_EXEC:
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
die("%s died with strange error", sender);
default:
- return -error;
+ return -err;
}
}
return 0;
}
-int cmd_push(int argc, const char **argv, char **envp)
+int cmd_push(int argc, const char **argv, const char *prefix)
{
int i;
- const char *repo = "origin"; // default repository
+ const char *repo = "origin"; /* default repository */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
i++;
break;
}
+ if (!strcmp(arg, "-v")) {
+ verbose=1;
+ continue;
+ }
+ if (!strncmp(arg, "--repo=", 7)) {
+ repo = arg+7;
+ continue;
+ }
if (!strcmp(arg, "--all")) {
all = 1;
continue;
tags = 1;
continue;
}
- if (!strcmp(arg, "--force")) {
+ if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
force = 1;
continue;
}