summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/1.8.4.2.txt77
-rw-r--r--Documentation/config.txt11
-rw-r--r--Documentation/git-branch.txt6
-rw-r--r--Documentation/git-merge.txt6
-rw-r--r--Documentation/git-unpack-objects.txt2
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/gitignore.txt6
-rwxr-xr-xGIT-VERSION-GEN2
l---------RelNotes2
-rw-r--r--bisect.c2
-rw-r--r--branch.c3
-rw-r--r--builtin/checkout.c99
-rw-r--r--builtin/clone.c44
-rw-r--r--builtin/commit.c8
-rw-r--r--builtin/ls-files.c2
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/shortlog.c6
-rw-r--r--cache.h9
-rw-r--r--commit.h4
-rw-r--r--contrib/completion/git-prompt.sh2
-rw-r--r--contrib/subtree/Makefile7
-rw-r--r--dir.c52
-rw-r--r--dir.h3
-rw-r--r--environment.c9
-rw-r--r--fetch-pack.c53
-rwxr-xr-xgit-add--interactive.perl2
-rwxr-xr-xgit-cvsserver.perl2
-rw-r--r--git-rebase--interactive.sh35
-rw-r--r--graph.c4
-rw-r--r--http-backend.c6
-rw-r--r--http-push.c2
-rw-r--r--ident.c45
-rw-r--r--list-objects.c24
-rw-r--r--list-objects.h2
-rw-r--r--merge-recursive.c4
-rw-r--r--pretty.c2
-rw-r--r--revision.c59
-rw-r--r--sha1_file.c7
-rw-r--r--shallow.c79
-rwxr-xr-xt/t0001-init.sh4
-rwxr-xr-xt/t2010-checkout-ambiguous.sh6
-rwxr-xr-xt/t2024-checkout-dwim.sh27
-rwxr-xr-xt/t3010-ls-files-killed-modified.sh27
-rwxr-xr-xt/t3200-branch.sh38
-rwxr-xr-xt/t3404-rebase-interactive.sh89
-rwxr-xr-xt/t3409-rebase-preserve-merges.sh23
-rwxr-xr-xt/t4014-format-patch.sh10
-rwxr-xr-xt/t4201-shortlog.sh16
-rwxr-xr-xt/t4203-mailmap.sh11
-rwxr-xr-xt/t4212-log-corrupt.sh9
-rwxr-xr-xt/t4254-am-corrupt.sh36
-rwxr-xr-xt/t5500-fetch-pack.sh11
-rwxr-xr-xt/t5530-upload-pack-error.sh3
-rwxr-xr-xt/t5570-git-daemon.sh3
-rwxr-xr-xt/t5601-clone.sh2
-rwxr-xr-xt/t5701-clone-local.sh4
-rwxr-xr-xt/t5702-clone-options.sh10
-rwxr-xr-xt/t6000-rev-list-misc.sh8
-rw-r--r--t/test-lib.sh2
-rw-r--r--upload-pack.c153
61 files changed, 863 insertions, 324 deletions
diff --git a/Documentation/RelNotes/1.8.4.2.txt b/Documentation/RelNotes/1.8.4.2.txt
new file mode 100644
index 0000000000..9adccb1efb
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.2.txt
@@ -0,0 +1,77 @@
+Git v1.8.4.2 Release Notes
+========================
+
+Fixes since v1.8.4.1
+--------------------
+
+ * "git clone" gave some progress messages to the standard output, not
+ to the standard error, and did not allow suppressing them with the
+ "--no-progress" option.
+
+ * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+ from line, i.e. when <whom> is the same as the real author.
+
+ * "git shortlog" used to choke and die when there is a malformed
+ commit (e.g. missing authors); it now simply ignore such a commit
+ and keeps going.
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+ line option correctly.
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+ that made it impossible to base your local work on anything but a
+ local branch of the upstream repository you are tracking from.
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+ that may overlap the paths in the index to find killed files, but
+ shared code with the logic to find all the untracked files, which
+ made it unnecessarily inefficient.
+
+ * When there is no sufficient overlap between old and new history
+ during a "git fetch" into a shallow repository, objects that the
+ sending side knows the receiving end has were unnecessarily sent.
+
+ * When running "fetch -q", a long silence while the sender side
+ computes the set of objects to send can be mistaken by proxies as
+ dropped connection. The server side has been taught to send a
+ small empty messages to keep the connection alive.
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+ http-backend" should tell the client what methods are allowed with
+ the "Allow" header.
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+ executable files.
+
+ * The implementation of "add -i" has a crippling code to work around
+ ActiveState Perl limitation but it by mistake also triggered on Git
+ for Windows where MSYS perl is used.
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+ gitfile, but did not do the same when the default ".git" is a
+ gitfile.
+
+ * When an object is not found after checking the packfiles and then
+ loose object directory, read_sha1_file() re-checks the packfiles to
+ prevent racing with a concurrent repacker; teach the same logic to
+ has_sha1_file().
+
+ * "git commit --author=$name", when $name is not in the canonical
+ "A. U. Thor <au.thor@example.xz>" format, looks for a matching name
+ from existing history, but did not consult mailmap to grab the
+ preferred author name.
+
+ * The commit object names in the insn sheet that was prepared at the
+ beginning of "rebase -i" session can become ambiguous as the
+ rebasing progresses and the repository gains more commits. Make
+ sure the internal record is kept with full 40-hex object names.
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+ and as a side effect, left merge summary message in the log, but
+ when rebasing, there should not be a need for merge summary.
+
+ * "git rebase -i" forgot that the comment character can be
+ configurable while reading its insn sheet.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ec57a15ac5..6b35578711 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2216,6 +2216,17 @@ uploadpack.allowtipsha1inwant::
of a hidden ref (by default, such a request is rejected).
see also `uploadpack.hiderefs`.
+uploadpack.keepalive::
+ When `upload-pack` has started `pack-objects`, there may be a
+ quiet period while `pack-objects` prepares the pack. Normally
+ it would output progress information, but if `--quiet` was used
+ for the fetch, `pack-objects` will output nothing at all until
+ the pack data begins. Some clients and networks may consider
+ the server to be hung and give up. Setting this option instructs
+ `upload-pack` to send an empty keepalive packet every
+ `uploadpack.keepalive` seconds. Setting this option to 0
+ disables keepalive packets entirely. The default is 5 seconds.
+
url.<base>.insteadOf::
Any URL that starts with this value will be rewritten to
start, instead, with <base>. In cases where some site serves a
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index b7cb625b89..311b33674e 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -48,7 +48,8 @@ working tree to it; use "git checkout <newbranch>" to switch to the
new branch.
When a local branch is started off a remote-tracking branch, Git sets up the
-branch so that 'git pull' will appropriately merge from
+branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
+configuration entries) so that 'git pull' will appropriately merge from
the remote-tracking branch. This behavior may be changed via the global
`branch.autosetupmerge` configuration flag. That setting can be
overridden by using the `--track` and `--no-track` options, and
@@ -156,7 +157,8 @@ This option is only applicable in non-verbose mode.
-t::
--track::
- When creating a new branch, set up configuration to mark the
+ When creating a new branch, set up `branch.<name>.remote` and
+ `branch.<name>.merge` configuration entries to mark the
start-point branch as "upstream" from the new branch. This
configuration will tell git to show the relationship between the
two branches in `git status` and `git branch -v`. Furthermore,
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index a74c3713c6..439545926e 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
- [-s <strategy>] [-X <strategy-option>]
+ [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
[--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
'git merge' <msg> HEAD <commit>...
'git merge' --abort
@@ -65,6 +65,10 @@ OPTIONS
-------
include::merge-options.txt[]
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign the resulting merge commit.
+
-m <msg>::
Set the commit message to be used for the merge commit (in
case one is created).
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index ff23494e70..12cb108b85 100644
--- a/Documentation/git-unpack-objects.txt
+++ b/Documentation/git-unpack-objects.txt
@@ -9,7 +9,7 @@ git-unpack-objects - Unpack objects from a packed archive
SYNOPSIS
--------
[verse]
-'git unpack-objects' [-n] [-q] [-r] [--strict] <pack-file
+'git unpack-objects' [-n] [-q] [-r] [--strict] < <pack-file>
DESCRIPTION
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 5b83e0ab98..90c5f37ceb 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.8.4.1/git.html[documentation for release 1.8.4.1]
+* link:v1.8.4.2/git.html[documentation for release 1.8.4.2]
* release notes for
+ link:RelNotes/1.8.4.2.txt[1.8.4.2],
link:RelNotes/1.8.4.1.txt[1.8.4.1],
link:RelNotes/1.8.4.txt[1.8.4].
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 54e334e3af..f971960512 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -113,12 +113,12 @@ full pathname may have special meaning:
- A leading "`**`" followed by a slash means match in all
directories. For example, "`**/foo`" matches file or directory
- "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
+ "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
matches file or directory "`bar`" anywhere that is directly
under directory "`foo`".
- - A trailing "/**" matches everything inside. For example,
- "abc/**" matches all files inside directory "abc", relative
+ - A trailing "`/**`" matches everything inside. For example,
+ "`abc/**`" matches all files inside directory "`abc`", relative
to the location of the `.gitignore` file, with infinite depth.
- A slash followed by two consecutive asterisks then a slash
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index b4147d6db5..d801493b23 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.4.1
+DEF_VER=v1.8.4.2
LF='
'
diff --git a/RelNotes b/RelNotes
index d573a270aa..c3d6c6c277 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.4.1.txt \ No newline at end of file
+Documentation/RelNotes/1.8.4.2.txt \ No newline at end of file
diff --git a/bisect.c b/bisect.c
index 71c19581da..1e46a4f50e 100644
--- a/bisect.c
+++ b/bisect.c
@@ -624,7 +624,7 @@ static void bisect_common(struct rev_info *revs)
if (prepare_revision_walk(revs))
die("revision walk setup failed");
if (revs->tree_objects)
- mark_edges_uninteresting(revs->commits, revs, NULL);
+ mark_edges_uninteresting(revs, NULL);
}
static void exit_if_skipped_commits(struct commit_list *tried,
diff --git a/branch.c b/branch.c
index c5c6984cb5..2d15c19e3e 100644
--- a/branch.c
+++ b/branch.c
@@ -203,8 +203,7 @@ static int check_tracking_branch(struct remote *remote, void *cb_data)
struct refspec query;
memset(&query, 0, sizeof(struct refspec));
query.dst = tracking_branch;
- return !(remote_find_tracking(remote, &query) ||
- prefixcmp(query.src, "refs/heads/"));
+ return !remote_find_tracking(remote, &query);
}
static int validate_remote_tracking_branch(char *ref)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 7025938ae3..22cc7fcb59 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -880,7 +880,9 @@ static int parse_branchname_arg(int argc, const char **argv,
int argcount = 0;
unsigned char branch_rev[20];
const char *arg;
- int has_dash_dash;
+ int dash_dash_pos;
+ int has_dash_dash = 0;
+ int i;
/*
* case 1: git checkout <ref> -- [<paths>]
@@ -892,20 +894,30 @@ static int parse_branchname_arg(int argc, const char **argv,
*
* everything after the '--' must be paths.
*
- * case 3: git checkout <something> [<paths>]
+ * case 3: git checkout <something> [--]
*
- * With no paths, if <something> is a commit, that is to
- * switch to the branch or detach HEAD at it. As a special case,
- * if <something> is A...B (missing A or B means HEAD but you can
- * omit at most one side), and if there is a unique merge base
- * between A and B, A...B names that merge base.
+ * (a) If <something> is a commit, that is to
+ * switch to the branch or detach HEAD at it. As a special case,
+ * if <something> is A...B (missing A or B means HEAD but you can
+ * omit at most one side), and if there is a unique merge base
+ * between A and B, A...B names that merge base.
*
- * With no paths, if <something> is _not_ a commit, no -t nor -b
- * was given, and there is a tracking branch whose name is
- * <something> in one and only one remote, then this is a short-hand
- * to fork local <something> from that remote-tracking branch.
+ * (b) If <something> is _not_ a commit, either "--" is present
+ * or <something> is not a path, no -t nor -b was given, and
+ * and there is a tracking branch whose name is <something>
+ * in one and only one remote, then this is a short-hand to
+ * fork local <something> from that remote-tracking branch.
*
- * Otherwise <something> shall not be ambiguous.
+ * (c) Otherwise, if "--" is present, treat it like case (1).
+ *
+ * (d) Otherwise :
+ * - if it's a reference, treat it like case (1)
+ * - else if it's a path, treat it like case (2)
+ * - else: fail.
+ *
+ * case 4: git checkout <something> <paths>
+ *
+ * The first argument must not be ambiguous.
* - If it's *only* a reference, treat it like case (1).
* - If it's only a path, treat it like case (2).
* - else: fail.
@@ -914,28 +926,59 @@ static int parse_branchname_arg(int argc, const char **argv,
if (!argc)
return 0;
- if (!strcmp(argv[0], "--")) /* case (2) */
- return 1;
-
arg = argv[0];
- has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
+ dash_dash_pos = -1;
+ for (i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ dash_dash_pos = i;
+ break;
+ }
+ }
+ if (dash_dash_pos == 0)
+ return 1; /* case (2) */
+ else if (dash_dash_pos == 1)
+ has_dash_dash = 1; /* case (3) or (1) */
+ else if (dash_dash_pos >= 2)
+ die(_("only one reference expected, %d given."), dash_dash_pos);
if (!strcmp(arg, "-"))
arg = "@{-1}";
if (get_sha1_mb(arg, rev)) {
- if (has_dash_dash) /* case (1) */
- die(_("invalid reference: %s"), arg);
- if (dwim_new_local_branch_ok &&
- !check_filename(NULL, arg) &&
- argc == 1) {
+ /*
+ * Either case (3) or (4), with <something> not being
+ * a commit, or an attempt to use case (1) with an
+ * invalid ref.
+ *
+ * It's likely an error, but we need to find out if
+ * we should auto-create the branch, case (3).(b).
+ */
+ int recover_with_dwim = dwim_new_local_branch_ok;
+
+ if (check_filename(NULL, arg) && !has_dash_dash)
+ recover_with_dwim = 0;
+ /*
+ * Accept "git checkout foo" and "git checkout foo --"
+ * as candidates for dwim.
+ */
+ if (!(argc == 1 && !has_dash_dash) &&
+ !(argc == 2 && has_dash_dash))
+ recover_with_dwim = 0;
+
+ if (recover_with_dwim) {
const char *remote = unique_tracking_name(arg, rev);
- if (!remote)
- return argcount;
- *new_branch = arg;
- arg = remote;
- /* DWIMmed to create local branch */
- } else {
+ if (remote) {
+ *new_branch = arg;
+ arg = remote;
+ /* DWIMmed to create local branch, case (3).(b) */
+ } else {
+ recover_with_dwim = 0;
+ }
+ }
+
+ if (!recover_with_dwim) {
+ if (has_dash_dash)
+ die(_("invalid reference: %s"), arg);
return argcount;
}
}
@@ -965,7 +1008,7 @@ static int parse_branchname_arg(int argc, const char **argv,
if (!*source_tree) /* case (1): want a tree */
die(_("reference is not a tree: %s"), arg);
- if (!has_dash_dash) {/* case (3 -> 1) */
+ if (!has_dash_dash) {/* case (3).(d) -> (1) */
/*
* Do not complain the most common case
* git checkout branch
diff --git a/builtin/clone.c b/builtin/clone.c
index 21ad9f945c..552f3409e3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -380,7 +380,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
}
if (0 <= option_verbosity)
- printf(_("done.\n"));
+ fprintf(stderr, _("done.\n"));
}
static const char *junk_work_tree;
@@ -551,13 +551,13 @@ static void update_remote_refs(const struct ref *refs,
const struct ref *rm = mapped_refs;
if (check_connectivity) {
- if (0 <= option_verbosity)
- printf(_("Checking connectivity... "));
+ if (transport->progress)
+ fprintf(stderr, _("Checking connectivity... "));
if (check_everything_connected_with_transport(iterate_ref_map,
0, &rm, transport))
die(_("remote did not send all necessary objects"));
- if (0 <= option_verbosity)
- printf(_("done\n"));
+ if (transport->progress)
+ fprintf(stderr, _("done\n"));
}
if (refs) {
@@ -850,9 +850,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
@@ -885,27 +885,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
- if (!is_local) {
- if (!transport->get_refs_list || !transport->fetch)
- die(_("Don't know how to clone %s"), transport->url);
+ if (!transport->get_refs_list || (!is_local && !transport->fetch))
+ die(_("Don't know how to clone %s"), transport->url);
- transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+ transport_set_option(transport, TRANS_OPT_KEEP, "yes");
- if (option_depth)
- transport_set_option(transport, TRANS_OPT_DEPTH,
- option_depth);
- if (option_single_branch)
- transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
+ if (option_depth)
+ transport_set_option(transport, TRANS_OPT_DEPTH,
+ option_depth);
+ if (option_single_branch)
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- transport_set_verbosity(transport, option_verbosity, option_progress);
+ transport_set_verbosity(transport, option_verbosity, option_progress);
- if (option_upload_pack)
- transport_set_option(transport, TRANS_OPT_UPLOADPACK,
- option_upload_pack);
+ if (option_upload_pack)
+ transport_set_option(transport, TRANS_OPT_UPLOADPACK,
+ option_upload_pack);
- if (transport->smart_options && !option_depth)
- transport->smart_options->check_self_contained_and_connected = 1;
- }
+ if (transport->smart_options && !option_depth)
+ transport->smart_options->check_self_contained_and_connected = 1;
refs = transport_get_remote_refs(transport);
diff --git a/builtin/commit.c b/builtin/commit.c
index 10acc53f80..a48a7fe59c 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -30,6 +30,7 @@
#include "column.h"
#include "sequencer.h"
#include "notes-utils.h"
+#include "mailmap.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [options] [--] <pathspec>..."),
@@ -935,6 +936,7 @@ static const char *find_author_by_nickname(const char *name)
struct rev_info revs;
struct commit *commit;
struct strbuf buf = STRBUF_INIT;
+ struct string_list mailmap = STRING_LIST_INIT_NODUP;
const char *av[20];
int ac = 0;
@@ -945,13 +947,17 @@ static const char *find_author_by_nickname(const char *name)
av[++ac] = buf.buf;
av[++ac] = NULL;
setup_revisions(ac, av, &revs, NULL);
+ revs.mailmap = &mailmap;
+ read_mailmap(revs.mailmap, NULL);
+
prepare_revision_walk(&revs);
commit = get_revision(&revs);
if (commit) {
struct pretty_print_context ctx = {0};
ctx.date_mode = DATE_NORMAL;
strbuf_release(&buf);
- format_commit_message(commit, "%an <%ae>", &buf, &ctx);
+ format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+ clear_mailmap(&mailmap);
return strbuf_detach(&buf, NULL);
}
die(_("No existing author found with '%s'"), name);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 5cf3e31370..85004460bd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -219,6 +219,8 @@ static void show_files(struct dir_struct *dir)
/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
+ if (!show_others)
+ dir->flags |= DIR_COLLECT_KILLED_ONLY;
fill_directory(dir, pathspec);
if (show_others)
show_other_files(dir);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f069462cb0..dd117b379a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2378,7 +2378,7 @@ static void get_object_list(int ac, const char **av)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
+ mark_edges_uninteresting(&revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object, NULL);
if (keep_unreachable)
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index a5ec30d74e..4fc1616637 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -336,7 +336,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
+ mark_edges_uninteresting(&revs, show_edge);
if (bisect_list) {
int reaches = reaches, all = all;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 1434f8fee4..84ffbb798e 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -127,9 +127,11 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
author = buffer + 7;
buffer = eol;
}
- if (!author)
- die(_("Missing author: %s"),
+ if (!author) {
+ warning(_("Missing author: %s"),
sha1_to_hex(commit->object.sha1));
+ return;
+ }
if (log->user_format) {
struct pretty_print_context ctx = {0};
ctx.fmt = CMIT_FMT_USERFORMAT;
diff --git a/cache.h b/cache.h
index 85b544f38d..88d373dfe7 100644
--- a/cache.h
+++ b/cache.h
@@ -966,6 +966,15 @@ struct ident_split {
*/
extern int split_ident_line(struct ident_split *, const char *, int);
+/*
+ * Compare split idents for equality or strict ordering. Note that we
+ * compare only the ident part of the line, ignoring any timestamp.
+ *
+ * Because there are two fields, we must choose one as the primary key; we
+ * currently arbitrarily pick the email.
+ */
+extern int ident_cmp(const struct ident_split *, const struct ident_split *);
+
struct checkout {
const char *base_dir;
int base_dir_len;
diff --git a/commit.h b/commit.h
index f9504f70cc..c308674120 100644
--- a/commit.h
+++ b/commit.h
@@ -201,6 +201,10 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
extern void check_shallow_file_for_update(void);
extern void set_alternate_shallow_file(const char *path);
+extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
+extern void setup_alternate_shallow(struct lock_file *shallow_lock,
+ const char **alternate_shallow_file);
+extern char *setup_temporary_shallow(void);
int is_descendant_of(struct commit *, struct commit_list *);
int in_merge_bases(struct commit *, struct commit *);
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index d6c61b2bde..998722cf7f 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -110,7 +110,7 @@ __git_ps1_show_upstream ()
;;
svn-remote.*.url)
svn_remote[$((${#svn_remote[@]} + 1))]="$value"
- svn_url_pattern+="\\|$value"
+ svn_url_pattern="$svn_url_pattern\\|$value"
upstream=svn+git # default upstream is SVN if available, else git
;;
esac
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index 435b2dea29..4030a16898 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -21,13 +21,14 @@ GIT_SUBTREE := git-subtree
GIT_SUBTREE_DOC := git-subtree.1
GIT_SUBTREE_XML := git-subtree.xml
GIT_SUBTREE_TXT := git-subtree.txt
+GIT_SUBTREE_HTML := git-subtree.html
all: $(GIT_SUBTREE)
$(GIT_SUBTREE): $(GIT_SUBTREE_SH)
cp $< $@ && chmod +x $@
-doc: $(GIT_SUBTREE_DOC)
+doc: $(GIT_SUBTREE_DOC) $(GIT_SUBTREE_HTML)
install: $(GIT_SUBTREE)
$(INSTALL) -d -m 755 $(DESTDIR)$(libexecdir)
@@ -46,6 +47,10 @@ $(GIT_SUBTREE_XML): $(GIT_SUBTREE_TXT)
asciidoc -b docbook -d manpage -f $(ASCIIDOC_CONF) \
-agit_version=$(gitver) $^
+$(GIT_SUBTREE_HTML): $(GIT_SUBTREE_TXT)
+ asciidoc -b xhtml11 -d manpage -f $(ASCIIDOC_CONF) \
+ -agit_version=$(gitver) $^
+
test:
$(MAKE) -C t/ test
diff --git a/dir.c b/dir.c
index 910bfcde4e..1d63e98987 100644
--- a/dir.c
+++ b/dir.c
@@ -472,15 +472,14 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
unsigned long sz;
enum object_type type;
void *data;
- struct index_state *istate = &the_index;
len = strlen(path);
- pos = index_name_pos(istate, path, len);
+ pos = cache_name_pos(path, len);
if (pos < 0)
return NULL;
- if (!ce_skip_worktree(istate->cache[pos]))
+ if (!ce_skip_worktree(active_cache[pos]))
return NULL;
- data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+ data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
@@ -927,13 +926,13 @@ enum exist_status {
};
/*
- * Do not use the alphabetically stored index to look up
+ * Do not use the alphabetically sorted index to look up
* the directory name; instead, use the case insensitive
* name hash.
*/
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
{
- const struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);
+ const struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);
unsigned char endchar;
if (!ce)
@@ -1175,14 +1174,51 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
int dtype, struct dirent *de)
{
int exclude;
+ int has_path_in_index = !!cache_name_exists(path->buf, path->len, ignore_case);
+
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, path->buf, path->len);
/* Always exclude indexed files */
- if (dtype != DT_DIR &&
- cache_name_exists(path->buf, path->len, ignore_case))
+ if (dtype != DT_DIR && has_path_in_index)
return path_none;
+ /*
+ * When we are looking at a directory P in the working tree,
+ * there are three cases:
+ *
+ * (1) P exists in the index. Everything inside the directory P in
+ * the working tree needs to go when P is checked out from the
+ * index.
+ *
+ * (2) P does not exist in the index, but there is P/Q in the index.
+ * We know P will stay a directory when we check out the contents
+ * of the index, but we do not know yet if there is a directory
+ * P/Q in the working tree to be killed, so we need to recurse.
+ *
+ * (3) P does not exist in the index, and there is no P/Q in the index
+ * to require P to be a directory, either. Only in this case, we
+ * know that everything inside P will not be killed without
+ * recursing.
+ */
+ if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
+ (dtype == DT_DIR) &&
+ !has_path_in_index) {
+ /*
+ * NEEDSWORK: directory_exists_in_index_icase()
+ * assumes that one byte past the given path is
+ * readable and has '/', which needs to be fixed, but
+ * until then, work it around in the caller.
+ */
+ strbuf_addch(path, '/');
+ if (directory_exists_in_index(path->buf, path->len - 1) ==
+ index_nonexistent) {
+ strbuf_setlen(path, path->len - 1);
+ return path_none;
+ }
+ strbuf_setlen(path, path->len - 1);
+ }
+
exclude = is_excluded(dir, path->buf, &dtype);
/*
diff --git a/dir.h b/dir.h
index 3d6b80c933..4677b861f0 100644
--- a/dir.h
+++ b/dir.h
@@ -80,7 +80,8 @@ struct dir_struct {
DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
DIR_NO_GITLINKS = 1<<3,
DIR_COLLECT_IGNORED = 1<<4,
- DIR_SHOW_IGNORED_TOO = 1<<5
+ DIR_SHOW_IGNORED_TOO = 1<<5,
+ DIR_COLLECT_KILLED_ONLY = 1<<6
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
diff --git a/environment.c b/environment.c
index 5398c36dd4..378254c77a 100644
--- a/environment.c
+++ b/environment.c
@@ -123,14 +123,13 @@ static char *expand_namespace(const char *raw_namespace)
static void setup_git_env(void)
{
+ const char *gitfile;
+
git_dir = getenv(GIT_DIR_ENVIRONMENT);
- git_dir = git_dir ? xstrdup(git_dir) : NULL;
- if (!git_dir) {
- git_dir = read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
- git_dir = git_dir ? xstrdup(git_dir) : NULL;
- }
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ gitfile = read_gitfile(git_dir);
+ git_dir = xstrdup(gitfile ? gitfile : git_dir);
git_object_dir = getenv(DB_ENVIRONMENT);
if (!git_object_dir) {
git_object_dir = xmalloc(strlen(git_dir) + 9);
diff --git a/fetch-pack.c b/fetch-pack.c
index f5d99c1181..aff4f5abab 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -184,36 +184,6 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
}
}
-struct write_shallow_data {
- struct strbuf *out;
- int use_pack_protocol;
- int count;
-};
-
-static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
-{
- struct write_shallow_data *data = cb_data;
- const char *hex = sha1_to_hex(graft->sha1);
- data->count++;
- if (data->use_pack_protocol)
- packet_buf_write(data->out, "shallow %s", hex);
- else {
- strbuf_addstr(data->out, hex);
- strbuf_addch(data->out, '\n');
- }
- return 0;
-}
-
-static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
-{
- struct write_shallow_data data;
- data.out = out;
- data.use_pack_protocol = use_pack_protocol;
- data.count = 0;
- for_each_commit_graft(write_one_shallow, &data);
- return data.count;
-}
-
static enum ack_type get_ack(int fd, unsigned char *result_sha1)
{
int len;
@@ -795,27 +765,6 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
return strcmp(a->name, b->name);
}
-static void setup_alternate_shallow(void)
-{
- struct strbuf sb = STRBUF_INIT;
- int fd;
-
- check_shallow_file_for_update();
- fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
- LOCK_DIE_ON_ERROR);
- if (write_shallow_commits(&sb, 0)) {
- if (write_in_full(fd, sb.buf, sb.len) != sb.len)
- die_errno("failed to write to %s", shallow_lock.filename);
- alternate_shallow_file = shallow_lock.filename;
- } else
- /*
- * is_repository_shallow() sees empty string as "no
- * shallow file".
- */
- alternate_shallow_file = "";
- strbuf_release(&sb);
-}
-
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
@@ -896,7 +845,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->stateless_rpc)
packet_flush(fd[1]);
if (args->depth > 0)
- setup_alternate_shallow();
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 75a991f7ec..51563840f4 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -169,7 +169,7 @@ my %patch_modes = (
my %patch_mode_flavour = %{$patch_modes{stage}};
sub run_cmd_pipe {
- if ($^O eq 'MSWin32' || $^O eq 'msys') {
+ if ($^O eq 'MSWin32') {
my @invalid = grep {m/[":*]/} @_;
die "$^O does not support: @invalid\n" if @invalid;
my @args = map { m/ /o ? "\"$_\"": $_ } @_;
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index a0d796e570..67b1e7b463 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -4167,7 +4167,7 @@ sub convertToDbMode
# this half-converted form, but it isn't currently worth the
# backwards compatibility headaches.
- $mode=~/^\d\d(\d)\d{3}$/;
+ $mode=~/^\d{3}(\d)\d\d$/;
my $userBits=$1;
my $dbMode = "";
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 83d6d4676b..10bf318d0d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -352,8 +352,9 @@ pick_one_preserving_merges () {
msg_content="$(commit_message $sha1)"
# No point in merging the first parent, that's HEAD
new_parents=${new_parents# $first_parent}
+ merge_args="--no-log --no-ff"
if ! do_with_author output eval \
- 'git merge --no-ff $strategy_args -m "$msg_content" $new_parents'
+ 'git merge $merge_args $strategy_args -m "$msg_content" $new_parents'
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
die_with_patch $sha1 "Error redoing merge $sha1"
@@ -671,7 +672,7 @@ skip_unnecessary_picks () {
;;
esac
;;
- 3,#*|3,)
+ 3,"$comment_char"*|3,)
# copy comments
;;
*)
@@ -689,6 +690,32 @@ skip_unnecessary_picks () {
die "Could not skip unnecessary pick commands"
}
+transform_todo_ids () {
+ while read -r command rest
+ do
+ case "$command" in
+ "$comment_char"* | exec)
+ # Be careful for oddball commands like 'exec'
+ # that do not have a SHA-1 at the beginning of $rest.
+ ;;
+ *)
+ sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
+ rest="$sha1 ${rest#* }"
+ ;;
+ esac
+ printf '%s\n' "$command${rest:+ }$rest"
+ done <"$todo" >"$todo.new" &&
+ mv -f "$todo.new" "$todo"
+}
+
+expand_todo_ids() {
+ transform_todo_ids
+}
+
+collapse_todo_ids() {
+ transform_todo_ids --short=7
+}
+
# Rearrange the todo list that has both "pick sha1 msg" and
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
@@ -841,6 +868,7 @@ skip)
edit-todo)
git stripspace --strip-comments <"$todo" >"$todo".new
mv -f "$todo".new "$todo"
+ collapse_todo_ids
append_todo_help
git stripspace --comment-lines >>"$todo" <<\EOF
@@ -852,6 +880,7 @@ EOF
git_sequence_editor "$todo" ||
die "Could not execute editor"
+ expand_todo_ids
exit
;;
@@ -1008,6 +1037,8 @@ git_sequence_editor "$todo" ||
has_action "$todo" ||
die_abort "Nothing to do"
+expand_todo_ids
+
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
diff --git a/graph.c b/graph.c
index b24d04c406..640433166b 100644
--- a/graph.c
+++ b/graph.c
@@ -801,10 +801,10 @@ static int graph_draw_octopus_merge(struct git_graph *graph,
int num_dashes =
((graph->num_parents - dashless_commits) * 2) - 1;
for (i = 0; i < num_dashes; i++) {
- col_num = (i / 2) + dashless_commits;
+ col_num = (i / 2) + dashless_commits + graph->commit_index;
strbuf_write_column(sb, &graph->new_columns[col_num], '-');
}
- col_num = (i / 2) + dashless_commits;
+ col_num = (i / 2) + dashless_commits + graph->commit_index;
strbuf_write_column(sb, &graph->new_columns[col_num], '.');
return num_dashes + 1;
}
diff --git a/http-backend.c b/http-backend.c
index 0324417297..8c464bd805 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -594,9 +594,11 @@ int main(int argc, char **argv)
if (strcmp(method, c->method)) {
const char *proto = getenv("SERVER_PROTOCOL");
- if (proto && !strcmp(proto, "HTTP/1.1"))
+ if (proto && !strcmp(proto, "HTTP/1.1")) {
http_status(405, "Method Not Allowed");
- else
+ hdr_str("Allow", !strcmp(c->method, "GET") ?
+ "GET, HEAD" : c->method);
+ } else
http_status(400, "Bad Request");
hdr_nocache();
end_headers();
diff --git a/http-push.c b/http-push.c
index 6dad188b5f..cde6416d37 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1976,7 +1976,7 @@ int main(int argc, char **argv)
pushing = 0;
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, NULL);
+ mark_edges_uninteresting(&revs, NULL);
objects_to_send = get_delta(&revs, ref_lock);
finish_all_active_slots();
diff --git a/ident.c b/ident.c
index 1c123e685f..1d9b6e770d 100644
--- a/ident.c
+++ b/ident.c
@@ -233,7 +233,21 @@ int split_ident_line(struct ident_split *split, const char *line, int len)
if (!split->mail_end)
return status;
- for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
+ /*
+ * Look from the end-of-line to find the trailing ">" of the mail
+ * address, even though we should already know it as split->mail_end.
+ * This can help in cases of broken idents with an extra ">" somewhere
+ * in the email address. Note that we are assuming the timestamp will
+ * never have a ">" in it.
+ *
+ * Note that we will always find some ">" before going off the front of
+ * the string, because will always hit the split->mail_end closing
+ * bracket.
+ */
+ for (cp = line + len - 1; *cp != '>'; cp--)
+ ;
+
+ for (cp = cp + 1; cp < line + len && isspace(*cp); cp++)
;
if (line + len <= cp)
goto person_only;
@@ -402,3 +416,32 @@ int git_ident_config(const char *var, const char *value, void *data)
return 0;
}
+
+static int buf_cmp(const char *a_begin, const char *a_end,
+ const char *b_begin, const char *b_end)
+{
+ int a_len = a_end - a_begin;
+ int b_len = b_end - b_begin;
+ int min = a_len < b_len ? a_len : b_len;
+ int cmp;
+
+ cmp = memcmp(a_begin, b_begin, min);
+ if (cmp)
+ return cmp;
+
+ return a_len - b_len;
+}
+
+int ident_cmp(const struct ident_split *a,
+ const struct ident_split *b)
+{
+ int cmp;
+
+ cmp = buf_cmp(a->mail_begin, a->mail_end,
+ b->mail_begin, b->mail_end);
+ if (cmp)
+ return cmp;
+
+ return buf_cmp(a->name_begin, a->name_end,
+ b->name_begin, b->name_end);
+}
diff --git a/list-objects.c b/list-objects.c
index 3dd4a96019..05c8c5c616 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -145,19 +145,35 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
}
}
-void mark_edges_uninteresting(struct commit_list *list,
- struct rev_info *revs,
- show_edge_fn show_edge)
+void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
{
- for ( ; list; list = list->next) {
+ struct commit_list *list;
+ int i;
+
+ for (list = revs->commits; list; list = list->next) {
struct commit *commit = list->item;
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
+ if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
+ commit->object.flags |= SHOWN;
+ show_edge(commit);
+ }
continue;
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
+ for (i = 0; i < revs->cmdline.nr; i++) {
+ struct object *obj = revs->cmdline.rev[i].item;
+ struct commit *commit = (struct commit *)obj;
+ if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
+ continue;
+ mark_tree_uninteresting(commit->tree);
+ if (revs->edge_hint && !(obj->flags & SHOWN)) {
+ obj->flags |= SHOWN;
+ show_edge(commit);
+ }
+ }
}
static void add_pending_tree(struct rev_info *revs, struct tree *tree)
diff --git a/list-objects.h b/list-objects.h
index 3db7bb6fa3..136a1da5a6 100644
--- a/list-objects.h
+++ b/list-objects.h
@@ -6,6 +6,6 @@ typedef void (*show_object_fn)(struct object *, const struct name_path *, const
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
typedef void (*show_edge_fn)(struct commit *);
-void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
+void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
#endif
diff --git a/merge-recursive.c b/merge-recursive.c
index f95933b0aa..fc2f00176c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -2069,8 +2069,8 @@ int parse_merge_opt(struct merge_options *o, const char *s)
o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
else if (!strcmp(s, "histogram"))
o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
- else if (!strcmp(s, "diff-algorithm=")) {
- long value = parse_algorithm_value(s+15);
+ else if (!prefixcmp(s, "diff-algorithm=")) {
+ long value = parse_algorithm_value(s + strlen("diff-algorithm="));
if (value < 0)
return -1;
/* clear out previous settings */
diff --git a/pretty.c b/pretty.c
index 74563c92b4..b4e32b74d3 100644
--- a/pretty.c
+++ b/pretty.c
@@ -432,7 +432,7 @@ void pp_user_info(struct pretty_print_context *pp,
map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
if (pp->fmt == CMIT_FMT_EMAIL) {
- if (pp->from_ident) {
+ if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "From: ");
diff --git a/revision.c b/revision.c
index ac20d1aaed..f82b833fbc 100644
--- a/revision.c
+++ b/revision.c
@@ -1420,26 +1420,40 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
}
if (!get_sha1_committish(this, from_sha1) &&
!get_sha1_committish(next, sha1)) {
- struct commit *a, *b;
- struct commit_list *exclude;
-
- a = lookup_commit_reference(from_sha1);
- b = lookup_commit_reference(sha1);
- if (!a || !b) {
- if (revs->ignore_missing)
- return 0;
- die(symmetric ?
- "Invalid symmetric difference expression %s...%s" :
- "Invalid revision range %s..%s",
- arg, next);
- }
+ struct object *a_obj, *b_obj;
if (!cant_be_filename) {
*dotdot = '.';
verify_non_filename(revs->prefix, arg);
}
- if (symmetric) {
+ a_obj = parse_object(from_sha1);
+ b_obj = parse_object(sha1);
+ if (!a_obj || !b_obj) {
+ missing:
+ if (revs->ignore_missing)
+ return 0;
+ die(symmetric
+ ? "Invalid symmetric difference expression %s"
+ : "Invalid revision range %s", arg);
+ }
+
+ if (!symmetric) {
+ /* just A..B */
+ a_flags = flags_exclude;
+ } else {
+ /* A...B -- find merge bases between the two */
+ struct commit *a, *b;
+ struct commit_list *exclude;
+
+ a = (a_obj->type == OBJ_COMMIT
+ ? (struct commit *)a_obj
+ : lookup_commit_reference(a_obj->sha1));
+ b = (b_obj->type == OBJ_COMMIT
+ ? (struct commit *)b_obj
+ : lookup_commit_reference(b_obj->sha1));
+ if (!a || !b)
+ goto missing;
exclude = get_merge_bases(a, b, 1);
add_rev_cmdline_list(revs, exclude,
REV_CMD_MERGE_BASE,
@@ -1447,17 +1461,18 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
add_pending_commit_list(revs, exclude,
flags_exclude);
free_commit_list(exclude);
+
a_flags = flags | SYMMETRIC_LEFT;
- } else
- a_flags = flags_exclude;
- a->object.flags |= a_flags;
- b->object.flags |= flags;
- add_rev_cmdline(revs, &a->object, this,
+ }
+
+ a_obj->flags |= a_flags;
+ b_obj->flags |= flags;
+ add_rev_cmdline(revs, a_obj, this,
REV_CMD_LEFT, a_flags);
- add_rev_cmdline(revs, &b->object, next,
+ add_rev_cmdline(revs, b_obj, next,
REV_CMD_RIGHT, flags);
- add_pending_object(revs, &a->object, this);
- add_pending_object(revs, &b->object, next);
+ add_pending_object(revs, a_obj, this);
+ add_pending_object(revs, b_obj, next);
return 0;
}
*dotdot = '.';
diff --git a/sha1_file.c b/sha1_file.c
index 8e27db1bd2..613839db54 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2444,7 +2444,6 @@ static int sha1_loose_object_info(const unsigned char *sha1,
return 0;
}
-/* returns enum object_type or negative */
int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
{
struct cached_object *co;
@@ -2493,6 +2492,7 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
return 0;
}
+/* returns enum object_type or negative */
int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
{
enum object_type type;
@@ -2925,7 +2925,10 @@ int has_sha1_file(const unsigned char *sha1)
if (find_pack_entry(sha1, &e))
return 1;
- return has_loose_object(sha1);
+ if (has_loose_object(sha1))
+ return 1;
+ reprepare_packed_git();
+ return find_pack_entry(sha1, &e);
}
static void check_tree(const void *buf, size_t size)
diff --git a/shallow.c b/shallow.c
index 8a9c96d019..cdf37d694d 100644
--- a/shallow.c
+++ b/shallow.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "commit.h"
#include "tag.h"
+#include "pkt-line.h"
static int is_shallow = -1;
static struct stat shallow_stat;
@@ -141,3 +142,81 @@ void check_shallow_file_for_update(void)
)
die("shallow file was changed during fetch");
}
+
+struct write_shallow_data {
+ struct strbuf *out;
+ int use_pack_protocol;
+ int count;
+};
+
+static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
+{
+ struct write_shallow_data *data = cb_data;
+ const char *hex = sha1_to_hex(graft->sha1);
+ if (graft->nr_parent != -1)
+ return 0;
+ data->count++;
+ if (data->use_pack_protocol)
+ packet_buf_write(data->out, "shallow %s", hex);
+ else {
+ strbuf_addstr(data->out, hex);
+ strbuf_addch(data->out, '\n');
+ }
+ return 0;
+}
+
+int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
+{
+ struct write_shallow_data data;
+ data.out = out;
+ data.use_pack_protocol = use_pack_protocol;
+ data.count = 0;
+ for_each_commit_graft(write_one_shallow, &data);
+ return data.count;
+}
+
+char *setup_temporary_shallow(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int fd;
+
+ if (write_shallow_commits(&sb, 0)) {
+ struct strbuf path = STRBUF_INIT;
+ strbuf_addstr(&path, git_path("shallow_XXXXXX"));
+ fd = xmkstemp(path.buf);
+ if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+ die_errno("failed to write to %s",
+ path.buf);
+ close(fd);
+ strbuf_release(&sb);
+ return strbuf_detach(&path, NULL);
+ }
+ /*
+ * is_repository_shallow() sees empty string as "no shallow
+ * file".
+ */
+ return xstrdup("");
+}
+
+void setup_alternate_shallow(struct lock_file *shallow_lock,
+ const char **alternate_shallow_file)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int fd;
+
+ check_shallow_file_for_update();
+ fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
+ LOCK_DIE_ON_ERROR);
+ if (write_shallow_commits(&sb, 0)) {
+ if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+ die_errno("failed to write to %s",
+ shallow_lock->filename);
+ *alternate_shallow_file = shallow_lock->filename;
+ } else
+ /*
+ * is_repository_shallow() sees empty string as "no
+ * shallow file".
+ */
+ *alternate_shallow_file = "";
+ strbuf_release(&sb);
+}
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..9fb582b192 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -379,6 +379,10 @@ test_expect_success 'init with separate gitdir' '
test -d realgitdir/refs
'
+test_expect_success 're-init on .git file' '
+ ( cd newdir && git init )
+'
+
test_expect_success 're-init to update git link' '
(
cd newdir &&
diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh
index 7cc0a3582e..87bdf9c96b 100755
--- a/t/t2010-checkout-ambiguous.sh
+++ b/t/t2010-checkout-ambiguous.sh
@@ -47,4 +47,10 @@ test_expect_success 'disambiguate checking out from a tree-ish' '
git diff --exit-code --quiet
'
+test_expect_success 'accurate error message with more than one ref' '
+ test_must_fail git checkout HEAD master -- 2>actual &&
+ grep 2 actual &&
+ test_i18ngrep "one reference expected, 2 given" actual
+'
+
test_done
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index dee55e428f..6ecb559465 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -104,7 +104,7 @@ test_expect_success 'setup more remotes with unconventional refspecs' '
cd repo_c &&
test_commit c_master &&
git checkout -b bar &&
- test_commit c_bar
+ test_commit c_bar &&
git checkout -b spam &&
test_commit c_spam
) &&
@@ -113,9 +113,9 @@ test_expect_success 'setup more remotes with unconventional refspecs' '
cd repo_d &&
test_commit d_master &&
git checkout -b baz &&
- test_commit f_baz
+ test_commit d_baz &&
git checkout -b eggs &&
- test_commit c_eggs
+ test_commit d_eggs
) &&
git remote add repo_c repo_c &&
git config remote.repo_c.fetch \
@@ -164,4 +164,25 @@ test_expect_success 'checkout of branch from a single remote succeeds #4' '
test_branch_upstream eggs repo_d eggs
'
+test_expect_success 'checkout of branch with a file having the same name fails' '
+ git checkout -B master &&
+ test_might_fail git branch -D spam &&
+
+ >spam &&
+ test_must_fail git checkout spam &&
+ test_must_fail git rev-parse --verify refs/heads/spam &&
+ test_branch master
+'
+
+test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' '
+ git checkout -B master &&
+ test_might_fail git branch -D spam &&
+
+ >spam &&
+ git checkout spam -- &&
+ test_branch spam &&
+ test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
+ test_branch_upstream spam repo_c spam
+'
+
test_done
diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh
index f611d799b6..6d3b828a95 100755
--- a/t/t3010-ls-files-killed-modified.sh
+++ b/t/t3010-ls-files-killed-modified.sh
@@ -11,6 +11,7 @@ This test prepares the following in the cache:
path1 - a symlink
path2/file2 - a file in a directory
path3/file3 - a file in a directory
+ pathx/ju - a file in a directory
submod1/ - a submodule
submod2/ - another submodule
@@ -23,6 +24,7 @@ and the following on the filesystem:
path4 - a file
path5 - a symlink
path6/file6 - a file in a directory
+ pathx/ju/nk - a file in a directory to be killed
submod1/ - a submodule (modified from the cache)
submod2/ - a submodule (matches the cache)
@@ -44,14 +46,15 @@ modified without reporting path9 and path10. submod1 is also modified.
test_expect_success 'git update-index --add to add various paths.' '
date >path0 &&
test_ln_s_add xyzzy path1 &&
- mkdir path2 path3 &&
+ mkdir path2 path3 pathx &&
date >path2/file2 &&
date >path3/file3 &&
+ >pathx/ju &&
: >path7 &&
date >path8 &&
: >path9 &&
date >path10 &&
- git update-index --add -- path0 path?/file? path7 path8 path9 path10 &&
+ git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 &&
for i in 1 2
do
git init submod$i &&
@@ -77,7 +80,7 @@ test_expect_success 'git ls-files -k to show killed files.' '
date >path3 &&
date >path5
fi &&
- mkdir path0 path1 path6 &&
+ mkdir -p path0 path1 path6 pathx/ju &&
date >path0/file0 &&
date >path1/file1 &&
date >path6/file6 &&
@@ -85,16 +88,23 @@ test_expect_success 'git ls-files -k to show killed files.' '
: >path8 &&
: >path9 &&
touch path10 &&
- git ls-files -k >.output
-'
-
-test_expect_success 'validate git ls-files -k output.' '
- cat >.expected <<-\EOF &&
+ >pathx/ju/nk &&
+ cat >.expected <<-\EOF
path0/file0
path1/file1
path2
path3
+ pathx/ju/nk
EOF
+'
+
+test_expect_success 'git ls-files -k output (w/o icase)' '
+ git ls-files -k >.output
+ test_cmp .expected .output
+'
+
+test_expect_success 'git ls-files -k output (w/ icase)' '
+ git -c core.ignorecase=true ls-files -k >.output
test_cmp .expected .output
'
@@ -110,6 +120,7 @@ test_expect_success 'validate git ls-files -m output.' '
path3/file3
path7
path8
+ pathx/ju
submod1
EOF
test_cmp .expected .output
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 44ec6a45f4..55c9ab0b6a 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -319,8 +319,9 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '
test_expect_success 'tracking setup fails on non-matching refspec' '
git config remote.local.url . &&
- git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
+ git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
(git show-ref -q refs/remotes/local/master || git fetch local) &&
+ git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
test_must_fail git branch --track my5 local/master &&
test_must_fail git config branch.my5.remote &&
test_must_fail git config branch.my5.merge
@@ -870,4 +871,39 @@ test_expect_success '--merged catches invalid object names' '
test_must_fail git branch --merged 0000000000000000000000000000000000000000
'
+test_expect_success 'tracking with unexpected .fetch refspec' '
+ rm -rf a b c d &&
+ git init a &&
+ (
+ cd a &&
+ test_commit a
+ ) &&
+ git init b &&
+ (
+ cd b &&
+ test_commit b
+ ) &&
+ git init c &&
+ (
+ cd c &&
+ test_commit c &&
+ git remote add a ../a &&
+ git remote add b ../b &&
+ git fetch --all
+ ) &&
+ git init d &&
+ (
+ cd d &&
+ git remote add c ../c &&
+ git config remote.c.fetch "+refs/remotes/*:refs/remotes/*" &&
+ git fetch c &&
+ git branch --track local/a/master remotes/a/master &&
+ test "$(git config branch.local/a/master.remote)" = "c" &&
+ test "$(git config branch.local/a/master.merge)" = "refs/remotes/a/master" &&
+ git rev-parse --verify a >expect &&
+ git rev-parse --verify local/a/master >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 4dbeddb0de..50e22b1cad 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -29,8 +29,6 @@ Initial setup:
. "$TEST_DIRECTORY"/lib-rebase.sh
-set_fake_editor
-
# WARNING: Modifications to the initial repository can change the SHA ID used
# in the expect2 file for the 'stop on conflicting pick' test.
@@ -72,6 +70,7 @@ export SHELL
test_expect_success 'rebase -i with the exec command' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-one
2 exec_>touch-two exec_false exec_>touch-three
3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
@@ -93,6 +92,7 @@ test_expect_success 'rebase -i with the exec command' '
test_expect_success 'rebase -i with the exec command runs from tree root' '
git checkout master &&
mkdir subdir && (cd subdir &&
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-subdir" \
git rebase -i HEAD^
) &&
@@ -103,6 +103,7 @@ test_expect_success 'rebase -i with the exec command runs from tree root' '
test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="exec_echo_foo_>file1 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^
@@ -116,6 +117,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
git checkout master &&
test_when_finished "git rebase --abort" &&
(
+ set_fake_editor &&
FAKE_LINES="exec_this-command-does-not-exist 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^ >actual 2>&1
@@ -125,6 +127,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
test_expect_success 'no changes are a nop' '
git checkout branch2 &&
+ set_fake_editor &&
git rebase -i F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse HEAD)
@@ -134,6 +137,7 @@ test_expect_success 'test the [branch] option' '
git checkout -b dead-end &&
git rm file6 &&
git commit -m "stop here" &&
+ set_fake_editor &&
git rebase -i F branch2 &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse branch2) &&
@@ -142,6 +146,7 @@ test_expect_success 'test the [branch] option' '
test_expect_success 'test --onto <branch>' '
git checkout -b test-onto branch2 &&
+ set_fake_editor &&
git rebase -i --onto branch1 F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
@@ -151,6 +156,7 @@ test_expect_success 'test --onto <branch>' '
test_expect_success 'rebase on top of a non-conflicting commit' '
git checkout branch1 &&
git tag original-branch1 &&
+ set_fake_editor &&
git rebase -i branch2 &&
test file6 = $(git diff --name-only original-branch1) &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
@@ -163,6 +169,7 @@ test_expect_success 'reflog for the branch shows state before rebase' '
'
test_expect_success 'exchange two commits' '
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -188,6 +195,7 @@ EOF
test_expect_success 'stop on conflicting pick' '
git tag new-branch1 &&
+ set_fake_editor &&
test_must_fail git rebase -i master &&
test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
test_cmp expect .git/rebase-merge/patch &&
@@ -208,6 +216,7 @@ test_expect_success 'abort' '
test_expect_success 'abort with error when new base cannot be checked out' '
git rm --cached file1 &&
git commit -m "remove file in base" &&
+ set_fake_editor &&
test_must_fail git rebase -i master > output 2>&1 &&
grep "The following untracked working tree files would be overwritten by checkout:" \
output &&
@@ -222,6 +231,7 @@ test_expect_success 'retain authorship' '
test_tick &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
git tag twerp &&
+ set_fake_editor &&
git rebase -i --onto master HEAD^ &&
git show HEAD | grep "^Author: Twerp Snog"
'
@@ -232,6 +242,7 @@ test_expect_success 'squash' '
test_tick &&
GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
echo "******************************" &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
git rebase -i --onto master HEAD~2 &&
test B = $(cat file7) &&
@@ -244,6 +255,7 @@ test_expect_success 'retain authorship when squashing' '
test_expect_success '-p handles "no changes" gracefully' '
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i -p HEAD^ &&
git update-index --refresh &&
git diff-files --quiet &&
@@ -253,6 +265,7 @@ test_expect_success '-p handles "no changes" gracefully' '
test_expect_failure 'exchange two commits with -p' '
git checkout H &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -287,6 +300,7 @@ test_expect_success 'preserve merges with -p' '
git commit -m M file1 &&
git checkout -b to-be-rebased &&
test_tick &&
+ set_fake_editor &&
git rebase -i -p --onto branch1 master &&
git update-index --refresh &&
git diff-files --quiet &&
@@ -301,6 +315,7 @@ test_expect_success 'preserve merges with -p' '
'
test_expect_success 'edit ancestor with -p' '
+ set_fake_editor &&
FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
echo 2 > unrelated-file &&
test_tick &&
@@ -314,6 +329,7 @@ test_expect_success 'edit ancestor with -p' '
test_expect_success '--continue tries to commit' '
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
@@ -325,6 +341,7 @@ test_expect_success '--continue tries to commit' '
test_expect_success 'verbose flag is heeded, even after --continue' '
git reset --hard master@{1} &&
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
@@ -334,6 +351,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
test_expect_success 'multi-squash only fires up editor once' '
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -344,6 +362,7 @@ test_expect_success 'multi-squash only fires up editor once' '
test_expect_success 'multi-fixup does not fire up editor' '
git checkout -b multi-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
@@ -355,6 +374,7 @@ test_expect_success 'multi-fixup does not fire up editor' '
test_expect_success 'commit message used after conflict' '
git checkout -b conflict-fixup conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 fixup 4" &&
export FAKE_LINES &&
@@ -373,6 +393,7 @@ test_expect_success 'commit message used after conflict' '
test_expect_success 'commit message retained after conflict' '
git checkout -b conflict-squash conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 squash 4" &&
export FAKE_LINES &&
@@ -399,6 +420,7 @@ EOF
test_expect_success 'squash and fixup generate correct log messages' '
git checkout -b squash-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -411,6 +433,7 @@ test_expect_success 'squash and fixup generate correct log messages' '
test_expect_success 'squash ignores comments' '
git checkout -b skip-comments E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -423,6 +446,7 @@ test_expect_success 'squash ignores comments' '
test_expect_success 'squash ignores blank lines' '
git checkout -b skip-blank-lines E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -435,6 +459,7 @@ test_expect_success 'squash ignores blank lines' '
test_expect_success 'squash works as expected' '
git checkout -b squash-works no-conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
git rebase -i HEAD~3 &&
test $one = $(git rev-parse HEAD~2)
@@ -443,6 +468,7 @@ test_expect_success 'squash works as expected' '
test_expect_success 'interrupted squash works as expected' '
git checkout -b interrupted-squash conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="1 squash 3 2" &&
export FAKE_LINES &&
@@ -460,6 +486,7 @@ test_expect_success 'interrupted squash works as expected' '
test_expect_success 'interrupted squash works as expected (case 2)' '
git checkout -b interrupted-squash2 conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="3 squash 1 2" &&
export FAKE_LINES &&
@@ -484,6 +511,7 @@ test_expect_success '--continue tries to commit, even for "edit"' '
git commit -m "unrelated change" &&
parent=$(git rev-parse HEAD^) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo edited > file7 &&
git add file7 &&
@@ -496,6 +524,7 @@ test_expect_success '--continue tries to commit, even for "edit"' '
test_expect_success 'aborted --continue does not squash commits after "edit"' '
old=$(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
@@ -510,6 +539,7 @@ test_expect_success 'aborted --continue does not squash commits after "edit"' '
test_expect_success 'auto-amend only edited commits after "edit"' '
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
@@ -528,6 +558,7 @@ test_expect_success 'auto-amend only edited commits after "edit"' '
test_expect_success 'clean error after failed "exec"' '
test_tick &&
test_when_finished "git rebase --abort || :" &&
+ set_fake_editor &&
(
FAKE_LINES="1 exec_false" &&
export FAKE_LINES &&
@@ -543,6 +574,7 @@ test_expect_success 'rebase a detached HEAD' '
grandparent=$(git rev-parse HEAD~2) &&
git checkout $(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test $grandparent = $(git rev-parse HEAD~2)
'
@@ -559,6 +591,7 @@ test_expect_success 'rebase a commit violating pre-commit' '
test_must_fail git commit -m doesnt-verify file1 &&
git commit -m doesnt-verify --no-verify file1 &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES=2 git rebase -i HEAD~2
'
@@ -580,6 +613,7 @@ test_expect_success 'rebase with a file named HEAD in worktree' '
git commit -m "Add body"
) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
test "$(git show -s --pretty=format:%an)" = "Squashed Away"
@@ -591,6 +625,7 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' '
GIT_EDITOR=: git commit --amend \
--author="Somebody else <somebody@else.com>" &&
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
+ set_fake_editor &&
git rebase -i branch3 &&
test $(git rev-parse branch3) = $(git rev-parse branch4)
@@ -615,10 +650,12 @@ test_expect_success 'submodule rebase setup' '
git commit -a -m "submodule second"
) &&
test_tick &&
+ set_fake_editor &&
git commit -a -m "Three changes submodule"
'
test_expect_success 'submodule rebase -i' '
+ set_fake_editor &&
FAKE_LINES="1 squash 2 3" git rebase -i A
'
@@ -636,6 +673,7 @@ test_expect_success 'submodule conflict setup' '
'
test_expect_success 'rebase -i continue with only submodule staged' '
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git add sub &&
git rebase --continue &&
@@ -645,6 +683,7 @@ test_expect_success 'rebase -i continue with only submodule staged' '
test_expect_success 'rebase -i continue with unstaged submodule' '
git checkout submodule-topic &&
git reset --hard &&
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git reset &&
git rebase --continue &&
@@ -657,6 +696,7 @@ test_expect_success 'avoid unnecessary reset' '
test-chmtime =123456789 file3 &&
git update-index --refresh &&
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i HEAD~4 &&
test $HEAD = $(git rev-parse HEAD) &&
MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
@@ -665,6 +705,7 @@ test_expect_success 'avoid unnecessary reset' '
test_expect_success 'reword' '
git checkout -b reword-branch master &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A &&
git show HEAD | grep "E changed" &&
test $(git rev-parse master) != $(git rev-parse HEAD) &&
@@ -684,6 +725,7 @@ test_expect_success 'rebase -i can copy notes' '
test_commit n2 &&
test_commit n3 &&
git notes add -m"a note" n3 &&
+ set_fake_editor &&
git rebase -i --onto n1 n2 &&
test "a note" = "$(git notes show HEAD)"
'
@@ -697,6 +739,7 @@ EOF
test_expect_success 'rebase -i can copy notes over a fixup' '
git reset --hard n3 &&
git notes add -m"an earlier note" n2 &&
+ set_fake_editor &&
GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
git notes show > output &&
test_cmp expect output
@@ -706,6 +749,7 @@ test_expect_success 'rebase while detaching HEAD' '
git symbolic-ref HEAD &&
grandparent=$(git rev-parse HEAD~2) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
test $grandparent = $(git rev-parse HEAD~2) &&
test_must_fail git symbolic-ref HEAD
@@ -715,6 +759,7 @@ test_tick # Ensure that the rebased commits get a different timestamp.
test_expect_success 'always cherry-pick with --no-ff' '
git checkout no-ff-branch &&
git tag original-no-ff-branch &&
+ set_fake_editor &&
git rebase -i --no-ff A &&
touch empty &&
for p in 0 1 2
@@ -747,6 +792,7 @@ test_expect_success 'set up commits with funny messages' '
test_expect_success 'rebase-i history with funny messages' '
git rev-list A..funny >expect &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 4" git rebase -i A &&
git rev-list A.. >actual &&
test_cmp expect actual
@@ -763,6 +809,7 @@ test_expect_success 'prepare for rebase -i --exec' '
test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -776,6 +823,7 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' '
test_expect_success 'running "git rebase --exec git show HEAD -i"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -789,6 +837,7 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' '
test_expect_success 'running "git rebase -ix git show HEAD"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -802,6 +851,7 @@ test_expect_success 'running "git rebase -ix git show HEAD"' '
test_expect_success 'rebase -ix with several <CMD>' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
@@ -815,6 +865,7 @@ test_expect_success 'rebase -ix with several <CMD>' '
test_expect_success 'rebase -ix with several instances of --exec' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
@@ -836,6 +887,7 @@ test_expect_success 'rebase -ix with --autosquash' '
echo bis >bis.txt &&
git add bis.txt &&
git commit -m "fixup! two_exec" &&
+ set_fake_editor &&
(
git checkout -b autosquash_actual &&
git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
@@ -854,6 +906,7 @@ test_expect_success 'rebase -ix with --autosquash' '
test_expect_success 'rebase --exec without -i shows error message' '
git reset --hard execute &&
+ set_fake_editor &&
test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
echo "The --exec option must be used with the --interactive option" >expected &&
test_i18ncmp expected actual
@@ -862,6 +915,7 @@ test_expect_success 'rebase --exec without -i shows error message' '
test_expect_success 'rebase -i --exec without <CMD>' '
git reset --hard execute &&
+ set_fake_editor &&
test_must_fail git rebase -i --exec 2>tmp &&
sed -e "1d" tmp >actual &&
test_must_fail git rebase -h >expected &&
@@ -871,6 +925,7 @@ test_expect_success 'rebase -i --exec without <CMD>' '
test_expect_success 'rebase -i --root re-order and drop commits' '
git checkout E &&
+ set_fake_editor &&
FAKE_LINES="3 1 2 5" git rebase -i --root &&
test E = $(git cat-file commit HEAD | sed -ne \$p) &&
test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
@@ -884,6 +939,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
echo B >file7 &&
git add file7 &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+ set_fake_editor &&
FAKE_LINES="2" git rebase -i --root &&
git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
git cat-file commit HEAD | grep -q "^different author$"
@@ -892,6 +948,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
test_expect_success 'rebase -i --root temporary sentinel commit' '
git checkout B &&
(
+ set_fake_editor &&
FAKE_LINES="2" &&
export FAKE_LINES &&
test_must_fail git rebase -i --root
@@ -902,6 +959,7 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
test_expect_success 'rebase -i --root fixup root commit' '
git checkout B &&
+ set_fake_editor &&
FAKE_LINES="1 fixup 2" git rebase -i --root &&
test A = $(git cat-file commit HEAD | sed -ne \$p) &&
test B = $(git show HEAD:file1) &&
@@ -911,6 +969,7 @@ test_expect_success 'rebase -i --root fixup root commit' '
test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
git reset --hard &&
git checkout conflict-branch &&
+ set_fake_editor &&
test_must_fail git rebase --onto HEAD~2 HEAD~ &&
test_must_fail git rebase --edit-todo &&
git rebase --abort
@@ -919,6 +978,7 @@ test_expect_success 'rebase --edit-todo does not works on non-interactive rebase
test_expect_success 'rebase --edit-todo can be used to modify todo' '
git reset --hard &&
git checkout no-conflict-branch^0 &&
+ set_fake_editor &&
FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
FAKE_LINES="2 1" git rebase --edit-todo &&
git rebase --continue
@@ -929,6 +989,7 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' '
test_expect_success 'rebase -i produces readable reflog' '
git reset --hard &&
git branch -f branch-reflog-test H &&
+ set_fake_editor &&
git rebase -i --onto I F branch-reflog-test &&
cat >expect <<-\EOF &&
rebase -i (start): checkout I
@@ -989,4 +1050,28 @@ test_expect_success 'rebase -i error on commits with \ in message' '
test_expect_code 1 grep " emp" error
'
+test_expect_success 'short SHA-1 setup' '
+ test_when_finished "git checkout master" &&
+ git checkout --orphan collide &&
+ git rm -rf . &&
+ (
+ unset test_tick &&
+ test_commit collide1 collide &&
+ test_commit --notick collide2 collide &&
+ test_commit --notick collide3 collide
+ )
+'
+
+test_expect_success 'short SHA-1 collide' '
+ test_when_finished "reset_rebase && git checkout master" &&
+ git checkout collide &&
+ (
+ unset test_tick &&
+ test_tick &&
+ set_fake_editor &&
+ FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
+ FAKE_LINES="reword 1 2" git rebase -i HEAD~2
+ )
+'
+
test_done
diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh
index 2e0c36415f..8c251c57a6 100755
--- a/t/t3409-rebase-preserve-merges.sh
+++ b/t/t3409-rebase-preserve-merges.sh
@@ -28,6 +28,8 @@ export GIT_AUTHOR_EMAIL
# \--A3 <-- topic2
# \
# B2 <-- origin/topic
+#
+# Clone 4 (same as Clone 3)
test_expect_success 'setup for merge-preserving rebase' \
'echo First > A &&
@@ -64,6 +66,16 @@ test_expect_success 'setup for merge-preserving rebase' \
git merge --no-ff topic2
) &&
+ git clone ./. clone4 &&
+ (
+ cd clone4 &&
+ git checkout -b topic2 origin/topic &&
+ echo Sixth > A &&
+ git commit -a -m "Modify A3" &&
+ git checkout -b topic origin/topic &&
+ git merge --no-ff topic2
+ ) &&
+
git checkout topic &&
echo Fourth >> B &&
git commit -a -m "Modify B2"
@@ -96,4 +108,15 @@ test_expect_success 'rebase -p preserves no-ff merges' '
)
'
+test_expect_success 'rebase -p ignores merge.log config' '
+ (
+ cd clone4 &&
+ git fetch &&
+ git -c merge.log=1 rebase -p origin/topic &&
+ echo >expected &&
+ git log --format="%b" -1 >current &&
+ test_cmp expected current
+ )
+'
+
test_done
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 668933bfb2..8f272bce84 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1000,6 +1000,16 @@ test_expect_success '--from uses committer ident' '
test_cmp expect patch.head
'
+test_expect_success '--from omits redundant in-body header' '
+ git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
+ cat >expect <<-\EOF &&
+ From: A U Thor <author@example.com>
+
+ EOF
+ sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
+ test_cmp expect patch.head
+'
+
test_expect_success 'in-body headers trigger content encoding' '
GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
test_when_finished "git reset --hard HEAD^" &&
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 5493500ef1..42866992cf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -172,4 +172,20 @@ test_expect_success 'shortlog encoding' '
git shortlog HEAD~2.. > out &&
test_cmp expect out'
+test_expect_success 'shortlog ignores commits with missing authors' '
+ git commit --allow-empty -m normal &&
+ git commit --allow-empty -m soon-to-be-broken &&
+ git cat-file commit HEAD >commit.tmp &&
+ sed "/^author/d" commit.tmp >broken.tmp &&
+ commit=$(git hash-object -w -t commit --stdin <broken.tmp) &&
+ git update-ref HEAD $commit &&
+ cat >expect <<-\EOF &&
+ A U Thor (1):
+ normal
+
+ EOF
+ git shortlog HEAD~2.. >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index ce3eace065..0dd8b65d7c 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -484,4 +484,15 @@ test_expect_success 'Blame output (complex mapping)' '
test_cmp expect actual.fuzz
'
+cat >expect <<\EOF
+Some Dude <some@dude.xx>
+EOF
+
+test_expect_success 'commit --author honors mailmap' '
+ test_must_fail git commit --author "nick" --allow-empty -meight &&
+ git commit --author "Some Dude" --allow-empty -meight &&
+ git show --pretty=format:"%an <%ae>%n" >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index ec5099b83d..93c7c366cf 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -13,11 +13,16 @@ test_expect_success 'setup' '
git update-ref refs/heads/broken_email $(cat broken_email.hash)
'
+test_expect_success 'fsck notices broken commit' '
+ git fsck 2>actual &&
+ test_i18ngrep invalid.author actual
+'
+
test_expect_success 'git log with broken author email' '
{
echo commit $(cat broken_email.hash)
echo "Author: A U Thor <author@example.com>"
- echo "Date: Thu Jan 1 00:00:00 1970 +0000"
+ echo "Date: Thu Apr 7 15:13:13 2005 -0700"
echo
echo " foo"
} >expect.out &&
@@ -30,7 +35,7 @@ test_expect_success 'git log with broken author email' '
'
test_expect_success 'git log --format with broken author email' '
- echo "A U Thor+author@example.com+" >expect.out &&
+ echo "A U Thor+author@example.com+Thu Apr 7 15:13:13 2005 -0700" >expect.out &&
: >expect.err &&
git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err &&
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
index b7da95fac5..85716dd6ec 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -3,20 +3,19 @@
test_description='git am with corrupt input'
. ./test-lib.sh
-# Note the missing "+++" line:
-cat > bad-patch.diff <<'EOF'
-From: A U Thor <au.thor@example.com>
-diff --git a/f b/f
-index 7898192..6178079 100644
---- a/f
-@@ -1 +1 @@
--a
-+b
-EOF
-
test_expect_success setup '
- test $? = 0 &&
- echo a > f &&
+ # Note the missing "+++" line:
+ cat >bad-patch.diff <<-\EOF &&
+ From: A U Thor <au.thor@example.com>
+ diff --git a/f b/f
+ index 7898192..6178079 100644
+ --- a/f
+ @@ -1 +1 @@
+ -a
+ +b
+ EOF
+
+ echo a >f &&
git add f &&
test_tick &&
git commit -m initial
@@ -26,17 +25,12 @@ test_expect_success setup '
# fatal: unable to write file '(null)' mode 100644: Bad address
# Also, it had the unwanted side-effect of deleting f.
test_expect_success 'try to apply corrupted patch' '
- git am bad-patch.diff 2> actual
- test $? = 1
+ test_must_fail git am bad-patch.diff 2>actual
'
-cat > expected <<EOF
-fatal: git diff header lacks filename information (line 4)
-EOF
-
test_expect_success 'compare diagnostic; ensure file is still here' '
- test $? = 0 &&
- test -f f &&
+ echo "fatal: git diff header lacks filename information (line 4)" >expected &&
+ test_path_is_file f &&
test_cmp expected actual
'
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index a80584ea0e..d87ddf73b7 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -393,6 +393,17 @@ test_expect_success 'fetch in shallow repo unreachable shallow objects' '
git fsck --no-dangling
)
'
+test_expect_success 'fetch creating new shallow root' '
+ (
+ git clone "file://$(pwd)/." shallow10 &&
+ git commit --allow-empty -m empty &&
+ cd shallow10 &&
+ git fetch --depth=1 --progress 2>actual &&
+ # This should fetch only the empty commit, no tree or
+ # blob objects
+ grep "remote: Total 1" actual
+ )
+'
test_expect_success 'setup tests for the --stdin parameter' '
for head in C D E F
diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh
index c983d3694c..3932e797f7 100755
--- a/t/t5530-upload-pack-error.sh
+++ b/t/t5530-upload-pack-error.sh
@@ -54,9 +54,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' '
printf "0032want %s\n0034shallow %s00000009done\n0000" \
$(git rev-parse HEAD) $(git rev-parse HEAD^) >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
- # pack-objects survived
- grep "Total.*, reused" output.err &&
- # but there was an error, which must have been in rev-list
grep "bad tree object" output.err
'
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index f01edffa3c..1309702ba4 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -122,8 +122,7 @@ test_remote_error()
fi
test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output &&
- echo "fatal: remote error: $msg: /$repo" >expect &&
- test_cmp expect output
+ test_i18ngrep "fatal: remote error: $msg: /$repo" output &&
ret=$?
chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
(exit $ret)
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 0629149edd..b3b11e61c0 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -36,7 +36,7 @@ test_expect_success 'clone with excess parameters (2)' '
test_expect_success C_LOCALE_OUTPUT 'output from clone' '
rm -fr dst &&
- git clone -n "file://$(pwd)/src" dst >output &&
+ git clone -n "file://$(pwd)/src" dst >output 2>&1 &&
test $(grep Clon output | wc -l) = 1
'
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index 7ff6e0e16c..c4903687fb 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -134,4 +134,8 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' '
! repo_is_hardlinked force-nonlocal
'
+test_expect_success 'cloning locally respects "-u" for fetching refs' '
+ test_must_fail git clone --bare -u false a should_not_work.git
+'
+
test_done
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 85cadfad6d..9e24ec88e6 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -19,17 +19,19 @@ test_expect_success 'clone -o' '
'
-test_expect_success 'redirected clone' '
+test_expect_success 'redirected clone does not show progress' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- test_must_be_empty err
+ ! grep % err &&
+ test_i18ngrep ! "Checking connectivity" err
'
-test_expect_success 'redirected clone -v' '
+
+test_expect_success 'redirected clone -v does show progress' '
git clone --progress "file://$(pwd)/parent" clone-redirected-progress \
>out 2>err &&
- test -s err
+ grep % err
'
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
index b10685af4e..15e3d6476c 100755
--- a/t/t6000-rev-list-misc.sh
+++ b/t/t6000-rev-list-misc.sh
@@ -48,4 +48,12 @@ test_expect_success 'rev-list --objects with pathspecs and copied files' '
! grep one output
'
+test_expect_success 'rev-list A..B and rev-list ^A B are the same' '
+ git commit --allow-empty -m another &&
+ git tag -a -m "annotated" v1.0 &&
+ git rev-list --objects ^v1.0^ v1.0 >expect &&
+ git rev-list --objects v1.0^..v1.0 >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1aa27bdbbf..c5e914a781 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -325,7 +325,7 @@ trap 'die' EXIT
. "$TEST_DIRECTORY/test-lib-functions.sh"
# You are not expected to call test_ok_ and test_failure_ directly, use
-# the text_expect_* functions instead.
+# the test_expect_* functions instead.
test_ok_ () {
test_success=$(($test_success + 1))
diff --git a/upload-pack.c b/upload-pack.c
index 127e59a603..8327dc0b7c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -40,6 +40,7 @@ static struct object_array have_obj;
static struct object_array want_obj;
static struct object_array extra_edge_obj;
static unsigned int timeout;
+static int keepalive = 5;
/* 0 for no sideband,
* otherwise maximum packet size (up to 65520 bytes).
*/
@@ -68,87 +69,28 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
return sz;
}
-static FILE *pack_pipe = NULL;
-static void show_commit(struct commit *commit, void *data)
-{
- if (commit->object.flags & BOUNDARY)
- fputc('-', pack_pipe);
- if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0)
- die("broken output pipe");
- fputc('\n', pack_pipe);
- fflush(pack_pipe);
- free(commit->buffer);
- commit->buffer = NULL;
-}
-
-static void show_object(struct object *obj,
- const struct name_path *path, const char *component,
- void *cb_data)
-{
- show_object_with_name(pack_pipe, obj, path, component);
-}
-
-static void show_edge(struct commit *commit)
-{
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
-}
-
-static int do_rev_list(int in, int out, void *user_data)
-{
- int i;
- struct rev_info revs;
-
- pack_pipe = xfdopen(out, "w");
- init_revisions(&revs, NULL);
- revs.tag_objects = 1;
- revs.tree_objects = 1;
- revs.blob_objects = 1;
- if (use_thin_pack)
- revs.edge_hint = 1;
-
- for (i = 0; i < want_obj.nr; i++) {
- struct object *o = want_obj.objects[i].item;
- /* why??? */
- o->flags &= ~UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- for (i = 0; i < have_obj.nr; i++) {
- struct object *o = have_obj.objects[i].item;
- o->flags |= UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- setup_revisions(0, NULL, &revs, NULL);
- if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
- if (use_thin_pack)
- for (i = 0; i < extra_edge_obj.nr; i++)
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(
- extra_edge_obj.objects[i].item->sha1));
- traverse_commit_list(&revs, show_commit, show_object, NULL);
- fflush(pack_pipe);
- fclose(pack_pipe);
- return 0;
-}
-
static void create_pack_file(void)
{
- struct async rev_list;
struct child_process pack_objects;
char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[10];
- int arg = 0;
+ const char *argv[12];
+ int i, arg = 0;
+ FILE *pipe_fd;
+ char *shallow_file = NULL;
- argv[arg++] = "pack-objects";
- if (!shallow_nr) {
- argv[arg++] = "--revs";
- if (use_thin_pack)
- argv[arg++] = "--thin";
+ if (shallow_nr) {
+ shallow_file = setup_temporary_shallow();
+ argv[arg++] = "--shallow-file";
+ argv[arg++] = shallow_file;
}
+ argv[arg++] = "pack-objects";
+ argv[arg++] = "--revs";
+ if (use_thin_pack)
+ argv[arg++] = "--thin";
argv[arg++] = "--stdout";
if (!no_progress)
@@ -169,29 +111,21 @@ static void create_pack_file(void)
if (start_command(&pack_objects))
die("git upload-pack: unable to fork git-pack-objects");
- if (shallow_nr) {
- memset(&rev_list, 0, sizeof(rev_list));
- rev_list.proc = do_rev_list;
- rev_list.out = pack_objects.in;
- if (start_async(&rev_list))
- die("git upload-pack: unable to fork git-rev-list");
- }
- else {
- FILE *pipe_fd = xfdopen(pack_objects.in, "w");
- int i;
-
- for (i = 0; i < want_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(want_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "--not\n");
- for (i = 0; i < have_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(have_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "\n");
- fflush(pipe_fd);
- fclose(pipe_fd);
- }
-
+ pipe_fd = xfdopen(pack_objects.in, "w");
+
+ for (i = 0; i < want_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(want_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "--not\n");
+ for (i = 0; i < have_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(have_obj.objects[i].item->sha1));
+ for (i = 0; i < extra_edge_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(extra_edge_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "\n");
+ fflush(pipe_fd);
+ fclose(pipe_fd);
/* We read from pack_objects.err to capture stderr output for
* progress bar, and pack_objects.out to capture the pack data.
@@ -200,6 +134,7 @@ static void create_pack_file(void)
while (1) {
struct pollfd pfd[2];
int pe, pu, pollsize;
+ int ret;
reset_timeout();
@@ -222,7 +157,8 @@ static void create_pack_file(void)
if (!pollsize)
break;
- if (poll(pfd, pollsize, -1) < 0) {
+ ret = poll(pfd, pollsize, 1000 * keepalive);
+ if (ret < 0) {
if (errno != EINTR) {
error("poll failed, resuming: %s",
strerror(errno));
@@ -284,14 +220,32 @@ static void create_pack_file(void)
if (sz < 0)
goto fail;
}
+
+ /*
+ * We hit the keepalive timeout without saying anything; send
+ * an empty message on the data sideband just to let the other
+ * side know we're still working on it, but don't have any data
+ * yet.
+ *
+ * If we don't have a sideband channel, there's no room in the
+ * protocol to say anything, so those clients are just out of
+ * luck.
+ */
+ if (!ret && use_sideband) {
+ static const char buf[] = "0005\1";
+ write_or_die(1, buf, 5);
+ }
}
if (finish_command(&pack_objects)) {
error("git upload-pack: git-pack-objects died with error.");
goto fail;
}
- if (shallow_nr && finish_async(&rev_list))
- goto fail; /* error was already reported */
+ if (shallow_file) {
+ if (*shallow_file)
+ unlink(shallow_file);
+ free(shallow_file);
+ }
/* flush the data */
if (0 <= buffered) {
@@ -785,6 +739,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
{
if (!strcmp("uploadpack.allowtipsha1inwant", var))
allow_tip_sha1_in_want = git_config_bool(var, value);
+ else if (!strcmp("uploadpack.keepalive", var)) {
+ keepalive = git_config_int(var, value);
+ if (!keepalive)
+ keepalive = -1;
+ }
return parse_hide_refs_config(var, value, "uploadpack");
}