Extend transfer.hideRefs to work better with use of namespaces.
* lf/ref-is-hidden-namespace:
t5509: add basic tests for hideRefs
hideRefs: add support for matching full refs
upload-pack: strip refs before calling ref_is_hidden()
config.txt: document the semantics of hideRefs with namespaces
--- /dev/null
+Git v2.6.3 Release Notes
+========================
+
+Fixes since v2.6.2
+------------------
+
+ * The error message from "git blame --contents --reverse" incorrectly
+ talked about "--contents --children".
+
+ * "git merge-file" tried to signal how many conflicts it found, which
+ obviously would not work well when there are too many of them.
+
+ * The name-hash subsystem that is used to cope with case insensitive
+ filesystems keeps track of directories and their on-filesystem
+ cases for all the paths in the index by holding a pointer to a
+ randomly chosen cache entry that is inside the directory (for its
+ ce->ce_name component). This pointer was not updated even when the
+ cache entry was removed from the index, leading to use after free.
+ This was fixed by recording the path for each directory instead of
+ borrowing cache entries and restructuring the API somewhat.
+
+ * When the "git am" command was reimplemented in C, "git am -3" had a
+ small regression where it is aborted in its error handling codepath
+ when underlying merge-recursive failed in some ways.
+
+ * The synopsis text and the usage string of subcommands that read
+ list of things from the standard input are often shown as if they
+ only take input from a file on a filesystem, which was misleading.
+
+ * A couple of commands still showed "[options]" in their usage string
+ to note where options should come on their command line, but we
+ spell that "[<options>]" in most places these days.
+
+ * The submodule code has been taught to work better with separate
+ work trees created via "git worktree add".
+
+ * When "git gc --auto" is backgrounded, its diagnosis message is
+ lost. It now is saved to a file in $GIT_DIR and is shown next time
+ the "gc --auto" is run.
+
+ * Work around "git p4" failing when the P4 depot records the contents
+ in UTF-16 without UTF-16 BOM.
+
+ * Recent update to "rebase -i" that tries to sanity check the edited
+ insn sheet before it uses it has become too picky on Windows where
+ CRLF left by the editor is turned into a trailing CR on the line
+ read via the "read" built-in command.
+
+ * "git clone --dissociate" runs a big "git repack" process at the
+ end, and it helps to close file descriptors that are open on the
+ packs and their idx files before doing so on filesystems that
+ cannot remove a file that is still open.
+
+ * Correct "git p4 --detect-labels" so that it does not fail to create
+ a tag that points at a commit that is also being imported.
+
+ * The internal stripspace() function has been moved to where it
+ logically belongs to, i.e. strbuf API, and the command line parser
+ of "git stripspace" has been updated to use the parse_options API.
+
+ * Prepare for Git on-disk repository representation to undergo
+ backward incompatible changes by introducing a new repository
+ format version "1", with an extension mechanism.
+
+ * "git gc" used to barf when a symbolic ref has gone dangling
+ (e.g. the branch that used to be your upstream's default when you
+ cloned from it is now gone, and you did "fetch --prune").
+
+ * The normalize_ceiling_entry() function does not muck with the end
+ of the path it accepts, and the real world callers do rely on that,
+ but a test insisted that the function drops a trailing slash.
+
+ * "git gc" is safe to run anytime only because it has the built-in
+ grace period to protect young objects. In order to run with no
+ grace period, the user must make sure that the repository is
+ quiescent.
+
+ * A recent "filter-branch --msg-filter" broke skipping of the commit
+ object header, which is fixed.
+
+ * "git --literal-pathspecs add -u/-A" without any command line
+ argument misbehaved ever since Git 2.0.
+
+ * Merging a branch that removes a path and another that changes the
+ mode bits on the same path should have conflicted at the path, but
+ it didn't and silently favoured the removal.
+
+ * "git imap-send" did not compile well with older version of cURL library.
+
+ * The linkage order of libraries was wrong in places around libcurl.
+
+ * It was not possible to use a repository-lookalike created by "git
+ worktree add" as a local source of "git clone".
+
+ * When "git send-email" wanted to talk over Net::SMTP::SSL,
+ Net::Cmd::datasend() did not like to be fed too many bytes at the
+ same time and failed to send messages. Send the payload one line
+ at a time to work around the problem.
+
+ * We peek objects from submodule's object store by linking it to the
+ list of alternate object databases, but the code to do so forgot to
+ correctly initialize the list.
+
+ * "git status --branch --short" accessed beyond the constant string
+ "HEAD", which has been corrected.
+
+ * "git daemon" uses "run_command()" without "finish_command()", so it
+ needs to release resources itself, which it forgot to do.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
* "git blame" learnt to take "--first-parent" and "--reverse" at the
same time when it makes sense.
+ * "git checkout" did not follow the usual "--[no-]progress"
+ convention and implemented only "--quiet" that is essentially
+ a superset of "--no-progress". Extend the command to support the
+ usual "--[no-]progress".
+
Performance, Internal Implementation, Development Support etc.
not even exist or may be a directory.
(merge cfe2d4b da/difftool later to maint).
+ * A Range: request can be responded with a full response and when
+ asked properly libcurl knows how to strip the result down to the
+ requested range. However, we were hand-crafting a range request
+ and it did not kick in.
+
* Code clean-up, minor fixes etc.
(merge 15ed07d jc/rerere later to maint).
(merge e7a7401 pt/pull-builtin later to maint).
--quiet::
Quiet, suppress feedback messages.
+--[no-]progress::
+ Progress status is reported on the standard error stream
+ by default when it is attached to a terminal, unless `--quiet`
+ is specified. This flag enables progress reporting even if not
+ attached to a terminal, regardless of `--quiet`.
+
-f::
--force::
When switching branches, proceed even if the index or the
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v2.6.2/git.html[documentation for release 2.6.2]
+* link:v2.6.3/git.html[documentation for release 2.6.3]
* release notes for
+ link:RelNotes/2.6.3.txt[2.6.3],
link:RelNotes/2.6.2.txt[2.6.2],
link:RelNotes/2.6.1.txt[2.6.1],
link:RelNotes/2.6.0.txt[2.6].
int overwrite_ignore;
int ignore_skipworktree;
int ignore_other_worktrees;
+ int show_progress;
const char *new_branch;
const char *new_branch_force;
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
- opts.verbose_update = !o->quiet && isatty(2);
+ opts.verbose_update = o->show_progress;
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
topts.update = 1;
topts.merge = 1;
topts.gently = opts->merge && old->commit;
- topts.verbose_update = !opts->quiet && isatty(2);
+ topts.verbose_update = opts->show_progress;
topts.fn = twoway_merge;
if (opts->overwrite_ignore) {
topts.dir = xcalloc(1, sizeof(*topts.dir));
N_("second guess 'git checkout <no-such-branch>'")),
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
N_("do not check if another worktree is holding the given ref")),
+ OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
OPT_END(),
};
memset(&new, 0, sizeof(new));
opts.overwrite_ignore = 1;
opts.prefix = prefix;
+ opts.show_progress = -1;
gitmodules_config();
git_config(git_checkout_config, &opts);
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
+ if (opts.show_progress < 0) {
+ if (opts.quiet)
+ opts.show_progress = 0;
+ else
+ opts.show_progress = isatty(2);
+ }
+
if (conflict_style) {
opts.merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
static unsigned long loose, packed, packed_loose;
static off_t loose_size;
-static void real_report_garbage(const char *desc, const char *path)
+static const char *bits_to_msg(unsigned seen_bits)
+{
+ switch (seen_bits) {
+ case 0:
+ return "no corresponding .idx or .pack";
+ case PACKDIR_FILE_GARBAGE:
+ return "garbage found";
+ case PACKDIR_FILE_PACK:
+ return "no corresponding .idx";
+ case PACKDIR_FILE_IDX:
+ return "no corresponding .pack";
+ case PACKDIR_FILE_PACK|PACKDIR_FILE_IDX:
+ default:
+ return NULL;
+ }
+}
+
+static void real_report_garbage(unsigned seen_bits, const char *path)
{
struct stat st;
+ const char *desc = bits_to_msg(seen_bits);
+
+ if (!desc)
+ return;
+
if (!stat(path, &st))
size_garbage += st.st_size;
warning("%s: %s", desc, path);
static void loose_garbage(const char *path)
{
if (verbose)
- report_garbage("garbage found", path);
+ report_garbage(PACKDIR_FILE_GARBAGE, path);
}
static int count_loose(const unsigned char *sha1, const char *path, void *data)
static struct tempfile pidfile;
static struct lock_file log_lock;
+static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
+
+static void clean_pack_garbage(void)
+{
+ int i;
+ for (i = 0; i < pack_garbage.nr; i++)
+ unlink_or_warn(pack_garbage.items[i].string);
+ string_list_clear(&pack_garbage, 0);
+}
+
+static void report_pack_garbage(unsigned seen_bits, const char *path)
+{
+ if (seen_bits == PACKDIR_FILE_IDX)
+ string_list_append(&pack_garbage, path);
+}
+
static void git_config_date_string(const char *key, const char **output)
{
if (git_config_get_string_const(key, output))
if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
return error(FAILED_RUN, rerere.argv[0]);
+ report_garbage = report_pack_garbage;
+ reprepare_packed_git();
+ if (pack_garbage.nr > 0)
+ clean_pack_garbage();
+
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
-/* A hook for count-objects to report invalid files in pack directory */
-extern void (*report_garbage)(const char *desc, const char *path);
+/* A hook to report invalid files in pack directory */
+#define PACKDIR_FILE_PACK 1
+#define PACKDIR_FILE_IDX 2
+#define PACKDIR_FILE_GARBAGE 4
+extern void (*report_garbage)(unsigned seen_bits, const char *path);
extern void prepare_packed_git(void);
extern void reprepare_packed_git(void);
#endif
#define PREV_BUF_SIZE 4096
-#define RANGE_HEADER_SIZE 30
char curl_errorstr[CURL_ERROR_SIZE];
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
#endif
return cached_accept_language;
}
+static void http_opt_request_remainder(CURL *curl, off_t pos)
+{
+ char buf[128];
+ xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos);
+ curl_easy_setopt(curl, CURLOPT_RANGE, buf);
+}
+
/* http_request() targets */
#define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1
curl_easy_setopt(slot->curl, CURLOPT_FILE, result);
if (target == HTTP_REQUEST_FILE) {
- long posn = ftell(result);
+ off_t posn = ftello(result);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite);
- if (posn > 0) {
- strbuf_addf(&buf, "Range: bytes=%ld-", posn);
- headers = curl_slist_append(headers, buf.buf);
- strbuf_reset(&buf);
- }
+ if (posn > 0)
+ http_opt_request_remainder(slot->curl, posn);
} else
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer);
fclose(preq->packfile);
preq->packfile = NULL;
}
- if (preq->range_header != NULL) {
- curl_slist_free_all(preq->range_header);
- preq->range_header = NULL;
- }
preq->slot = NULL;
free(preq->url);
free(preq);
struct http_pack_request *new_http_pack_request(
struct packed_git *target, const char *base_url)
{
- long prev_posn = 0;
- char range[RANGE_HEADER_SIZE];
+ off_t prev_posn = 0;
struct strbuf buf = STRBUF_INIT;
struct http_pack_request *preq;
* If there is data present from a previous transfer attempt,
* resume where it left off
*/
- prev_posn = ftell(preq->packfile);
+ prev_posn = ftello(preq->packfile);
if (prev_posn>0) {
if (http_is_verbose)
fprintf(stderr,
"Resuming fetch of pack %s at byte %ld\n",
sha1_to_hex(target->sha1), prev_posn);
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
- preq->range_header = curl_slist_append(NULL, range);
- curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
- preq->range_header);
+ http_opt_request_remainder(preq->slot->curl, prev_posn);
}
return preq;
int prevlocal;
char prev_buf[PREV_BUF_SIZE];
ssize_t prev_read = 0;
- long prev_posn = 0;
- char range[RANGE_HEADER_SIZE];
- struct curl_slist *range_header = NULL;
+ off_t prev_posn = 0;
struct http_object_request *freq;
freq = xcalloc(1, sizeof(*freq));
fprintf(stderr,
"Resuming fetch of object %s at byte %ld\n",
hex, prev_posn);
- xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
- range_header = curl_slist_append(range_header, range);
- curl_easy_setopt(freq->slot->curl,
- CURLOPT_HTTPHEADER, range_header);
+ http_opt_request_remainder(freq->slot->curl, prev_posn);
}
return freq;
struct packed_git **lst;
FILE *packfile;
char tmpfile[PATH_MAX];
- struct curl_slist *range_header;
struct active_request_slot *slot;
};
strbuf_setlen(&sb, len);
strbuf_addstr(&sb, path);
if (file_exists(sb.buf))
- report_garbage("unused in linked checkout", sb.buf);
+ report_garbage(PACKDIR_FILE_GARBAGE, sb.buf);
}
strbuf_release(&sb);
}
packed_git = pack;
}
-void (*report_garbage)(const char *desc, const char *path);
+void (*report_garbage)(unsigned seen_bits, const char *path);
static void report_helper(const struct string_list *list,
int seen_bits, int first, int last)
{
- const char *msg;
- switch (seen_bits) {
- case 0:
- msg = "no corresponding .idx or .pack";
- break;
- case 1:
- msg = "no corresponding .idx";
- break;
- case 2:
- msg = "no corresponding .pack";
- break;
- default:
+ if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
return;
- }
+
for (; first < last; first++)
- report_garbage(msg, list->items[first].string);
+ report_garbage(seen_bits, list->items[first].string);
}
static void report_pack_garbage(struct string_list *list)
if (baselen == -1) {
const char *dot = strrchr(path, '.');
if (!dot) {
- report_garbage("garbage found", path);
+ report_garbage(PACKDIR_FILE_GARBAGE, path);
continue;
}
baselen = dot - path + 1;
ends_with(de->d_name, ".keep"))
string_list_append(&garbage, path.buf);
else
- report_garbage("garbage found", path.buf);
+ report_garbage(PACKDIR_FILE_GARBAGE, path.buf);
}
closedir(dir);
report_pack_garbage(&garbage);
test_expect_success 'garbage report in count-objects -v' '
test_when_finished "rm -f .git/objects/pack/fake*" &&
+ test_when_finished "rm -f .git/objects/pack/foo*" &&
: >.git/objects/pack/foo &&
: >.git/objects/pack/foo.bar &&
: >.git/objects/pack/foo.keep &&
test_cmp expected actual
'
+test_expect_success 'clean pack garbage with gc' '
+ test_when_finished "rm -f .git/objects/pack/fake*" &&
+ test_when_finished "rm -f .git/objects/pack/foo*" &&
+ : >.git/objects/pack/foo.keep &&
+ : >.git/objects/pack/foo.pack &&
+ : >.git/objects/pack/fake.idx &&
+ : >.git/objects/pack/fake2.keep &&
+ : >.git/objects/pack/fake2.idx &&
+ : >.git/objects/pack/fake3.keep &&
+ git gc &&
+ git count-objects -v 2>stderr &&
+ grep "^warning:" stderr | sort >actual &&
+ cat >expected <<\EOF &&
+warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep
+warning: no corresponding .idx: .git/objects/pack/foo.keep
+warning: no corresponding .idx: .git/objects/pack/foo.pack
+EOF
+ test_cmp expected actual
+'
+
test_expect_success 'prune .git/shallow' '
SHA1=`echo hi|git commit-tree HEAD^{tree}` &&
echo $SHA1 >.git/shallow &&