summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-archive.txt5
-rw-r--r--Documentation/git-config.txt2
-rw-r--r--Documentation/git-filter-branch.txt5
-rw-r--r--builtin-add.c3
-rw-r--r--builtin-grep.c90
-rw-r--r--builtin-log.c31
-rw-r--r--contrib/emacs/git.el197
-rw-r--r--diff-lib.c2
-rw-r--r--diff.c2
-rw-r--r--diffcore-rename.c19
-rwxr-xr-xgit-clone.sh6
-rwxr-xr-xt/t2200-add-update.sh11
-rwxr-xr-xt/t7002-grep.sh4
-rw-r--r--templates/hooks--update2
-rw-r--r--wt-status.c1
15 files changed, 296 insertions, 84 deletions
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index f2080eb6ad..e1e2d60fef 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -15,7 +15,8 @@ SYNOPSIS
DESCRIPTION
-----------
Creates an archive of the specified format containing the tree
-structure for the named tree. If <prefix> is specified it is
+structure for the named tree, and writes it out to the standard
+output. If <prefix> is specified it is
prepended to the filenames in the archive.
'git-archive' behaves differently when given a tree ID versus when
@@ -31,7 +32,7 @@ OPTIONS
-------
--format=<fmt>::
- Format of the resulting archive: 'tar', 'zip'... The default
+ Format of the resulting archive: 'tar' or 'zip'. The default
is 'tar'.
--list, -l::
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 5b794f4399..a592b61e2f 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -142,7 +142,7 @@ FILES
If not set explicitly with '--file', there are three files where
git-config will search for configuration options:
-.git/config::
+$GIT_DIR/config::
Repository specific configuration file. (The filename is
of course relative to the repository root, not the working
directory.)
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 29bb8cec0c..c878ed395e 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -220,11 +220,6 @@ git filter-branch --commit-filter '
fi' HEAD
------------------------------------------------------------------------------
-Note that the changes introduced by the commits, and not reverted by
-subsequent commits, will still be in the rewritten branch. If you want
-to throw out _changes_ together with the commits, you should use the
-interactive mode of gitlink:git-rebase[1].
-
The function 'skip_commits' is defined as follows:
--------------------------
diff --git a/builtin-add.c b/builtin-add.c
index 105a9f0e1f..3d8b8b4f89 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -95,9 +95,10 @@ static void update_callback(struct diff_queue_struct *q,
const char *path = p->one->path;
switch (p->status) {
default:
- die("unexpacted diff status %c", p->status);
+ die("unexpected diff status %c", p->status);
case DIFF_STATUS_UNMERGED:
case DIFF_STATUS_MODIFIED:
+ case DIFF_STATUS_TYPE_CHANGED:
add_file_to_cache(path, verbose);
break;
case DIFF_STATUS_DELETED:
diff --git a/builtin-grep.c b/builtin-grep.c
index e13cb31f2b..c7b45c4d58 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -187,6 +187,78 @@ static int exec_grep(int argc, const char **argv)
else die("maximum number of args exceeded"); \
} while (0)
+/*
+ * If you send a singleton filename to grep, it does not give
+ * the name of the file. GNU grep has "-H" but we would want
+ * that behaviour in a portable way.
+ *
+ * So we keep two pathnames in argv buffer unsent to grep in
+ * the main loop if we need to do more than one grep.
+ */
+static int flush_grep(struct grep_opt *opt,
+ int argc, int arg0, const char **argv, int *kept)
+{
+ int status;
+ int count = argc - arg0;
+ const char *kept_0 = NULL;
+
+ if (count <= 2) {
+ /*
+ * Because we keep at least 2 paths in the call from
+ * the main loop (i.e. kept != NULL), and MAXARGS is
+ * far greater than 2, this usually is a call to
+ * conclude the grep. However, the user could attempt
+ * to overflow the argv buffer by giving too many
+ * options to leave very small number of real
+ * arguments even for the call in the main loop.
+ */
+ if (kept)
+ die("insanely many options to grep");
+
+ /*
+ * If we have two or more paths, we do not have to do
+ * anything special, but we need to push /dev/null to
+ * get "-H" behaviour of GNU grep portably but when we
+ * are not doing "-l" nor "-L" nor "-c".
+ */
+ if (count == 1 &&
+ !opt->name_only &&
+ !opt->unmatch_name_only &&
+ !opt->count) {
+ argv[argc++] = "/dev/null";
+ argv[argc] = NULL;
+ }
+ }
+
+ else if (kept) {
+ /*
+ * Called because we found many paths and haven't finished
+ * iterating over the cache yet. We keep two paths
+ * for the concluding call. argv[argc-2] and argv[argc-1]
+ * has the last two paths, so save the first one away,
+ * replace it with NULL while sending the list to grep,
+ * and recover them after we are done.
+ */
+ *kept = 2;
+ kept_0 = argv[argc-2];
+ argv[argc-2] = NULL;
+ argc -= 2;
+ }
+
+ status = exec_grep(argc, argv);
+
+ if (kept_0) {
+ /*
+ * Then recover them. Now the last arg is beyond the
+ * terminating NULL which is at argc, and the second
+ * from the last is what we saved away in kept_0
+ */
+ argv[arg0++] = kept_0;
+ argv[arg0] = argv[argc+1];
+ }
+ return status;
+}
+
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
{
int i, nr, argc, hit, len, status;
@@ -253,22 +325,12 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
push_arg(p->pattern);
}
- /*
- * To make sure we get the header printed out when we want it,
- * add /dev/null to the paths to grep. This is unnecessary
- * (and wrong) with "-l" or "-L", which always print out the
- * name anyway.
- *
- * GNU grep has "-H", but this is portable.
- */
- if (!opt->name_only && !opt->unmatch_name_only)
- push_arg("/dev/null");
-
hit = 0;
argc = nr;
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
char *name;
+ int kept;
if (!S_ISREG(ntohl(ce->ce_mode)))
continue;
if (!pathspec_matches(paths, ce->name))
@@ -283,10 +345,10 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
argv[argc++] = name;
if (argc < MAXARGS && !ce_stage(ce))
continue;
- status = exec_grep(argc, argv);
+ status = flush_grep(opt, argc, nr, argv, &kept);
if (0 < status)
hit = 1;
- argc = nr;
+ argc = nr + kept;
if (ce_stage(ce)) {
do {
i++;
@@ -296,7 +358,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
}
}
if (argc > nr) {
- status = exec_grep(argc, argv);
+ status = flush_grep(opt, argc, nr, argv, NULL);
if (0 < status)
hit = 1;
}
diff --git a/builtin-log.c b/builtin-log.c
index fa81c25920..c6cc3aef52 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -437,6 +437,34 @@ static void gen_message_id(char *dest, unsigned int length, char *base)
(int)(email_end - email_start - 1), email_start + 1);
}
+static const char *clean_message_id(const char *msg_id)
+{
+ char ch;
+ const char *a, *z, *m;
+ char *n;
+ size_t len;
+
+ m = msg_id;
+ while ((ch = *m) && (isspace(ch) || (ch == '<')))
+ m++;
+ a = m;
+ z = NULL;
+ while ((ch = *m)) {
+ if (!isspace(ch) && (ch != '>'))
+ z = m;
+ m++;
+ }
+ if (!z)
+ die("insane in-reply-to: %s", msg_id);
+ if (++z == m)
+ return a;
+ len = z - a;
+ n = xmalloc(len + 1);
+ memcpy(n, a, len);
+ n[len] = 0;
+ return n;
+}
+
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
struct commit *commit;
@@ -625,7 +653,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (numbered)
rev.total = total + start_number - 1;
rev.add_signoff = add_signoff;
- rev.ref_message_id = in_reply_to;
+ if (in_reply_to)
+ rev.ref_message_id = clean_message_id(in_reply_to);
while (0 <= --nr) {
int shown;
commit = list[nr];
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index 280557ecd4..2d77fd47ec 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -97,6 +97,21 @@ if there is already one that displays the same directory."
:group 'git
:type 'string)
+(defcustom git-show-uptodate nil
+ "Whether to display up-to-date files."
+ :group 'git
+ :type 'boolean)
+
+(defcustom git-show-ignored nil
+ "Whether to display ignored files."
+ :group 'git
+ :type 'boolean)
+
+(defcustom git-show-unknown t
+ "Whether to display unknown files."
+ :group 'git
+ :type 'boolean)
+
(defface git-status-face
'((((class color) (background light)) (:foreground "purple"))
@@ -479,6 +494,27 @@ and returns the process output as a string."
(setf (git-fileinfo->orig-name info) nil)
(setf (git-fileinfo->needs-refresh info) t))))
+(defun git-set-filenames-state (status files state)
+ "Set the state of a list of named files."
+ (when files
+ (setq files (sort files #'string-lessp))
+ (let ((file (pop files))
+ (node (ewoc-nth status 0)))
+ (while (and file node)
+ (let ((info (ewoc-data node)))
+ (cond ((string-lessp (git-fileinfo->name info) file)
+ (setq node (ewoc-next status node)))
+ ((string-equal (git-fileinfo->name info) file)
+ (unless (eq (git-fileinfo->state info) state)
+ (setf (git-fileinfo->state info) state)
+ (setf (git-fileinfo->rename-state info) nil)
+ (setf (git-fileinfo->orig-name info) nil)
+ (setf (git-fileinfo->needs-refresh info) t))
+ (setq file (pop files)))
+ (t (setq file (pop files)))))))
+ (unless state ;; delete files whose state has been set to nil
+ (ewoc-filter status (lambda (info) (git-fileinfo->state info))))))
+
(defun git-state-code (code)
"Convert from a string to a added/deleted/modified state."
(case (string-to-char code)
@@ -532,19 +568,36 @@ and returns the process output as a string."
" " (git-escape-file-name (git-fileinfo->name info))
(git-rename-as-string info))))
-(defun git-insert-fileinfo (status info &optional refresh)
- "Insert INFO in the status buffer, optionally refreshing an existing one."
- (let ((node (and refresh
- (git-find-status-file status (git-fileinfo->name info)))))
- (setf (git-fileinfo->needs-refresh info) t)
- (when node ;preserve the marked flag
- (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))))
- (if node (setf (ewoc-data node) info) (ewoc-enter-last status info))))
+(defun git-insert-info-list (status infolist)
+ "Insert a list of file infos in the status buffer, replacing existing ones if any."
+ (setq infolist (sort infolist
+ (lambda (info1 info2)
+ (string-lessp (git-fileinfo->name info1)
+ (git-fileinfo->name info2)))))
+ (let ((info (pop infolist))
+ (node (ewoc-nth status 0)))
+ (while info
+ (setf (git-fileinfo->needs-refresh info) t)
+ (cond ((not node)
+ (ewoc-enter-last status info)
+ (setq info (pop infolist)))
+ ((string-lessp (git-fileinfo->name (ewoc-data node))
+ (git-fileinfo->name info))
+ (setq node (ewoc-next status node)))
+ ((string-equal (git-fileinfo->name (ewoc-data node))
+ (git-fileinfo->name info))
+ ;; preserve the marked flag
+ (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node)))
+ (setf (ewoc-data node) info)
+ (setq info (pop infolist)))
+ (t
+ (ewoc-enter-before status node info)
+ (setq info (pop infolist)))))))
(defun git-run-diff-index (status files)
"Run git-diff-index on FILES and parse the results into STATUS.
Return the list of files that haven't been handled."
- (let ((refresh files))
+ (let (infolist)
(with-temp-buffer
(apply #'git-run-command t nil "diff-index" "-z" "-M" "HEAD" "--" files)
(goto-char (point-min))
@@ -558,13 +611,14 @@ Return the list of files that haven't been handled."
(new-name (match-string 8)))
(if new-name ; copy or rename
(if (eq ?C (string-to-char state))
- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) refresh)
- (git-insert-fileinfo status (git-create-fileinfo 'deleted name 0 0 'rename new-name) refresh)
- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)) refresh)
- (git-insert-fileinfo status (git-create-fileinfo (git-state-code state) name old-perm new-perm) refresh))
+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) infolist)
+ (push (git-create-fileinfo 'deleted name 0 0 'rename new-name) infolist)
+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'rename name) infolist))
+ (push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist))
(setq files (delete name files))
- (when new-name (setq files (delete new-name files)))))))
- files)
+ (when new-name (setq files (delete new-name files))))))
+ (git-insert-info-list status infolist)
+ files))
(defun git-find-status-file (status file)
"Find a given file in the status ewoc and return its node."
@@ -576,16 +630,16 @@ Return the list of files that haven't been handled."
(defun git-run-ls-files (status files default-state &rest options)
"Run git-ls-files on FILES and parse the results into STATUS.
Return the list of files that haven't been handled."
- (let ((refresh files))
+ (let (infolist)
(with-temp-buffer
- (apply #'git-run-command t nil "ls-files" "-z" "-t" (append options (list "--") files))
+ (apply #'git-run-command t nil "ls-files" "-z" (append options (list "--") files))
(goto-char (point-min))
- (while (re-search-forward "\\([HMRCK?]\\) \\([^\0]*\\)\0" nil t 1)
- (let ((state (match-string 1))
- (name (match-string 2)))
- (git-insert-fileinfo status (git-create-fileinfo (or (git-state-code state) default-state) name) refresh)
- (setq files (delete name files))))))
- files)
+ (while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
+ (let ((name (match-string 1)))
+ (push (git-create-fileinfo default-state name) infolist)
+ (setq files (delete name files)))))
+ (git-insert-info-list status infolist)
+ files))
(defun git-run-ls-unmerged (status files)
"Run git-ls-files -u on FILES and parse the results into STATUS."
@@ -594,9 +648,8 @@ Return the list of files that haven't been handled."
(goto-char (point-min))
(let (unmerged-files)
(while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t)
- (let ((node (git-find-status-file status (match-string 1))))
- (when node (push (ewoc-data node) unmerged-files))))
- (git-set-files-state unmerged-files 'unmerged))))
+ (push (match-string 1) unmerged-files))
+ (git-set-filenames-state status unmerged-files 'unmerged))))
(defun git-get-exclude-files ()
"Get the list of exclude files to pass to git-ls-files."
@@ -608,34 +661,30 @@ Return the list of files that haven't been handled."
(push config files))
files))
+(defun git-run-ls-files-with-excludes (status files default-state &rest options)
+ "Run git-ls-files on FILES with appropriate --exclude-from options."
+ (let ((exclude-files (git-get-exclude-files)))
+ (apply #'git-run-ls-files status files default-state
+ (concat "--exclude-per-directory=" git-per-dir-ignore-file)
+ (append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
+
(defun git-update-status-files (files &optional default-state)
"Update the status of FILES from the index."
(unless git-status (error "Not in git-status buffer."))
- (let* ((status git-status)
- (remaining-files
+ (unless files
+ (when git-show-uptodate (git-run-ls-files git-status nil 'uptodate "-c")))
+ (let* ((remaining-files
(if (git-empty-db-p) ; we need some special handling for an empty db
- (git-run-ls-files status files 'added "-c")
- (git-run-diff-index status files))))
- (git-run-ls-unmerged status files)
- (when (or (not files) remaining-files)
- (let ((exclude-files (git-get-exclude-files)))
- (setq remaining-files (apply #'git-run-ls-files status remaining-files 'unknown "-o"
- (concat "--exclude-per-directory=" git-per-dir-ignore-file)
- (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
- ; mark remaining files with the default state (or remove them if nil)
- (when remaining-files
- (if default-state
- (ewoc-map (lambda (info)
- (when (member (git-fileinfo->name info) remaining-files)
- (git-set-files-state (list info) default-state))
- nil)
- status)
- (ewoc-filter status
- (lambda (info files)
- (not (member (git-fileinfo->name info) files)))
- remaining-files)))
+ (git-run-ls-files git-status files 'added "-c")
+ (git-run-diff-index git-status files))))
+ (git-run-ls-unmerged git-status files)
+ (when (or remaining-files (and git-show-unknown (not files)))
+ (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'unknown "-o")))
+ (when (or remaining-files (and git-show-ignored (not files)))
+ (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'ignored "-o" "-i")))
+ (git-set-filenames-state git-status remaining-files default-state)
(git-refresh-files)
- (git-refresh-ewoc-hf status)))
+ (git-refresh-ewoc-hf git-status)))
(defun git-marked-files ()
"Return a list of all marked files, or if none a list containing just the file at cursor position."
@@ -853,7 +902,7 @@ Return the list of files that haven't been handled."
(defun git-add-file ()
"Add marked file(s) to the index cache."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unknown))))
+ (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
(unless files
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
(apply #'git-run-command nil nil "update-index" "--add" "--" files)
@@ -871,7 +920,7 @@ Return the list of files that haven't been handled."
(defun git-remove-file ()
"Remove the marked file(s)."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'added 'modified 'unknown 'uptodate))))
+ (let ((files (git-get-filenames (git-marked-files-state 'added 'modified 'unknown 'uptodate 'ignored))))
(unless files
(push (file-relative-name (read-file-name "File to remove: " nil nil t)) files))
(if (yes-or-no-p
@@ -916,11 +965,41 @@ Return the list of files that haven't been handled."
(interactive)
(ewoc-filter git-status
(lambda (info)
- (not (or (eq (git-fileinfo->state info) 'ignored)
- (eq (git-fileinfo->state info) 'uptodate)))))
+ (case (git-fileinfo->state info)
+ ('ignored git-show-ignored)
+ ('uptodate git-show-uptodate)
+ ('unknown git-show-unknown)
+ (t t))))
(unless (ewoc-nth git-status 0) ; refresh header if list is empty
(git-refresh-ewoc-hf git-status)))
+(defun git-toggle-show-uptodate ()
+ "Toogle the option for showing up-to-date files."
+ (interactive)
+ (if (setq git-show-uptodate (not git-show-uptodate))
+ (git-refresh-status)
+ (git-remove-handled)))
+
+(defun git-toggle-show-ignored ()
+ "Toogle the option for showing ignored files."
+ (interactive)
+ (if (setq git-show-ignored (not git-show-ignored))
+ (progn
+ (git-run-ls-files-with-excludes git-status nil 'ignored "-o" "-i")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status))
+ (git-remove-handled)))
+
+(defun git-toggle-show-unknown ()
+ "Toogle the option for showing unknown files."
+ (interactive)
+ (if (setq git-show-unknown (not git-show-unknown))
+ (progn
+ (git-run-ls-files-with-excludes git-status nil 'unknown "-o")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status))
+ (git-remove-handled)))
+
(defun git-setup-diff-buffer (buffer)
"Setup a buffer for displaying a diff."
(let ((dir default-directory))
@@ -1146,7 +1225,8 @@ Return the list of files that haven't been handled."
(unless git-status-mode-map
(let ((map (make-keymap))
- (diff-map (make-sparse-keymap)))
+ (diff-map (make-sparse-keymap))
+ (toggle-map (make-sparse-keymap)))
(suppress-keymap map)
(define-key map "?" 'git-help)
(define-key map "h" 'git-help)
@@ -1170,6 +1250,7 @@ Return the list of files that haven't been handled."
(define-key map "q" 'git-status-quit)
(define-key map "r" 'git-remove-file)
(define-key map "R" 'git-resolve-file)
+ (define-key map "t" toggle-map)
(define-key map "T" 'git-toggle-all-marks)
(define-key map "u" 'git-unmark-file)
(define-key map "U" 'git-revert-file)
@@ -1186,6 +1267,11 @@ Return the list of files that haven't been handled."
(define-key diff-map "h" 'git-diff-file-merge-head)
(define-key diff-map "m" 'git-diff-file-mine)
(define-key diff-map "o" 'git-diff-file-other)
+ ; the toggle submap
+ (define-key toggle-map "u" 'git-toggle-show-uptodate)
+ (define-key toggle-map "i" 'git-toggle-show-ignored)
+ (define-key toggle-map "k" 'git-toggle-show-unknown)
+ (define-key toggle-map "m" 'git-toggle-all-marks)
(setq git-status-mode-map map)))
;; git mode should only run in the *git status* buffer
@@ -1207,6 +1293,9 @@ Commands:
(let ((status (ewoc-create 'git-fileinfo-prettyprint "" "")))
(set (make-local-variable 'git-status) status))
(set (make-local-variable 'list-buffers-directory) default-directory)
+ (make-local-variable 'git-show-uptodate)
+ (make-local-variable 'git-show-ignored)
+ (make-local-variable 'git-show-unknown)
(run-hooks 'git-status-mode-hook)))
(defun git-find-status-buffer (dir)
diff --git a/diff-lib.c b/diff-lib.c
index f5568c3b36..da5571302d 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -298,6 +298,8 @@ int setup_diff_no_index(struct rev_info *revs,
revs->diffopt.nr_paths = 2;
revs->diffopt.no_index = 1;
revs->max_count = -2;
+ if (diff_setup_done(&revs->diffopt) < 0)
+ die("diff_setup_done failed");
return 0;
}
diff --git a/diff.c b/diff.c
index 1aca5df522..0ee9ea1c1b 100644
--- a/diff.c
+++ b/diff.c
@@ -17,7 +17,7 @@
#endif
static int diff_detect_rename_default;
-static int diff_rename_limit_default = -1;
+static int diff_rename_limit_default = 100;
static int diff_use_color_default;
int diff_auto_refresh_index = 1;
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 6bde4396f2..41b35c3a9e 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -298,10 +298,25 @@ void diffcore_rename(struct diff_options *options)
else if (detect_rename == DIFF_DETECT_COPY)
register_rename_src(p->one, 1, p->score);
}
- if (rename_dst_nr == 0 || rename_src_nr == 0 ||
- (0 < rename_limit && rename_limit < rename_dst_nr))
+ if (rename_dst_nr == 0 || rename_src_nr == 0)
goto cleanup; /* nothing to do */
+ /*
+ * This basically does a test for the rename matrix not
+ * growing larger than a "rename_limit" square matrix, ie:
+ *
+ * rename_dst_nr * rename_src_nr > rename_limit * rename_limit
+ *
+ * but handles the potential overflow case specially (and we
+ * assume at least 32-bit integers)
+ */
+ if (rename_limit <= 0 || rename_limit > 32767)
+ rename_limit = 32767;
+ if (rename_dst_nr > rename_limit && rename_src_nr > rename_limit)
+ goto cleanup;
+ if (rename_dst_nr * rename_src_nr > rename_limit * rename_limit)
+ goto cleanup;
+
/* We really want to cull the candidates list early
* with cheap tests in order to avoid doing deltas.
* The first round matches up the up-to-date entries,
diff --git a/git-clone.sh b/git-clone.sh
index 18003ab4b3..5e582fe247 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -34,7 +34,11 @@ fi
http_fetch () {
# $1 = Remote, $2 = Local
- curl -nsfL $curl_extra_args "$1" >"$2"
+ curl -nsfL $curl_extra_args "$1" >"$2" ||
+ case $? in
+ 126|127) exit ;;
+ *) return $? ;;
+ esac
}
clone_dumb_http () {
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 61d08bb431..eb1ced3c37 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -16,11 +16,12 @@ only the updates to dir/sub.'
test_expect_success setup '
echo initial >check &&
echo initial >top &&
+ echo initial >foo &&
mkdir dir1 dir2 &&
echo initial >dir1/sub1 &&
echo initial >dir1/sub2 &&
echo initial >dir2/sub3 &&
- git add check dir1 dir2 top &&
+ git add check dir1 dir2 top foo &&
test_tick
git-commit -m initial &&
@@ -76,4 +77,12 @@ test_expect_success 'change gets noticed' '
'
+test_expect_success 'replace a file with a symlink' '
+
+ rm foo &&
+ ln -s top foo &&
+ git add -u -- foo
+
+'
+
test_done
diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh
index 6bfb899ed1..68b2b92879 100755
--- a/t/t7002-grep.sh
+++ b/t/t7002-grep.sh
@@ -107,6 +107,10 @@ do
diff expected actual
'
+ test_expect_failure "grep -c $L (no /dev/null)" '
+ git grep -c test $H | grep -q "/dev/null"
+ '
+
done
test_done
diff --git a/templates/hooks--update b/templates/hooks--update
index 9d3795c6d0..d8c76264be 100644
--- a/templates/hooks--update
+++ b/templates/hooks--update
@@ -42,7 +42,7 @@ fi
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a branch
-if [ -z "${newrev##0*}" ]; then
+if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
newrev_type=commit
else
newrev_type=$(git-cat-file -t $newrev)
diff --git a/wt-status.c b/wt-status.c
index 52054201c2..10ce6eedc7 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -227,6 +227,7 @@ static void wt_status_print_updated(struct wt_status *s)
rev.diffopt.format_callback = wt_status_print_updated_cb;
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = 1;
+ rev.diffopt.rename_limit = 100;
wt_read_cache(s);
run_diff_index(&rev, 1);
}