Merge branch 'fg/push-default'
authorJunio C Hamano <gitster@pobox.com>
Thu, 26 Mar 2009 07:26:25 +0000 (00:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 26 Mar 2009 07:26:25 +0000 (00:26 -0700)
* fg/push-default:
builtin-push.c: Fix typo: "anythig" -> "anything"
Display warning for default git push with no push.default config
New config push.default to decide default behavior for push

Conflicts:
Documentation/config.txt

1  2 
Documentation/RelNotes-1.6.3.txt
Documentation/config.txt
builtin-push.c
cache.h
config.c
index 5860b515f57adee9ebf0e3ddb4f8042a7f46dc8a,7c02b2a305a66133011b635951a5da8b1cf8e42f..0d8260a842863828b0e967407f33c8f5c231b178
@@@ -22,6 -22,13 +22,13 @@@ branch pointed at by its HEAD, gets a l
  should happen upon such a push by setting the configuration variable
  receive.denyDeleteCurrent in the receiving repository.
  
+ In a future release, the default of "git push" without further
+ arguments might be changed. Currently, it will push all matching
+ refspecs to the current remote.  A configuration variable push.default
+ has been introduced to select the default behaviour.  To ease the
+ transition, a big warning is issued if this is not configured and a
+ git push without arguments is attempted.
  
  Updates since v1.6.2
  --------------------
  
  (performance)
  
 +* many uses of lstat(2) in the codepath for "git checkout" have been
 +  optimized out.
 +
  (usability, bells and whistles)
  
 +* rsync:/path/to/repo can be used to run git over rsync for local
 +  repositories.  It may not be useful in practice; meant primarily for
 +  testing.
 +
 +* (msysgit) progress output that is sent over the sideband protocol can
 +  be handled appropriately in Windows console.
 +
  * "--pretty=<style>" option to the log family of commands can now be
    spelled as "--format=<style>".  In addition, --format=%formatstring
    is a short-hand for --pretty=tformat:%formatstring.
  * git-bisect shows not just the number of remaining commits whose goodness
    is unknown, but also shows the estimated number of remaining rounds.
  
 +* You can give --date=<format> option to git-blame.
 +
  * git-branch -r shows HEAD symref that points at a remote branch in
    interest of each tracked remote repository.
  
  * git-config learned -e option to open an editor to edit the config file
    directly.
  
 +* git-clone runs post-checkout hook when run without --no-checkout.
 +
  * git-format-patch can be told to use attachment with a new configuration,
    format.attach.
  
 +* git-format-patch can be told to produce deep or shallow message threads.
 +
 +* git-grep learned to highlight the found substrings in color.
 +
  * git-imap-send learned to work around Thunderbird's inability to easily
    disable format=flowed with a new configuration, imap.preformattedHTML.
  
    descendant of the commit you are rebasing onto with --force-rebase
    option.
  
 +* git-rebase can be told to report diffstat with the --stat option.
 +
 +* Output from git-remote command has been vastly improved.
 +
  * git-send-email learned --confirm option to review the Cc: list before
    sending the messages out.
  
@@@ -92,8 -77,6 +99,8 @@@
  
  * Test scripts can be run under valgrind.
  
 +* Makefile learned 'coverage' option to run the test suites with
 +  coverage tracking enabled.
  
  Fixes since v1.6.2
  ------------------
@@@ -104,11 -87,25 +111,11 @@@ release, unless otherwise noted
  Here are fixes that this release has, but have not been backported to
  v1.6.2.X series.
  
 -* .gitignore learned to handle backslash as a quoting mechanism for
 -  comment introduction character "#" (backport by merging dd482ee if
 -  needed).
 -
 -* timestamp output in --date=relative mode used to display timestamps that
 -  are long time ago in the default mode; it now uses "N years M months
 -  ago", and "N years ago" (backport by picking 10edf37 if needed).
 -
 -* git-add -i/-p now works with non-ASCII pathnames (backport by picking
 -  8851f48 if needed).
 -
 -* "git hash-object -w" did not read from the configuration file from the
 -  correct .git directory (backport by merging 272459a if needed).
 -
 -* git-send-email learned to correctly handle multiple Cc: addresses
 -  (backport by merging afe756c if needed).
 +* git-gc spent excessive amount of time to decide if an object appears
 +  in a locally existing pack (if needed, backport by merging 69e020a).
  
  ---
  exec >/var/tmp/1
 -O=v1.6.2-77-g8cc3fe4
 +O=v1.6.2.1-213-g7d4e3a7
  echo O=$(git describe master)
  git shortlog --no-merges $O..master ^maint
diff --combined Documentation/config.txt
index 12540b605f4f15e93703bed226ab43c0b8d6716b,7b2b3f44aa5cbd1cf5c17fb7976a1e29d11c8c90..750675530cf4a15137e837c9d15acb8f23ae7cd3
@@@ -25,7 -25,7 +25,7 @@@ blank lines are ignored
  The file consists of sections and variables.  A section begins with
  the name of the section in square brackets and continues until the next
  section begins.  Section names are not case sensitive.  Only alphanumeric
 -characters, '`-`' and '`.`' are allowed in section names.  Each variable
 +characters, `-` and `.` are allowed in section names.  Each variable
  must belong to some section, which means that there must be section
  header before first setting of a variable.
  
@@@ -39,7 -39,7 +39,7 @@@ in the section header, like in example 
  --------
  
  Subsection names can contain any characters except newline (doublequote
 -'`"`' and backslash have to be escaped as '`\"`' and '`\\`',
 +`"` and backslash have to be escaped as `\"` and `\\`,
  respectively) and are case sensitive.  Section header cannot span multiple
  lines.  Variables may belong directly to a section or to a given subsection.
  You can have `[section]` if you have `[section "subsection"]`, but you
@@@ -53,7 -53,7 +53,7 @@@ All the other lines are recognized as s
  'name = value'.  If there is no equal sign on the line, the entire line
  is taken as 'name' and the variable is recognized as boolean "true".
  The variable names are case-insensitive and only alphanumeric
 -characters and '`-`' are allowed.  There can be more than one value
 +characters and `-` are allowed.  There can be more than one value
  for a given variable; we say then that variable is multivalued.
  
  Leading and trailing whitespace in a variable value is discarded.
@@@ -69,15 -69,15 +69,15 @@@ String values may be entirely or partia
  You need to enclose variable value in double quotes if you want to
  preserve leading or trailing whitespace, or if variable value contains
  beginning of comment characters (if it contains '#' or ';').
 -Double quote '`"`' and backslash '`\`' characters in variable value must
 -be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
 +Double quote `"` and backslash `\` characters in variable value must
 +be escaped: use `\"` for `"` and `\\` for `\`.
  
 -The following escape sequences (beside '`\"`' and '`\\`') are recognized:
 -'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB)
 -and '`\b`' for backspace (BS).  No other char escape sequence, nor octal
 +The following escape sequences (beside `\"` and `\\`) are recognized:
 +`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
 +and `\b` for backspace (BS).  No other char escape sequence, nor octal
  char sequences are valid.
  
 -Variable value ending in a '`\`' is continued on the next line in the
 +Variable value ending in a `\` is continued on the next line in the
  customary UNIX fashion.
  
  Some variables may require special value format.
@@@ -221,11 -221,6 +221,11 @@@ core.gitProxy:
  Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
  (which always applies universally, without the special "for"
  handling).
 ++
 +The special string `none` can be used as the proxy command to
 +specify that no proxy be used for a given domain pattern.
 +This is useful for excluding servers inside a firewall from
 +proxy use, while defaulting to a common proxy for external domains.
  
  core.ignoreStat::
        If true, commands which modify both the working tree and the index
@@@ -387,9 -382,9 +387,9 @@@ core.pager:
        to override git's default settings this way, you need
        to be explicit.  For example, to disable the S option
        in a backward compatible manner, set `core.pager`
 -      to "`less -+$LESS -FRX`".  This will be passed to the
 +      to `less -+$LESS -FRX`.  This will be passed to the
        shell by git, which will translate the final command to
 -      "`LESS=FRSX less -+FRSX -FRX`".
 +      `LESS=FRSX less -+FRSX -FRX`.
  
  core.whitespace::
        A comma separated list of common whitespace problems to
@@@ -553,25 -548,6 +553,25 @@@ color.diff.<slot>:
        whitespace errors). The values of these variables may be specified as
        in color.branch.<slot>.
  
 +color.grep::
 +      When set to `always`, always highlight matches.  When `false` (or
 +      `never`), never.  When set to `true` or `auto`, use color only
 +      when the output is written to the terminal.  Defaults to `false`.
 +
 +color.grep.external::
 +      The string value of this variable is passed to an external 'grep'
 +      command as a command line option if match highlighting is turned
 +      on.  If set to an empty string, no option is passed at all,
 +      turning off coloring for external 'grep' calls; this is the default.
 +      For GNU grep, set it to `--color=always` to highlight matches even
 +      when a pager is used.
 +
 +color.grep.match::
 +      Use customized color for matches.  The value of this variable
 +      may be specified as in color.branch.<slot>.  It is passed using
 +      the environment variables 'GREP_COLOR' and 'GREP_COLORS' when
 +      calling an external 'grep'.
 +
  color.interactive::
        When set to `always`, always use colors for interactive prompts
        and displays (such as those used by "git-add --interactive").
@@@ -701,16 -677,6 +701,16 @@@ format.pretty:
        See linkgit:git-log[1], linkgit:git-show[1],
        linkgit:git-whatchanged[1].
  
 +format.thread::
 +      The default threading style for 'git-format-patch'.  Can be
 +      either a boolean value, `shallow` or `deep`.  'Shallow'
 +      threading makes every mail a reply to the head of the series,
 +      where the head is chosen from the cover letter, the
 +      `\--in-reply-to`, and the first patch mail, in this order.
 +      'Deep' threading makes every mail a reply to the previous one.
 +      A true boolean value is the same as `shallow`, and a false
 +      value disables threading.
 +
  gc.aggressiveWindow::
        The window size parameter used in the delta compression
        algorithm used by 'git-gc --aggressive'.  This defaults
@@@ -1185,7 -1151,7 +1185,7 @@@ pager.<cmd>:
        particular git subcommand when writing to a tty.  If
        `\--paginate` or `\--no-pager` is specified on the command line,
        it takes precedence over this option.  To disable pagination for
 -      all commands, set `core.pager` or 'GIT_PAGER' to "`cat`".
 +      all commands, set `core.pager` or `GIT_PAGER` to `cat`.
  
  pull.octopus::
        The default merge strategy to use when pulling multiple branches
  pull.twohead::
        The default merge strategy to use when pulling a single branch.
  
+ push.default::
+       Defines the action git push should take if no refspec is given
+       on the command line, no refspec is configured in the remote, and
+       no refspec is implied by any of the options given on the command
+       line.
+ +
+ The term `current remote` means the remote configured for the current
+ branch, or `origin` if no remote is configured. `origin` is also used
+ if you are not on any branch. Possible values are:
+ +
+ * `nothing` do not push anything.
+ * `matching` push all matching branches to the current remote.
+   All branches having the same name in both ends are considered to be
+   matching. This is the current default value.
+ * `tracking` push the current branch to the branch it is tracking.
+ * `current` push the current branch to a branch of the same name on the
+   current remote.
 +rebase.stat::
 +      Whether to show a diffstat of what changed upstream since the last
 +      rebase. False by default.
 +
  receive.fsckObjects::
        If it is set to true, git-receive-pack will check all received
        objects. It will abort in the case of a malformed object or a
diff --combined builtin-push.c
index ca36fb1e5834fc581bc7bf8ed54184bbecdc2389,bbf019850e5b93a2e36584fc00573dd180a19be0..2eabcd3bdfb3f5d5705125a8f74d21d4ab1deafc
@@@ -48,16 -48,78 +48,81 @@@ static void set_refspecs(const char **r
        }
  }
  
+ static void setup_push_tracking(void)
+ {
+       struct strbuf refspec = STRBUF_INIT;
+       struct branch *branch = branch_get(NULL);
+       if (!branch)
+               die("You are not currently on a branch.");
+       if (!branch->merge_nr)
+               die("The current branch %s is not tracking anything.",
+                   branch->name);
+       if (branch->merge_nr != 1)
+               die("The current branch %s is tracking multiple branches, "
+                   "refusing to push.", branch->name);
+       strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
+       add_refspec(refspec.buf);
+ }
+ static const char *warn_unconfigured_push_msg[] = {
+       "You did not specify any refspecs to push, and the current remote",
+       "has not configured any push refspecs. The default action in this",
+       "case is to push all matching refspecs, that is, all branches",
+       "that exist both locally and remotely will be updated.  This may",
+       "not necessarily be what you want to happen.",
+       "",
+       "You can specify what action you want to take in this case, and",
+       "avoid seeing this message again, by configuring 'push.default' to:",
+       "  'nothing'  : Do not push anything",
+       "  'matching' : Push all matching branches (default)",
+       "  'tracking' : Push the current branch to whatever it is tracking",
+       "  'current'  : Push the current branch"
+ };
+ static void warn_unconfigured_push(void)
+ {
+       int i;
+       for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
+               warning("%s", warn_unconfigured_push_msg[i]);
+ }
+ static void setup_default_push_refspecs(void)
+ {
+       git_config(git_default_config, NULL);
+       switch (push_default) {
+       case PUSH_DEFAULT_UNSPECIFIED:
+               warn_unconfigured_push();
+               /* fallthrough */
+       case PUSH_DEFAULT_MATCHING:
+               add_refspec(":");
+               break;
+       case PUSH_DEFAULT_TRACKING:
+               setup_push_tracking();
+               break;
+       case PUSH_DEFAULT_CURRENT:
+               add_refspec("HEAD");
+               break;
+       case PUSH_DEFAULT_NOTHING:
+               die("You didn't specify any refspecs to push, and "
+                   "push.default is \"nothing\".");
+               break;
+       }
+ }
  static int do_push(const char *repo, int flags)
  {
        int i, errs;
        struct remote *remote = remote_get(repo);
  
 -      if (!remote)
 -              die("bad repository '%s'", repo);
 +      if (!remote) {
 +              if (repo)
 +                      die("bad repository '%s'", repo);
 +              die("No destination configured to push to.");
 +      }
  
        if (remote->mirror)
                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
                return error("--all and --mirror are incompatible");
        }
  
-       if (!refspec
-               && !(flags & TRANSPORT_PUSH_ALL)
-               && remote->push_refspec_nr) {
-               refspec = remote->push_refspec;
-               refspec_nr = remote->push_refspec_nr;
+       if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
+               if (remote->push_refspec_nr) {
+                       refspec = remote->push_refspec;
+                       refspec_nr = remote->push_refspec_nr;
+               } else if (!(flags & TRANSPORT_PUSH_MIRROR))
+                       setup_default_push_refspecs();
        }
        errs = 0;
        for (i = 0; i < remote->url_nr; i++) {
diff --combined cache.h
index 39789ee94a2f2e7dd1600115f4033ccf0e52c07b,df4f117ac660aeed05c47bede988f07b13697c18..f48e80bc057fb5970200cd12a791af56fa4eef8a
+++ b/cache.h
@@@ -140,8 -140,8 +140,8 @@@ struct ondisk_cache_entry_extended 
  };
  
  struct cache_entry {
 -      unsigned int ce_ctime;
 -      unsigned int ce_mtime;
 +      struct cache_time ce_ctime;
 +      struct cache_time ce_mtime;
        unsigned int ce_dev;
        unsigned int ce_ino;
        unsigned int ce_mode;
@@@ -282,7 -282,7 +282,7 @@@ struct index_state 
        struct cache_entry **cache;
        unsigned int cache_nr, cache_alloc, cache_changed;
        struct cache_tree *cache_tree;
 -      time_t timestamp;
 +      struct cache_time timestamp;
        void *alloc;
        unsigned name_hash_initialized : 1,
                 initialized : 1;
@@@ -428,7 -428,7 +428,7 @@@ extern int read_index_preload(struct in
  extern int read_index_from(struct index_state *, const char *path);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
 -extern int write_index(const struct index_state *, int newfd);
 +extern int write_index(struct index_state *, int newfd);
  extern int discard_index(struct index_state *);
  extern int unmerged_index(const struct index_state *);
  extern int verify_path(const char *path);
@@@ -443,7 -443,6 +443,7 @@@ extern int add_index_entry(struct index
  extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
  extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
  extern int remove_index_entry_at(struct index_state *, int pos);
 +extern void remove_marked_cache_entries(struct index_state *istate);
  extern int remove_file_from_index(struct index_state *, const char *path);
  #define ADD_CACHE_VERBOSE 1
  #define ADD_CACHE_PRETEND 2
@@@ -542,8 -541,17 +542,17 @@@ enum rebase_setup_type 
        AUTOREBASE_ALWAYS,
  };
  
+ enum push_default_type {
+       PUSH_DEFAULT_UNSPECIFIED = -1,
+       PUSH_DEFAULT_NOTHING = 0,
+       PUSH_DEFAULT_MATCHING,
+       PUSH_DEFAULT_TRACKING,
+       PUSH_DEFAULT_CURRENT,
+ };
  extern enum branch_track git_branch_track;
  extern enum rebase_setup_type autorebase;
+ extern enum push_default_type push_default;
  
  #define GIT_REPO_VERSION 0
  extern int repository_format_version;
@@@ -645,8 -653,7 +654,8 @@@ extern int check_sha1_signature(const u
  
  extern int move_temp_to_file(const char *tmpfile, const char *filename);
  
 -extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
 +extern int has_sha1_pack(const unsigned char *sha1);
 +extern int has_sha1_kept_pack(const unsigned char *sha1);
  extern int has_sha1_file(const unsigned char *sha1);
  extern int has_loose_object_nonlocal(const unsigned char *sha1);
  
@@@ -726,13 -733,11 +735,13 @@@ struct checkout 
  };
  
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 -extern int has_symlink_leading_path(int len, const char *name);
 -extern int has_symlink_or_noent_leading_path(int len, const char *name);
 -extern int has_dirs_only_path(int len, const char *name, int prefix_len);
 -extern void invalidate_lstat_cache(int len, const char *name);
 +extern int has_symlink_leading_path(const char *name, int len);
 +extern int has_symlink_or_noent_leading_path(const char *name, int len);
 +extern int has_dirs_only_path(const char *name, int len, int prefix_len);
 +extern void invalidate_lstat_cache(const char *name, int len);
  extern void clear_lstat_cache(void);
 +extern void schedule_dir_for_removal(const char *name, int len);
 +extern void remove_scheduled_dirs(void);
  
  extern struct alternate_object_database {
        struct alternate_object_database *next;
@@@ -805,7 -810,7 +814,7 @@@ struct ref 
  #define REF_HEADS     (1u << 1)
  #define REF_TAGS      (1u << 2)
  
 -extern struct ref *find_ref_by_name(struct ref *list, const char *name);
 +extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
  
  #define CONNECT_VERBOSE       (1u << 0)
  extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
@@@ -843,6 -848,7 +852,6 @@@ extern void *unpack_entry(struct packed
  extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
  extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
  extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
 -extern int matches_pack_name(struct packed_git *p, const char *name);
  
  /* Dumb servers support */
  extern int update_server_info(int);
diff --combined config.c
index 50efd639c4d68af1428a8a45606ae4897a8d2dd9,30443e32799270c84c6a89c03acae25de83b2476..b76fe4c6dcc966f8c7c15da44d15f7cf45740f5b
+++ b/config.c
@@@ -565,6 -565,31 +565,31 @@@ static int git_default_branch_config(co
        return 0;
  }
  
+ static int git_default_push_config(const char *var, const char *value)
+ {
+       if (!strcmp(var, "push.default")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               else if (!strcmp(value, "nothing"))
+                       push_default = PUSH_DEFAULT_NOTHING;
+               else if (!strcmp(value, "matching"))
+                       push_default = PUSH_DEFAULT_MATCHING;
+               else if (!strcmp(value, "tracking"))
+                       push_default = PUSH_DEFAULT_TRACKING;
+               else if (!strcmp(value, "current"))
+                       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 0;
+       }
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+ }
  static int git_default_mailmap_config(const char *var, const char *value)
  {
        if (!strcmp(var, "mailmap.file"))
@@@ -588,6 -613,9 +613,9 @@@ int git_default_config(const char *var
        if (!prefixcmp(var, "branch."))
                return git_default_branch_config(var, value);
  
+       if (!prefixcmp(var, "push."))
+               return git_default_push_config(var, value);
        if (!prefixcmp(var, "mailmap."))
                return git_default_mailmap_config(var, value);
  
@@@ -644,37 -672,28 +672,37 @@@ int git_config_global(void
  
  int git_config(config_fn_t fn, void *data)
  {
 -      int ret = 0;
 +      int ret = 0, found = 0;
        char *repo_config = NULL;
        const char *home = NULL;
  
        /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
        if (config_exclusive_filename)
                return git_config_from_file(fn, config_exclusive_filename, data);
 -      if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
 +      if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
 +              found += 1;
 +      }
  
        home = getenv("HOME");
        if (git_config_global() && home) {
                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 -              if (!access(user_config, R_OK))
 +              if (!access(user_config, R_OK)) {
                        ret += git_config_from_file(fn, user_config, data);
 +                      found += 1;
 +              }
                free(user_config);
        }
  
        repo_config = git_pathdup("config");
 -      ret += git_config_from_file(fn, repo_config, data);
 +      if (!access(repo_config, R_OK)) {
 +              ret += git_config_from_file(fn, repo_config, data);
 +              found += 1;
 +      }
        free(repo_config);
 +      if (found == 0)
 +              return -1;
        return ret;
  }