Merge branch 'mm/simple-push'
authorJunio C Hamano <gitster@pobox.com>
Wed, 2 May 2012 20:51:24 +0000 (13:51 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 2 May 2012 20:51:24 +0000 (13:51 -0700)
New users tend to work on one branch at a time and push the result
out. The current and upstream modes of push is a more suitable default
mode than matching mode for these people, but neither is surprise-free
depending on how the project is set up. Introduce a "simple" mode that
is a subset of "upstream" but only works when the branch is named the same
between the remote and local repositories.

The plan is to make it the new default when push.default is not
configured.

By Matthieu Moy (5) and others
* mm/simple-push:
push.default doc: explain simple after upstream
push: document the future default change for push.default (matching -> simple)
t5570: use explicit push refspec
push: introduce new push.default mode "simple"
t5528-push-default.sh: add helper functions
Undocument deprecated alias 'push.default=tracking'
Documentation: explain push.default option a bit more

1  2 
Documentation/config.txt
builtin/push.c
cache.h
config.c
diff --combined Documentation/config.txt
index 83ad8ebce01ab0cf1af1bb1b50fd5f5b37f0f292,6a4c130602bfb36e816347281c17d69e6f7aa4d3..40a6e8fb891bdf62b646264d26deb4457e156fa4
@@@ -95,9 -95,7 +95,9 @@@ included file is expanded immediately, 
  found at the location of the include directive. If the value of the
  `include.path` variable is a relative path, the path is considered to be
  relative to the configuration file in which the include directive was
 -found. See below for examples.
 +found. The value of `include.path` is subject to tilde expansion: `{tilde}/`
 +is expanded to the value of `$HOME`, and `{tilde}user/` to the specified
 +user's home directory. See below for examples.
  
  Example
  ~~~~~~~
        [include]
                path = /path/to/foo.inc ; include by absolute path
                path = foo ; expand "foo" relative to the current file
 +              path = ~/foo ; expand "foo" in your $HOME directory
  
  Variables
  ~~~~~~~~~
@@@ -1683,12 -1680,30 +1683,30 @@@ push.default:
        line. Possible values are:
  +
  * `nothing` - do not push anything.
- * `matching` - push all matching branches.
-   All branches having the same name in both ends are considered to be
-   matching. This is the default.
+ * `matching` - push all branches having the same name in both ends.
+   This is for those who prepare all the branches into a publishable
+   shape and then push them out with a single command.  It is not
+   appropriate for pushing into a repository shared by multiple users,
+   since locally stalled branches will attempt a non-fast forward push
+   if other users updated the branch.
+   +
+   This is currently the default, but Git 2.0 will change the default
+   to `simple`.
  * `upstream` - push the current branch to its upstream branch.
- * `tracking` - deprecated synonym for `upstream`.
+   With this, `git push` will update the same remote ref as the one which
+   is merged by `git pull`, making `push` and `pull` symmetrical.
+   See "branch.<name>.merge" for how to configure the upstream branch.
+ * `simple` - like `upstream`, but refuses to push if the upstream
+   branch's name is different from the local one. This is the safest
+   option and is well-suited for beginners. It will become the default
+   in Git 2.0.
  * `current` - push the current branch to a branch of the same name.
+   +
+   The `simple`, `current` and `upstream` modes are for those who want to
+   push out a single branch after finishing work, even when the other
+   branches are not yet ready to be pushed out. If you are working with
+   other people to push into the same shared repository, you would want
+   to use one of these.
  
  rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
diff --combined builtin/push.c
index 19c40d7a55199984d7cdc1efbacfca7b628a4d20,08ccb891c679827aa904b6fe93a5a7d9d9bcaaae..fdfcc6c71607a7412666b7cc647db98e1b85c8c1
@@@ -76,7 -76,44 +76,44 @@@ static int push_url_of_remote(struct re
        return remote->url_nr;
  }
  
- static void setup_push_upstream(struct remote *remote)
+ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote) {
+       /*
+        * There's no point in using shorten_unambiguous_ref here,
+        * as the ambiguity would be on the remote side, not what
+        * we have locally. Plus, this is supposed to be the simple
+        * mode. If the user is doing something crazy like setting
+        * upstream to a non-branch, we should probably be showing
+        * them the big ugly fully qualified ref.
+        */
+       const char *advice_maybe = "";
+       const char *short_upstream =
+               skip_prefix(branch->merge[0]->src, "refs/heads/");
+       if (!short_upstream)
+               short_upstream = branch->merge[0]->src;
+       /*
+        * Don't show advice for people who explicitely set
+        * push.default.
+        */
+       if (push_default == PUSH_DEFAULT_UNSPECIFIED)
+               advice_maybe = _("\n"
+                                "To choose either option permanently, "
+                                "see push.default in 'git help config'.");
+       die(_("The upstream branch of your current branch does not match\n"
+             "the name of your current branch.  To push to the upstream branch\n"
+             "on the remote, use\n"
+             "\n"
+             "    git push %s HEAD:%s\n"
+             "\n"
+             "To push to the branch of the same name on the remote, use\n"
+             "\n"
+             "    git push %s %s\n"
+             "%s"),
+           remote->name, short_upstream,
+           remote->name, branch->name, advice_maybe);
+ }
+ static void setup_push_upstream(struct remote *remote, int simple)
  {
        struct strbuf refspec = STRBUF_INIT;
        struct branch *branch = branch_get(NULL);
                      "your current branch '%s', without telling me what to push\n"
                      "to update which remote branch."),
                    remote->name, branch->name);
+       if (simple && strcmp(branch->refname, branch->merge[0]->src))
+               die_push_simple(branch, remote);
  
        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
        add_refspec(refspec.buf);
@@@ -119,8 -158,12 +158,12 @@@ static void setup_default_push_refspecs
                add_refspec(":");
                break;
  
+       case PUSH_DEFAULT_SIMPLE:
+               setup_push_upstream(remote, 1);
+               break;
        case PUSH_DEFAULT_UPSTREAM:
-               setup_push_upstream(remote);
+               setup_push_upstream(remote, 0);
                break;
  
        case PUSH_DEFAULT_CURRENT:
@@@ -284,21 -327,13 +327,21 @@@ static int option_parse_recurse_submodu
                                   const char *arg, int unset)
  {
        int *flags = opt->value;
 +
 +      if (*flags & (TRANSPORT_RECURSE_SUBMODULES_CHECK |
 +                    TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND))
 +              die("%s can only be used once.", opt->long_name);
 +
        if (arg) {
                if (!strcmp(arg, "check"))
                        *flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
 +              else if (!strcmp(arg, "on-demand"))
 +                      *flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND;
                else
                        die("bad %s argument: %s", opt->long_name, arg);
        } else
 -              die("option %s needs an argument (check)", opt->long_name);
 +              die("option %s needs an argument (check|on-demand)",
 +                              opt->long_name);
  
        return 0;
  }
diff --combined cache.h
index d8f6f1e78e1da3e47996bf7bcc9ac6e5b5f8e2b5,b60d49085e26ac543e810278b4066dfb33651c2e..5e419a11cc7c92f60b89d6350597cb4085e34dfb
+++ b/cache.h
@@@ -105,9 -105,6 +105,9 @@@ struct cache_header 
        unsigned int hdr_entries;
  };
  
 +#define INDEX_FORMAT_LB 2
 +#define INDEX_FORMAT_UB 4
 +
  /*
   * The "cache_time" is just the low 32 bits of the
   * time. It doesn't matter if it overflows - we only
@@@ -118,6 -115,48 +118,6 @@@ struct cache_time 
        unsigned int nsec;
  };
  
 -/*
 - * dev/ino/uid/gid/size are also just tracked to the low 32 bits
 - * Again - this is just a (very strong in practice) heuristic that
 - * the inode hasn't changed.
 - *
 - * We save the fields in big-endian order to allow using the
 - * index file over NFS transparently.
 - */
 -struct ondisk_cache_entry {
 -      struct cache_time ctime;
 -      struct cache_time mtime;
 -      unsigned int dev;
 -      unsigned int ino;
 -      unsigned int mode;
 -      unsigned int uid;
 -      unsigned int gid;
 -      unsigned int size;
 -      unsigned char sha1[20];
 -      unsigned short flags;
 -      char name[FLEX_ARRAY]; /* more */
 -};
 -
 -/*
 - * This struct is used when CE_EXTENDED bit is 1
 - * The struct must match ondisk_cache_entry exactly from
 - * ctime till flags
 - */
 -struct ondisk_cache_entry_extended {
 -      struct cache_time ctime;
 -      struct cache_time mtime;
 -      unsigned int dev;
 -      unsigned int ino;
 -      unsigned int mode;
 -      unsigned int uid;
 -      unsigned int gid;
 -      unsigned int size;
 -      unsigned char sha1[20];
 -      unsigned short flags;
 -      unsigned short flags2;
 -      char name[FLEX_ARRAY]; /* more */
 -};
 -
  struct cache_entry {
        struct cache_time ce_ctime;
        struct cache_time ce_mtime;
@@@ -214,6 -253,9 +214,6 @@@ static inline size_t ce_namelen(const s
  }
  
  #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 -#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
 -                          ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
 -                          ondisk_cache_entry_size(ce_namelen(ce)))
  #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
  #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
@@@ -264,11 -306,13 +264,11 @@@ static inline unsigned int canon_mode(u
        return S_IFGITLINK;
  }
  
 -#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
  #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
 -#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
 -#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
  
  struct index_state {
        struct cache_entry **cache;
 +      unsigned int version;
        unsigned int cache_nr, cache_alloc, cache_changed;
        struct string_list *resolve_undo;
        struct cache_tree *cache_tree;
@@@ -580,6 -624,7 +580,7 @@@ enum rebase_setup_type 
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
+       PUSH_DEFAULT_SIMPLE,
        PUSH_DEFAULT_UPSTREAM,
        PUSH_DEFAULT_CURRENT,
        PUSH_DEFAULT_UNSPECIFIED
diff --combined config.c
index ac69cb62935cfe86fec4b557ad6546366e6b7d70,bfe0c79aea43c8f9974974fc6248310791152b91..eeee986022fc8f235c43a2d45eb942fc0095f8b1
+++ b/config.c
@@@ -37,11 -37,6 +37,11 @@@ static int handle_path_include(const ch
  {
        int ret = 0;
        struct strbuf buf = STRBUF_INIT;
 +      char *expanded = expand_user_path(path);
 +
 +      if (!expanded)
 +              return error("Could not expand include path '%s'", path);
 +      path = expanded;
  
        /*
         * Use an absolute path as-is, but interpret relative paths
@@@ -68,7 -63,6 +68,7 @@@
                inc->depth--;
        }
        strbuf_release(&buf);
 +      free(expanded);
        return ret;
  }
  
@@@ -835,6 -829,8 +835,8 @@@ static int git_default_push_config(cons
                        push_default = PUSH_DEFAULT_NOTHING;
                else if (!strcmp(value, "matching"))
                        push_default = PUSH_DEFAULT_MATCHING;
+               else if (!strcmp(value, "simple"))
+                       push_default = PUSH_DEFAULT_SIMPLE;
                else if (!strcmp(value, "upstream"))
                        push_default = PUSH_DEFAULT_UPSTREAM;
                else if (!strcmp(value, "tracking")) /* deprecated */
                        push_default = PUSH_DEFAULT_CURRENT;
                else {
                        error("Malformed value for %s: %s", var, value);
-                       return error("Must be one of nothing, matching, "
-                                    "tracking or current.");
+                       return error("Must be one of nothing, matching, simple, "
+                                    "upstream or current.");
                }
                return 0;
        }
@@@ -1558,42 -1554,20 +1560,42 @@@ static int section_name_match (const ch
        return 0;
  }
  
 +static int section_name_is_ok(const char *name)
 +{
 +      /* Empty section names are bogus. */
 +      if (!*name)
 +              return 0;
 +
 +      /*
 +       * Before a dot, we must be alphanumeric or dash. After the first dot,
 +       * anything goes, so we can stop checking.
 +       */
 +      for (; *name && *name != '.'; name++)
 +              if (*name != '-' && !isalnum(*name))
 +                      return 0;
 +      return 1;
 +}
 +
  /* if new_name == NULL, the section is removed instead */
  int git_config_rename_section_in_file(const char *config_filename,
                                      const char *old_name, const char *new_name)
  {
        int ret = 0, remove = 0;
        char *filename_buf = NULL;
 -      struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
 +      struct lock_file *lock;
        int out_fd;
        char buf[1024];
        FILE *config_file;
  
 +      if (new_name && !section_name_is_ok(new_name)) {
 +              ret = error("invalid section name: %s", new_name);
 +              goto out;
 +      }
 +
        if (!config_filename)
                config_filename = filename_buf = git_pathdup("config");
  
 +      lock = xcalloc(sizeof(struct lock_file), 1);
        out_fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (out_fd < 0) {
                ret = error("could not lock config file %s", config_filename);