aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-05-03 23:28:09 -0700
committerJunio C Hamano <junkio@cox.net>2006-05-03 23:28:09 -0700
commit5dfde8715664d389de640d9475fb1678b8403596 (patch)
tree90c0f6d13b887942c98c3144ce8cfeb5b8b0db67
parentdd371b49f98d9c08f7fbd4900976739a6aeb9ec6 (diff)
parentc9889e40858fa8b9265b58519e7281c07f3632c6 (diff)
downloadgit-5dfde8715664d389de640d9475fb1678b8403596.tar.gz
git-5dfde8715664d389de640d9475fb1678b8403596.tar.xz
Merge branch 'js/remoteconfig'
* js/remoteconfig: Revert "fetch, pull: ask config for remote information" fetch, pull: ask config for remote information builtin-push: also ask config for remote information builtin-push: make it official. Fix builtin-push to honor Push: lines in remotes file. builtin-push: resurrect parsing of Push: lines git builtin "push"
-rw-r--r--Makefile7
-rw-r--r--builtin-push.c312
-rw-r--r--builtin.h2
-rw-r--r--git.c1
4 files changed, 319 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 8ce27a65f..9cb40a816 100644
--- a/Makefile
+++ b/Makefile
@@ -118,7 +118,7 @@ SCRIPT_SH = \
git-count-objects.sh git-diff.sh git-fetch.sh \
git-format-patch.sh git-ls-remote.sh \
git-merge-one-file.sh git-parse-remote.sh \
- git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
+ git-prune.sh git-pull.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.sh \
git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \
git-tag.sh git-verify-tag.sh git-whatchanged.sh \
@@ -167,7 +167,8 @@ PROGRAMS = \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
-BUILT_INS = git-log$X
+BUILT_INS = git-log$X \
+ git-push$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -214,7 +215,7 @@ LIB_OBJS = \
$(DIFF_OBJS)
BUILTIN_OBJS = \
- builtin-log.o builtin-help.o
+ builtin-log.o builtin-help.o builtin-push.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-push.c b/builtin-push.c
new file mode 100644
index 000000000..06d06ff31
--- /dev/null
+++ b/builtin-push.c
@@ -0,0 +1,312 @@
+/*
+ * "git push"
+ */
+#include "cache.h"
+#include "refs.h"
+#include "run-command.h"
+#include "builtin.h"
+
+#define MAX_URI (16)
+
+static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
+
+static int all = 0, tags = 0, force = 0, thin = 1;
+static const char *execute = NULL;
+
+#define BUF_SIZE (2084)
+static char buffer[BUF_SIZE];
+
+static const char **refspec = NULL;
+static int refspec_nr = 0;
+
+static void add_refspec(const char *ref)
+{
+ int nr = refspec_nr + 1;
+ refspec = xrealloc(refspec, nr * sizeof(char *));
+ refspec[nr-1] = ref;
+ refspec_nr = nr;
+}
+
+static int expand_one_ref(const char *ref, const unsigned char *sha1)
+{
+ /* Ignore the "refs/" at the beginning of the refname */
+ ref += 5;
+
+ if (strncmp(ref, "tags/", 5))
+ return 0;
+
+ add_refspec(strdup(ref));
+ return 0;
+}
+
+static void expand_refspecs(void)
+{
+ if (all) {
+ if (refspec_nr)
+ die("cannot mix '--all' and a refspec");
+
+ /*
+ * No need to expand "--all" - we'll just use
+ * the "--all" flag to send-pack
+ */
+ return;
+ }
+ if (!tags)
+ return;
+ for_each_ref(expand_one_ref);
+}
+
+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;
+ }
+ expand_refspecs();
+}
+
+static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+ int n = 0;
+ FILE *f = fopen(git_path("remotes/%s", repo), "r");
+ int has_explicit_refspec = refspec_nr;
+
+ if (!f)
+ return -1;
+ while (fgets(buffer, BUF_SIZE, f)) {
+ int is_refspec;
+ char *s, *p;
+
+ if (!strncmp("URL: ", buffer, 5)) {
+ is_refspec = 0;
+ s = buffer + 5;
+ } else if (!strncmp("Push: ", buffer, 6)) {
+ is_refspec = 1;
+ s = buffer + 6;
+ } else
+ continue;
+
+ /* Remove whitespace at the head.. */
+ while (isspace(*s))
+ s++;
+ if (!*s)
+ continue;
+
+ /* ..and at the end */
+ p = s + strlen(s);
+ while (isspace(p[-1]))
+ *--p = 0;
+
+ if (!is_refspec) {
+ if (n < MAX_URI)
+ uri[n++] = strdup(s);
+ else
+ error("more than %d URL's specified, ignoreing the rest", MAX_URI);
+ }
+ else if (is_refspec && !has_explicit_refspec)
+ add_refspec(strdup(s));
+ }
+ fclose(f);
+ if (!n)
+ die("remote '%s' has no URL", repo);
+ 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++] = strdup(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(strdup(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;
+
+ 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, '/');
+ int n = slash ? slash - repo : 1000;
+ FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
+ char *s, *p;
+ int len;
+
+ if (!f)
+ return 0;
+ s = fgets(buffer, BUF_SIZE, f);
+ fclose(f);
+ if (!s)
+ return 0;
+ while (isspace(*s))
+ s++;
+ if (!*s)
+ return 0;
+ p = s + strlen(s);
+ while (isspace(p[-1]))
+ *--p = 0;
+ len = p - s;
+ if (slash)
+ len += strlen(slash);
+ p = xmalloc(len + 1);
+ strcpy(p, s);
+ if (slash)
+ strcat(p, slash);
+ uri[0] = p;
+ return 1;
+}
+
+/*
+ * 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 (*repo != '/') {
+ n = get_remotes_uri(repo, uri);
+ 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;
+ }
+
+ uri[0] = repo;
+ return 1;
+}
+
+static int do_push(const char *repo)
+{
+ const char *uri[MAX_URI];
+ int i, n;
+ int remote;
+ const char **argv;
+ int argc;
+
+ n = read_config(repo, uri);
+ if (n <= 0)
+ die("bad repository '%s'", repo);
+
+ argv = xmalloc((refspec_nr + 10) * sizeof(char *));
+ argv[0] = "dummy-send-pack";
+ argc = 1;
+ if (all)
+ argv[argc++] = "--all";
+ if (force)
+ 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;
+
+ for (i = 0; i < n; i++) {
+ int error;
+ const char *dest = uri[i];
+ const char *sender = "git-send-pack";
+ if (!strncmp(dest, "http://", 7) ||
+ !strncmp(dest, "https://", 8))
+ sender = "git-http-push";
+ argv[0] = sender;
+ argv[remote] = dest;
+ error = run_command_v(argc, argv);
+ if (!error)
+ continue;
+ switch (error) {
+ case -ERR_RUN_COMMAND_FORK:
+ die("unable to fork for %s", sender);
+ case -ERR_RUN_COMMAND_EXEC:
+ die("unable to exec %s", sender);
+ case -ERR_RUN_COMMAND_WAITPID:
+ case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
+ case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
+ case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
+ die("%s died with strange error", sender);
+ default:
+ return -error;
+ }
+ }
+ return 0;
+}
+
+int cmd_push(int argc, const char **argv, char **envp)
+{
+ int i;
+ const char *repo = "origin"; // default repository
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (arg[0] != '-') {
+ repo = arg;
+ i++;
+ break;
+ }
+ if (!strcmp(arg, "--all")) {
+ all = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--tags")) {
+ tags = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--force")) {
+ force = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--thin")) {
+ thin = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-thin")) {
+ thin = 0;
+ continue;
+ }
+ if (!strncmp(arg, "--exec=", 7)) {
+ execute = arg;
+ continue;
+ }
+ usage(push_usage);
+ }
+ set_refspecs(argv + i, argc - i);
+ return do_push(repo);
+}
diff --git a/builtin.h b/builtin.h
index 47408a058..94fa9b546 100644
--- a/builtin.h
+++ b/builtin.h
@@ -20,4 +20,6 @@ extern int cmd_whatchanged(int argc, const char **argv, char **envp);
extern int cmd_show(int argc, const char **argv, char **envp);
extern int cmd_log(int argc, const char **argv, char **envp);
+extern int cmd_push(int argc, const char **argv, char **envp);
+
#endif
diff --git a/git.c b/git.c
index 01b7e28b8..fd479e97c 100644
--- a/git.c
+++ b/git.c
@@ -46,6 +46,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "log", cmd_log },
{ "whatchanged", cmd_whatchanged },
{ "show", cmd_show },
+ { "push", cmd_push },
};
int i;