Merge branch 'pb/remote-mirror-config'
authorJunio C Hamano <gitster@pobox.com>
Tue, 6 May 2008 02:15:39 +0000 (19:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 6 May 2008 02:15:39 +0000 (19:15 -0700)
* pb/remote-mirror-config:
Add a remote.*.mirror configuration option

1  2 
Documentation/config.txt
Documentation/git-push.txt
builtin-remote.c
remote.c
diff --combined Documentation/config.txt
index 824e416e9f8157d54d3f37e0e520fff5f9a125c0,03f1c3f215f12fb5a5b36885bb82389c85304dda..00f089fee4178b8d402307979b8adc898af6fdc7
@@@ -234,13 -234,7 +234,13 @@@ core.worktree:
        used in combination with repositories found automatically in
        a .git directory (i.e. $GIT_DIR is not set).
        This can be overridden by the GIT_WORK_TREE environment
 -      variable and the '--work-tree' command line option.
 +      variable and the '--work-tree' command line option. It can be
 +      a absolute path or relative path to the directory specified by
 +      --git-dir or GIT_DIR.
 +      Note: If --git-dir or GIT_DIR are specified but none of
 +      --work-tree, GIT_WORK_TREE and core.worktree is specified,
 +      the current working directory is regarded as the top directory
 +      of your working tree.
  
  core.logAllRefUpdates::
        Enable the reflog. Updates to a ref <ref> is logged to the file
@@@ -267,12 -261,7 +267,12 @@@ core.sharedRepository:
        group-writable). When 'all' (or 'world' or 'everybody'), the
        repository will be readable by all users, additionally to being
        group-shareable. When 'umask' (or 'false'), git will use permissions
 -      reported by umask(2). See linkgit:git-init[1]. False by default.
 +      reported by umask(2). When '0xxx', where '0xxx' is an octal number,
 +      files in the repository will have this mode value. '0xxx' will override
 +      user's umask value, and thus, users with a safe umask (0077) can use
 +      this option. Examples: '0660' is equivalent to 'group'. '0640' is a
 +      repository that is group-readable but not group-writable.
 +      See linkgit:git-init[1]. False by default.
  
  core.warnAmbiguousRefs::
        If true, git will warn you if the ref name you passed it is ambiguous
@@@ -921,6 -910,10 +921,10 @@@ remote.<name>.push:
        The default set of "refspec" for linkgit:git-push[1]. See
        linkgit:git-push[1].
  
+ remote.<name>.mirror::
+       If true, pushing to this remote will automatically behave
+       as if the `\--mirror` option was given on the command line.
  remote.<name>.skipDefaultUpdate::
        If true, this remote will be skipped by default when updating
        using the update subcommand of linkgit:git-remote[1].
index 05859491378243639e81c9c8ab7deffb90d83d07,dc1d4b0b6446e568933c74c78987473127045798..f06d94e318d6d0bf918430bafc746e96a2abe7a1
@@@ -35,15 -35,14 +35,15 @@@ OPTION
        by the source ref, followed by a colon `:`, followed by
        the destination ref.
  +
 -The <src> side can be an
 -arbitrary "SHA1 expression" that can be used as an
 -argument to `git-cat-file -t`.  E.g. `master~4` (push
 -four parents before the current master head).
 +The <src> side represents the source branch (or arbitrary
 +"SHA1 expression", such as `master~4` (four parents before the
 +tip of `master` branch); see linkgit:git-rev-parse[1]) that you
 +want to push.  The <dst> side represents the destination location.
  +
  The local ref that matches <src> is used
 -to fast forward the remote ref that matches <dst>.  If
 -the optional plus `+` is used, the remote ref is updated
 +to fast forward the remote ref that matches <dst> (or, if no <dst> was
 +specified, the same ref that <src> referred to locally).  If
 +the optional leading plus `+` is used, the remote ref is updated
  even if it does not result in a fast forward update.
  +
  Note: If no explicit refspec is found, (that is neither
@@@ -70,7 -69,9 +70,9 @@@ the remote repository
        be mirrored to the remote repository.  Newly created local
        refs will be pushed to the remote end, locally updated refs
        will be force updated on the remote end, and deleted refs
-       will be removed from the remote end.
+       will be removed from the remote end.  This is the default
+       if the configuration option `remote.<remote>.mirror` is
+       set.
  
  \--dry-run::
        Do everything except actually send the updates.
@@@ -166,8 -167,7 +168,8 @@@ git push origin master:
        Find a ref that matches `master` in the source repository
        (most likely, it would find `refs/heads/master`), and update
        the same ref (e.g. `refs/heads/master`) in `origin` repository
 -      with it.
 +      with it.  If `master` did not exist remotely, it would be
 +      created.
  
  git push origin :experimental::
        Find a ref that matches `experimental` in the `origin` repository
@@@ -181,10 -181,9 +183,10 @@@ git push origin master:satellite/master
  
  git push origin master:refs/heads/experimental::
        Create the branch `experimental` in the `origin` repository
 -      by copying the current `master` branch.  This form is usually
 -      needed to create a new branch in the remote repository as
 -      there is no `experimental` branch to match.
 +      by copying the current `master` branch.  This form is only
 +      needed to create a new branch or tag in the remote repository when
 +      the local name and the remote name are different; otherwise,
 +      the ref name on its own will work.
  
  Author
  ------
diff --combined builtin-remote.c
index 93bb84e1d4c762c6c049276202ebc2320447e9c8,9d4432bcd5c4104482eca65bf7d06b8b60b8c184..8b63619ef08a2ac3d96000908fe4986396ddd6a2
@@@ -107,7 -107,6 +107,7 @@@ static int add(int argc, const char **a
                struct path_list_item *item = track.items + i;
  
                strbuf_reset(&buf2);
 +              strbuf_addch(&buf2, '+');
                if (mirror)
                        strbuf_addf(&buf2, "refs/%s:refs/%s",
                                        item->path, item->path);
                        return 1;
        }
  
+       if (mirror) {
+               strbuf_reset(&buf);
+               strbuf_addf(&buf, "remote.%s.mirror", name);
+               if (git_config_set(buf.buf, "yes"))
+                       return 1;
+       }
        if (fetch && fetch_remote(name))
                return 1;
  
diff --combined remote.c
index 2d9af4023eba6f8b2fe528ccbf03569fcaa265ee,65ff4141d1317a581942a8979dfe50c0e09eb502..870d224a3931bf0468c0b74334c0fb49a06ad731
+++ b/remote.c
@@@ -337,44 -337,49 +337,49 @@@ static int handle_config(const char *ke
                return 0;
        }
        remote = make_remote(name, subkey - name);
-       if (!value) {
-               /* if we ever have a boolean variable, e.g. "remote.*.disabled"
-                * [remote "frotz"]
-                *      disabled
-                * is a valid way to set it to true; we get NULL in value so
-                * we need to handle it here.
-                *
-                * if (!strcmp(subkey, ".disabled")) {
-                *      val = git_config_bool(key, value);
-                *      return 0;
-                * } else
-                *
-                */
-               return 0; /* ignore unknown booleans */
-       }
-       if (!strcmp(subkey, ".url")) {
-               add_url(remote, xstrdup(value));
+       if (!strcmp(subkey, ".mirror"))
+               remote->mirror = git_config_bool(key, value);
+       else if (!strcmp(subkey, ".skipdefaultupdate"))
+               remote->skip_default_update = git_config_bool(key, value);
+       else if (!strcmp(subkey, ".url")) {
+               const char *v;
+               if (git_config_string(&v, key, value))
+                       return -1;
+               add_url(remote, v);
        } else if (!strcmp(subkey, ".push")) {
-               add_push_refspec(remote, xstrdup(value));
+               const char *v;
+               if (git_config_string(&v, key, value))
+                       return -1;
+               add_push_refspec(remote, v);
        } else if (!strcmp(subkey, ".fetch")) {
-               add_fetch_refspec(remote, xstrdup(value));
+               const char *v;
+               if (git_config_string(&v, key, value))
+                       return -1;
+               add_fetch_refspec(remote, v);
        } else if (!strcmp(subkey, ".receivepack")) {
+               const char *v;
+               if (git_config_string(&v, key, value))
+                       return -1;
                if (!remote->receivepack)
-                       remote->receivepack = xstrdup(value);
+                       remote->receivepack = v;
                else
                        error("more than one receivepack given, using the first");
        } else if (!strcmp(subkey, ".uploadpack")) {
+               const char *v;
+               if (git_config_string(&v, key, value))
+                       return -1;
                if (!remote->uploadpack)
-                       remote->uploadpack = xstrdup(value);
+                       remote->uploadpack = v;
                else
                        error("more than one uploadpack given, using the first");
        } else if (!strcmp(subkey, ".tagopt")) {
                if (!strcmp(value, "--no-tags"))
                        remote->fetch_tags = -1;
        } else if (!strcmp(subkey, ".proxy")) {
-               remote->http_proxy = xstrdup(value);
-       } else if (!strcmp(subkey, ".skipdefaultupdate"))
-               remote->skip_default_update = 1;
+               return git_config_string((const char **)&remote->http_proxy,
+                                        key, value);
+       }
        return 0;
  }
  
@@@ -812,26 -817,6 +817,26 @@@ static struct ref *make_linked_ref(cons
        return ret;
  }
  
 +static char *guess_ref(const char *name, struct ref *peer)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      unsigned char sha1[20];
 +
 +      const char *r = resolve_ref(peer->name, sha1, 1, NULL);
 +      if (!r)
 +              return NULL;
 +
 +      if (!prefixcmp(r, "refs/heads/"))
 +              strbuf_addstr(&buf, "refs/heads/");
 +      else if (!prefixcmp(r, "refs/tags/"))
 +              strbuf_addstr(&buf, "refs/tags/");
 +      else
 +              return NULL;
 +
 +      strbuf_addstr(&buf, name);
 +      return strbuf_detach(&buf, NULL);
 +}
 +
  static int match_explicit(struct ref *src, struct ref *dst,
                          struct ref ***dst_tail,
                          struct refspec *rs,
        struct ref *matched_src, *matched_dst;
  
        const char *dst_value = rs->dst;
 +      char *dst_guess;
  
        if (rs->pattern)
                return errs;
        case 0:
                if (!memcmp(dst_value, "refs/", 5))
                        matched_dst = make_linked_ref(dst_value, dst_tail);
 +              else if((dst_guess = guess_ref(dst_value, matched_src)))
 +                      matched_dst = make_linked_ref(dst_guess, dst_tail);
                else
 -                      error("dst refspec %s does not match any "
 -                            "existing ref on the remote and does "
 -                            "not start with refs/.", dst_value);
 +                      error("unable to push to unqualified destination: %s\n"
 +                            "The destination refspec neither matches an "
 +                            "existing ref on the remote nor\n"
 +                            "begins with refs/, and we are unable to "
 +                            "guess a prefix based on the source ref.",
 +                            dst_value);
                break;
        default:
                matched_dst = NULL;