aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/1.7.6.5.txt26
-rw-r--r--Documentation/RelNotes/1.7.7.5.txt14
-rw-r--r--Documentation/RelNotes/1.7.8.1.txt38
-rw-r--r--Documentation/config.txt19
-rw-r--r--Documentation/git-mv.txt8
-rw-r--r--Documentation/git-stripspace.txt69
-rw-r--r--Documentation/git.txt9
-rw-r--r--Makefile6
l---------RelNotes2
-rw-r--r--archive.c18
-rw-r--r--branch.c8
-rw-r--r--branch.h3
-rw-r--r--builtin/apply.c13
-rw-r--r--builtin/blame.c2
-rw-r--r--builtin/branch.c11
-rw-r--r--builtin/checkout.c17
-rw-r--r--builtin/clone.c4
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/fetch-pack.c15
-rw-r--r--builtin/fetch.c87
-rw-r--r--builtin/grep.c11
-rw-r--r--builtin/index-pack.c4
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/log.c2
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/mv.c6
-rw-r--r--builtin/pack-objects.c57
-rw-r--r--builtin/revert.c140
-rw-r--r--builtin/send-pack.c3
-rw-r--r--builtin/stripspace.c2
-rw-r--r--cache.h3
-rw-r--r--compat/snprintf.c9
-rw-r--r--compat/strtoimax.c10
-rw-r--r--config.c41
-rw-r--r--connect.c37
-rw-r--r--convert.c54
-rw-r--r--dir.c50
-rw-r--r--fast-import.c28
-rw-r--r--git-compat-util.h2
-rw-r--r--git-rebase--interactive.sh36
-rw-r--r--http-fetch.c2
-rw-r--r--http-push.c2
-rw-r--r--http.c54
-rw-r--r--http.h5
-rw-r--r--imap-send.c1
-rw-r--r--list-objects.c9
-rw-r--r--object.c2
-rw-r--r--pack-write.c4
-rw-r--r--pack.h3
-rw-r--r--read-cache.c42
-rw-r--r--remote-curl.c4
-rw-r--r--sequencer.c10
-rw-r--r--sequencer.h12
-rw-r--r--sha1_file.c3
-rw-r--r--submodule.c6
-rw-r--r--t/lib-httpd/apache.conf3
-rwxr-xr-xt/t2018-checkout-branch.sh9
-rwxr-xr-xt/t3200-branch.sh16
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh162
-rwxr-xr-xt/t4131-apply-fake-ancestor.sh2
-rwxr-xr-xt/t4136-apply-check.sh19
-rwxr-xr-xt/t5000-tar-tree.sh8
-rwxr-xr-xt/t5500-fetch-pack.sh6
-rwxr-xr-xt/t5527-fetch-odd-refs.sh29
-rwxr-xr-xt/t5540-http-push.sh34
-rwxr-xr-xt/t7106-reset-sequence.sh52
-rwxr-xr-xt/t9301-fast-import-notes.sh63
-rw-r--r--transport.c7
-rw-r--r--tree-diff.c22
-rw-r--r--tree-walk.c75
-rw-r--r--tree-walk.h18
-rw-r--r--tree.c11
-rw-r--r--unpack-trees.c6
-rw-r--r--userdiff.c2
75 files changed, 1103 insertions, 472 deletions
diff --git a/Documentation/RelNotes/1.7.6.5.txt b/Documentation/RelNotes/1.7.6.5.txt
new file mode 100644
index 000000000..6713132a9
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.5.txt
@@ -0,0 +1,26 @@
+Git v1.7.6.5 Release Notes
+==========================
+
+Fixes since v1.7.6.4
+--------------------
+
+ * The date parser did not accept timezone designators that lack minutes
+ part and also has a colon between "hh:mm".
+
+ * After fetching from a remote that has very long refname, the reporting
+ output could have corrupted by overrunning a static buffer.
+
+ * "git mergetool" did not use its arguments as pathspec, but as a path to
+ the file that may not even have any conflict.
+
+ * "git name-rev --all" tried to name all _objects_, naturally failing to
+ describe many blobs and trees, instead of showing only commits as
+ advertised in its documentation.
+
+ * "git remote rename $a $b" were not careful to match the remote name
+ against $a (i.e. source side of the remote nickname).
+
+ * "gitweb" used to produce a non-working link while showing the contents
+ of a blob, when JavaScript actions are enabled.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.7.5.txt b/Documentation/RelNotes/1.7.7.5.txt
new file mode 100644
index 000000000..7b0931987
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.5.txt
@@ -0,0 +1,14 @@
+Git v1.7.7.5 Release Notes
+==========================
+
+Fixes since v1.7.7.4
+--------------------
+
+ * After fetching from a remote that has very long refname, the reporting
+ output could have corrupted by overrunning a static buffer.
+
+ * "git checkout" and "git merge" treated in-tree .gitignore and exclude
+ file in $GIT_DIR/info/ directory inconsistently when deciding which
+ untracked files are ignored and expendable.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.1.txt b/Documentation/RelNotes/1.7.8.1.txt
new file mode 100644
index 000000000..33dc948b9
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.1.txt
@@ -0,0 +1,38 @@
+Git v1.7.8.1 Release Notes
+==========================
+
+Fixes since v1.7.8
+------------------
+
+ * In some codepaths (notably, checkout and merge), the ignore patterns
+ recorded in $GIT_DIR/info/exclude were not honored. They now are.
+
+ * "git apply --check" did not error out when given an empty input
+ without any patch.
+
+ * "git archive" mistakenly allowed remote clients to ask for commits
+ that are not at the tip of any ref.
+
+ * "git checkout" and "git merge" treated in-tree .gitignore and exclude
+ file in $GIT_DIR/info/ directory inconsistently when deciding which
+ untracked files are ignored and expendable.
+
+ * LF-to-CRLF streaming filter used when checking out a large-ish blob
+ fell into an infinite loop with a rare input.
+
+ * The function header pattern for files with "diff=cpp" attribute did
+ not consider "type *funcname(type param1,..." as the beginning of a
+ function.
+
+ * The error message from "git diff" and "git status" when they fail
+ to inspect changes in submodules did not report which submodule they
+ had trouble with.
+
+ * After fetching from a remote that has very long refname, the reporting
+ output could have corrupted by overrunning a static buffer.
+
+ * "git pack-objects" avoids creating cyclic dependencies among deltas
+ when seeing a broken packfile that records the same object in both
+ the deflated form and as a delta.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d..f22d92677 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -115,35 +115,32 @@ in the appropriate manual page. You will find a description of non-core
porcelain configuration variables in the respective porcelain documentation.
advice.*::
- When set to 'true', display the given optional help message.
- When set to 'false', do not display. The configuration variables
- are:
+ These variables control various optional help messages designed to
+ aid new users. All 'advice.*' variables default to 'true', and you
+ can tell Git that you do not need help by setting these to 'false':
+
--
pushNonFastForward::
Advice shown when linkgit:git-push[1] refuses
- non-fast-forward refs. Default: true.
+ non-fast-forward refs.
statusHints::
Directions on how to stage/unstage/add shown in the
output of linkgit:git-status[1] and the template shown
- when writing commit messages. Default: true.
+ when writing commit messages.
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
- Default: true.
resolveConflict::
Advices shown by various commands when conflicts
prevent the operation from being performed.
- Default: true.
implicitIdentity::
Advice on how to set your identity configuration when
your information is guessed from the system username and
- domain name. Default: true.
-
+ domain name.
detachedHead::
- Advice shown when you used linkgit::git-checkout[1] to
+ Advice shown when you used linkgit:git-checkout[1] to
move to the detach HEAD state, to instruct how to create
- a local branch after the fact. Default: true.
+ a local branch after the fact.
--
core.fileMode::
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index b8db37396..e3c844861 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -15,8 +15,8 @@ DESCRIPTION
-----------
This script is used to move or rename a file, directory or symlink.
- git mv [-f] [-n] <source> <destination>
- git mv [-f] [-n] [-k] <source> ... <destination directory>
+ git mv [-v] [-f] [-n] [-k] <source> <destination>
+ git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
In the first form, it renames <source>, which must exist and be either
a file, symlink or directory, to <destination>.
@@ -40,6 +40,10 @@ OPTIONS
--dry-run::
Do nothing; only show what would happen
+-v::
+--verbose::
+ Report the names of files as they are moved.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
index b78f031cd..a80d94650 100644
--- a/Documentation/git-stripspace.txt
+++ b/Documentation/git-stripspace.txt
@@ -3,26 +3,83 @@ git-stripspace(1)
NAME
----
-git-stripspace - Filter out empty lines
+git-stripspace - Remove unnecessary whitespace
SYNOPSIS
--------
[verse]
-'git stripspace' [-s | --strip-comments] < <stream>
+'git stripspace' [-s | --strip-comments] < input
DESCRIPTION
-----------
-Remove multiple empty lines, and empty lines at beginning and end.
+
+Clean the input in the manner used by 'git' for text such as commit
+messages, notes, tags and branch descriptions.
+
+With no arguments, this will:
+
+- remove trailing whitespace from all lines
+- collapse multiple consecutive empty lines into one empty line
+- remove empty lines from the beginning and end of the input
+- add a missing '\n' to the last line if necessary.
+
+In the case where the input consists entirely of whitespace characters, no
+output will be produced.
+
+*NOTE*: This is intended for cleaning metadata, prefer the `--whitespace=fix`
+mode of linkgit:git-apply[1] for correcting whitespace of patches or files in
+the repository.
OPTIONS
-------
-s::
--strip-comments::
- In addition to empty lines, also strip lines starting with '#'.
+ Skip and remove all lines starting with '#'.
+
+EXAMPLES
+--------
+
+Given the following noisy input with '$' indicating the end of a line:
-<stream>::
- Byte stream to act on.
+--------
+|A brief introduction $
+| $
+|$
+|A new paragraph$
+|# with a commented-out line $
+|explaining lots of stuff.$
+|$
+|# An old paragraph, also commented-out. $
+| $
+|The end.$
+| $
+---------
+
+Use 'git stripspace' with no arguments to obtain:
+
+--------
+|A brief introduction$
+|$
+|A new paragraph$
+|# with a commented-out line$
+|explaining lots of stuff.$
+|$
+|# An old paragraph, also commented-out.$
+|$
+|The end.$
+---------
+
+Use 'git stripspace --strip-comments' to obtain:
+
+--------
+|A brief introduction$
+|$
+|A new paragraph$
+|explaining lots of stuff.$
+|$
+|The end.$
+---------
GIT
---
diff --git a/Documentation/git.txt b/Documentation/git.txt
index e869032fc..da7d48787 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -49,15 +49,20 @@ Documentation for older releases are available here:
* release notes for
link:RelNotes/1.7.8.txt[1.7.8].
-* link:v1.7.7.1/git.html[documentation for release 1.7.7.1]
+* link:v1.7.7.5/git.html[documentation for release 1.7.7.5]
* release notes for
+ link:RelNotes/1.7.7.5.txt[1.7.7.5],
+ link:RelNotes/1.7.7.4.txt[1.7.7.4],
+ link:RelNotes/1.7.7.3.txt[1.7.7.3],
+ link:RelNotes/1.7.7.2.txt[1.7.7.2],
link:RelNotes/1.7.7.1.txt[1.7.7.1],
link:RelNotes/1.7.7.txt[1.7.7].
-* link:v1.7.6.4/git.html[documentation for release 1.7.6.4]
+* link:v1.7.6.5/git.html[documentation for release 1.7.6.5]
* release notes for
+ link:RelNotes/1.7.6.5.txt[1.7.6.5],
link:RelNotes/1.7.6.4.txt[1.7.6.4],
link:RelNotes/1.7.6.3.txt[1.7.6.3],
link:RelNotes/1.7.6.2.txt[1.7.6.2],
diff --git a/Makefile b/Makefile
index b1c80a678..b21d2f141 100644
--- a/Makefile
+++ b/Makefile
@@ -57,8 +57,8 @@ all::
#
# Define NO_STRLCPY if you don't have strlcpy.
#
-# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
-# If your compiler also does not support long long or does not have
+# Define NO_STRTOUMAX if you don't have both strtoimax and strtoumax in the
+# C library. If your compiler also does not support long long or does not have
# strtoull, define NO_STRTOULL.
#
# Define NO_SETENV if you don't have setenv in the C library.
@@ -1478,7 +1478,7 @@ ifdef NO_STRLCPY
endif
ifdef NO_STRTOUMAX
COMPAT_CFLAGS += -DNO_STRTOUMAX
- COMPAT_OBJS += compat/strtoumax.o
+ COMPAT_OBJS += compat/strtoumax.o compat/strtoimax.o
endif
ifdef NO_STRTOULL
COMPAT_CFLAGS += -DNO_STRTOULL
diff --git a/RelNotes b/RelNotes
index 7d9276973..96a35fb99 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.8.txt \ No newline at end of file
+Documentation/RelNotes/1.7.8.1.txt \ No newline at end of file
diff --git a/archive.c b/archive.c
index 2ae740a71..164bbd014 100644
--- a/archive.c
+++ b/archive.c
@@ -247,7 +247,8 @@ static void parse_pathspec_arg(const char **pathspec,
}
static void parse_treeish_arg(const char **argv,
- struct archiver_args *ar_args, const char *prefix)
+ struct archiver_args *ar_args, const char *prefix,
+ int remote)
{
const char *name = argv[0];
const unsigned char *commit_sha1;
@@ -256,8 +257,17 @@ static void parse_treeish_arg(const char **argv,
const struct commit *commit;
unsigned char sha1[20];
- if (get_sha1(name, sha1))
- die("Not a valid object name");
+ /* Remotes are only allowed to fetch actual refs */
+ if (remote) {
+ char *ref = NULL;
+ if (!dwim_ref(name, strlen(name), sha1, &ref))
+ die("no such ref: %s", name);
+ free(ref);
+ }
+ else {
+ if (get_sha1(name, sha1))
+ die("Not a valid object name");
+ }
commit = lookup_commit_reference_gently(sha1, 1);
if (commit) {
@@ -414,7 +424,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
setup_git_directory();
}
- parse_treeish_arg(argv, &args, prefix);
+ parse_treeish_arg(argv, &args, prefix, remote);
parse_pathspec_arg(argv + 1, &args);
return ar->write_archive(ar, &args);
diff --git a/branch.c b/branch.c
index 025a97be0..d7fd267b7 100644
--- a/branch.c
+++ b/branch.c
@@ -3,7 +3,6 @@
#include "refs.h"
#include "remote.h"
#include "commit.h"
-#include "sequencer.h"
struct tracking {
struct refspec spec;
@@ -160,7 +159,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
void create_branch(const char *head,
const char *name, const char *start_name,
- int force, int reflog, enum branch_track track)
+ int force, int reflog, int clobber_head,
+ enum branch_track track)
{
struct ref_lock *lock = NULL;
struct commit *commit;
@@ -175,7 +175,8 @@ void create_branch(const char *head,
explicit_tracking = 1;
if (validate_new_branchname(name, &ref, force,
- track == BRANCH_TRACK_OVERRIDE)) {
+ track == BRANCH_TRACK_OVERRIDE ||
+ clobber_head)) {
if (!force)
dont_change_ref = 1;
else
@@ -247,5 +248,4 @@ void remove_branch_state(void)
unlink(git_path("MERGE_MSG"));
unlink(git_path("MERGE_MODE"));
unlink(git_path("SQUASH_MSG"));
- remove_sequencer_state(0);
}
diff --git a/branch.h b/branch.h
index 1285158dd..e125ff4ca 100644
--- a/branch.h
+++ b/branch.h
@@ -13,7 +13,8 @@
* branch for (if any).
*/
void create_branch(const char *head, const char *name, const char *start_name,
- int force, int reflog, enum branch_track track);
+ int force, int reflog,
+ int clobber_head, enum branch_track track);
/*
* Validates that the requested branch may be created, returning the
diff --git a/builtin/apply.c b/builtin/apply.c
index 84a8a0b52..c24dc546d 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -250,9 +250,6 @@ static int fuzzy_matchlines(const char *s1, size_t n1,
const char *last2 = s2 + n2 - 1;
int result = 0;
- if (n1 < 0 || n2 < 0)
- return 0;
-
/* ignore line endings */
while ((*last1 == '\r') || (*last1 == '\n'))
last1--;
@@ -3590,15 +3587,12 @@ static int write_out_one_reject(struct patch *patch)
return -1;
}
-static int write_out_results(struct patch *list, int skipped_patch)
+static int write_out_results(struct patch *list)
{
int phase;
int errs = 0;
struct patch *l;
- if (!list && !skipped_patch)
- return error("No changes");
-
for (phase = 0; phase < 2; phase++) {
l = list;
while (l) {
@@ -3724,6 +3718,9 @@ static int apply_patch(int fd, const char *filename, int options)
offset += nr;
}
+ if (!list && !skipped_patch)
+ die("unrecognized input");
+
if (whitespace_error && (ws_error_action == die_on_ws_error))
apply = 0;
@@ -3741,7 +3738,7 @@ static int apply_patch(int fd, const char *filename, int options)
!apply_with_reject)
exit(1);
- if (apply && write_out_results(list, skipped_patch))
+ if (apply && write_out_results(list))
exit(1);
if (fake_ancestor)
diff --git a/builtin/blame.c b/builtin/blame.c
index 80febbe42..5a67c202f 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1598,7 +1598,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
int tz;
if (show_raw_time) {
- sprintf(time_buf, "%lu %s", time, tz_str);
+ snprintf(time_buf, sizeof(time_buf), "%lu %s", time, tz_str);
}
else {
tz = atoi(tz_str);
diff --git a/builtin/branch.c b/builtin/branch.c
index 55cad766c..df908ed8f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -568,6 +568,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
unsigned char sha1[20];
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
int recovery = 0;
+ int clobber_head_ok;
if (!oldname)
die(_("cannot rename the current branch while not on any."));
@@ -583,7 +584,13 @@ static void rename_branch(const char *oldname, const char *newname, int force)
die(_("Invalid branch name: '%s'"), oldname);
}
- validate_new_branchname(newname, &newref, force, 0);
+ /*
+ * A command like "git branch -M currentbranch currentbranch" cannot
+ * cause the worktree to become inconsistent with HEAD, so allow it.
+ */
+ clobber_head_ok = !strcmp(oldname, newname);
+
+ validate_new_branchname(newname, &newref, force, clobber_head_ok);
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
@@ -730,7 +737,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
- force_create, reflog, track);
+ force_create, reflog, 0, track);
} else
usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a8077242..44e73b5a4 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -411,7 +411,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.fn = twoway_merge;
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->flags |= DIR_SHOW_IGNORED;
- topts.dir->exclude_per_dir = ".gitignore";
+ setup_standard_excludes(topts.dir);
tree = parse_tree_indirect(old->commit ?
old->commit->object.sha1 :
EMPTY_TREE_SHA1_BIN);
@@ -540,7 +540,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,
else
create_branch(old->name, opts->new_branch, new->name,
opts->new_branch_force ? 1 : 0,
- opts->new_branch_log, opts->track);
+ opts->new_branch_log,
+ opts->new_branch_force ? 1 : 0,
+ opts->track);
new->name = opts->new_branch;
setup_branch_path(new);
}
@@ -565,8 +567,12 @@ static void update_refs_for_switch(struct checkout_opts *opts,
create_symref("HEAD", new->path, msg.buf);
if (!opts->quiet) {
if (old->path && !strcmp(new->path, old->path)) {
- fprintf(stderr, _("Already on '%s'\n"),
- new->name);
+ if (opts->new_branch_force)
+ fprintf(stderr, _("Reset branch '%s'\n"),
+ new->name);
+ else
+ fprintf(stderr, _("Already on '%s'\n"),
+ new->name);
} else if (opts->new_branch) {
if (opts->branch_exists)
fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
@@ -1057,7 +1063,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
- !!opts.new_branch_force, 0);
+ !!opts.new_branch_force,
+ !!opts.new_branch_force);
strbuf_release(&buf);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index efe8b6cce..86db95473 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -84,8 +84,8 @@ static struct option builtin_clone_options[] = {
"directory from which templates will be used"),
OPT_CALLBACK(0 , "reference", &option_reference, "repo",
"reference repository", &opt_parse_reference),
- OPT_STRING('o', "origin", &option_origin, "branch",
- "use <branch> instead of 'origin' to track upstream"),
+ OPT_STRING('o', "origin", &option_origin, "name",
+ "use <name> instead of 'origin' to track upstream"),
OPT_STRING('b', "branch", &option_branch, "branch",
"checkout <branch> instead of the remote's HEAD"),
OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
diff --git a/builtin/commit.c b/builtin/commit.c
index 8f2bebecf..b02e2c4e8 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -138,7 +138,7 @@ static struct option builtin_commit_options[] = {
OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
- OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
+ OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
OPT_FILENAME('t', "template", &template_file, "use specified template file"),
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
diff --git a/builtin/diff.c b/builtin/diff.c
index 1118689fb..0fe638fc4 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -182,7 +182,7 @@ static int builtin_diff_combined(struct rev_info *revs,
hashcpy((unsigned char *)(parent + i), ent[i].item->sha1);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
- free(parent);
+ free((void *)parent);
return 0;
}
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c6bc8eb0a..6207ecd29 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -556,11 +556,16 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
continue;
}
else {
- int order = path_match(ref->name, nr_match, match);
- if (order) {
- return_refs[order-1] = ref;
- continue; /* we will link it later */
+ int i;
+ for (i = 0; i < nr_match; i++) {
+ if (!strcmp(ref->name, match[i])) {
+ match[i][0] = '\0';
+ return_refs[i] = ref;
+ break;
+ }
}
+ if (i < nr_match)
+ continue; /* we will link it later */
}
free(ref);
}
@@ -976,7 +981,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.verbose ? CONNECT_VERBOSE : 0);
}
- get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
+ get_remote_heads(fd[0], &ref, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
nr_heads, heads, pack_lockfile_ptr);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 91731b909..8761a33b4 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -240,23 +240,23 @@ static int s_update_ref(const char *action,
static int update_local_ref(struct ref *ref,
const char *remote,
- char *display)
+ struct strbuf *display)
{
struct commit *current = NULL, *updated;
enum object_type type;
struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = prettify_refname(ref->name);
- *display = 0;
type = sha1_object_info(ref->new_sha1, NULL);
if (type < 0)
die(_("object %s not found"), sha1_to_hex(ref->new_sha1));
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbosity > 0)
- sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH,
- _("[up to date]"), REFCOL_WIDTH, remote,
- pretty_ref);
+ strbuf_addf(display, "= %-*s %-*s -> %s",
+ TRANSPORT_SUMMARY_WIDTH,
+ _("[up to date]"), REFCOL_WIDTH,
+ remote, pretty_ref);
return 0;
}
@@ -268,9 +268,10 @@ static int update_local_ref(struct ref *ref,
* If this is the head, and it's not okay to update
* the head, and the old value of the head isn't empty...
*/
- sprintf(display, _("! %-*s %-*s -> %s (can't fetch in current branch)"),
- TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
- pretty_ref);
+ strbuf_addf(display,
+ _("! %-*s %-*s -> %s (can't fetch in current branch)"),
+ TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+ REFCOL_WIDTH, remote, pretty_ref);
return 1;
}
@@ -278,9 +279,11 @@ static int update_local_ref(struct ref *ref,
!prefixcmp(ref->name, "refs/tags/")) {
int r;
r = s_update_ref("updating tag", ref, 0);
- sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
- TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), REFCOL_WIDTH, remote,
- pretty_ref, r ? _(" (unable to update local ref)") : "");
+ strbuf_addf(display, "%c %-*s %-*s -> %s%s",
+ r ? '!' : '-',
+ TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
+ REFCOL_WIDTH, remote, pretty_ref,
+ r ? _(" (unable to update local ref)") : "");
return r;
}
@@ -303,9 +306,11 @@ static int update_local_ref(struct ref *ref,
}
r = s_update_ref(msg, ref, 0);
- sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
- TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
- r ? _(" (unable to update local ref)") : "");
+ strbuf_addf(display, "%c %-*s %-*s -> %s%s",
+ r ? '!' : '*',
+ TRANSPORT_SUMMARY_WIDTH, what,
+ REFCOL_WIDTH, remote, pretty_ref,
+ r ? _(" (unable to update local ref)") : "");
return r;
}
@@ -319,9 +324,11 @@ static int update_local_ref(struct ref *ref,
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("fast-forward", ref, 1);
- sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
- TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
- pretty_ref, r ? _(" (unable to update local ref)") : "");
+ strbuf_addf(display, "%c %-*s %-*s -> %s%s",
+ r ? '!' : ' ',
+ TRANSPORT_SUMMARY_WIDTH, quickref,
+ REFCOL_WIDTH, remote, pretty_ref,
+ r ? _(" (unable to update local ref)") : "");
return r;
} else if (force || ref->force) {
char quickref[84];
@@ -333,15 +340,17 @@ static int update_local_ref(struct ref *ref,
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("forced-update", ref, 1);
- sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+',
- TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
- pretty_ref,
- r ? _("unable to update local ref") : _("forced update"));
+ strbuf_addf(display, "%c %-*s %-*s -> %s (%s)",
+ r ? '!' : '+',
+ TRANSPORT_SUMMARY_WIDTH, quickref,
+ REFCOL_WIDTH, remote, pretty_ref,
+ r ? _("unable to update local ref") : _("forced update"));
return r;
} else {
- sprintf(display, "! %-*s %-*s -> %s %s",
- TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
- pretty_ref, _("(non-fast-forward)"));
+ strbuf_addf(display, "! %-*s %-*s -> %s %s",
+ TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+ REFCOL_WIDTH, remote, pretty_ref,
+ _("(non-fast-forward)"));
return 1;
}
}
@@ -363,8 +372,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
{
FILE *fp;
struct commit *commit;
- int url_len, i, note_len, shown_url = 0, rc = 0;
- char note[1024];
+ int url_len, i, shown_url = 0, rc = 0;
+ struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
@@ -427,19 +436,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (4 < i && !strncmp(".git", url + i - 3, 4))
url_len = i - 3;
- note_len = 0;
+ strbuf_reset(&note);
if (*what) {
if (*kind)
- note_len += sprintf(note + note_len, "%s ",
- kind);
- note_len += sprintf(note + note_len, "'%s' of ", what);
+ strbuf_addf(&note, "%s ", kind);
+ strbuf_addf(&note, "'%s' of ", what);
}
- note[note_len] = '\0';
fprintf(fp, "%s\t%s\t%s",
sha1_to_hex(commit ? commit->object.sha1 :
rm->old_sha1),
rm->merge ? "" : "not-for-merge",
- note);
+ note.buf);
for (i = 0; i < url_len; ++i)
if ('\n' == url[i])
fputs("\\n", fp);
@@ -447,21 +454,24 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
fputc(url[i], fp);
fputc('\n', fp);
+ strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, what, note);
+ rc |= update_local_ref(ref, what, &note);
free(ref);
} else
- sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
- TRANSPORT_SUMMARY_WIDTH, *kind ? kind : "branch",
- REFCOL_WIDTH, *what ? what : "HEAD");
- if (*note) {
+ strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
+ TRANSPORT_SUMMARY_WIDTH,
+ *kind ? kind : "branch",
+ REFCOL_WIDTH,
+ *what ? what : "HEAD");
+ if (note.len) {
if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"),
url_len, url);
shown_url = 1;
}
if (verbosity >= 0)
- fprintf(stderr, " %s\n", note);
+ fprintf(stderr, " %s\n", note.buf);
}
}
@@ -471,6 +481,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
"branches"), remote_name);
abort:
+ strbuf_release(&note);
free(url);
fclose(fp);
return rc;
diff --git a/builtin/grep.c b/builtin/grep.c
index 3d7329d78..988ea1d33 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -557,18 +557,19 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
struct tree_desc *tree, struct strbuf *base, int tn_len)
{
- int hit = 0, match = 0;
+ int hit = 0;
+ enum interesting match = entry_not_interesting;
struct name_entry entry;
int old_baselen = base->len;
while (tree_entry(tree, &entry)) {
- int te_len = tree_entry_len(entry.path, entry.sha1);
+ int te_len = tree_entry_len(&entry);
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, tn_len, pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0945adbb3..98025da76 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1122,8 +1122,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (!index_name)
die("--verify with no packfile name given");
read_idx_option(&opts, index_name);
- opts.flags |= WRITE_IDX_VERIFY;
+ opts.flags |= WRITE_IDX_VERIFY | WRITE_IDX_STRICT;
}
+ if (strict)
+ opts.flags |= WRITE_IDX_STRICT;
curr_pack = open_pack_file(pack_name);
parse_pack_header();
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c88..0dacb8b79 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -351,7 +351,7 @@ static void separate_git_dir(const char *git_dir)
else if (S_ISDIR(st.st_mode))
src = git_link;
else
- die(_("unable to handle file type %d"), st.st_mode);
+ die(_("unable to handle file type %d"), (int)st.st_mode);
if (rename(src, git_dir))
die_errno(_("unable to move %s to %s"), src, git_dir);
diff --git a/builtin/log.c b/builtin/log.c
index f5d493059..56bc555d1 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -72,8 +72,6 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
static void cmd_log_init_defaults(struct rev_info *rev)
{
- rev->abbrev = DEFAULT_ABBREV;
- rev->commit_format = CMIT_FMT_DEFAULT;
if (fmt_pretty)
get_commit_format(fmt_pretty, rev);
rev->verbose_header = 1;
diff --git a/builtin/merge.c b/builtin/merge.c
index 2870a6af6..138737624 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -775,7 +775,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
memset(&t, 0, sizeof(t));
memset(&dir, 0, sizeof(dir));
dir.flags |= DIR_SHOW_IGNORED;
- dir.exclude_per_dir = ".gitignore";
+ setup_standard_excludes(&dir);
opts.dir = &dir;
opts.head_idx = 1;
diff --git a/builtin/mv.c b/builtin/mv.c
index 5efe6c576..2a144b011 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -59,6 +59,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int i, newfd;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
+ OPT__VERBOSE(&verbose, "be verbose"),
OPT__DRY_RUN(&show_only, "dry run"),
OPT__FORCE(&force, "force move/rename even if target exists"),
OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
@@ -93,7 +94,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
destination = copy_pathspec(dest_path[0], argv, argc, 1);
} else {
if (argc != 1)
- usage_with_options(builtin_mv_usage, builtin_mv_options);
+ die("destination '%s' is not a directory", dest_path[0]);
destination = dest_path;
}
@@ -176,7 +177,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
* check both source and destination
*/
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
- warning(_("%s; will overwrite!"), bad);
+ if (verbose)
+ warning(_("overwriting '%s'"), dst);
bad = NULL;
} else
bad = _("Cannot overwrite");
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 824ecee20..b1895aaaa 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -409,25 +409,56 @@ static unsigned long write_object(struct sha1file *f,
return hdrlen + datalen;
}
-static int write_one(struct sha1file *f,
- struct object_entry *e,
- off_t *offset)
+enum write_one_status {
+ WRITE_ONE_SKIP = -1, /* already written */
+ WRITE_ONE_BREAK = 0, /* writing this will bust the limit; not written */
+ WRITE_ONE_WRITTEN = 1, /* normal */
+ WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
+};
+
+static enum write_one_status write_one(struct sha1file *f,
+ struct object_entry *e,
+ off_t *offset)
{
unsigned long size;
+ int recursing;
- /* offset is non zero if object is written already. */
- if (e->idx.offset || e->preferred_base)
- return -1;
+ /*
+ * we set offset to 1 (which is an impossible value) to mark
+ * the fact that this object is involved in "write its base
+ * first before writing a deltified object" recursion.
+ */
+ recursing = (e->idx.offset == 1);
+ if (recursing) {
+ warning("recursive delta detected for object %s",
+ sha1_to_hex(e->idx.sha1));
+ return WRITE_ONE_RECURSIVE;
+ } else if (e->idx.offset || e->preferred_base) {
+ /* offset is non zero if object is written already. */
+ return WRITE_ONE_SKIP;
+ }
/* if we are deltified, write out base object first. */
- if (e->delta && !write_one(f, e->delta, offset))
- return 0;
+ if (e->delta) {
+ e->idx.offset = 1; /* now recurse */
+ switch (write_one(f, e->delta, offset)) {
+ case WRITE_ONE_RECURSIVE:
+ /* we cannot depend on this one */
+ e->delta = NULL;
+ break;
+ default:
+ break;
+ case WRITE_ONE_BREAK:
+ e->idx.offset = recursing;
+ return WRITE_ONE_BREAK;
+ }
+ }
e->idx.offset = *offset;
size = write_object(f, e, *offset);
if (!size) {
- e->idx.offset = 0;
- return 0;
+ e->idx.offset = recursing;
+ return WRITE_ONE_BREAK;
}
written_list[nr_written++] = &e->idx;
@@ -435,7 +466,7 @@ static int write_one(struct sha1file *f,
if (signed_add_overflows(*offset, size))
die("pack too large for current definition of off_t");
*offset += size;
- return 1;
+ return WRITE_ONE_WRITTEN;
}
static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
@@ -640,7 +671,7 @@ static void write_pack_file(void)
nr_written = 0;
for (; i < nr_objects; i++) {
struct object_entry *e = write_order[i];
- if (!write_one(f, e, &offset))
+ if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
break;
display_progress(progress_state, written);
}
@@ -1015,7 +1046,7 @@ static void add_pbase_object(struct tree_desc *tree,
while (tree_entry(tree,&entry)) {
if (S_ISGITLINK(entry.mode))
continue;
- cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
+ cmp = tree_entry_len(&entry) != cmplen ? 1 :
memcmp(name, entry.path, cmplen);
if (cmp > 0)
continue;
diff --git a/builtin/revert.c b/builtin/revert.c
index 1ea525c10..028bcbcd7 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -60,13 +60,14 @@ struct replay_opts {
int allow_rerere_auto;
int mainline;
- int commit_argc;
- const char **commit_argv;
/* Merge strategy */
const char *strategy;
const char **xopts;
size_t xopts_nr, xopts_alloc;
+
+ /* Only used by REPLAY_NONE */
+ struct rev_info *revs;
};
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -169,9 +170,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
die(_("program error"));
}
- opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
- PARSE_OPT_KEEP_ARGV0 |
- PARSE_OPT_KEEP_UNKNOWN);
+ argc = parse_options(argc, argv, NULL, options, usage_str,
+ PARSE_OPT_KEEP_ARGV0 |
+ PARSE_OPT_KEEP_UNKNOWN);
/* Check for incompatible subcommands */
verify_opt_mutually_compatible(me,
@@ -213,9 +214,6 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
NULL);
}
- else if (opts->commit_argc < 2)
- usage_with_options(usage_str, options);
-
if (opts->allow_ff)
verify_opt_compatible(me, "--ff",
"--signoff", opts->signoff,
@@ -223,7 +221,20 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
"-x", opts->record_origin,
"--edit", opts->edit,
NULL);
- opts->commit_argv = argv;
+
+ if (opts->subcommand != REPLAY_NONE) {
+ opts->revs = NULL;
+ } else {
+ opts->revs = xmalloc(sizeof(*opts->revs));
+ init_revisions(opts->revs, NULL);
+ opts->revs->no_walk = 1;
+ if (argc < 2)
+ usage_with_options(usage_str, options);
+ argc = setup_revisions(argc, argv, opts->revs, NULL);
+ }
+
+ if (argc > 1)
+ usage_with_options(usage_str, options);
}
struct commit_message {
@@ -631,23 +642,15 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
return res;
}
-static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
+static void prepare_revs(struct replay_opts *opts)
{
- int argc;
-
- init_revisions(revs, NULL);
- revs->no_walk = 1;
if (opts->action != REVERT)
- revs->reverse = 1;
-
- argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
- if (argc > 1)
- usage(*revert_or_cherry_pick_usage(opts));
+ opts->revs->reverse ^= 1;
- if (prepare_revision_walk(revs))
+ if (prepare_revision_walk(opts->revs))
die(_("revision walk setup failed"));
- if (!revs->commits)
+ if (!opts->revs->commits)
die(_("empty commit set passed"));
}
@@ -844,14 +847,13 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
static void walk_revs_populate_todo(struct commit_list **todo_list,
struct replay_opts *opts)
{
- struct rev_info revs;
struct commit *commit;
struct commit_list **next;
- prepare_revs(&revs, opts);
+ prepare_revs(opts);
next = todo_list;
- while ((commit = get_revision(&revs)))
+ while ((commit = get_revision(opts->revs)))
next = commit_list_append(commit, next);
}
@@ -942,7 +944,7 @@ static int sequencer_rollback(struct replay_opts *opts)
}
if (reset_for_rollback(sha1))
goto fail;
- remove_sequencer_state(1);
+ remove_sequencer_state();
strbuf_release(&buf);
return 0;
fail:
@@ -1016,33 +1018,64 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
for (cur = todo_list; cur; cur = cur->next) {
save_todo(cur, opts);
res = do_pick_commit(cur->item, opts);
- if (res) {
- if (!cur->next)
- /*
- * An error was encountered while
- * picking the last commit; the
- * sequencer state is useless now --
- * the user simply needs to resolve
- * the conflict and commit
- */
- remove_sequencer_state(0);
+ if (res)
return res;
- }
}
/*
* Sequence of picks finished successfully; cleanup by
* removing the .git/sequencer directory
*/
- remove_sequencer_state(1);
+ remove_sequencer_state();
return 0;
}
+static int continue_single_pick(void)
+{
+ const char *argv[] = { "commit", NULL };
+
+ if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
+ !file_exists(git_path("REVERT_HEAD")))
+ return error(_("no cherry-pick or revert in progress"));
+ return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static int sequencer_continue(struct replay_opts *opts)
+{
+ struct commit_list *todo_list = NULL;
+
+ if (!file_exists(git_path(SEQ_TODO_FILE)))
+ return continue_single_pick();
+ read_populate_opts(&opts);
+ read_populate_todo(&todo_list, opts);
+
+ /* Verify that the conflict has been resolved */
+ if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
+ file_exists(git_path("REVERT_HEAD"))) {
+ int ret = continue_single_pick();
+ if (ret)
+ return ret;
+ }
+ if (index_differs_from("HEAD", 0))
+ return error_dirty_index(opts);
+ todo_list = todo_list->next;
+ return pick_commits(todo_list, opts);
+}
+
+static int single_pick(struct commit *cmit, struct replay_opts *opts)
+{
+ setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
+ return do_pick_commit(cmit, opts);
+}
+
static int pick_revisions(struct replay_opts *opts)
{
struct commit_list *todo_list = NULL;
unsigned char sha1[20];
+ if (opts->subcommand == REPLAY_NONE)
+ assert(opts->revs);
+
read_and_refresh_cache(opts);
/*
@@ -1051,21 +1084,32 @@ static int pick_revisions(struct replay_opts *opts)
* one that is being continued
*/
if (opts->subcommand == REPLAY_REMOVE_STATE) {
- remove_sequencer_state(1);
+ remove_sequencer_state();
return 0;
}
if (opts->subcommand == REPLAY_ROLLBACK)
return sequencer_rollback(opts);
- if (opts->subcommand == REPLAY_CONTINUE) {
- if (!file_exists(git_path(SEQ_TODO_FILE)))
- return error(_("No %s in progress"), action_name(opts));
- read_populate_opts(&opts);
- read_populate_todo(&todo_list, opts);
-
- /* Verify that the conflict has been resolved */
- if (!index_differs_from("HEAD", 0))
- todo_list = todo_list->next;
- return pick_commits(todo_list, opts);
+ if (opts->subcommand == REPLAY_CONTINUE)
+ return sequencer_continue(opts);
+
+ /*
+ * If we were called as "git cherry-pick <commit>", just
+ * cherry-pick/revert it, set CHERRY_PICK_HEAD /
+ * REVERT_HEAD, and don't touch the sequencer state.
+ * This means it is possible to cherry-pick in the middle
+ * of a cherry-pick sequence.
+ */
+ if (opts->revs->cmdline.nr == 1 &&
+ opts->revs->cmdline.rev->whence == REV_CMD_REV &&
+ opts->revs->no_walk &&
+ !opts->revs->cmdline.rev->flags) {
+ struct commit *cmit;
+ if (prepare_revision_walk(opts->revs))
+ die(_("revision walk setup failed"));
+ cmit = get_revision(opts->revs);
+ if (!cmit || get_revision(opts->revs))
+ die("BUG: expected exactly one commit from walk");
+ return single_pick(cmit, opts);
}
/*
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index e0b8030f2..cd1115ffc 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -494,8 +494,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
memset(&extra_have, 0, sizeof(extra_have));
- get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
- &extra_have);
+ get_remote_heads(fd[0], &remote_refs, REF_NORMAL, &extra_have);
transport_verify_remote_names(nr_refspecs, refspecs);
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 1288ffcc5..f16986c0a 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -75,7 +75,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
!strcmp(argv[1], "--strip-comments")))
strip_comments = 1;
else if (argc > 1)
- usage("git stripspace [-s | --strip-comments] < <stream>");
+ usage("git stripspace [-s | --strip-comments] < input");
if (strbuf_read(&buf, 0, 1024) < 0)
die_errno("could not read the input");
diff --git a/cache.h b/cache.h
index 2e6ad3604..79c612fc2 100644
--- a/cache.h
+++ b/cache.h
@@ -1028,12 +1028,11 @@ extern char *git_getpass(const char *prompt);
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
extern int finish_connect(struct child_process *conn);
extern int git_connection_is_socket(struct child_process *conn);
-extern int path_match(const char *path, int nr, char **match);
struct extra_have_objects {
int nr, alloc;
unsigned char (*array)[20];
};
-extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
+extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
diff --git a/compat/snprintf.c b/compat/snprintf.c
index e1e0e7543..42ea1ac11 100644
--- a/compat/snprintf.c
+++ b/compat/snprintf.c
@@ -19,11 +19,14 @@
#undef vsnprintf
int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
{
+ va_list cp;
char *s;
int ret = -1;
if (maxsize > 0) {
- ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+ va_copy(cp, ap);
+ ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
+ va_end(cp);
if (ret == maxsize-1)
ret = -1;
/* Windows does not NUL-terminate if result fills buffer */
@@ -42,7 +45,9 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
if (! str)
break;
s = str;
- ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+ va_copy(cp, ap);
+ ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
+ va_end(cp);
if (ret == maxsize-1)
ret = -1;
}
diff --git a/compat/strtoimax.c b/compat/strtoimax.c
new file mode 100644
index 000000000..ac09ed89e
--- /dev/null
+++ b/compat/strtoimax.c
@@ -0,0 +1,10 @@
+#include "../git-compat-util.h"
+
+intmax_t gitstrtoimax (const char *nptr, char **endptr, int base)
+{
+#if defined(NO_STRTOULL)
+ return strtol(nptr, endptr, base);
+#else
+ return strtoll(nptr, endptr, base);
+#endif
+}
diff --git a/config.c b/config.c
index b6d789a18..5ea101fb2 100644
--- a/config.c
+++ b/config.c
@@ -333,7 +333,7 @@ static int git_parse_file(config_fn_t fn, void *data)
die("bad config file line %d in %s", cf->linenr, cf->name);
}
-static int parse_unit_factor(const char *end, unsigned long *val)
+static int parse_unit_factor(const char *end, uintmax_t *val)
{
if (!*end)
return 1;
@@ -356,11 +356,23 @@ static int git_parse_long(const char *value, long *ret)
{
if (value && *value) {
char *end;
- long val = strtol(value, &end, 0);
- unsigned long factor = 1;
+ intmax_t val;
+ uintmax_t uval;
+ uintmax_t factor = 1;
+
+ errno = 0;
+ val = strtoimax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
if (!parse_unit_factor(end, &factor))
return 0;
- *ret = val * factor;
+ uval = abs(val);
+ uval *= factor;
+ if ((uval > maximum_signed_value_of_type(long)) ||
+ (abs(val) > uval))
+ return 0;
+ val *= factor;
+ *ret = val;
return 1;
}
return 0;
@@ -370,9 +382,19 @@ int git_parse_ulong(const char *value, unsigned long *ret)
{
if (value && *value) {
char *end;
- unsigned long val = strtoul(value, &end, 0);
+ uintmax_t val;
+ uintmax_t oldval;
+
+ errno = 0;
+ val = strtoumax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
+ oldval = val;
if (!parse_unit_factor(end, &val))
return 0;
+ if ((val > maximum_unsigned_value_of_type(long)) ||
+ (oldval > val))
+ return 0;
*ret = val;
return 1;
}
@@ -553,7 +575,7 @@ static int git_default_core_config(const char *var, const char *value)
if (!strcmp(var, "core.packedgitwindowsize")) {
int pgsz_x2 = getpagesize() * 2;
- packed_git_window_size = git_config_int(var, value);
+ packed_git_window_size = git_config_ulong(var, value);
/* This value must be multiple of (pagesize * 2) */
packed_git_window_size /= pgsz_x2;
@@ -564,18 +586,17 @@ static int git_default_core_config(const char *var, const char *value)
}
if (!strcmp(var, "core.bigfilethreshold")) {
- long n = git_config_int(var, value);
- big_file_threshold = 0 < n ? n : 0;
+ big_file_threshold = git_config_ulong(var, value);
return 0;
}
if (!strcmp(var, "core.packedgitlimit")) {
- packed_git_limit = git_config_int(var, value);
+ packed_git_limit = git_config_ulong(var, value);
return 0;
}
if (!strcmp(var, "core.deltabasecachelimit")) {
- delta_base_cache_limit = git_config_int(var, value);
+ delta_base_cache_limit = git_config_ulong(var, value);
return 0;
}
diff --git a/connect.c b/connect.c
index 51990fa0c..c8d0ea5d7 100644
--- a/connect.c
+++ b/connect.c
@@ -53,7 +53,6 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1
* Read all the refs from the other end
*/
struct ref **get_remote_heads(int in, struct ref **list,
- int nr_match, char **match,
unsigned int flags,
struct extra_have_objects *extra_have)
{
@@ -92,8 +91,6 @@ struct ref **get_remote_heads(int in, struct ref **list,
if (!check_ref(name, name_len, flags))
continue;
- if (nr_match && !path_match(name, nr_match, match))
- continue;
ref = alloc_ref(buffer + 41);
hashcpy(ref->old_sha1, old_sha1);
*list = ref;
@@ -108,27 +105,6 @@ int server_supports(const char *feature)
strstr(server_capabilities, feature) != NULL;
}
-int path_match(const char *path, int nr, char **match)
-{
- int i;
- int pathlen = strlen(path);
-
- for (i = 0; i < nr; i++) {
- char *s = match[i];
- int len = strlen(s);
-
- if (!len || len > pathlen)
- continue;
- if (memcmp(path + pathlen - len, s, len))
- continue;
- if (pathlen > len && path[pathlen - len - 1] != '/')
- continue;
- *s = 0;
- return (i + 1);
- }
- return 0;
-}
-
enum protocol {
PROTO_LOCAL = 1,
PROTO_SSH,
@@ -175,6 +151,15 @@ static void get_host_and_port(char **host, const char **port)
}
}
+static void enable_keepalive(int sockfd)
+{
+ int ka = 1;
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0)
+ fprintf(stderr, "unable to set SO_KEEPALIVE on socket: %s\n",
+ strerror(errno));
+}
+
#ifndef NO_IPV6
static const char *ai_name(const struct addrinfo *ai)
@@ -239,6 +224,8 @@ static int git_tcp_connect_sock(char *host, int flags)
if (sockfd < 0)
die("unable to connect to %s:\n%s", host, error_message.buf);
+ enable_keepalive(sockfd);
+
if (flags & CONNECT_VERBOSE)
fprintf(stderr, "done.\n");
@@ -312,6 +299,8 @@ static int git_tcp_connect_sock(char *host, int flags)
if (sockfd < 0)
die("unable to connect to %s:\n%s", host, error_message.buf);
+ enable_keepalive(sockfd);
+
if (flags & CONNECT_VERBOSE)
fprintf(stderr, "done.\n");
diff --git a/convert.c b/convert.c
index 86e9c29ec..c9ab54ffd 100644
--- a/convert.c
+++ b/convert.c
@@ -876,24 +876,42 @@ int is_null_stream_filter(struct stream_filter *filter)
/*
* LF-to-CRLF filter
*/
+
+struct lf_to_crlf_filter {
+ struct stream_filter filter;
+ unsigned want_lf:1;
+};
+
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
const char *input, size_t *isize_p,
char *output, size_t *osize_p)
{
- size_t count;
+ size_t count, o = 0;
+ struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
+
+ /* Output a pending LF if we need to */
+ if (lf_to_crlf->want_lf) {
+ output[o++] = '\n';
+ lf_to_crlf->want_lf = 0;
+ }
+
+ /* We are told to drain */
+ if (!input) {
+ *osize_p -= o;
+ return 0;
+ }
- if (!input)
- return 0; /* we do not keep any states */
count = *isize_p;
if (count) {
- size_t i, o;
- for (i = o = 0; o < *osize_p && i < count; i++) {
+ size_t i;
+ for (i = 0; o < *osize_p && i < count; i++) {
char ch = input[i];
if (ch == '\n') {
- if (o + 1 < *osize_p)
- output[o++] = '\r';
- else
- break;
+ output[o++] = '\r';
+ if (o >= *osize_p) {
+ lf_to_crlf->want_lf = 1;
+ continue; /* We need to increase i */
+ }
}
output[o++] = ch;
}
@@ -904,15 +922,23 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
return 0;
}
+static void lf_to_crlf_free_fn(struct stream_filter *filter)
+{
+ free(filter);
+}
+
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
lf_to_crlf_filter_fn,
- null_free_fn,
+ lf_to_crlf_free_fn,
};
-static struct stream_filter lf_to_crlf_filter_singleton = {
- &lf_to_crlf_vtbl,
-};
+static struct stream_filter *lf_to_crlf_filter(void)
+{
+ struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
+ lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
+ return (struct stream_filter *)lf_to_crlf;
+}
/*
* Cascade filter
@@ -1194,7 +1220,7 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
else if (output_eol(crlf_action) == EOL_CRLF &&
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
- filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
+ filter = cascade_filter(filter, lf_to_crlf_filter());
return filter;
}
diff --git a/dir.c b/dir.c
index 6c0d78257..0a78d00b5 100644
--- a/dir.c
+++ b/dir.c
@@ -968,34 +968,34 @@ static int read_directory_recursive(struct dir_struct *dir,
{
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;
+ struct dirent *de;
+ char path[PATH_MAX + 1];
- if (fdir) {
- struct dirent *de;
- char path[PATH_MAX + 1];
- memcpy(path, base, baselen);
-
- while ((de = readdir(fdir)) != NULL) {
- int len;
- switch (treat_path(dir, de, path, sizeof(path),
- baselen, simplify, &len)) {
- case path_recurse:
- contents += read_directory_recursive
- (dir, path, len, 0, simplify);
- continue;
- case path_ignored:
- continue;
- case path_handled:
- break;
- }
- contents++;
- if (check_only)
- goto exit_early;
- else
- dir_add_name(dir, path, len);
+ if (!fdir)
+ return 0;
+
+ memcpy(path, base, baselen);
+
+ while ((de = readdir(fdir)) != NULL) {
+ int len;
+ switch (treat_path(dir, de, path, sizeof(path),
+ baselen, simplify, &len)) {
+ case path_recurse:
+ contents += read_directory_recursive(dir, path, len, 0, simplify);
+ continue;
+ case path_ignored:
+ continue;
+ case path_handled:
+ break;
}
-exit_early:
- closedir(fdir);
+ contents++;
+ if (check_only)
+ goto exit_early;
+ else
+ dir_add_name(dir, path, len);
}
+exit_early:
+ closedir(fdir);
return contents;
}
diff --git a/fast-import.c b/fast-import.c
index 8d8ea3c45..f4bfe0f66 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2173,6 +2173,11 @@ static uintmax_t do_change_note_fanout(
if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) {
/* This is a note entry */
+ if (fanout == 0xff) {
+ /* Counting mode, no rename */
+ num_notes++;
+ continue;
+ }
construct_path_with_fanout(hex_sha1, fanout, realpath);
if (!strcmp(fullpath, realpath)) {
/* Note entry is in correct location */
@@ -2379,7 +2384,7 @@ static void file_change_cr(struct branch *b, int rename)
leaf.tree);
}
-static void note_change_n(struct branch *b, unsigned char old_fanout)
+static void note_change_n(struct branch *b, unsigned char *old_fanout)
{
const char *p = command_buf.buf + 2;
static struct strbuf uq = STRBUF_INIT;
@@ -2390,6 +2395,23 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
uint16_t inline_data = 0;
unsigned char new_fanout;
+ /*
+ * When loading a branch, we don't traverse its tree to count the real
+ * number of notes (too expensive to do this for all non-note refs).
+ * This means that recently loaded notes refs might incorrectly have
+ * b->num_notes == 0, and consequently, old_fanout might be wrong.
+ *
+ * Fix this by traversing the tree and counting the number of notes
+ * when b->num_notes == 0. If the notes tree is truly empty, the
+ * calculation should not take long.
+ */
+ if (b->num_notes == 0 && *old_fanout == 0) {
+ /* Invoke change_note_fanout() in "counting mode". */
+ b->num_notes = change_note_fanout(&b->branch_tree, 0xff);
+ *old_fanout = convert_num_notes_to_fanout(b->num_notes);
+ }
+
+ /* Now parse the notemodify command. */
/* <dataref> or 'inline' */
if (*p == ':') {
char *x;
@@ -2450,7 +2472,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
typename(type), command_buf.buf);
}
- construct_path_with_fanout(sha1_to_hex(commit_sha1), old_fanout, path);
+ construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
if (tree_content_remove(&b->branch_tree, path, NULL))
b->num_notes--;
@@ -2637,7 +2659,7 @@ static void parse_new_commit(void)
else if (!prefixcmp(command_buf.buf, "C "))
file_change_cr(b, 0);
else if (!prefixcmp(command_buf.buf, "N "))
- note_change_n(b, prev_fanout);
+ note_change_n(b, &prev_fanout);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
else if (!prefixcmp(command_buf.buf, "ls "))
diff --git a/git-compat-util.h b/git-compat-util.h
index 8b4dd5c02..230e198fc 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -351,6 +351,8 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
#ifdef NO_STRTOUMAX
#define strtoumax gitstrtoumax
extern uintmax_t gitstrtoumax(const char *, char **, int);
+#define strtoimax gitstrtoimax
+extern intmax_t gitstrtoimax(const char *, char **, int);
#endif
#ifdef NO_STRTOK_R
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 804001bb4..5812222eb 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -143,6 +143,21 @@ die_with_patch () {
die "$2"
}
+exit_with_patch () {
+ echo "$1" > "$state_dir"/stopped-sha
+ make_patch $1
+ git rev-parse --verify HEAD > "$amend"
+ warn "You can amend the commit now, with"
+ warn
+ warn " git commit --amend"
+ warn
+ warn "Once you are satisfied with your changes, run"
+ warn
+ warn " git rebase --continue"
+ warn
+ exit $2
+}
+
die_abort () {
rm -rf "$state_dir"
die "$1"
@@ -408,7 +423,13 @@ do_next () {
mark_action_done
pick_one $sha1 ||
die_with_patch $sha1 "Could not apply $sha1... $rest"
- git commit --amend --no-post-rewrite
+ git commit --amend --no-post-rewrite || {
+ warn "Could not amend commit after successfully picking $sha1... $rest"
+ warn "This is most likely due to an empty commit message, or the pre-commit hook"
+ warn "failed. If the pre-commit hook failed, you may need to resolve the issue before"
+ warn "you are able to reword the commit."
+ exit_with_patch $sha1 1
+ }
record_in_rewritten $sha1
;;
edit|e)
@@ -417,19 +438,8 @@ do_next () {
mark_action_done
pick_one $sha1 ||
die_with_patch $sha1 "Could not apply $sha1... $rest"
- echo "$sha1" > "$state_dir"/stopped-sha
- make_patch $sha1
- git rev-parse --verify HEAD > "$amend"
warn "Stopped at $sha1... $rest"
- warn "You can amend the commit now, with"
- warn
- warn " git commit --amend"
- warn
- warn "Once you are satisfied with your changes, run"
- warn
- warn " git rebase --continue"
- warn
- exit 0
+ exit_with_patch $sha1 0
;;
squash|s|fixup|f)
case "$command" in
diff --git a/http-fetch.c b/http-fetch.c
index 69299b7bd..94d47cbb2 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -67,7 +67,7 @@ int main(int argc, const char **argv)
git_config(git_default_config, NULL);
- http_init(NULL, url);
+ http_init(NULL, url, 0);
walker = get_http_walker(url);
walker->get_tree = get_tree;
walker->get_history = get_history;
diff --git a/http-push.c b/http-push.c
index edd553b7f..cdfdd4f79 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1820,7 +1820,7 @@ int main(int argc, char **argv)
memset(remote_dir_exists, -1, 256);
- http_init(NULL, repo->url);
+ http_init(NULL, repo->url, 1);
#ifdef USE_CURL_MULTI
is_running_queue = 0;
diff --git a/http.c b/http.c
index e6c75976e..5a1047345 100644
--- a/http.c
+++ b/http.c
@@ -4,7 +4,6 @@
#include "run-command.h"
#include "url.h"
-int data_received;
int active_requests;
int http_is_verbose;
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -43,6 +42,7 @@ static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
static const char *curl_cookie_file;
static char *user_name, *user_pass, *description;
+static int http_proactive_auth;
static const char *user_agent;
#if LIBCURL_VERSION_NUM >= 0x071700
@@ -99,13 +99,11 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
struct strbuf *buffer = buffer_;
strbuf_add(buffer, ptr, size);
- data_received++;
return size;
}
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
{
- data_received++;
return eltsize * nmemb;
}
@@ -279,6 +277,9 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
#endif
+ if (http_proactive_auth)
+ init_curl_http_auth(result);
+
if (ssl_cert != NULL)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
if (has_cert_password())
@@ -367,7 +368,7 @@ static void set_from_env(const char **var, const char *envname)
*var = val;
}
-void http_init(struct remote *remote, const char *url)
+void http_init(struct remote *remote, const char *url, int proactive_auth)
{
char *low_speed_limit;
char *low_speed_time;
@@ -378,6 +379,8 @@ void http_init(struct remote *remote, const char *url)
curl_global_init(CURL_GLOBAL_ALL);
+ http_proactive_auth = proactive_auth;
+
if (remote && remote->http_proxy)
curl_http_proxy = xstrdup(remote->http_proxy);
@@ -536,7 +539,6 @@ struct active_request_slot *get_active_slot(void)
active_requests++;
slot->in_use = 1;
- slot->local = NULL;
slot->results = NULL;
slot->finished = NULL;
slot->callback_data = NULL;
@@ -640,8 +642,6 @@ void step_active_slots(void)
void run_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
- long last_pos = 0;
- long current_pos;
fd_set readfds;
fd_set writefds;
fd_set excfds;
@@ -651,25 +651,33 @@ void run_active_slot(struct active_request_slot *slot)
slot->finished = &finished;
while (!finished) {
- data_received = 0;
step_active_slots();
- if (!data_received && slot->local != NULL) {
- current_pos = ftell(slot->local);
- if (current_pos > last_pos)
- data_received++;
- last_pos = current_pos;
- }
+ if (slot->in_use) {
+#if LIBCURL_VERSION_NUM >= 0x070f04
+ long curl_timeout;
+ curl_multi_timeout(curlm, &curl_timeout);
+ if (curl_timeout == 0) {
+ continue;
+ } else if (curl_timeout == -1) {
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 50000;
+ } else {
+ select_timeout.tv_sec = curl_timeout / 1000;
+ select_timeout.tv_usec = (curl_timeout % 1000) * 1000;
+ }
+#else
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 50000;
+#endif
- if (slot->in_use && !data_received) {
- max_fd = 0;
+ max_fd = -1;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&excfds);
- select_timeout.tv_sec = 0;
- select_timeout.tv_usec = 50000;
- select(max_fd, &readfds, &writefds,
- &excfds, &select_timeout);
+ curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
+
+ select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
}
}
#else
@@ -814,7 +822,6 @@ static int http_request(const char *url, void *result, int target, int options)
headers = curl_slist_append(headers, buf.buf);
strbuf_reset(&buf);
}
- slot->local = result;
} else
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer);
@@ -862,7 +869,6 @@ static int http_request(const char *url, void *result, int target, int options)
ret = HTTP_START_FAILED;
}
- slot->local = NULL;
curl_slist_free_all(headers);
strbuf_release(&buf);
@@ -1057,7 +1063,6 @@ void release_http_pack_request(struct http_pack_request *preq)
if (preq->packfile != NULL) {
fclose(preq->packfile);
preq->packfile = NULL;
- preq->slot->local = NULL;
}
if (preq->range_header != NULL) {
curl_slist_free_all(preq->range_header);
@@ -1079,7 +1084,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
fclose(preq->packfile);
preq->packfile = NULL;
- preq->slot->local = NULL;
lst = preq->lst;
while (*lst != p)
@@ -1148,7 +1152,6 @@ struct http_pack_request *new_http_pack_request(
}
preq->slot = get_active_slot();
- preq->slot->local = preq->packfile;
curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
@@ -1205,7 +1208,6 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
git_SHA1_Update(&freq->c, expn,
sizeof(expn) - freq->stream.avail_out);
} while (freq->stream.avail_in && freq->zret == Z_OK);
- data_received++;
return size;
}
diff --git a/http.h b/http.h
index 3c332a98e..0b6165389 100644
--- a/http.h
+++ b/http.h
@@ -49,7 +49,6 @@ struct slot_results {
struct active_request_slot {
CURL *curl;
- FILE *local;
int in_use;
CURLcode curl_result;
long http_code;
@@ -86,10 +85,10 @@ extern void add_fill_function(void *data, int (*fill)(void *));
extern void step_active_slots(void);
#endif
-extern void http_init(struct remote *remote, const char *url);
+extern void http_init(struct remote *remote, const char *url,
+ int proactive_auth);
extern void http_cleanup(void);
-extern int data_received;
extern int active_requests;
extern int http_is_verbose;
extern size_t http_post_buffer;
diff --git a/imap-send.c b/imap-send.c
index e1ad1a48c..80e0e8c05 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -161,7 +161,6 @@ static struct imap_server_conf server = {
struct imap_store_conf {
struct store_conf gen;
struct imap_server_conf *server;
- unsigned use_namespace:1;
};
#define NIL (void *)0x1
diff --git a/list-objects.c b/list-objects.c
index 39d80c017..3dd4a9601 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -71,7 +71,8 @@ static void process_tree(struct rev_info *revs,
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
- int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
+ enum interesting match = revs->diffopt.pathspec.nr == 0 ?
+ all_entries_interesting: entry_not_interesting;
int baselen = base->len;
if (!revs->tree_objects)
@@ -97,12 +98,12 @@ static void process_tree(struct rev_info *revs,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, 0,
&revs->diffopt.pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/object.c b/object.c
index 31976b5d7..d8d09f92a 100644
--- a/object.c
+++ b/object.c
@@ -149,6 +149,8 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
struct tree *tree = lookup_tree(sha1);
if (tree) {
obj = &tree->object;
+ if (!tree->buffer)
+ tree->object.parsed = 0;
if (!tree->object.parsed) {
if (parse_tree_buffer(tree, buffer, size))
return NULL;
diff --git a/pack-write.c b/pack-write.c
index 9cd3bfbb4..f84adde3e 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -129,6 +129,10 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
}
sha1write(f, obj->sha1, 20);
git_SHA1_Update(&ctx, obj->sha1, 20);
+ if ((opts->flags & WRITE_IDX_STRICT) &&
+ (i && !hashcmp(list[-2]->sha1, obj->sha1)))
+ die("The same object %s appears twice in the pack",
+ sha1_to_hex(obj->sha1));
}
if (index_version >= 2) {
diff --git a/pack.h b/pack.h
index 722a54e00..aca473931 100644
--- a/pack.h
+++ b/pack.h
@@ -37,7 +37,8 @@ struct pack_header {
struct pack_idx_option {
unsigned flags;
/* flag bits */
-#define WRITE_IDX_VERIFY 01
+#define WRITE_IDX_VERIFY 01 /* verify only, do not write the idx file */
+#define WRITE_IDX_STRICT 02
uint32_t version;
uint32_t off32_limit;
diff --git a/read-cache.c b/read-cache.c
index 5790a9104..27e9fc6ee 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1001,7 +1001,8 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
*/
static struct cache_entry *refresh_cache_ent(struct index_state *istate,
struct cache_entry *ce,
- unsigned int options, int *err)
+ unsigned int options, int *err,
+ int *changed_ret)
{
struct stat st;
struct cache_entry *updated;
@@ -1033,6 +1034,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
}
changed = ie_match_stat(istate, ce, &st, options);
+ if (changed_ret)
+ *changed_ret = changed;
if (!changed) {
/*
* The path is unchanged. If we were told to ignore
@@ -1102,14 +1105,21 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
int first = 1;
int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
- const char *needs_update_fmt;
- const char *needs_merge_fmt;
-
- needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
- needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
+ const char *modified_fmt;
+ const char *deleted_fmt;
+ const char *typechange_fmt;
+ const char *added_fmt;
+ const char *unmerged_fmt;
+
+ modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+ deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
+ typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
+ added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
+ unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new;
int cache_errno = 0;
+ int changed = 0;
ce = istate->cache[i];
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
@@ -1122,7 +1132,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
i--;
if (allow_unmerged)
continue;
- show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
+ show_file(unmerged_fmt, ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
@@ -1130,10 +1140,12 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
continue;
- new = refresh_cache_ent(istate, ce, options, &cache_errno);
+ new = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
if (new == ce)
continue;
if (!new) {
+ const char *fmt;
+
if (not_new && cache_errno == ENOENT)
continue;
if (really && cache_errno == EINVAL) {
@@ -1145,7 +1157,17 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
}
if (quiet)
continue;
- show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
+
+ if (cache_errno == ENOENT)
+ fmt = deleted_fmt;
+ else if (ce->ce_flags & CE_INTENT_TO_ADD)
+ fmt = added_fmt; /* must be before other checks */
+ else if (changed & TYPE_CHANGED)
+ fmt = typechange_fmt;
+ else
+ fmt = modified_fmt;
+ show_file(fmt,
+ ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
@@ -1157,7 +1179,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
{
- return refresh_cache_ent(&the_index, ce, really, NULL);
+ return refresh_cache_ent(&the_index, ce, really, NULL, NULL);
}
static int verify_hdr(struct cache_header *hdr, unsigned long size)
diff --git a/remote-curl.c b/remote-curl.c
index 0e720ee8b..6a352de7b 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -200,7 +200,7 @@ static struct ref *parse_git_refs(struct discovery *heads)
if (start_async(&async))
die("cannot start thread to parse advertised refs");
- get_remote_heads(async.out, &list, 0, NULL, 0, NULL);
+ get_remote_heads(async.out, &list, 0, NULL);
close(async.out);
if (finish_async(&async))
die("ref parsing thread failed");
@@ -859,7 +859,7 @@ int main(int argc, const char **argv)
url = strbuf_detach(&buf, NULL);
- http_init(remote, url);
+ http_init(remote, url, 0);
do {
if (strbuf_getline(&buf, stdin, '\n') == EOF) {
diff --git a/sequencer.c b/sequencer.c
index bc2c046aa..d1f28a694 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3,17 +3,11 @@
#include "strbuf.h"
#include "dir.h"
-void remove_sequencer_state(int aggressive)
+void remove_sequencer_state(void)
{
struct strbuf seq_dir = STRBUF_INIT;
- struct strbuf seq_old_dir = STRBUF_INIT;
strbuf_addf(&seq_dir, "%s", git_path(SEQ_DIR));
- strbuf_addf(&seq_old_dir, "%s", git_path(SEQ_OLD_DIR));
- remove_dir_recursively(&seq_old_dir, 0);
- rename(git_path(SEQ_DIR), git_path(SEQ_OLD_DIR));
- if (aggressive)
- remove_dir_recursively(&seq_old_dir, 0);
+ remove_dir_recursively(&seq_dir, 0);
strbuf_release(&seq_dir);
- strbuf_release(&seq_old_dir);
}
diff --git a/sequencer.h b/sequencer.h
index f435fdb4b..2d4528f29 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -2,19 +2,11 @@
#define SEQUENCER_H
#define SEQ_DIR "sequencer"
-#define SEQ_OLD_DIR "sequencer-old"
#define SEQ_HEAD_FILE "sequencer/head"
#define SEQ_TODO_FILE "sequencer/todo"
#define SEQ_OPTS_FILE "sequencer/opts"
-/*
- * Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring
- * any errors. Intended to be used by 'git reset'.
- *
- * With the aggressive flag, it additionally removes SEQ_OLD_DIR,
- * ignoring any errors. Inteded to be used by the sequencer's
- * '--quit' subcommand.
- */
-void remove_sequencer_state(int aggressive);
+/* Removes SEQ_DIR. */
+extern void remove_sequencer_state(void);
#endif
diff --git a/sha1_file.c b/sha1_file.c
index 6dcae3882..956422ba4 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1267,7 +1267,8 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
while (c & 0x80) {
if (len <= used || bitsizeof(long) <= shift) {
error("bad object header");
- return 0;
+ size = used = 0;
+ break;
}
c = buf[used++];
size += (c & 0x7f) << shift;
diff --git a/submodule.c b/submodule.c
index 0fd10a0fd..68c1ba90b 100644
--- a/submodule.c
+++ b/submodule.c
@@ -391,7 +391,7 @@ static void commit_need_pushing(struct commit *commit, struct commit_list *paren
rev.diffopt.format_callback_data = needs_pushing;
diff_tree_combined(commit->object.sha1, parents, n, 1, &rev);
- free(parents);
+ free((void *)parents);
}
int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remotes_name)
@@ -689,7 +689,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
cp.out = -1;
cp.dir = path;
if (start_command(&cp))
- die("Could not run git status --porcelain");
+ die("Could not run 'git status --porcelain' in submodule %s", path);
len = strbuf_read(&buf, cp.out, 1024);
line = buf.buf;
@@ -714,7 +714,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
close(cp.out);
if (finish_command(&cp))
- die("git status --porcelain failed");
+ die("'git status --porcelain' failed in submodule %s", path);
strbuf_release(&buf);
return dirty_submodule;
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 0a4cdfa93..3c12b05d6 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -92,6 +92,9 @@ SSLEngine On
<Location /dumb/>
Dav on
</Location>
+ <Location /auth/dumb>
+ Dav on
+ </Location>
</IfDefine>
<IfDefine SVN>
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 75874e85d..274126236 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -189,12 +189,13 @@ test_expect_success 'checkout -b <describe>' '
test_cmp expect actual
'
-test_expect_success 'checkout -B to the current branch fails before merging' '
+test_expect_success 'checkout -B to the current branch works' '
git checkout branch1 &&
+ git checkout -B branch1-scratch &&
+
setup_dirty_mergeable &&
- git commit -mfooble &&
- test_must_fail git checkout -B branch1 initial &&
- test_must_fail test_dirty_mergeable
+ git checkout -B branch1-scratch initial &&
+ test_dirty_mergeable
'
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index bc73c2099..76903323a 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -115,6 +115,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
git branch -M baz bam
'
+test_expect_success 'git branch -M master should work when master is checked out' '
+ git checkout master &&
+ git branch -M master
+'
+
+test_expect_success 'git branch -M master master should work when master is checked out' '
+ git checkout master &&
+ git branch -M master master
+'
+
+test_expect_success 'git branch -M master2 master2 should work when master is checked out' '
+ git checkout master &&
+ git branch master2 &&
+ git branch -M master2 master2
+'
+
test_expect_success 'git branch -v -d t should work' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 2c4c1c851..e80050e1f 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -2,6 +2,7 @@
test_description='Test cherry-pick continuation features
+ + conflicting: rewrites unrelated to conflicting
+ yetanotherpick: rewrites foo to e
+ anotherpick: rewrites foo to d
+ picked: rewrites foo to c
@@ -27,6 +28,7 @@ test_cmp_rev () {
}
test_expect_success setup '
+ git config advice.detachedhead false
echo unrelated >unrelated &&
git add unrelated &&
test_commit initial foo a &&
@@ -35,8 +37,8 @@ test_expect_success setup '
test_commit picked foo c &&
test_commit anotherpick foo d &&
test_commit yetanotherpick foo e &&
- git config advice.detachedhead false
-
+ pristine_detach initial &&
+ test_commit conflicting unrelated
'
test_expect_success 'cherry-pick persists data on failure' '
@@ -48,6 +50,18 @@ test_expect_success 'cherry-pick persists data on failure' '
test_path_is_file .git/sequencer/opts
'
+test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ test_cmp_rev picked CHERRY_PICK_HEAD &&
+ # "oops, I forgot that these patches rely on the change from base"
+ git checkout HEAD foo &&
+ git cherry-pick base &&
+ git cherry-pick picked &&
+ git cherry-pick --continue &&
+ git diff --exit-code anotherpick
+'
+
test_expect_success 'cherry-pick persists opts correctly' '
pristine_detach initial &&
test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
@@ -189,10 +203,10 @@ test_expect_success '--abort refuses to clobber unrelated change, harder case' '
test_cmp_rev initial HEAD
'
-test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
+test_expect_success 'cherry-pick still writes sequencer state when one commit is left' '
pristine_detach initial &&
test_must_fail git cherry-pick base..picked &&
- test_path_is_missing .git/sequencer &&
+ test_path_is_dir .git/sequencer &&
echo "resolved" >foo &&
git add foo &&
git commit &&
@@ -213,7 +227,7 @@ test_expect_success 'cherry-pick cleans up sequencer state when one commit is le
test_cmp expect actual
'
-test_expect_failure '--abort after last commit in sequence' '
+test_expect_success '--abort after last commit in sequence' '
pristine_detach initial &&
test_must_fail git cherry-pick base..picked &&
git cherry-pick --abort &&
@@ -243,7 +257,66 @@ test_expect_success '--continue complains when there are unresolved conflicts' '
test_must_fail git cherry-pick --continue
'
-test_expect_success '--continue continues after conflicts are resolved' '
+test_expect_success '--continue of single cherry-pick' '
+ pristine_detach initial &&
+ echo c >expect &&
+ test_must_fail git cherry-pick picked &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+
+ test_cmp expect foo &&
+ test_cmp_rev initial HEAD^ &&
+ git diff --exit-code HEAD &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success '--continue of single revert' '
+ pristine_detach initial &&
+ echo resolved >expect &&
+ echo "Revert \"picked\"" >expect.msg &&
+ test_must_fail git revert picked &&
+ echo resolved >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+
+ git diff --exit-code HEAD &&
+ test_cmp expect foo &&
+ test_cmp_rev initial HEAD^ &&
+ git diff-tree -s --pretty=tformat:%s HEAD >msg &&
+ test_cmp expect.msg msg &&
+ test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+ test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success '--continue after resolving conflicts' '
+ pristine_detach initial &&
+ echo d >expect &&
+ cat >expect.log <<-\EOF &&
+ OBJID
+ :100644 100644 OBJID OBJID M foo
+ OBJID
+ :100644 100644 OBJID OBJID M foo
+ OBJID
+ :100644 100644 OBJID OBJID M unrelated
+ OBJID
+ :000000 100644 OBJID OBJID A foo
+ :000000 100644 OBJID OBJID A unrelated
+ EOF
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual.log &&
+ test_cmp expect foo &&
+ test_cmp expect.log actual.log
+'
+
+test_expect_success '--continue after resolving conflicts and committing' '
pristine_detach initial &&
test_must_fail git cherry-pick base..anotherpick &&
echo "c" >foo &&
@@ -270,6 +343,29 @@ test_expect_success '--continue continues after conflicts are resolved' '
test_cmp expect actual
'
+test_expect_success '--continue asks for help after resolving patch to nil' '
+ pristine_detach conflicting &&
+ test_must_fail git cherry-pick initial..picked &&
+
+ test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
+ git checkout HEAD -- unrelated &&
+ test_must_fail git cherry-pick --continue 2>msg &&
+ test_i18ngrep "The previous cherry-pick is now empty" msg
+'
+
+test_expect_success 'follow advice and skip nil patch' '
+ pristine_detach conflicting &&
+ test_must_fail git cherry-pick initial..picked &&
+
+ git checkout HEAD -- unrelated &&
+ test_must_fail git cherry-pick --continue &&
+ git reset &&
+ git cherry-pick --continue &&
+
+ git rev-list initial..HEAD >commits &&
+ test_line_count = 3 commits
+'
+
test_expect_success '--continue respects opts' '
pristine_detach initial &&
test_must_fail git cherry-pick -x base..anotherpick &&
@@ -288,6 +384,29 @@ test_expect_success '--continue respects opts' '
grep "cherry picked from" anotherpick_msg
'
+test_expect_success '--continue of single-pick respects -x' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -x picked &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ git cat-file commit HEAD >msg &&
+ grep "cherry picked from" msg
+'
+
+test_expect_success '--continue respects -x in first commit in multi-pick' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -x picked anotherpick &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ git cat-file commit HEAD^ >msg &&
+ picked=$(git rev-parse --verify picked) &&
+ grep "cherry picked from.*$picked" msg
+'
+
test_expect_success '--signoff is not automatically propagated to resolved conflict' '
pristine_detach initial &&
test_must_fail git cherry-pick --signoff base..anotherpick &&
@@ -306,6 +425,32 @@ test_expect_success '--signoff is not automatically propagated to resolved confl
grep "Signed-off-by:" anotherpick_msg
'
+test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s picked anotherpick &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+
+ git diff --exit-code HEAD &&
+ test_cmp_rev initial HEAD^^ &&
+ git cat-file commit HEAD^ >msg &&
+ ! grep Signed-off-by: msg
+'
+
+test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s picked &&
+ echo c >foo &&
+ git add foo &&
+ git cherry-pick --continue &&
+
+ git diff --exit-code HEAD &&
+ test_cmp_rev initial HEAD^ &&
+ git cat-file commit HEAD >msg &&
+ ! grep Signed-off-by: msg
+'
+
test_expect_success 'malformed instruction sheet 1' '
pristine_detach initial &&
test_must_fail git cherry-pick base..anotherpick &&
@@ -328,4 +473,9 @@ test_expect_success 'malformed instruction sheet 2' '
test_must_fail git cherry-pick --continue
'
+test_expect_success 'empty commit set' '
+ pristine_detach initial &&
+ test_expect_code 128 git cherry-pick base..base
+'
+
test_done
diff --git a/t/t4131-apply-fake-ancestor.sh b/t/t4131-apply-fake-ancestor.sh
index 94373ca9a..b1361ce54 100755
--- a/t/t4131-apply-fake-ancestor.sh
+++ b/t/t4131-apply-fake-ancestor.sh
@@ -11,7 +11,7 @@ test_expect_success 'setup' '
test_commit 1 &&
test_commit 2 &&
mkdir sub &&
- test_commit 3 sub/3 &&
+ test_commit 3 sub/3.t &&
test_commit 4
'
diff --git a/t/t4136-apply-check.sh b/t/t4136-apply-check.sh
new file mode 100755
index 000000000..a321f7c24
--- /dev/null
+++ b/t/t4136-apply-check.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='git apply should exit non-zero with unrecognized input.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit 1
+'
+
+test_expect_success 'apply --check exits non-zero with unrecognized input' '
+ test_must_fail git apply --check - <<-\EOF
+ I am not a patch
+ I look nothing like a patch
+ git apply must fail
+ EOF
+'
+
+test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index d9068981f..c05c676ca 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -242,6 +242,14 @@ test_expect_success \
'git archive --list outside of a git repo' \
'GIT_DIR=some/non-existing/directory git archive --list'
+test_expect_success 'clients cannot access unreachable commits' '
+ test_commit unreachable &&
+ sha1=`git rev-parse HEAD` &&
+ git reset --hard HEAD^ &&
+ git archive $sha1 >remote.tar &&
+ test_must_fail git archive --remote=. $sha1 >remote.tar
+'
+
test_expect_success 'git-archive --prefix=olde-' '
git archive --prefix=olde- >h.tar HEAD &&
(
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index bafcca765..9bf69e9a0 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -97,7 +97,7 @@ test_expect_success 'setup' '
git symbolic-ref HEAD refs/heads/B
'
-pull_to_client 1st "B A" $((11*3))
+pull_to_client 1st "refs/heads/B refs/heads/A" $((11*3))
test_expect_success 'post 1st pull setup' '
add A11 $A10 &&
@@ -110,9 +110,9 @@ test_expect_success 'post 1st pull setup' '
done
'
-pull_to_client 2nd "B" $((64*3))
+pull_to_client 2nd "refs/heads/B" $((64*3))
-pull_to_client 3rd "A" $((1*3))
+pull_to_client 3rd "refs/heads/A" $((1*3))
test_expect_success 'clone shallow' '
git clone --depth 2 "file://$(pwd)/." shallow
diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh
new file mode 100755
index 000000000..edea9f957
--- /dev/null
+++ b/t/t5527-fetch-odd-refs.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+test_description='test fetching of oddly-named refs'
+. ./test-lib.sh
+
+# afterwards we will have:
+# HEAD - two
+# refs/for/refs/heads/master - one
+# refs/heads/master - three
+test_expect_success 'setup repo with odd suffix ref' '
+ echo content >file &&
+ git add . &&
+ git commit -m one &&
+ git update-ref refs/for/refs/heads/master HEAD &&
+ echo content >>file &&
+ git commit -a -m two &&
+ echo content >>file &&
+ git commit -a -m three &&
+ git checkout HEAD^
+'
+
+test_expect_success 'suffix ref is ignored during fetch' '
+ git clone --bare file://"$PWD" suffix &&
+ echo three >expect &&
+ git --git-dir=suffix log -1 --format=%s refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh
index 64767d870..1eea64765 100755
--- a/t/t5540-http-push.sh
+++ b/t/t5540-http-push.sh
@@ -40,6 +40,22 @@ test_expect_success 'setup remote repository' '
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
'
+test_expect_success 'create password-protected repository' '
+ mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb" &&
+ cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+ "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git"
+'
+
+test_expect_success 'setup askpass helper' '
+ cat >askpass <<-\EOF &&
+ #!/bin/sh
+ echo user@host
+ EOF
+ chmod +x askpass &&
+ GIT_ASKPASS="$PWD/askpass" &&
+ export GIT_ASKPASS
+'
+
test_expect_success 'clone remote repository' '
cd "$ROOT_PATH" &&
git clone $HTTPD_URL/dumb/test_repo.git test_repo_clone
@@ -144,6 +160,24 @@ test_expect_success 'PUT and MOVE sends object to URLs with SHA-1 hash suffix' '
test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
"$ROOT_PATH"/test_repo_clone master
+test_expect_success 'push to password-protected repository (user in URL)' '
+ test_commit pw-user &&
+ git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD &&
+ git rev-parse --verify HEAD >expect &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
+ rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'push to password-protected repository (no user in URL)' '
+ test_commit pw-nouser &&
+ git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
+ git rev-parse --verify HEAD >expect &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
+ rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
+'
+
stop_httpd
test_done
diff --git a/t/t7106-reset-sequence.sh b/t/t7106-reset-sequence.sh
deleted file mode 100755
index 83f7ea59c..000000000
--- a/t/t7106-reset-sequence.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-test_description='Test interaction of reset --hard with sequencer
-
- + anotherpick: rewrites foo to d
- + picked: rewrites foo to c
- + unrelatedpick: rewrites unrelated to reallyunrelated
- + base: rewrites foo to b
- + initial: writes foo as a, unrelated as unrelated
-'
-
-. ./test-lib.sh
-
-pristine_detach () {
- git cherry-pick --quit &&
- git checkout -f "$1^0" &&
- git read-tree -u --reset HEAD &&
- git clean -d -f -f -q -x
-}
-
-test_expect_success setup '
- echo unrelated >unrelated &&
- git add unrelated &&
- test_commit initial foo a &&
- test_commit base foo b &&
- test_commit unrelatedpick unrelated reallyunrelated &&
- test_commit picked foo c &&
- test_commit anotherpick foo d &&
- git config advice.detachedhead false
-
-'
-
-test_expect_success 'reset --hard cleans up sequencer state, providing one-level undo' '
- pristine_detach initial &&
- test_must_fail git cherry-pick base..anotherpick &&
- test_path_is_dir .git/sequencer &&
- git reset --hard &&
- test_path_is_missing .git/sequencer &&
- test_path_is_dir .git/sequencer-old &&
- git reset --hard &&
- test_path_is_missing .git/sequencer-old
-'
-
-test_expect_success 'cherry-pick --abort does not leave sequencer-old dir' '
- pristine_detach initial &&
- test_must_fail git cherry-pick base..anotherpick &&
- git cherry-pick --abort &&
- test_path_is_missing .git/sequencer &&
- test_path_is_missing .git/sequencer-old
-'
-
-test_done
diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh
index 463254c72..83acf68bc 100755
--- a/t/t9301-fast-import-notes.sh
+++ b/t/t9301-fast-import-notes.sh
@@ -505,9 +505,63 @@ test_expect_success 'verify that non-notes are untouched by a fanout change' '
test_cmp expect_non-note3 actual
'
+
+# Change the notes for the three top commits
+test_tick
+cat >input <<INPUT_END
+commit refs/notes/many_notes
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+changing notes for the top three commits
+COMMIT
+from refs/notes/many_notes^0
+INPUT_END
+
+rm expect
+i=$num_commits
+j=0
+while test $j -lt 3
+do
+ cat >>input <<INPUT_END
+N inline refs/heads/many_commits~$j
+data <<EOF
+changed note for commit #$i
+EOF
+INPUT_END
+ cat >>expect <<EXPECT_END
+ commit #$i
+ changed note for commit #$i
+EXPECT_END
+ i=$(($i - 1))
+ j=$(($j + 1))
+done
+
+test_expect_success 'change a few existing notes' '
+
+ git fast-import <input &&
+ GIT_NOTES_REF=refs/notes/many_notes git log -n3 refs/heads/many_commits |
+ grep "^ " > actual &&
+ test_cmp expect actual
+
+'
+
+test_expect_success 'verify that changing notes respect existing fanout' '
+
+ # None of the entries in the top-level notes tree should be a full SHA1
+ git ls-tree --name-only refs/notes/many_notes |
+ while read path
+ do
+ if test $(expr length "$path") -ge 40
+ then
+ return 1
+ fi
+ done
+
+'
+
remaining_notes=10
test_tick
-cat >>input <<INPUT_END
+cat >input <<INPUT_END
commit refs/notes/many_notes
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
data <<COMMIT
@@ -516,12 +570,11 @@ COMMIT
from refs/notes/many_notes^0
INPUT_END
-i=$remaining_notes
-while test $i -lt $num_commits
+i=$(($num_commits - $remaining_notes))
+for sha1 in $(git rev-list -n $i refs/heads/many_commits)
do
- i=$(($i + 1))
cat >>input <<INPUT_END
-N 0000000000000000000000000000000000000000 :$i
+N 0000000000000000000000000000000000000000 $sha1
INPUT_END
done
diff --git a/transport.c b/transport.c
index 51814b5da..c2245d4f0 100644
--- a/transport.c
+++ b/transport.c
@@ -502,7 +502,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
struct ref *refs;
connect_setup(transport, for_push, 0);
- get_remote_heads(data->fd[0], &refs, 0, NULL,
+ get_remote_heads(data->fd[0], &refs,
for_push ? REF_NORMAL : 0, &data->extra_have);
data->got_remote_heads = 1;
@@ -537,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport,
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
- get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
+ get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
data->got_remote_heads = 1;
}
@@ -772,8 +772,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
struct ref *tmp_refs;
connect_setup(transport, 1, 0);
- get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
- NULL);
+ get_remote_heads(data->fd[0], &tmp_refs, REF_NORMAL, NULL);
data->got_remote_heads = 1;
}
diff --git a/tree-diff.c b/tree-diff.c
index b3cc2e475..7a51d091b 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -21,8 +21,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
sha1 = tree_entry_extract(t1, &path1, &mode1);
sha2 = tree_entry_extract(t2, &path2, &mode2);
- pathlen1 = tree_entry_len(path1, sha1);
- pathlen2 = tree_entry_len(path2, sha2);
+ pathlen1 = tree_entry_len(&t1->entry);
+ pathlen2 = tree_entry_len(&t2->entry);
cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
if (cmp < 0) {
show_entry(opt, "-", t1, base);
@@ -64,14 +64,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
static void show_tree(struct diff_options *opt, const char *prefix,
struct tree_desc *desc, struct strbuf *base)
{
- int match = 0;
+ enum interesting match = entry_not_interesting;
for (; desc->size; update_tree_entry(desc)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&desc->entry, base, 0,
&opt->pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
show_entry(opt, prefix, desc, base);
@@ -85,7 +85,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
unsigned mode;
const char *path;
const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
- int pathlen = tree_entry_len(path, sha1);
+ int pathlen = tree_entry_len(&desc->entry);
int old_baselen = base->len;
strbuf_add(base, path, pathlen);
@@ -114,12 +114,13 @@ static void show_entry(struct diff_options *opt, const char *prefix,
}
static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
- struct diff_options *opt, int *match)
+ struct diff_options *opt,
+ enum interesting *match)
{
while (t->size) {
*match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
if (*match) {
- if (*match < 0)
+ if (*match == all_entries_not_interesting)
t->size = 0;
break;
}
@@ -132,7 +133,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
{
struct strbuf base;
int baselen = strlen(base_str);
- int t1_match = 0, t2_match = 0;
+ enum interesting t1_match = entry_not_interesting;
+ enum interesting t2_match = entry_not_interesting;
/* Enable recursion indefinitely */
opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
diff --git a/tree-walk.c b/tree-walk.c
index 418107ec8..f82dba6a1 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -116,7 +116,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
{
- int len = tree_entry_len(n->path, n->sha1);
+ int len = tree_entry_len(n);
int pathlen = info->pathlen;
path[pathlen + len] = 0;
@@ -126,7 +126,7 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
break;
path[--pathlen] = '/';
n = &info->name;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
info = info->prev;
pathlen -= len;
}
@@ -253,7 +253,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
* The caller wants "first" from this tree, or nothing.
*/
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -271,7 +271,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
while (probe.size) {
entry_extract(&probe, a);
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -362,7 +362,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
e = entry + i;
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (!first) {
first = e->path;
first_len = len;
@@ -381,7 +381,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
/* Cull the ones that are not the earliest */
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (name_compare(e->path, len, first, first_len))
entry_clear(e);
}
@@ -434,8 +434,8 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
int entrylen, cmp;
sha1 = tree_entry_extract(t, &entry, mode);
+ entrylen = tree_entry_len(&t->entry);
update_tree_entry(t);
- entrylen = tree_entry_len(entry, sha1);
if (entrylen > namelen)
continue;
cmp = memcmp(name, entry, entrylen);
@@ -465,7 +465,6 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
int retval;
void *tree;
unsigned long size;
- struct tree_desc t;
unsigned char root[20];
tree = read_object_with_reference(tree_sha1, tree_type, &size, root);
@@ -478,8 +477,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
return 0;
}
- init_tree_desc(&t, tree, size);
- retval = find_tree_entry(&t, name, sha1, mode);
+ if (!size) {
+ retval = -1;
+ } else {
+ struct tree_desc t;
+ init_tree_desc(&t, tree, size);
+ retval = find_tree_entry(&t, name, sha1, mode);
+ }
free(tree);
return retval;
}
@@ -573,30 +577,26 @@ static int match_dir_prefix(const char *base,
*
* Pre-condition: either baselen == base_offset (i.e. empty path)
* or base[baselen-1] == '/' (i.e. with trailing slash).
- *
- * Return:
- * - 2 for "yes, and all subsequent entries will be"
- * - 1 for yes
- * - zero for no
- * - negative for "no, and no subsequent entries will be either"
*/
-int tree_entry_interesting(const struct name_entry *entry,
- struct strbuf *base, int base_offset,
- const struct pathspec *ps)
+enum interesting tree_entry_interesting(const struct name_entry *entry,
+ struct strbuf *base, int base_offset,
+ const struct pathspec *ps)
{
int i;
int pathlen, baselen = base->len - base_offset;
- int never_interesting = ps->has_wildcard ? 0 : -1;
+ int never_interesting = ps->has_wildcard ?
+ entry_not_interesting : all_entries_not_interesting;
if (!ps->nr) {
if (!ps->recursive || ps->max_depth == -1)
- return 2;
- return !!within_depth(base->buf + base_offset, baselen,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return all_entries_interesting;
+ return within_depth(base->buf + base_offset, baselen,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
- pathlen = tree_entry_len(entry->path, entry->sha1);
+ pathlen = tree_entry_len(entry);
for (i = ps->nr - 1; i >= 0; i--) {
const struct pathspec_item *item = ps->items+i;
@@ -610,12 +610,13 @@ int tree_entry_interesting(const struct name_entry *entry,
goto match_wildcards;
if (!ps->recursive || ps->max_depth == -1)
- return 2;
+ return all_entries_interesting;
- return !!within_depth(base_str + matchlen + 1,
- baselen - matchlen - 1,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return within_depth(base_str + matchlen + 1,
+ baselen - matchlen - 1,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
/* Either there must be no base, or the base must match. */
@@ -623,25 +624,25 @@ int tree_entry_interesting(const struct name_entry *entry,
if (match_entry(entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
- return 1;
+ return entry_interesting;
- if (ps->items[i].use_wildcard) {
+ if (item->use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0))
- return 1;
+ return entry_interesting;
/*
* Match all directories. We'll try to
* match files later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
continue;
}
match_wildcards:
- if (!ps->items[i].use_wildcard)
+ if (!item->use_wildcard)
continue;
/*
@@ -653,7 +654,7 @@ match_wildcards:
if (!fnmatch(match, base->buf + base_offset, 0)) {
strbuf_setlen(base, base_offset + baselen);
- return 1;
+ return entry_interesting;
}
strbuf_setlen(base, base_offset + baselen);
@@ -662,7 +663,7 @@ match_wildcards:
* later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
return never_interesting; /* No matches */
}
diff --git a/tree-walk.h b/tree-walk.h
index 0089581e1..2bf0db981 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -20,9 +20,9 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
return desc->entry.sha1;
}
-static inline int tree_entry_len(const char *name, const unsigned char *sha1)
+static inline int tree_entry_len(const struct name_entry *ne)
{
- return (const char *)sha1 - name - 1;
+ return (const char *)ne->sha1 - ne->path - 1;
}
void update_tree_entry(struct tree_desc *);
@@ -58,9 +58,19 @@ extern void setup_traverse_info(struct traverse_info *info, const char *base);
static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
{
- return info->pathlen + tree_entry_len(n->path, n->sha1);
+ return info->pathlen + tree_entry_len(n);
}
-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
+/* in general, positive means "kind of interesting" */
+enum interesting {
+ all_entries_not_interesting = -1, /* no, and no subsequent entries will be either */
+ entry_not_interesting = 0,
+ entry_interesting = 1,
+ all_entries_interesting = 2 /* yes, and all subsequent entries will be */
+};
+
+extern enum interesting tree_entry_interesting(const struct name_entry *,
+ struct strbuf *, int,
+ const struct pathspec *ps);
#endif
diff --git a/tree.c b/tree.c
index 698ecf7af..676e9f710 100644
--- a/tree.c
+++ b/tree.c
@@ -52,7 +52,8 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
struct tree_desc desc;
struct name_entry entry;
unsigned char sha1[20];
- int len, retval = 0, oldlen = base->len;
+ int len, oldlen = base->len;
+ enum interesting retval = entry_not_interesting;
if (parse_tree(tree))
return -1;
@@ -60,11 +61,11 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (retval != 2) {
+ if (retval != all_entries_interesting) {
retval = tree_entry_interesting(&entry, base, 0, pathspec);
- if (retval < 0)
+ if (retval == all_entries_not_interesting)
break;
- if (retval == 0)
+ if (retval == entry_not_interesting)
continue;
}
@@ -99,7 +100,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
else
continue;
- len = tree_entry_len(entry.path, entry.sha1);
+ len = tree_entry_len(&entry);
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
retval = read_tree_1(lookup_tree(sha1),
diff --git a/unpack-trees.c b/unpack-trees.c
index 8282f5e5f..7c9ecf665 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -446,7 +446,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo.prev = info;
newinfo.pathspec = info->pathspec;
newinfo.name = *p;
- newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1;
+ newinfo.pathlen += tree_entry_len(p) + 1;
newinfo.conflicts |= df_conflicts;
for (i = 0; i < n; i++, dirmask >>= 1) {
@@ -495,7 +495,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}
@@ -626,7 +626,7 @@ static int find_cache_pos(struct traverse_info *info,
struct unpack_trees_options *o = info->data;
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- int p_len = tree_entry_len(p->path, p->sha1);
+ int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
struct cache_entry *ce = index->cache[pos];
diff --git a/userdiff.c b/userdiff.c
index bf553ad91..7244aac74 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -115,7 +115,7 @@ PATTERNS("cpp",
/* Jump targets or access declarations */
"!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
/* C/++ functions/methods at top level */
- "^([A-Za-z_][A-Za-z_0-9]*([ \t]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
+ "^([A-Za-z_][A-Za-z_0-9]*([ \t*]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
/* compound type at top level */
"^((struct|class|enum)[^;]*)$",
/* -- */