diff --git a/Documentation/RelNotes/2.53.0.adoc b/Documentation/RelNotes/2.53.0.adoc index d71948829c9ee2..91cfb7adfaab8f 100644 --- a/Documentation/RelNotes/2.53.0.adoc +++ b/Documentation/RelNotes/2.53.0.adoc @@ -31,6 +31,9 @@ UI, Workflows & Features * "git repo struct" learned to take "-z" as a synonym to "--format=nul". + * More object database related information are shown in "git repo + structure" output. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -83,6 +86,9 @@ Performance, Internal Implementation, Development Support etc. * The code path that enumerates promisor objects have been optimized to skip pointlessly parsing blob objects. + * Prepare test suite for Git for Windows that supports symbolic + links. + Fixes since v2.52 ----------------- @@ -204,6 +210,17 @@ Fixes since v2.52 has been corrected. (merge b7b17ec8a6 kn/fix-fetch-backfill-tag-with-batched-ref-updates later to maint). + * Document "rev-list --filter-provided-objects" better. + (merge 6d8dc99478 jt/doc-rev-list-filter-provided-objects later to maint). + + * Even when there is no changes in the packfile and no need to + recompute bitmaps, "git repack" recomputed and updated the MIDX + file, which has been corrected. + (merge 6ce9d558ce ps/repack-avoid-noop-midx-rewrite later to maint). + + * Update HTTP tests to adjust for changes in curl 8.18.0 + (merge 17f4b01da7 jk/test-curl-updates later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 46207a54cc qj/doc-http-bad-want-response later to maint). (merge df90eccd93 kh/doc-commit-extra-references later to maint). @@ -221,3 +238,7 @@ Fixes since v2.52 (merge 4ce170c522 ds/doc-scalar-config later to maint). (merge a0c813951a jc/doc-commit-signoff-config later to maint). (merge 8ee262985a ja/doc-misc-fixes later to maint). + (merge 1722c2244b mh/doc-core-attributesfile later to maint). + (merge c469ca26c5 dk/ci-rust-fix later to maint). + (merge 12f0be0857 gf/clear-path-cache-cleanup later to maint). + (merge 949df6ed6b js/test-func-comment-fix later to maint). diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc index 01202da7cd4a36..9bc9de29d90ecd 100644 --- a/Documentation/config/core.adoc +++ b/Documentation/config/core.adoc @@ -492,10 +492,9 @@ core.askPass:: command-line argument and write the password on its STDOUT. core.attributesFile:: - In addition to `.gitattributes` (per-directory) and - `.git/info/attributes`, Git looks into this file for attributes - (see linkgit:gitattributes[5]). Path expansions are made the same - way as for `core.excludesFile`. Its default value is + Specifies the pathname to the file that contains attributes (see + linkgit:gitattributes[5]), in addition to `.gitattributes` (per-directory) + and `.git/info/attributes`. Its default value is `$XDG_CONFIG_HOME/git/attributes`. If `$XDG_CONFIG_HOME` is either not set or empty, `$HOME/.config/git/attributes` is used instead. diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index c4a78277df61c0..7d70270dfa5716 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -50,6 +50,8 @@ supported: + * Reference counts categorized by type * Reachable object counts categorized by type +* Total inflated size of reachable objects by type +* Total disk size of reachable objects by type + The output format can be chosen through the flag `--format`. Three formats are supported: diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc index d9665d82c8dfbe..453ec590571ffc 100644 --- a/Documentation/rev-list-options.adoc +++ b/Documentation/rev-list-options.adoc @@ -983,7 +983,9 @@ to name units in KiB, MiB, or GiB. For example, `blob:limit=1k` is the same as 'blob:limit=1024'. + The form `--filter=object:type=(tag|commit|tree|blob)` omits all objects -which are not of the requested type. +which are not of the requested type. Note that explicitly provided objects +ignore filters and are always printed unless `--filter-provided-objects` is +also specified. + The form `--filter=sparse:oid=` uses a sparse-checkout specification contained in the blob (or blob-expression) __ diff --git a/apply.c b/apply.c index c9fb45247d8cd2..3de4aa4d2eaac5 100644 --- a/apply.c +++ b/apply.c @@ -3818,7 +3818,7 @@ static int check_preimage(struct apply_state *state, if (*ce && !(*ce)->ce_mode) BUG("ce_mode == 0 for path '%s'", old_name); - if (trust_executable_bit) + if (trust_executable_bit || !S_ISREG(st->st_mode)) st_mode = ce_mode_from_stat(*ce, st->st_mode); else if (*ce) st_mode = (*ce)->ce_mode; diff --git a/builtin/repo.c b/builtin/repo.c index 0dd41b17783ed1..0ea045abc13f8c 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -2,6 +2,8 @@ #include "builtin.h" #include "environment.h" +#include "hex.h" +#include "odb.h" #include "parse-options.h" #include "path-walk.h" #include "progress.h" @@ -202,13 +204,19 @@ struct ref_stats { size_t others; }; -struct object_stats { +struct object_values { size_t tags; size_t commits; size_t trees; size_t blobs; }; +struct object_stats { + struct object_values type_counts; + struct object_values inflated_sizes; + struct object_values disk_sizes; +}; + struct repo_structure { struct ref_stats refs; struct object_stats objects; @@ -219,6 +227,7 @@ struct stats_table { int name_col_width; int value_col_width; + int unit_col_width; }; /* @@ -226,6 +235,7 @@ struct stats_table { */ struct stats_table_entry { char *value; + const char *unit; }; static void stats_table_vaddf(struct stats_table *table, @@ -246,11 +256,18 @@ static void stats_table_vaddf(struct stats_table *table, if (name_width > table->name_col_width) table->name_col_width = name_width; - if (entry) { + if (!entry) + return; + if (entry->value) { int value_width = utf8_strwidth(entry->value); if (value_width > table->value_col_width) table->value_col_width = value_width; } + if (entry->unit) { + int unit_width = utf8_strwidth(entry->unit); + if (unit_width > table->unit_col_width) + table->unit_col_width = unit_width; + } } static void stats_table_addf(struct stats_table *table, const char *format, ...) @@ -269,7 +286,21 @@ static void stats_table_count_addf(struct stats_table *table, size_t value, va_list ap; CALLOC_ARRAY(entry, 1); - entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value); + humanise_count(value, &entry->value, &entry->unit); + + va_start(ap, format); + stats_table_vaddf(table, entry, format, ap); + va_end(ap); +} + +static void stats_table_size_addf(struct stats_table *table, size_t value, + const char *format, ...) +{ + struct stats_table_entry *entry; + va_list ap; + + CALLOC_ARRAY(entry, 1); + humanise_bytes(value, &entry->value, &entry->unit, HUMANISE_COMPACT); va_start(ap, format); stats_table_vaddf(table, entry, format, ap); @@ -281,9 +312,9 @@ static inline size_t get_total_reference_count(struct ref_stats *stats) return stats->branches + stats->remotes + stats->tags + stats->others; } -static inline size_t get_total_object_count(struct object_stats *stats) +static inline size_t get_total_object_values(struct object_values *values) { - return stats->tags + stats->commits + stats->trees + stats->blobs; + return values->tags + values->commits + values->trees + values->blobs; } static void stats_table_setup_structure(struct stats_table *table, @@ -291,7 +322,9 @@ static void stats_table_setup_structure(struct stats_table *table, { struct object_stats *objects = &stats->objects; struct ref_stats *refs = &stats->refs; - size_t object_total; + size_t inflated_object_total; + size_t object_count_total; + size_t disk_object_total; size_t ref_total; ref_total = get_total_reference_count(refs); @@ -302,34 +335,66 @@ static void stats_table_setup_structure(struct stats_table *table, stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes")); stats_table_count_addf(table, refs->others, " * %s", _("Others")); - object_total = get_total_object_count(objects); + object_count_total = get_total_object_values(&objects->type_counts); stats_table_addf(table, ""); stats_table_addf(table, "* %s", _("Reachable objects")); - stats_table_count_addf(table, object_total, " * %s", _("Count")); - stats_table_count_addf(table, objects->commits, " * %s", _("Commits")); - stats_table_count_addf(table, objects->trees, " * %s", _("Trees")); - stats_table_count_addf(table, objects->blobs, " * %s", _("Blobs")); - stats_table_count_addf(table, objects->tags, " * %s", _("Tags")); + stats_table_count_addf(table, object_count_total, " * %s", _("Count")); + stats_table_count_addf(table, objects->type_counts.commits, + " * %s", _("Commits")); + stats_table_count_addf(table, objects->type_counts.trees, + " * %s", _("Trees")); + stats_table_count_addf(table, objects->type_counts.blobs, + " * %s", _("Blobs")); + stats_table_count_addf(table, objects->type_counts.tags, + " * %s", _("Tags")); + + inflated_object_total = get_total_object_values(&objects->inflated_sizes); + stats_table_size_addf(table, inflated_object_total, + " * %s", _("Inflated size")); + stats_table_size_addf(table, objects->inflated_sizes.commits, + " * %s", _("Commits")); + stats_table_size_addf(table, objects->inflated_sizes.trees, + " * %s", _("Trees")); + stats_table_size_addf(table, objects->inflated_sizes.blobs, + " * %s", _("Blobs")); + stats_table_size_addf(table, objects->inflated_sizes.tags, + " * %s", _("Tags")); + + disk_object_total = get_total_object_values(&objects->disk_sizes); + stats_table_size_addf(table, disk_object_total, + " * %s", _("Disk size")); + stats_table_size_addf(table, objects->disk_sizes.commits, + " * %s", _("Commits")); + stats_table_size_addf(table, objects->disk_sizes.trees, + " * %s", _("Trees")); + stats_table_size_addf(table, objects->disk_sizes.blobs, + " * %s", _("Blobs")); + stats_table_size_addf(table, objects->disk_sizes.tags, + " * %s", _("Tags")); } static void stats_table_print_structure(const struct stats_table *table) { const char *name_col_title = _("Repository structure"); const char *value_col_title = _("Value"); - int name_col_width = utf8_strwidth(name_col_title); - int value_col_width = utf8_strwidth(value_col_title); + int title_name_width = utf8_strwidth(name_col_title); + int title_value_width = utf8_strwidth(value_col_title); + int name_col_width = table->name_col_width; + int value_col_width = table->value_col_width; + int unit_col_width = table->unit_col_width; struct string_list_item *item; struct strbuf buf = STRBUF_INIT; - if (table->name_col_width > name_col_width) - name_col_width = table->name_col_width; - if (table->value_col_width > value_col_width) - value_col_width = table->value_col_width; + if (title_name_width > name_col_width) + name_col_width = title_name_width; + if (title_value_width > value_col_width + unit_col_width + 1) + value_col_width = title_value_width - unit_col_width; strbuf_addstr(&buf, "| "); strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, name_col_title); strbuf_addstr(&buf, " | "); - strbuf_utf8_align(&buf, ALIGN_LEFT, value_col_width, value_col_title); + strbuf_utf8_align(&buf, ALIGN_LEFT, + value_col_width + unit_col_width + 1, value_col_title); strbuf_addstr(&buf, " |"); printf("%s\n", buf.buf); @@ -337,17 +402,20 @@ static void stats_table_print_structure(const struct stats_table *table) for (int i = 0; i < name_col_width; i++) putchar('-'); printf(" | "); - for (int i = 0; i < value_col_width; i++) + for (int i = 0; i < value_col_width + unit_col_width + 1; i++) putchar('-'); printf(" |\n"); for_each_string_list_item(item, &table->rows) { struct stats_table_entry *entry = item->util; const char *value = ""; + const char *unit = ""; if (entry) { struct stats_table_entry *entry = item->util; value = entry->value; + if (entry->unit) + unit = entry->unit; } strbuf_reset(&buf); @@ -355,6 +423,8 @@ static void stats_table_print_structure(const struct stats_table *table) strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, item->string); strbuf_addstr(&buf, " | "); strbuf_utf8_align(&buf, ALIGN_RIGHT, value_col_width, value); + strbuf_addch(&buf, ' '); + strbuf_utf8_align(&buf, ALIGN_LEFT, unit_col_width, unit); strbuf_addstr(&buf, " |"); printf("%s\n", buf.buf); } @@ -389,13 +459,31 @@ static void structure_keyvalue_print(struct repo_structure *stats, (uintmax_t)stats->refs.others, value_delim); printf("objects.commits.count%c%" PRIuMAX "%c", key_delim, - (uintmax_t)stats->objects.commits, value_delim); + (uintmax_t)stats->objects.type_counts.commits, value_delim); printf("objects.trees.count%c%" PRIuMAX "%c", key_delim, - (uintmax_t)stats->objects.trees, value_delim); + (uintmax_t)stats->objects.type_counts.trees, value_delim); printf("objects.blobs.count%c%" PRIuMAX "%c", key_delim, - (uintmax_t)stats->objects.blobs, value_delim); + (uintmax_t)stats->objects.type_counts.blobs, value_delim); printf("objects.tags.count%c%" PRIuMAX "%c", key_delim, - (uintmax_t)stats->objects.tags, value_delim); + (uintmax_t)stats->objects.type_counts.tags, value_delim); + + printf("objects.commits.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.commits, value_delim); + printf("objects.trees.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.trees, value_delim); + printf("objects.blobs.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.blobs, value_delim); + printf("objects.tags.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.tags, value_delim); + + printf("objects.commits.disk_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.disk_sizes.commits, value_delim); + printf("objects.trees.disk_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.disk_sizes.trees, value_delim); + printf("objects.blobs.disk_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.disk_sizes.blobs, value_delim); + printf("objects.tags.disk_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.disk_sizes.tags, value_delim); fflush(stdout); } @@ -460,6 +548,7 @@ static void structure_count_references(struct ref_stats *stats, } struct count_objects_data { + struct object_database *odb; struct object_stats *stats; struct progress *progress; }; @@ -469,26 +558,53 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids, { struct count_objects_data *data = cb_data; struct object_stats *stats = data->stats; + size_t inflated_total = 0; + size_t disk_total = 0; size_t object_count; + for (size_t i = 0; i < oids->nr; i++) { + struct object_info oi = OBJECT_INFO_INIT; + unsigned long inflated; + off_t disk; + + oi.sizep = &inflated; + oi.disk_sizep = &disk; + + if (odb_read_object_info_extended(data->odb, &oids->oid[i], &oi, + OBJECT_INFO_SKIP_FETCH_OBJECT | + OBJECT_INFO_QUICK) < 0) + continue; + + inflated_total += inflated; + disk_total += disk; + } + switch (type) { case OBJ_TAG: - stats->tags += oids->nr; + stats->type_counts.tags += oids->nr; + stats->inflated_sizes.tags += inflated_total; + stats->disk_sizes.tags += disk_total; break; case OBJ_COMMIT: - stats->commits += oids->nr; + stats->type_counts.commits += oids->nr; + stats->inflated_sizes.commits += inflated_total; + stats->disk_sizes.commits += disk_total; break; case OBJ_TREE: - stats->trees += oids->nr; + stats->type_counts.trees += oids->nr; + stats->inflated_sizes.trees += inflated_total; + stats->disk_sizes.trees += disk_total; break; case OBJ_BLOB: - stats->blobs += oids->nr; + stats->type_counts.blobs += oids->nr; + stats->inflated_sizes.blobs += inflated_total; + stats->disk_sizes.blobs += disk_total; break; default: BUG("invalid object type"); } - object_count = get_total_object_count(stats); + object_count = get_total_object_values(&stats->type_counts); display_progress(data->progress, object_count); return 0; @@ -500,6 +616,7 @@ static void structure_count_objects(struct object_stats *stats, { struct path_walk_info info = PATH_WALK_INFO_INIT; struct count_objects_data data = { + .odb = repo->objects, .stats = stats, }; diff --git a/compat/mingw.c b/compat/mingw.c index 939f938fe27fe5..f09b49ff21ddab 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -629,6 +629,7 @@ int mingw_open (const char *filename, int oflags, ...) int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL); wchar_t wfilename[MAX_PATH]; open_fn_t open_fn; + WIN32_FILE_ATTRIBUTE_DATA fdata; DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void); @@ -653,6 +654,19 @@ int mingw_open (const char *filename, int oflags, ...) else if (xutftowcs_path(wfilename, filename) < 0) return -1; + /* + * When `symlink` exists and is a symbolic link pointing to a + * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would + * create that file. Not what we want: Linux would say `EEXIST` + * in that instance, which is therefore what Git expects. + */ + if (create && + GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) && + (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + errno = EEXIST; + return -1; + } + fd = open_fn(wfilename, oflags, mode); /* diff --git a/midx-write.c b/midx-write.c index e3e9be6d03cd6f..ce459b02c319cf 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1014,6 +1014,65 @@ static void clear_midx_files(struct odb_source *source, strbuf_release(&buf); } +static bool midx_needs_update(struct multi_pack_index *midx, struct write_midx_context *ctx) +{ + struct strset packs = STRSET_INIT; + struct strbuf buf = STRBUF_INIT; + bool needed = true; + + /* + * Ignore incremental updates for now. The assumption is that any + * incremental update would be either empty (in which case we will bail + * out later) or it would actually cover at least one new pack. + */ + if (ctx->incremental) + goto out; + + /* + * Otherwise, we need to verify that the packs covered by the existing + * MIDX match the packs that we already have. The logic to do so is way + * more complicated than it has any right to be. This is because: + * + * - We cannot assume any ordering. + * + * - The MIDX packs may not be loaded at all, and loading them would + * be wasteful. So we need to use the pack names tracked by the + * MIDX itself. + * + * - The MIDX pack names are tracking the ".idx" files, whereas the + * packs themselves are tracking the ".pack" files. So we need to + * strip suffixes. + */ + if (ctx->nr != midx->num_packs + midx->num_packs_in_base) + goto out; + + for (uint32_t i = 0; i < ctx->nr; i++) { + strbuf_reset(&buf); + strbuf_addstr(&buf, pack_basename(ctx->info[i].p)); + strbuf_strip_suffix(&buf, ".pack"); + + if (!strset_add(&packs, buf.buf)) + BUG("same pack added twice?"); + } + + for (uint32_t i = 0; i < ctx->nr; i++) { + strbuf_reset(&buf); + strbuf_addstr(&buf, midx->pack_names[i]); + strbuf_strip_suffix(&buf, ".idx"); + + if (!strset_contains(&packs, buf.buf)) + goto out; + strset_remove(&packs, buf.buf); + } + + needed = false; + +out: + strbuf_release(&buf); + strset_clear(&packs); + return needed; +} + static int write_midx_internal(struct odb_source *source, struct string_list *packs_to_include, struct string_list *packs_to_drop, @@ -1031,6 +1090,7 @@ static int write_midx_internal(struct odb_source *source, struct write_midx_context ctx = { .preferred_pack_idx = NO_PREFERRED_PACK, }; + struct multi_pack_index *midx_to_free = NULL; int bitmapped_packs_concat_len = 0; int pack_name_concat_len = 0; int dropped_packs = 0; @@ -1111,27 +1171,39 @@ static int write_midx_internal(struct odb_source *source, for_each_file_in_pack_dir(source->path, add_pack_to_midx, &ctx); stop_progress(&ctx.progress); - if ((ctx.m && ctx.nr == ctx.m->num_packs + ctx.m->num_packs_in_base) && - !ctx.incremental && - !(packs_to_include || packs_to_drop)) { - struct bitmap_index *bitmap_git; - int bitmap_exists; - int want_bitmap = flags & MIDX_WRITE_BITMAP; - - bitmap_git = prepare_midx_bitmap_git(ctx.m); - bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git); - free_bitmap_index(bitmap_git); - - if (bitmap_exists || !want_bitmap) { - /* - * The correct MIDX already exists, and so does a - * corresponding bitmap (or one wasn't requested). - */ - if (!want_bitmap) - clear_midx_files_ext(source, "bitmap", NULL); - result = 0; - goto cleanup; + if (!packs_to_drop) { + /* + * If there is no MIDX then either it doesn't exist, or we're + * doing a geometric repack. Try to load it from the source to + * tell these two cases apart. + */ + struct multi_pack_index *midx = ctx.m; + if (!midx) + midx = midx_to_free = load_multi_pack_index(ctx.source); + + if (midx && !midx_needs_update(midx, &ctx)) { + struct bitmap_index *bitmap_git; + int bitmap_exists; + int want_bitmap = flags & MIDX_WRITE_BITMAP; + + bitmap_git = prepare_midx_bitmap_git(midx); + bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git); + free_bitmap_index(bitmap_git); + + if (bitmap_exists || !want_bitmap) { + /* + * The correct MIDX already exists, and so does a + * corresponding bitmap (or one wasn't requested). + */ + if (!want_bitmap) + clear_midx_files_ext(source, "bitmap", NULL); + result = 0; + goto cleanup; + } } + + close_midx(midx_to_free); + midx_to_free = NULL; } if (ctx.incremental && !ctx.nr) { @@ -1487,6 +1559,7 @@ static int write_midx_internal(struct odb_source *source, free(keep_hashes); } strbuf_release(&midx_name); + close_midx(midx_to_free); trace2_region_leave("midx", "write_midx_internal", r); diff --git a/midx.c b/midx.c index 24e1e721754d0c..b681b18fc19a40 100644 --- a/midx.c +++ b/midx.c @@ -686,7 +686,7 @@ int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id) { if (m->preferred_pack_idx == -1) { uint32_t midx_pos; - if (load_midx_revindex(m) < 0) { + if (load_midx_revindex(m)) { m->preferred_pack_idx = -2; return -1; } diff --git a/object-file.c b/object-file.c index af1c3f972dbf17..6280e42f3412c3 100644 --- a/object-file.c +++ b/object-file.c @@ -426,7 +426,7 @@ int odb_source_loose_read_object_info(struct odb_source *source, unsigned long size_scratch; enum object_type type_scratch; - if (oi->delta_base_oid) + if (oi && oi->delta_base_oid) oidclr(oi->delta_base_oid, source->odb->repo->hash_algo); /* @@ -437,13 +437,13 @@ int odb_source_loose_read_object_info(struct odb_source *source, * return value implicitly indicates whether the * object even exists. */ - if (!oi->typep && !oi->sizep && !oi->contentp) { + if (!oi || (!oi->typep && !oi->sizep && !oi->contentp)) { struct stat st; - if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK)) + if ((!oi || !oi->disk_sizep) && (flags & OBJECT_INFO_QUICK)) return quick_has_loose(source->loose, oid) ? 0 : -1; if (stat_loose_object(source->loose, oid, &st, &path) < 0) return -1; - if (oi->disk_sizep) + if (oi && oi->disk_sizep) *oi->disk_sizep = st.st_size; return 0; } diff --git a/odb.c b/odb.c index 7b5da2de32190c..ffd78e1c467219 100644 --- a/odb.c +++ b/odb.c @@ -677,34 +677,31 @@ static int do_oid_object_info_extended(struct object_database *odb, const struct object_id *oid, struct object_info *oi, unsigned flags) { - static struct object_info blank_oi = OBJECT_INFO_INIT; const struct cached_object *co; const struct object_id *real = oid; int already_retried = 0; - if (flags & OBJECT_INFO_LOOKUP_REPLACE) real = lookup_replace_object(odb->repo, oid); if (is_null_oid(real)) return -1; - if (!oi) - oi = &blank_oi; - co = find_cached_object(odb, real); if (co) { - if (oi->typep) - *(oi->typep) = co->type; - if (oi->sizep) - *(oi->sizep) = co->size; - if (oi->disk_sizep) - *(oi->disk_sizep) = 0; - if (oi->delta_base_oid) - oidclr(oi->delta_base_oid, odb->repo->hash_algo); - if (oi->contentp) - *oi->contentp = xmemdupz(co->buf, co->size); - oi->whence = OI_CACHED; + if (oi) { + if (oi->typep) + *(oi->typep) = co->type; + if (oi->sizep) + *(oi->sizep) = co->size; + if (oi->disk_sizep) + *(oi->disk_sizep) = 0; + if (oi->delta_base_oid) + oidclr(oi->delta_base_oid, odb->repo->hash_algo); + if (oi->contentp) + *oi->contentp = xmemdupz(co->buf, co->size); + oi->whence = OI_CACHED; + } return 0; } diff --git a/pack-revindex.h b/pack-revindex.h index 422c2487ae32d8..004289209191d0 100644 --- a/pack-revindex.h +++ b/pack-revindex.h @@ -72,7 +72,8 @@ int verify_pack_revindex(struct packed_git *p); * multi-pack index by mmap-ing it and assigning pointers in the * multi_pack_index to point at it. * - * A negative number is returned on error. + * A negative number is returned on error. A positive number is returned in + * case the multi-pack-index does not have a reverse index. */ int load_midx_revindex(struct multi_pack_index *m); diff --git a/packfile.c b/packfile.c index c7438c5b094519..23a7f8a1917619 100644 --- a/packfile.c +++ b/packfile.c @@ -2138,7 +2138,6 @@ int packfile_store_read_object_info(struct packfile_store *store, struct object_info *oi, unsigned flags UNUSED) { - static struct object_info blank_oi = OBJECT_INFO_INIT; struct pack_entry e; int rtype; @@ -2149,7 +2148,7 @@ int packfile_store_read_object_info(struct packfile_store *store, * We know that the caller doesn't actually need the * information below, so return early. */ - if (oi == &blank_oi) + if (!oi) return 0; rtype = packed_object_info(store->odb->repo, e.p, e.offset, oi); diff --git a/refs/debug.c b/refs/debug.c index 3e31228c9a6c1f..639db0f26e1bbb 100644 --- a/refs/debug.c +++ b/refs/debug.c @@ -139,7 +139,7 @@ static int debug_optimize_required(struct ref_store *ref_store, struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; int res = drefs->refs->be->optimize_required(drefs->refs, opts, required); trace_printf_key(&trace_refs, "optimize_required: %s, res: %d\n", - required ? "yes" : "no", res); + *required ? "yes" : "no", res); return res; } diff --git a/repository.c b/repository.c index 863f24411b7bf9..c7e75215ac2ab2 100644 --- a/repository.c +++ b/repository.c @@ -349,7 +349,6 @@ int repo_submodule_init(struct repository *subrepo, static void repo_clear_path_cache(struct repo_path_cache *cache) { - FREE_AND_NULL(cache->squash_msg); FREE_AND_NULL(cache->squash_msg); FREE_AND_NULL(cache->merge_msg); FREE_AND_NULL(cache->merge_rr); diff --git a/src/cargo-meson.sh b/src/cargo-meson.sh index 3998db04354864..38728a371137f9 100755 --- a/src/cargo-meson.sh +++ b/src/cargo-meson.sh @@ -26,7 +26,7 @@ then exit $RET fi -case "$(cargo -vV | sed -s 's/^host: \(.*\)$/\1/')" in +case "$(cargo -vV | sed -n 's/^host: \(.*\)$/\1/p')" in *-windows-*) LIBNAME=gitcore.lib;; *) diff --git a/strbuf.c b/strbuf.c index 6c3851a7f84d72..7fb7d12ac0cb9e 100644 --- a/strbuf.c +++ b/strbuf.c @@ -836,47 +836,83 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s, strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn); } -static void strbuf_humanise(struct strbuf *buf, off_t bytes, - int humanise_rate) +void humanise_count(size_t count, char **value, const char **unit) +{ + if (count >= 1000000000) { + size_t x = count + 5000000; /* for rounding */ + *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000000), + (unsigned)(x % 1000000000 / 10000000)); + /* TRANSLATORS: SI decimal prefix symbol for 10^9 */ + *unit = _("G"); + } else if (count >= 1000000) { + size_t x = count + 5000; /* for rounding */ + *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000), + (unsigned)(x % 1000000 / 10000)); + /* TRANSLATORS: SI decimal prefix symbol for 10^6 */ + *unit = _("M"); + } else if (count >= 1000) { + size_t x = count + 5; /* for rounding */ + *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000), + (unsigned)(x % 1000 / 10)); + /* TRANSLATORS: SI decimal prefix symbol for 10^3 */ + *unit = _("k"); + } else { + *value = xstrfmt("%u", (unsigned)count); + *unit = NULL; + } +} + +void humanise_bytes(off_t bytes, char **value, const char **unit, + unsigned flags) { + int humanise_rate = flags & HUMANISE_RATE; + if (bytes > 1 << 30) { - strbuf_addf(buf, - humanise_rate == 0 ? - /* TRANSLATORS: IEC 80000-13:2008 gibibyte */ - _("%u.%2.2u GiB") : - /* TRANSLATORS: IEC 80000-13:2008 gibibyte/second */ - _("%u.%2.2u GiB/s"), - (unsigned)(bytes >> 30), - (unsigned)(bytes & ((1 << 30) - 1)) / 10737419); + *value = xstrfmt(_("%u.%2.2u"), (unsigned)(bytes >> 30), + (unsigned)(bytes & ((1 << 30) - 1)) / 10737419); + /* TRANSLATORS: IEC 80000-13:2008 gibibyte/second and gibibyte */ + *unit = humanise_rate ? _("GiB/s") : _("GiB"); } else if (bytes > 1 << 20) { - unsigned x = bytes + 5243; /* for rounding */ - strbuf_addf(buf, - humanise_rate == 0 ? - /* TRANSLATORS: IEC 80000-13:2008 mebibyte */ - _("%u.%2.2u MiB") : - /* TRANSLATORS: IEC 80000-13:2008 mebibyte/second */ - _("%u.%2.2u MiB/s"), - x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20); + unsigned x = bytes + 5243; /* for rounding */ + *value = xstrfmt(_("%u.%2.2u"), x >> 20, + ((x & ((1 << 20) - 1)) * 100) >> 20); + /* TRANSLATORS: IEC 80000-13:2008 mebibyte/second and mebibyte */ + *unit = humanise_rate ? _("MiB/s") : _("MiB"); } else if (bytes > 1 << 10) { - unsigned x = bytes + 5; /* for rounding */ - strbuf_addf(buf, - humanise_rate == 0 ? - /* TRANSLATORS: IEC 80000-13:2008 kibibyte */ - _("%u.%2.2u KiB") : - /* TRANSLATORS: IEC 80000-13:2008 kibibyte/second */ - _("%u.%2.2u KiB/s"), - x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10); + unsigned x = bytes + 5; /* for rounding */ + *value = xstrfmt(_("%u.%2.2u"), x >> 10, + ((x & ((1 << 10) - 1)) * 100) >> 10); + /* TRANSLATORS: IEC 80000-13:2008 kibibyte/second and kibibyte */ + *unit = humanise_rate ? _("KiB/s") : _("KiB"); } else { - strbuf_addf(buf, - humanise_rate == 0 ? - /* TRANSLATORS: IEC 80000-13:2008 byte */ - Q_("%u byte", "%u bytes", bytes) : + *value = xstrfmt("%u", (unsigned)bytes); + if (flags & HUMANISE_COMPACT) + /* TRANSLATORS: IEC 80000-13:2008 byte/second and byte */ + *unit = humanise_rate ? _("B/s") : _("B"); + else + *unit = humanise_rate ? /* TRANSLATORS: IEC 80000-13:2008 byte/second */ - Q_("%u byte/s", "%u bytes/s", bytes), - (unsigned)bytes); + Q_("byte/s", "bytes/s", bytes) : + /* TRANSLATORS: IEC 80000-13:2008 byte */ + Q_("byte", "bytes", bytes); } } +static void strbuf_humanise(struct strbuf *buf, off_t bytes, unsigned flags) +{ + char *value; + const char *unit; + + humanise_bytes(bytes, &value, &unit, flags); + + /* + * TRANSLATORS: The first argument is the number string. The second + * argument is the unit string (i.e. "12.34 MiB/s"). + */ + strbuf_addf(buf, _("%s %s"), value, unit); + free(value); +} + void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes) { strbuf_humanise(buf, bytes, 0); @@ -884,7 +920,7 @@ void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes) void strbuf_humanise_rate(struct strbuf *buf, off_t bytes) { - strbuf_humanise(buf, bytes, 1); + strbuf_humanise(buf, bytes, HUMANISE_RATE); } int printf_ln(const char *fmt, ...) diff --git a/strbuf.h b/strbuf.h index a580ac6084b7f1..06e284f9cca445 100644 --- a/strbuf.h +++ b/strbuf.h @@ -367,6 +367,31 @@ void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src); */ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags); +enum humanise_flags { + /* + * Use rate based units for humanised values. + */ + HUMANISE_RATE = (1 << 0), + /* + * Use compact "B" unit symbol instead of "byte/bytes" for humanised + * values. + */ + HUMANISE_COMPACT = (1 << 1), +}; + +/** + * Converts the given byte size into a downscaled human-readable value and + * corresponding unit as two separate strings. + */ +void humanise_bytes(off_t bytes, char **value, const char **unit, + unsigned flags); + +/** + * Converts the given count into a downscaled human-readable value and + * corresponding unit as two separate strings. + */ +void humanise_count(size_t count, char **value, const char **unit); + /** * Append the given byte size as a human-readable string (i.e. 12.23 KiB, * 3.50 MiB). diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c index 03cc5eea2c2944..442ad6b16f18d8 100644 --- a/t/helper/test-simple-ipc.c +++ b/t/helper/test-simple-ipc.c @@ -603,7 +603,12 @@ int cmd__simple_ipc(int argc, const char **argv) OPT_INTEGER(0, "bytecount", &cl_args.bytecount, N_("number of bytes")), OPT_INTEGER(0, "batchsize", &cl_args.batchsize, N_("number of requests per thread")), - OPT_STRING(0, "byte", &bytevalue, N_("byte"), N_("ballast character")), + /* + * The "byte" string here is not marked for translation and + * instead relies on translation in strbuf.c:humanise_bytes() to + * avoid conflict with the plural form. + */ + OPT_STRING(0, "byte", &bytevalue, "byte", N_("ballast character")), OPT_STRING(0, "token", &cl_args.token, N_("token"), N_("command token to send to the server")), OPT_END() diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 618da080dc9ea9..e4d32bb4d259f6 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' git init --separate-git-dir ../realgitdir ) && echo "gitdir: $(pwd)/realgitdir" >expected && - test_cmp expected newdir/.git && + case "$GIT_TEST_CMP" in + # `git diff --no-index` does not resolve symlinks + *--no-index*) cmp expected newdir/.git;; + *) test_cmp expected newdir/.git;; + esac && test_cmp expected newdir/here && test_path_is_dir realgitdir/refs ' diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index dc30289f7539ee..6f7cfd9e33f633 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to rmdir \"\$HOME/dir/\" && rm \"\$HOME/.git-credential-cache\" " && - mkdir -p -m 700 "$HOME/dir/" && + mkdir -p "$HOME/dir/" && + chmod 700 "$HOME/dir/" && ln -s "$HOME/dir" "$HOME/.git-credential-cache" && check approve cache <<-\EOF && protocol=https diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index b11126ed478129..74bfa2e9ba060d 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' -test_expect_success SYMLINKS 'symref transaction supports symlinks' ' +test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' ' test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" && git update-ref refs/heads/new @ && test_config core.prefersymlinkrefs true && diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index 1f61b666a7d382..0eee3bb8781b30 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out- echo .. >>expect && echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && test_cmp expect actual && - echo symlink 3 >expect && - echo ../ >>expect && + if test_have_prereq MINGW,SYMLINKS + then + test_write_lines "symlink 2" .. + else + test_write_lines "symlink 3" ../ + fi >expect && echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual && test_cmp expect actual ' test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' ' - echo HEAD: | git cat-file --batch-check >expect && - echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual && - test_cmp expect actual && - echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual && - test_cmp expect actual && + if test_have_prereq !MINGW + then + # The `up-down` and `up-down-trailing` symlinks are normalized + # in MSYS in `winsymlinks` mode and are therefore in a + # different shape than Git expects them. + echo HEAD: | git cat-file --batch-check >expect && + echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual + fi && echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual && test_cmp found actual && echo symlink 7 >expect && diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 8ff2b0c232b485..6e51f892f320bb 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks' ) ' -test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' ' +test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' ' ln -s foo bar && ( cd bar && @@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' ' ) ' -test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' ' +test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' ' ( cd bar && echo "[includeIf \"gitdir/i:BAR/\"]path=bar8" >>.git/config && diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh index df7d4ea52485da..17ff164b0596c9 100755 --- a/t/t1901-repo-structure.sh +++ b/t/t1901-repo-structure.sh @@ -4,27 +4,54 @@ test_description='test git repo structure' . ./test-lib.sh +object_type_disk_usage() { + disk_usage_opt="--disk-usage" + + if test "$2" = "true" + then + disk_usage_opt="--disk-usage=human" + fi + + if test "$1" = "all" + then + git rev-list --all --objects $disk_usage_opt + else + git rev-list --all --objects $disk_usage_opt \ + --filter=object:type=$1 --filter-provided-objects + fi +} + test_expect_success 'empty repository' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && cat >expect <<-\EOF && - | Repository structure | Value | - | -------------------- | ----- | - | * References | | - | * Count | 0 | - | * Branches | 0 | - | * Tags | 0 | - | * Remotes | 0 | - | * Others | 0 | - | | | - | * Reachable objects | | - | * Count | 0 | - | * Commits | 0 | - | * Trees | 0 | - | * Blobs | 0 | - | * Tags | 0 | + | Repository structure | Value | + | -------------------- | ------ | + | * References | | + | * Count | 0 | + | * Branches | 0 | + | * Tags | 0 | + | * Remotes | 0 | + | * Others | 0 | + | | | + | * Reachable objects | | + | * Count | 0 | + | * Commits | 0 | + | * Trees | 0 | + | * Blobs | 0 | + | * Tags | 0 | + | * Inflated size | 0 B | + | * Commits | 0 B | + | * Trees | 0 B | + | * Blobs | 0 B | + | * Tags | 0 B | + | * Disk size | 0 B | + | * Commits | 0 B | + | * Trees | 0 B | + | * Blobs | 0 B | + | * Tags | 0 B | EOF git repo structure >out 2>err && @@ -34,12 +61,12 @@ test_expect_success 'empty repository' ' ) ' -test_expect_success 'repository with references and objects' ' +test_expect_success SHA1 'repository with references and objects' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && - test_commit_bulk 42 && + test_commit_bulk 1005 && git tag -a foo -m bar && oid="$(git rev-parse HEAD)" && @@ -48,22 +75,35 @@ test_expect_success 'repository with references and objects' ' # Also creates a commit, tree, and blob. git notes add -m foo && - cat >expect <<-\EOF && - | Repository structure | Value | - | -------------------- | ----- | - | * References | | - | * Count | 4 | - | * Branches | 1 | - | * Tags | 1 | - | * Remotes | 1 | - | * Others | 1 | - | | | - | * Reachable objects | | - | * Count | 130 | - | * Commits | 43 | - | * Trees | 43 | - | * Blobs | 43 | - | * Tags | 1 | + # The tags disk size is handled specially due to the + # git-rev-list(1) --disk-usage=human option printing the full + # "byte/bytes" unit string instead of just "B". + cat >expect <<-EOF && + | Repository structure | Value | + | -------------------- | ---------- | + | * References | | + | * Count | 4 | + | * Branches | 1 | + | * Tags | 1 | + | * Remotes | 1 | + | * Others | 1 | + | | | + | * Reachable objects | | + | * Count | 3.02 k | + | * Commits | 1.01 k | + | * Trees | 1.01 k | + | * Blobs | 1.01 k | + | * Tags | 1 | + | * Inflated size | 16.03 MiB | + | * Commits | 217.92 KiB | + | * Trees | 15.81 MiB | + | * Blobs | 11.68 KiB | + | * Tags | 132 B | + | * Disk size | $(object_type_disk_usage all true) | + | * Commits | $(object_type_disk_usage commit true) | + | * Trees | $(object_type_disk_usage tree true) | + | * Blobs | $(object_type_disk_usage blob true) | + | * Tags | $(object_type_disk_usage tag) B | EOF git repo structure >out 2>err && @@ -73,7 +113,7 @@ test_expect_success 'repository with references and objects' ' ) ' -test_expect_success 'keyvalue and nul format' ' +test_expect_success SHA1 'keyvalue and nul format' ' test_when_finished "rm -rf repo" && git init repo && ( @@ -81,7 +121,7 @@ test_expect_success 'keyvalue and nul format' ' test_commit_bulk 42 && git tag -a foo -m bar && - cat >expect <<-\EOF && + cat >expect <<-EOF && references.branches.count=1 references.tags.count=1 references.remotes.count=0 @@ -90,6 +130,14 @@ test_expect_success 'keyvalue and nul format' ' objects.trees.count=42 objects.blobs.count=42 objects.tags.count=1 + objects.commits.inflated_size=9225 + objects.trees.inflated_size=28554 + objects.blobs.inflated_size=453 + objects.tags.inflated_size=132 + objects.commits.disk_size=$(object_type_disk_usage commit) + objects.trees.disk_size=$(object_type_disk_usage tree) + objects.blobs.disk_size=$(object_type_disk_usage blob) + objects.tags.disk_size=$(object_type_disk_usage tag) EOF git repo structure --format=keyvalue >out 2>err && diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 93f319a4b29fbb..794f8b5ab4e136 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -350,9 +350,73 @@ test_expect_success 'preferred pack from existing MIDX without bitmaps' ' # the new MIDX git multi-pack-index write --preferred-pack=pack-$pack.pack ) +' + +test_expect_success 'preferred pack cannot be determined without bitmap' ' + test_when_finished "rm -fr preferred-can-be-queried" && + git init preferred-can-be-queried && + ( + cd preferred-can-be-queried && + test_commit initial && + git repack -Adl --write-midx --no-write-bitmap-index && + test_must_fail test-tool read-midx --preferred-pack .git/objects 2>err && + test_grep "could not determine MIDX preferred pack" err && + git repack -Adl --write-midx --write-bitmap-index && + test-tool read-midx --preferred-pack .git/objects + ) +' + +test_midx_is_retained () { + test-tool chmtime =0 .git/objects/pack/multi-pack-index && + ls -l .git/objects/pack/multi-pack-index >expect && + git multi-pack-index write "$@" && + ls -l .git/objects/pack/multi-pack-index >actual && + test_cmp expect actual +} + +test_midx_is_rewritten () { + test-tool chmtime =0 .git/objects/pack/multi-pack-index && + ls -l .git/objects/pack/multi-pack-index >expect && + git multi-pack-index write "$@" && + ls -l .git/objects/pack/multi-pack-index >actual && + ! test_cmp expect actual +} + +test_expect_success 'up-to-date multi-pack-index is retained' ' + test_when_finished "rm -fr midx-up-to-date" && + git init midx-up-to-date && + ( + cd midx-up-to-date && + + # Write the initial pack that contains the most objects. + test_commit first && + test_commit second && + git repack -Ad --write-midx && + test_midx_is_retained && + + # Writing a new bitmap index should cause us to regenerate the MIDX. + test_midx_is_rewritten --bitmap && + test_midx_is_retained --bitmap && + # Ensure that writing a new packfile causes us to rewrite the index. + test_commit incremental && + git repack -d && + test_midx_is_rewritten && + test_midx_is_retained && + + for pack in .git/objects/pack/*.idx + do + basename "$pack" || exit 1 + done >stdin && + test_line_count = 2 stdin && + test_midx_is_retained --stdin-packs stdin.trimmed && + test_midx_is_rewritten --stdin-packs cookies.txt <<-\EOF && - 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue + 127.0.0.1 FALSE /smart_cookies FALSE 0 othername othervalue EOF sort >expect_cookies.txt <<-\EOF && - 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue - 127.0.0.1 FALSE /smart_cookies/repo.git/ FALSE 0 name value - 127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value + 127.0.0.1 FALSE /smart_cookies FALSE 0 othername othervalue + 127.0.0.1 FALSE /smart_cookies/repo.git FALSE 0 name value + 127.0.0.1 FALSE /smart_cookies/repo.git/info FALSE 0 name value EOF git config http.cookiefile cookies.txt && git config http.savecookies true && @@ -351,8 +351,11 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set tag -m "foo" cookie-tag && git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag && - grep "^[^#]" cookies.txt | sort >cookies_stripped.txt && - test_cmp expect_cookies.txt cookies_stripped.txt + # Strip trailing slashes from cookie paths to handle output from both + # old curl ("/smart_cookies/") and new ("/smart_cookies"). + HT=" " && + grep "^[^#]" cookies.txt | sed "s,/$HT,$HT," | sort >cookies_clean.txt && + test_cmp expect_cookies.txt cookies_clean.txt ' test_expect_success 'transfer.hiderefs works over smart-http' ' diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh index 317f33af5a7e60..c1febbae9d778b 100755 --- a/t/t5563-simple-http-auth.sh +++ b/t/t5563-simple-http-auth.sh @@ -469,7 +469,7 @@ test_expect_success 'access using basic auth with wwwauth header empty continuat EOF ' -test_expect_success 'access using basic auth with wwwauth header mixed line-endings' ' +test_expect_success 'access using basic auth with wwwauth header mixed continuations' ' test_when_finished "per_test_cleanup" && set_credential_reply get <<-EOF && @@ -490,7 +490,7 @@ test_expect_success 'access using basic auth with wwwauth header mixed line-endi printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" && printf "id=default response= \r\n" >>"$CHALLENGE" && printf "id=default response=\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && - printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh index 533ac85dc83409..53535a8ebfc393 100755 --- a/t/t6423-merge-rename-directories.sh +++ b/t/t6423-merge-rename-directories.sh @@ -5158,13 +5158,18 @@ test_setup_12m () { git switch B && git rm dir/subdir/file && mkdir dir && - ln -s /dev/null dir/subdir && + if test_have_prereq MINGW + then + cmd //c 'mklink dir\subdir NUL' + else + ln -s /dev/null dir/subdir + fi && git add . && git commit -m "B" ) } -test_expect_success '12m: Change parent of renamed-dir to symlink on other side' ' +test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' ' test_setup_12m && ( cd 12m && diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index 9fc1626fbfde89..98806cdb6fe9b7 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -287,6 +287,41 @@ test_expect_success '--geometric with pack.packSizeLimit' ' ) ' +test_expect_success '--geometric --write-midx retains up-to-date MIDX without bitmap index' ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + test_commit initial && + + test_path_is_missing .git/objects/pack/multi-pack-index && + git repack --geometric=2 --write-midx --no-write-bitmap-index && + test_path_is_file .git/objects/pack/multi-pack-index && + test-tool chmtime =0 .git/objects/pack/multi-pack-index && + + ls -l .git/objects/pack/ >expect && + git repack --geometric=2 --write-midx --no-write-bitmap-index && + ls -l .git/objects/pack/ >actual && + test_cmp expect actual + ) +' + +test_expect_success '--geometric --write-midx retains up-to-date MIDX with bitmap index' ' + test_when_finished "rm -fr repo" && + git init repo && + test_commit -C repo initial && + + test_path_is_missing repo/.git/objects/pack/multi-pack-index && + git -C repo repack --geometric=2 --write-midx --write-bitmap-index && + test_path_is_file repo/.git/objects/pack/multi-pack-index && + test-tool chmtime =0 repo/.git/objects/pack/multi-pack-index && + + ls -l repo/.git/objects/pack/ >expect && + git -C repo repack --geometric=2 --write-midx --write-bitmap-index && + ls -l repo/.git/objects/pack/ >actual && + test_cmp expect actual +' + test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' ' test_when_finished "rm -fr shared member" && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 9b74db55634b16..bf0f67378dbb23 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' c EOF git difftool --symlinks --dir-diff --extcmd ls >output && - grep -v ^/ output >actual && + grep -v ":\$" output >actual && test_cmp expect actual && git difftool --no-symlinks --dir-diff --extcmd ls >output && - grep -v ^/ output >actual && + grep -v ":\$" output >actual && test_cmp expect actual && # The left side contains symlink "c" that points to "b" @@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' EOF git difftool --symlinks --dir-diff --extcmd ls >output && - grep -v ^/ output >actual && + grep -v ":\$" output >actual && test_cmp expect actual && git difftool --no-symlinks --dir-diff --extcmd ls >output && - grep -v ^/ output >actual && + grep -v ":\$" output >actual && test_cmp expect actual ' diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 58a9b328d558f3..570b0c5680fc73 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -117,7 +117,12 @@ sub adjust_dirsep { unlink $tmpfile; # paths -is($r->repo_path, $abs_repo_dir . "/.git", "repo_path"); +my $abs_git_dir = $abs_repo_dir . "/.git"; +if ($^O eq 'msys' or $^O eq 'cygwin') { + $abs_git_dir = `cygpath -am "$abs_repo_dir/.git"`; + $abs_git_dir =~ s/\r?\n?$//; +} +is($r->repo_path, $abs_git_dir, "repo_path"); is($r->wc_path, $abs_repo_dir . "/", "wc_path"); is($r->wc_subdir, "", "wc_subdir initial"); $r->wc_chdir("directory1"); @@ -127,7 +132,7 @@ sub adjust_dirsep { # Object generation in sub directory chdir("directory2"); my $r2 = Git->repository(); -is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)"); +is($r2->repo_path, $abs_git_dir, "repo_path (2)"); is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)"); is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)"); diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 52d7759bf5762d..14e238d24da9ad 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1724,7 +1724,7 @@ test_detect_hash () { esac } -# Detect the hash algorithm in use. +# Detect the ref format in use. test_detect_ref_format () { echo "${GIT_TEST_DEFAULT_REF_FORMAT:-files}" }