diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3da5326f0ba90a..cf341d74dbff21 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -407,7 +407,7 @@ jobs: image: alpine:latest # Supported until 2025-04-02. - jobname: linux32 - image: i386/ubuntu:focal + image: i386/ubuntu:20.04 # A RHEL 8 compatible distro. Supported until 2029-05-31. - jobname: almalinux-8 image: almalinux:8 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0b9a0d82b684f..49f3689b6a15c2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,15 +42,15 @@ test:linux: - jobname: linux-reftable image: ubuntu:rolling CC: clang - - jobname: linux-breaking-changes - image: ubuntu:20.04 - CC: gcc - - jobname: fedora-breaking-changes-meson - image: fedora:latest - jobname: linux-TEST-vars image: ubuntu:20.04 CC: gcc CC_PACKAGE: gcc-8 + - jobname: linux-breaking-changes + image: ubuntu:rolling + CC: gcc + - jobname: fedora-breaking-changes-meson + image: fedora:latest - jobname: linux-leaks image: ubuntu:rolling CC: gcc @@ -60,13 +60,20 @@ test:linux: - jobname: linux-asan-ubsan image: ubuntu:rolling CC: clang + - jobname: linux-meson + image: ubuntu:rolling + CC: gcc - jobname: linux-musl-meson image: alpine:latest + # Supported until 2025-04-02. - jobname: linux32 image: i386/ubuntu:20.04 - - jobname: linux-meson - image: ubuntu:rolling - CC: gcc + # A RHEL 8 compatible distro. Supported until 2029-05-31. + - jobname: almalinux-8 + image: almalinux:8 + # Supported until 2026-08-31. + - jobname: debian-11 + image: debian:11 artifacts: paths: - t/failed-test-artifacts diff --git a/Documentation/RelNotes/2.55.0.adoc b/Documentation/RelNotes/2.55.0.adoc index 4bada0145d7969..b2adfe51bf19e4 100644 --- a/Documentation/RelNotes/2.55.0.adoc +++ b/Documentation/RelNotes/2.55.0.adoc @@ -70,6 +70,9 @@ UI, Workflows & Features that the user meant "git config set foo.bar baz". Give advice when giving an error message. + * "git rev-list" (and "git log" family of commands) learned a new "--max-count-oldest" + that picks oldest N commits in the range instead of the usual newest. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -188,6 +191,19 @@ Performance, Internal Implementation, Development Support etc. variables into 'repo_config_values' to tie them to a specific repository instance, avoiding cross-repository state leakage. + * Streaming revision walks have been optimized by using a priority queue + for date-sorting commits, speeding up walks repositories with many + merges. + + * A recent regression in t7527 that broke TAP output has been fixed, + some other test noise that also broke TAP output has been silenced, + and 'prove' is now configured to fail on invalid TAP output to + prevent future regressions. + + * A handful of inappropriate uses of the_repository have been + rewritten to use the right repository structure instance in the + unpack-trees.c codepath. + Fixes since v2.54 ----------------- @@ -348,6 +364,27 @@ Fixes since v2.54 has been improved. (merge 4a1eb9304a lo/doc-format-patch-subject-prefix later to maint). + * Advanced emulation of kill() used on Windows in GfW has been + upstreamed to improve the symptoms like left-behind .lock files and + that fails to let the child clean-up itself when it gets killed. + (merge 363f1d8b3a js/win-kill-child-more-gently later to maint). + + * The 'git describe --contains --all' command has been fixed to + properly honor the '--match' and '--exclude' options by passing + them down to 'git name-rev' with the appropriate reference + prefixes. + (merge 1891707d1b jk/describe-contains-all-match-fix later to maint). + + * Various typos, grammatical errors, and duplicated words in both + documentation and code comments have been corrected. + (merge dc6068df67 wy/docs-typofixes later to maint). + + * The subprocess handshake during startup has been made gentler by using + packet_read_line_gently() instead of packet_read_line() to prevent the + parent Git process from dying abruptly when a configured subprocess + (e.g., a clean/smudge filter) fails to start. + (merge 061a68e443 mm/subprocess-handshake-fix later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 80f4b802e9 ja/doc-difftool-synopsis-style later to maint). (merge b96490241e jc/doc-timestamps-in-stat later to maint). diff --git a/Documentation/config/sideband.adoc b/Documentation/config/sideband.adoc index 96fade7f5fee39..ff007aeb738a3d 100644 --- a/Documentation/config/sideband.adoc +++ b/Documentation/config/sideband.adoc @@ -13,7 +13,7 @@ sideband.allowControlCharacters:: Allow control sequences that move the cursor. This is disabled by default. `erase`:: - Allow control sequences that erase charactrs. This is + Allow control sequences that erase characters. This is disabled by default. `false`:: Mask all control characters other than line feeds and diff --git a/Documentation/fetch-options.adoc b/Documentation/fetch-options.adoc index 8074004377c1ed..035f780e583cee 100644 --- a/Documentation/fetch-options.adoc +++ b/Documentation/fetch-options.adoc @@ -1,6 +1,6 @@ `--all`:: `--no-all`:: - Fetch all remotes, except for the ones that has the + Fetch all remotes, except for the ones that have the `remote..skipFetchAll` configuration variable set. This overrides the configuration variable `fetch.all`. diff --git a/Documentation/git-format-rev.adoc b/Documentation/git-format-rev.adoc index c40d52e9f6d108..505a52feccd466 100644 --- a/Documentation/git-format-rev.adoc +++ b/Documentation/git-format-rev.adoc @@ -33,7 +33,7 @@ OPTIONS The argument `rev` is also accepted. `text`;; Formats all commit object names found in freeform text. These - must the full object names, i.e. abbreviated hexidecimal object + must be full object names, i.e. abbreviated hexadecimal object names will not be interpreted. + Anything that is parsed as an object name but that is not found to be a diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc index 9e666b9f10bc25..eaee6ee8399c57 100644 --- a/Documentation/rev-list-options.adoc +++ b/Documentation/rev-list-options.adoc @@ -16,7 +16,10 @@ ordering and formatting options, such as `--reverse`. `-`:: `-n `:: `--max-count=`:: - Limit the output to __ commits. + Limit the output to the first __ commits that would be shown. + +`--max-count-oldest=`:: + Limit the output to the last __ commits that would be shown. `--skip=`:: Skip __ commits before starting to show the commit output. diff --git a/builtin/describe.c b/builtin/describe.c index 1c47d7c0b7c38d..faaf44cec57364 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -712,13 +712,25 @@ int cmd_describe(int argc, NULL); if (always) strvec_push(&args, "--always"); - if (!all) { + if (!all) strvec_push(&args, "--tags"); + + for_each_string_list_item(item, &patterns) + strvec_pushf(&args, "--refs=refs/tags/%s", item->string); + for_each_string_list_item(item, &exclude_patterns) + strvec_pushf(&args, "--exclude=refs/tags/%s", item->string); + + if (all) { for_each_string_list_item(item, &patterns) - strvec_pushf(&args, "--refs=refs/tags/%s", item->string); + strvec_pushf(&args, "--refs=refs/heads/%s", item->string); for_each_string_list_item(item, &exclude_patterns) - strvec_pushf(&args, "--exclude=refs/tags/%s", item->string); + strvec_pushf(&args, "--exclude=refs/heads/%s", item->string); + for_each_string_list_item(item, &patterns) + strvec_pushf(&args, "--refs=refs/remotes/%s", item->string); + for_each_string_list_item(item, &exclude_patterns) + strvec_pushf(&args, "--exclude=refs/remotes/%s", item->string); } + if (argc) strvec_pushv(&args, argv); else diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 1cc55e5b2c3cfe..8a1709a1abeb9e 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -4281,6 +4281,7 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs traverse_commit_list(&revs, show_cruft_commit, show_cruft_object, NULL); stop_progress(&progress_state); + release_revisions(&revs); } static void read_cruft_objects(void) diff --git a/ci/lib.sh b/ci/lib.sh index 6e3799cfc3ccd5..b939110a6eefcf 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -254,7 +254,7 @@ then CI_OS_NAME=osx JOBS=$(nproc) ;; - *,alpine:*|*,fedora:*|*,ubuntu:*|*,i386/ubuntu:*) + *,almalinux:*|*,alpine:*|*,debian:*|*,fedora:*|*,ubuntu:*|*,i386/ubuntu:*) CI_OS_NAME=linux JOBS=$(nproc) ;; diff --git a/combine-diff.c b/combine-diff.c index b7998620687ed7..720768ce41b5df 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -666,7 +666,7 @@ static int make_hunks(struct sline *sline, unsigned long cnt, * (-) line, which records from what parents the line * was removed; this line does not appear in the result. * then check the set of parents the result has difference - * from, from all lines. If there are lines that has + * from, from all lines. If there are lines that have * different set of parents that the result has differences * from, that means we have more than two versions. * diff --git a/commit.c b/commit.c index fd8723502ed332..f1717ccbdc7fcc 100644 --- a/commit.c +++ b/commit.c @@ -760,19 +760,6 @@ void commit_list_free(struct commit_list *list) pop_commit(&list); } -struct commit_list * commit_list_insert_by_date(struct commit *item, struct commit_list **list) -{ - struct commit_list **pp = list; - struct commit_list *p; - while ((p = *pp) != NULL) { - if (p->item->date < item->date) { - break; - } - pp = &p->next; - } - return commit_list_insert(item, pp); -} - static int commit_list_compare_by_date(const struct commit_list *a, const struct commit_list *b) { diff --git a/commit.h b/commit.h index 5352056f87abfa..1061ed791bcad6 100644 --- a/commit.h +++ b/commit.h @@ -191,8 +191,6 @@ int commit_list_contains(struct commit *item, struct commit_list **commit_list_append(struct commit *commit, struct commit_list **next); unsigned commit_list_count(const struct commit_list *l); -struct commit_list *commit_list_insert_by_date(struct commit *item, - struct commit_list **list); void commit_list_sort_by_date(struct commit_list **list); /* Shallow copy of the input list */ diff --git a/compat/mingw.c b/compat/mingw.c index aa7525f419cb64..41e055f7de885e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -13,6 +13,7 @@ #include "symlinks.h" #include "trace2.h" #include "win32.h" +#include "win32/exit-process.h" #include "win32/lazyload.h" #include "wrapper.h" #include @@ -2251,16 +2252,28 @@ int mingw_execvp(const char *cmd, char *const *argv) int mingw_kill(pid_t pid, int sig) { if (pid > 0 && sig == SIGTERM) { - HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - - if (TerminateProcess(h, -1)) { + HANDLE h = OpenProcess(PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | PROCESS_VM_WRITE | + PROCESS_VM_READ | PROCESS_TERMINATE, + FALSE, pid); + int ret; + + if (h) + ret = exit_process(h, 128 + sig); + else { + h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); + if (!h) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + ret = terminate_process_tree(h, 128 + sig); + } + if (ret) { + errno = err_win_to_posix(GetLastError()); CloseHandle(h); - return 0; } - - errno = err_win_to_posix(GetLastError()); - CloseHandle(h); - return -1; + return ret; } else if (pid > 0 && sig == 0) { HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (h) { @@ -3610,7 +3623,14 @@ static void adjust_symlink_flags(void) symlink_file_flags |= 2; symlink_directory_flags |= 2; } +} +static BOOL WINAPI handle_ctrl_c(DWORD ctrl_type) +{ + if (ctrl_type != CTRL_C_EVENT) + return FALSE; /* we did not handle this */ + mingw_raise(SIGINT); + return TRUE; /* we did handle this */ } #ifdef _MSC_VER @@ -3647,6 +3667,8 @@ int wmain(int argc, const wchar_t **wargv) #endif #endif + SetConsoleCtrlHandler(handle_ctrl_c, TRUE); + maybe_redirect_std_handles(); adjust_symlink_flags(); diff --git a/compat/win32/exit-process.h b/compat/win32/exit-process.h new file mode 100644 index 00000000000000..d53989884cfb0c --- /dev/null +++ b/compat/win32/exit-process.h @@ -0,0 +1,165 @@ +#ifndef EXIT_PROCESS_H +#define EXIT_PROCESS_H + +/* + * This file contains functions to terminate a Win32 process, as gently as + * possible. + * + * At first, we will attempt to inject a thread that calls ExitProcess(). If + * that fails, we will fall back to terminating the entire process tree. + * + * For simplicity, these functions are marked as file-local. + */ + +#include + +/* + * Terminates the process corresponding to the process ID and all of its + * directly and indirectly spawned subprocesses. + * + * This way of terminating the processes is not gentle: the processes get + * no chance of cleaning up after themselves (closing file handles, removing + * .lock files, terminating spawned processes (if any), etc). + */ +static int terminate_process_tree(HANDLE main_process, int exit_status) +{ + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 entry; + DWORD pids[16384]; + int max_len = sizeof(pids) / sizeof(*pids), i, len, ret = 0; + pid_t pid = GetProcessId(main_process); + + pids[0] = (DWORD)pid; + len = 1; + + /* + * Even if Process32First()/Process32Next() seem to traverse the + * processes in topological order (i.e. parent processes before + * child processes), there is nothing in the Win32 API documentation + * suggesting that this is guaranteed. + * + * Therefore, run through them at least twice and stop when no more + * process IDs were added to the list. + */ + for (;;) { + int orig_len = len; + + memset(&entry, 0, sizeof(entry)); + entry.dwSize = sizeof(entry); + + if (!Process32First(snapshot, &entry)) + break; + + do { + for (i = len - 1; i >= 0; i--) { + if (pids[i] == entry.th32ProcessID) + break; + if (pids[i] == entry.th32ParentProcessID) + pids[len++] = entry.th32ProcessID; + } + } while (len < max_len && Process32Next(snapshot, &entry)); + + if (orig_len == len || len >= max_len) + break; + } + + for (i = len - 1; i > 0; i--) { + HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, pids[i]); + + if (process) { + if (!TerminateProcess(process, exit_status)) + ret = -1; + CloseHandle(process); + } + } + if (!TerminateProcess(main_process, exit_status)) + ret = -1; + CloseHandle(main_process); + + return ret; +} + +/** + * Determine whether a process runs in the same architecture as the current + * one. That test is required before we assume that GetProcAddress() returns + * a valid address *for the target process*. + */ +static inline int process_architecture_matches_current(HANDLE process) +{ + static BOOL current_is_wow = -1; + BOOL is_wow; + + if (current_is_wow == -1 && + !IsWow64Process (GetCurrentProcess(), ¤t_is_wow)) + current_is_wow = -2; + if (current_is_wow == -2) + return 0; /* could not determine current process' WoW-ness */ + if (!IsWow64Process (process, &is_wow)) + return 0; /* cannot determine */ + return is_wow == current_is_wow; +} + +/** + * Inject a thread into the given process that runs ExitProcess(). + * + * Note: as kernel32.dll is loaded before any process, the other process and + * this process will have ExitProcess() at the same address. + * + * This function expects the process handle to have the access rights for + * CreateRemoteThread(): PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, + * PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ. + * + * The idea comes from the Dr Dobb's article "A Safer Alternative to + * TerminateProcess()" by Andrew Tucker (July 1, 1999), + * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 + * + * If this method fails, we fall back to running terminate_process_tree(). + */ +static int exit_process(HANDLE process, int exit_code) +{ + DWORD code; + + if (GetExitCodeProcess(process, &code) && code == STILL_ACTIVE) { + static int initialized; + static LPTHREAD_START_ROUTINE exit_process_address; + PVOID arg = (PVOID)(intptr_t)exit_code; + DWORD thread_id; + HANDLE thread = NULL; + + if (!initialized) { + HINSTANCE kernel32 = GetModuleHandleA("kernel32"); + if (!kernel32) + die("BUG: cannot find kernel32"); + exit_process_address = + (LPTHREAD_START_ROUTINE)(void (*)(void)) + GetProcAddress(kernel32, "ExitProcess"); + initialized = 1; + } + if (!exit_process_address || + !process_architecture_matches_current(process)) + return terminate_process_tree(process, exit_code); + + thread = CreateRemoteThread(process, NULL, 0, + exit_process_address, + arg, 0, &thread_id); + if (thread) { + CloseHandle(thread); + /* + * If the process survives for 10 seconds (a completely + * arbitrary value picked from thin air), fall back to + * killing the process tree via TerminateProcess(). + */ + if (WaitForSingleObject(process, 10000) == + WAIT_OBJECT_0) { + CloseHandle(process); + return 0; + } + } + + return terminate_process_tree(process, exit_code); + } + + return 0; +} + +#endif diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index a8e7c6ddbfb2b1..e8757877104eb9 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2195,7 +2195,7 @@ __git_log_common_options=" --not --all --branches --tags --remotes --first-parent --merges --no-merges - --max-count= + --max-count= --max-count-oldest= --max-age= --since= --after= --min-age= --until= --before= --min-parents= --max-parents= diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 18d2b564487e91..4194687cfbb9b5 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -75,7 +75,7 @@ test_create_pre2_32_repo () { # # Create a simple subtree on a new branch named ORPHAN in REPO. # The subtree is then merged into the current branch of REPO, -# under PREFIX. The generated subtree has has one commit +# under PREFIX. The generated subtree has one commit # with subject and tag FILENAME with a single file "FILENAME.t" # # When this method returns: diff --git a/csum-file.h b/csum-file.h index a9b390d3366875..a270738a7a3cad 100644 --- a/csum-file.h +++ b/csum-file.h @@ -52,7 +52,7 @@ struct hashfd_options { */ struct progress *progress; - /* The length of the buffer that shall be used read read data. */ + /* The length of the buffer that shall be used to read data. */ size_t buffer_len; }; diff --git a/date.c b/date.c index 05b78d852f0705..014065b419aee7 100644 --- a/date.c +++ b/date.c @@ -1074,7 +1074,7 @@ void datestamp(struct strbuf *out) * * The tm->tm_mday field has an additional logic of using negative values * for date adjustments: -2 means yesterday and -3 the day before that, - * and so on. The idea is to deref such adjustments until we are sure + * and so on. The idea is to defer such adjustments until we are sure * there's no explicit mday specification in the approxidate string. */ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec) diff --git a/delta-islands.c b/delta-islands.c index f4d2468790ce4f..e71a7e1c055dc8 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -527,7 +527,7 @@ void free_island_marks(void) kh_destroy_oid_map(island_marks); } - /* detect use-after-free with a an address which is never valid: */ + /* detect use-after-free with an address which is never valid: */ island_marks = (void *)-1; } diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index a52d569911c48e..b0915be86fc475 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -203,7 +203,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o, for (i = 0; i < q->nr; i++) diff_free_filepair(q->queue[i]); } else { - /* Showing only the filepairs that has the needle */ + /* Showing only the filepairs that have the needle */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (pickaxe_match(p, o, regexp, kws, fn)) diff --git a/odb.h b/odb.h index 73553ed5a7b1ea..0030467a52a4e5 100644 --- a/odb.h +++ b/odb.h @@ -40,7 +40,7 @@ struct object_database { struct repository *repo; /* - * State of current current object database transaction. Only one + * State of current object database transaction. Only one * transaction may be pending at a time. Is NULL when no transaction is * configured. */ diff --git a/parse-options.c b/parse-options.c index a676da86f5d617..f4647e0099ea99 100644 --- a/parse-options.c +++ b/parse-options.c @@ -1149,7 +1149,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx, (ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) { /* * Found an unknown option given to a command with - * subcommands that has a default operation mode: + * subcommands that have a default operation mode: * we treat this option and all remaining args as * arguments meant to that default operation mode. * So we are done parsing. diff --git a/replay.h b/replay.h index 1851a07705ab03..faf95c7459e594 100644 --- a/replay.h +++ b/replay.h @@ -32,7 +32,7 @@ struct replay_revisions_options { /* * Starting point at which to create the new commits; must be a - * committish. References pointing at decendants of `onto` will be + * committish. References pointing at descendants of `onto` will be * updated to point to the new commits. */ const char *onto; diff --git a/rerere.c b/rerere.c index 0296700f9f448f..28a740b771cf99 100644 --- a/rerere.c +++ b/rerere.c @@ -548,7 +548,7 @@ static int check_one_conflict(struct index_state *istate, int i, int *type) /* * Scan the index and find paths that have conflicts that rerere can - * handle, i.e. the ones that has both stages #2 and #3. + * handle, i.e. the ones that have both stages #2 and #3. * * NEEDSWORK: we do not record or replay a previous "resolve by * deletion" for a delete-modify conflict, as that is inherently risky diff --git a/revision.c b/revision.c index 3e592bf71901e3..e91d7e1f11356a 100644 --- a/revision.c +++ b/revision.c @@ -1116,7 +1116,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) } static int process_parents(struct rev_info *revs, struct commit *commit, - struct commit_list **list, struct prio_queue *queue) + struct prio_queue *queue) { struct commit_list *parent = commit->parents; unsigned pass_flags; @@ -1158,8 +1158,6 @@ static int process_parents(struct rev_info *revs, struct commit *commit, if (p->object.flags & SEEN) continue; p->object.flags |= (SEEN | NOT_USER_GIVEN); - if (list) - commit_list_insert_by_date(p, list); if (queue) prio_queue_put(queue, p); if (revs->exclude_first_parent_only) @@ -1207,8 +1205,6 @@ static int process_parents(struct rev_info *revs, struct commit *commit, p->object.flags |= pass_flags | CHILD_VISITED; if (!(p->object.flags & SEEN)) { p->object.flags |= (SEEN | NOT_USER_GIVEN); - if (list) - commit_list_insert_by_date(p, list); if (queue) prio_queue_put(queue, p); } @@ -1470,7 +1466,7 @@ static int limit_list(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; - if (process_parents(revs, commit, NULL, &queue) < 0) { + if (process_parents(revs, commit, &queue) < 0) { clear_prio_queue(&queue); return -1; } @@ -2343,10 +2339,28 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } if ((argcount = parse_long_opt("max-count", argv, &optarg))) { + if (revs->max_count_type == 1) + die_for_incompatible_opt2(1, "--max-count", 1, + "--max-count-oldest"); revs->max_count = parse_count(optarg); revs->no_walk = 0; + revs->max_count_type = 0; return argcount; + } else if ((argcount = parse_long_opt("max-count-oldest", argv, &optarg))) { + if (revs->max_count_type == 0 && revs->max_count != -1) + die_for_incompatible_opt2(1, "--max-count", 1, + "--max-count-oldest"); + if (revs->skip_count > 0) + die_for_incompatible_opt2(1, "--skip", 1, + "--max-count-oldest"); + revs->max_count = parse_count(optarg); + revs->no_walk = 0; + revs->max_count_type = 1; + revs->max_count_stage = 0; } else if ((argcount = parse_long_opt("skip", argv, &optarg))) { + if (revs->max_count_type == 1) + die_for_incompatible_opt2(1, "--skip", 1, + "--max-count-oldest"); revs->skip_count = parse_count(optarg); return argcount; } else if ((*arg == '-') && isdigit(arg[1])) { @@ -3268,6 +3282,7 @@ static void free_void_commit_list(void *list) void release_revisions(struct rev_info *revs) { commit_list_free(revs->commits); + clear_prio_queue(&revs->commit_queue); commit_list_free(revs->ancestry_path_bottoms); release_display_notes(&revs->notes_opt); object_array_clear(&revs->pending); @@ -3737,7 +3752,7 @@ static void explore_walk_step(struct rev_info *revs) if (revs->max_age != -1 && (c->date < revs->max_age)) c->object.flags |= UNINTERESTING; - if (process_parents(revs, c, NULL, NULL) < 0) + if (process_parents(revs, c, NULL) < 0) return; if (c->object.flags & UNINTERESTING) @@ -3913,7 +3928,7 @@ static void expand_topo_walk(struct rev_info *revs, struct commit *commit) { struct commit_list *p; struct topo_walk_info *info = revs->topo_walk_info; - if (process_parents(revs, commit, NULL, NULL) < 0) { + if (process_parents(revs, commit, NULL) < 0) { if (!revs->ignore_missing_links) die("Failed to traverse parents of commit %s", oid_to_hex(&commit->object.oid)); @@ -3949,6 +3964,13 @@ static void expand_topo_walk(struct rev_info *revs, struct commit *commit) } } +void rev_info_commit_list_to_queue(struct rev_info *revs) +{ + while (revs->commits) + prio_queue_put(&revs->commit_queue, pop_commit(&revs->commits)); +} + + int prepare_revision_walk(struct rev_info *revs) { int i; @@ -4017,7 +4039,7 @@ static enum rewrite_result rewrite_one_1(struct rev_info *revs, for (;;) { struct commit *p = *pp; if (!revs->limited) - if (process_parents(revs, p, NULL, queue) < 0) + if (process_parents(revs, p, queue) < 0) return rewrite_one_error; if (p->object.flags & UNINTERESTING) return rewrite_one_ok; @@ -4031,27 +4053,18 @@ static enum rewrite_result rewrite_one_1(struct rev_info *revs, } } -static void merge_queue_into_list(struct prio_queue *q, struct commit_list **list) +static void merge_queue_into_prio_queue(struct prio_queue *from, + struct prio_queue *to) { - while (q->nr) { - struct commit *item = prio_queue_peek(q); - struct commit_list *p = *list; - - if (p && p->item->date >= item->date) - list = &p->next; - else { - p = commit_list_insert(item, list); - list = &p->next; /* skip newly added item */ - prio_queue_get(q); /* pop item */ - } - } + while (from->nr) + prio_queue_put(to, prio_queue_get(from)); } static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp) { struct prio_queue queue = { compare_commits_by_commit_date }; enum rewrite_result ret = rewrite_one_1(revs, pp, &queue); - merge_queue_into_list(&queue, &revs->commits); + merge_queue_into_prio_queue(&queue, &revs->commit_queue); clear_prio_queue(&queue); return ret; } @@ -4338,22 +4351,57 @@ static void track_linear(struct rev_info *revs, struct commit *commit) revs->previous_parents = commit_list_copy(commit->parents); } +enum rev_walk_mode { + REV_WALK_REFLOG, + REV_WALK_TOPO, + REV_WALK_LIMITED, + REV_WALK_NO_WALK, + REV_WALK_STREAMING, +}; + +static enum rev_walk_mode get_walk_mode(struct rev_info *revs) +{ + if (revs->reflog_info) + return REV_WALK_REFLOG; + if (revs->topo_walk_info) + return REV_WALK_TOPO; + if (revs->limited) + return REV_WALK_LIMITED; + if (revs->no_walk) + return REV_WALK_NO_WALK; + return REV_WALK_STREAMING; +} + static struct commit *get_revision_1(struct rev_info *revs) { + enum rev_walk_mode mode = get_walk_mode(revs); + + if (mode == REV_WALK_STREAMING && revs->commits) + rev_info_commit_list_to_queue(revs); + while (1) { struct commit *commit; - if (revs->reflog_info) + switch (mode) { + case REV_WALK_REFLOG: commit = next_reflog_entry(revs->reflog_info); - else if (revs->topo_walk_info) + break; + case REV_WALK_TOPO: commit = next_topo_commit(revs); - else + break; + case REV_WALK_LIMITED: + case REV_WALK_NO_WALK: commit = pop_commit(&revs->commits); + break; + case REV_WALK_STREAMING: + commit = prio_queue_get(&revs->commit_queue); + break; + } if (!commit) return NULL; - if (revs->reflog_info) + if (mode == REV_WALK_REFLOG) commit->object.flags &= ~(ADDED | SEEN | SHOWN); /* @@ -4361,20 +4409,29 @@ static struct commit *get_revision_1(struct rev_info *revs) * the parents here. We also need to do the date-based limiting * that we'd otherwise have done in limit_list(). */ - if (!revs->limited) { - if (revs->max_age != -1 && - comparison_date(revs, commit) < revs->max_age) - continue; + if (mode != REV_WALK_LIMITED && + revs->max_age != -1 && + comparison_date(revs, commit) < revs->max_age) + continue; - if (revs->reflog_info) - try_to_simplify_commit(revs, commit); - else if (revs->topo_walk_info) - expand_topo_walk(revs, commit); - else if (process_parents(revs, commit, &revs->commits, NULL) < 0) { + switch (mode) { + case REV_WALK_REFLOG: + try_to_simplify_commit(revs, commit); + break; + case REV_WALK_TOPO: + expand_topo_walk(revs, commit); + break; + case REV_WALK_STREAMING: + if (process_parents(revs, commit, + &revs->commit_queue) < 0) { if (!revs->ignore_missing_links) die("Failed to traverse parents of commit %s", - oid_to_hex(&commit->object.oid)); + oid_to_hex(&commit->object.oid)); } + break; + case REV_WALK_NO_WALK: + case REV_WALK_LIMITED: + break; } switch (simplify_commit(revs, commit)) { @@ -4536,15 +4593,91 @@ static struct commit *get_revision_internal(struct rev_info *revs) return c; } +static void retrieve_oldest_commits(struct rev_info *revs, + struct commit_list **queue) +{ + struct commit *c; + int max_count = revs->max_count; + int queuei_count = 0; + int queueo_count = 0; + struct commit_list *queueo = NULL; + struct commit_list *queuei = NULL; + struct commit_list *reversed_queue = NULL; + struct commit_list *p; + + revs->max_count = -1; + while ((c = get_revision_internal(revs))) { + /* + * We need to reset SHOWN status otherwise --graph breaks. + * It is fine to do, get_revision_internal() doesn't consider + * children commits as they have been already processed and the + * traversal happens only child to parent. + * + * We do this because the --graph machinery relies on the status + * of the parents to decide how the printing will happen. + * + * We can't simply replace this instruction with a + * graph_update() as it doesn't do the actualy printing, we'd + * have to remove any commit that goes over the + * --max-count-oldest limit from revs->graph. + */ + c->object.flags &= ~(SHOWN | CHILD_SHOWN); + commit_list_insert(c, &queuei); + if (!(c->object.flags & BOUNDARY)) + queuei_count++; + while (queuei_count + queueo_count > max_count) { + if (!queueo_count) { + while ((c = pop_commit(&queuei))) { + commit_list_insert(c, &queueo); + queueo_count++; + } + queuei_count = 0; + } + c = pop_commit(&queueo); + queueo_count--; + /* We need to do this otherwise we'll discard the + * commits that go over the --max-count-oldest limit but + * not their respective boundaries. This matters only if + * we're discarding the commit right before the boundary. + */ + for (p = c->parents; p; p = p->next) + p->item->object.flags &= ~CHILD_SHOWN; + } + } + + while ((c = pop_commit(&queueo))) + commit_list_insert(c, &reversed_queue); + while ((c = pop_commit(&queuei))) + commit_list_insert(c, &queueo); + while ((c = pop_commit(&queueo))) + commit_list_insert(c, &reversed_queue); + + while ((c = pop_commit(&reversed_queue))) + commit_list_insert(c, queue); +} + struct commit *get_revision(struct rev_info *revs) { struct commit *c; struct commit_list *reversed; + struct commit_list *queue = NULL; + struct commit_list *p; + + if (revs->max_count_type == 1 && !revs->max_count_stage) { + retrieve_oldest_commits(revs, &queue); + commit_list_free(revs->commits); + revs->commits = queue; + revs->max_count_stage = 1; + } if (revs->reverse) { reversed = NULL; - while ((c = get_revision_internal(revs))) - commit_list_insert(c, &reversed); + if (revs->max_count_type == 1) + while ((c = pop_commit(&revs->commits))) + commit_list_insert(c, &reversed); + else + while ((c = get_revision_internal(revs))) + commit_list_insert(c, &reversed); commit_list_free(revs->commits); revs->commits = reversed; revs->reverse = 0; @@ -4558,7 +4691,18 @@ struct commit *get_revision(struct rev_info *revs) return c; } - c = get_revision_internal(revs); + if (revs->max_count_stage) { + c = pop_commit(&revs->commits); + if (c) { + c->object.flags |= SHOWN; + if (!(c->object.flags & BOUNDARY)) + for (p = c->parents; p; p = p->next) + p->item->object.flags |= CHILD_SHOWN; + } + } else { + c = get_revision_internal(revs); + } + if (c && revs->graph) graph_update(revs->graph, c); if (!c) { diff --git a/revision.h b/revision.h index c9a11827cc702e..00c392be37195d 100644 --- a/revision.h +++ b/revision.h @@ -12,6 +12,7 @@ #include "decorate.h" #include "ident.h" #include "list-objects-filter-options.h" +#include "prio-queue.h" #include "strvec.h" /** @@ -122,8 +123,14 @@ struct oidset; struct topo_walk_info; struct rev_info { - /* Starting list */ + /* + * Work queue of commits, stored as either a linked list or a + * priority queue, but never both at the same time. + * rev_info_commit_list_to_queue() converts list to queue. + */ struct commit_list *commits; + struct prio_queue commit_queue; + struct object_array pending; struct repository *repo; @@ -310,6 +317,8 @@ struct rev_info { /* special limits */ int skip_count; int max_count; + unsigned int max_count_type:1; + unsigned int max_count_stage:1; timestamp_t max_age; timestamp_t max_age_as_filter; timestamp_t min_age; @@ -401,6 +410,7 @@ struct rev_info { * uninitialized. */ #define REV_INFO_INIT { \ + .commit_queue = { .compare = compare_commits_by_commit_date }, \ .abbrev = DEFAULT_ABBREV, \ .simplify_history = 1, \ .pruning.flags.recursive = 1, \ @@ -479,6 +489,8 @@ void reset_revision_walk(void); */ int prepare_revision_walk(struct rev_info *revs); +/* Drain the commits linked list into the priority queue. */ +void rev_info_commit_list_to_queue(struct rev_info *revs); /** * Takes a pointer to a `rev_info` structure and iterates over it, returning a * `struct commit *` each time you call it. The end of the revision list is diff --git a/sub-process.c b/sub-process.c index 83bf0a0e82e56d..2d5c965169727b 100644 --- a/sub-process.c +++ b/sub-process.c @@ -132,17 +132,24 @@ static int handshake_version(struct child_process *process, if (packet_flush_gently(process->in)) return error("Could not write flush packet"); - if (!(line = packet_read_line(process->out, NULL)) || - !skip_prefix(line, welcome_prefix, &p) || + if (packet_read_line_gently(process->out, NULL, &line) < 0) + return error("could not read greeting from subprocess '%s'", + process->args.v[0]); + if (!line || !skip_prefix(line, welcome_prefix, &p) || strcmp(p, "-server")) return error("Unexpected line '%s', expected %s-server", line ? line : "", welcome_prefix); - if (!(line = packet_read_line(process->out, NULL)) || - !skip_prefix(line, "version=", &p) || + if (packet_read_line_gently(process->out, NULL, &line) < 0) + return error("could not read version from subprocess '%s'", + process->args.v[0]); + if (!line || !skip_prefix(line, "version=", &p) || strtol_i(p, 10, chosen_version)) return error("Unexpected line '%s', expected version", line ? line : ""); - if ((line = packet_read_line(process->out, NULL))) + if (packet_read_line_gently(process->out, NULL, &line) < 0) + return error("could not read version flush from subprocess '%s'", + process->args.v[0]); + if (line) return error("Unexpected line '%s', expected flush", line); /* Check to make sure that the version received is supported */ @@ -171,8 +178,15 @@ static int handshake_capabilities(struct child_process *process, if (packet_flush_gently(process->in)) return error("Could not write flush packet"); - while ((line = packet_read_line(process->out, NULL))) { + for (;;) { const char *p; + int len = packet_read_line_gently(process->out, NULL, &line); + + if (len < 0) + return error("could not read capabilities from subprocess '%s'", + process->args.v[0]); + if (!line) + break; if (!skip_prefix(line, "capability=", &p)) continue; diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index d22e9c684a495a..910886818768f0 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -65,6 +65,7 @@ pidfile="$TRASH_DIRECTORY/p4d.pid" stop_p4d_and_watchdog () { kill -9 $p4d_pid $watchdog_pid + wait $p4d_pid $watchdog_pid 2>/dev/null } # git p4 submit generates a temp file, which will @@ -174,8 +175,7 @@ retry_until_success () { } stop_and_cleanup_p4d () { - kill -9 $p4d_pid $watchdog_pid - wait $p4d_pid + stop_p4d_and_watchdog rm -rf "$db" "$cli" "$pidfile" } diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index f0d50d769e9fc5..033b00a364ee7a 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -857,6 +857,23 @@ test_expect_success 'invalid process filter must fail (and not hang!)' ' ) ' +test_expect_success 'missing process filter with space in path does not die' ' + test_config_global filter.protocol.process "/non existent/tool" && + test_config_global filter.protocol.required true && + rm -rf repo && + mkdir repo && + ( + cd repo && + git init && + + echo "*.r filter=protocol" >.gitattributes && + + cp "$TEST_ROOT/test.o" test.r && + test_must_fail git add . 2>git-stderr.log && + test_grep "clean filter.*protocol.*failed" git-stderr.log + ) +' + test_expect_success 'delayed checkout in process filter' ' test_config_global filter.a.process "test-tool rot13-filter --log=a.log clean smudge delay" && test_config_global filter.a.required true && diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 05cee9e41bb48d..75edb0eb38c039 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -1882,6 +1882,46 @@ test_expect_success 'log --graph with --name-status' ' test_cmp_graph --name-status tangle..reach ' +test_expect_success 'log --max-count-oldest=3 --oneline' ' + test_when_finished rm expect && + git log --oneline | tail -n3 >expect && + git log --oneline --max-count-oldest=3 >actual && + test_cmp expect actual +' + +test_expect_success 'log --max-count-oldest=3 --reverse --oneline' ' + test_when_finished rm expect && + git log --oneline --reverse | head -n3 >expect && + git log --oneline --max-count-oldest=3 --reverse >actual && + test_cmp expect actual +' + +test_expect_success 'log --max-count-oldest with --max-count' ' + test_when_finished rm stderr && + test_must_fail git log --max-count-oldest=3 --max-count=3 2>stderr && + test_grep "cannot be used together" stderr +' + +test_expect_success 'log --max-count-oldest with --skip' ' + test_when_finished rm stderr && + test_must_fail git log --max-count-oldest=3 --skip=1 2>stderr && + test_grep "cannot be used together" stderr +' + +test_expect_success 'log --max-count-oldest=1000 --graph --boundary' ' + test_when_finished rm expect actual && + git log --graph --boundary >expect && + git log --max-count-oldest=1000 --graph --boundary >actual && + test_cmp expect actual +' + +test_expect_success 'log --oneline --graph --boundary --max-count-oldest=1' ' + test_when_finished rm -f actual && + git log --oneline --graph --boundary --max-count-oldest=1 \ + HEAD~1..HEAD >actual && + test_line_count = 2 actual +' + cat >expect <<-\EOF * reach | diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index 249548eb9bc159..c9817c1b354810 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -180,7 +180,7 @@ test_expect_success 'mailmap.file set' ' git shortlog HEAD >actual && test_cmp expect actual && - # The internal_mailmap/.mailmap file is an a subdirectory, but + # The internal_mailmap/.mailmap file is in a subdirectory, but # as shown here it can also be outside the repository test_when_finished "rm -rf sub-repo" && git clone . sub-repo && diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 8ee3d2c37d0253..4d72033e391d6a 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -359,6 +359,28 @@ test_expect_success 'describe --contains and --no-match' ' test_cmp expect actual ' +test_expect_success 'describe --contains --all --match no matching commit' ' + echo "tags/A^0" >expect && + tagged_commit=$(git rev-parse "refs/tags/A^0") && + test_must_fail git describe --contains --all --match="B" $tagged_commit +' + +check_describe "tags/A^0" --contains --all --match="A" $(git rev-parse "refs/tags/A^0") + +check_describe "branch_A" --contains --all --match="branch*" $(git rev-parse "refs/tags/A^0") + +check_describe "branch_C~1" --contains --all --match="branch*" --exclude="branch_A" $(git rev-parse "refs/tags/A^0") + +check_describe "branch_A" --contains --all \ + --exclude="A" --exclude="c" --exclude="test*" --exclude="origin/remote_branch_A" \ + $(git rev-parse "refs/tags/A^0") + +check_describe "remotes/origin/remote_branch_A" --contains --all --match="origin/remote*" $(git rev-parse "refs/tags/A^0") + +check_describe "remotes/origin/remote_branch_C~1" --contains --all \ + --match="origin/remote*" --exclude="origin/remote_branch_A" \ + $(git rev-parse "refs/tags/A^0") + test_expect_success 'setup and absorb a submodule' ' test_create_repo sub1 && test_commit -C sub1 initial && diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index b63c162f9bac3f..d881e27466c18e 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -25,7 +25,8 @@ maybe_timeout () { "$@" fi } -verify_fsmonitor_works () { + +test_lazy_prereq FSMONITOR_WORKS ' git init test_fsmonitor_smoke || return 1 GIT_TRACE_FSMONITOR="$PWD/smoke.trace" && @@ -50,9 +51,9 @@ verify_fsmonitor_works () { ret=$? rm -rf test_fsmonitor_smoke smoke.trace return $ret -} +' -if ! verify_fsmonitor_works +if ! test_have_prereq FSMONITOR_WORKS then skip_all="filesystem does not deliver fsmonitor events (container/overlayfs?)" test_done diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 1b195bee599a37..d61c4a4d73c390 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -18,8 +18,9 @@ test_invalid_grep_expression() { ' } -LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' && - test_set_prereq MB_REGEX +test_lazy_prereq MB_REGEX ' + LC_ALL=en_US.UTF-8 test-tool regex "^.$" "¿" +' cat >hello.c < diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index af28b01fefa49c..1ab98b9c373a7e 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -232,7 +232,7 @@ test_expect_success POSIXPERM,SYMLINKS "$name" ' test_cmp expected.$(test_oid algo) a ' -test_expect_success 'exit if remote refs are ambigious' ' +test_expect_success 'exit if remote refs are ambiguous' ' git config --add svn-remote.svn.fetch \ bar:refs/remotes/git-svn && test_must_fail git svn migrate diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 28f61f08fb4cec..55dc9eabfc42fe 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2444,7 +2444,7 @@ test_expect_success FUNNYNAMES \ >repeated-quoted/2-file && >repeated-quoted/3\"file && # ... and here, too. - # Still, we shold only list the directory name only once. + # Still, we should list the directory name only once. test_path_completion repeated repeated-quoted ' diff --git a/t/test-lib-github-workflow-markup.sh b/t/test-lib-github-workflow-markup.sh index 33405c90d740d4..fa29a62aa311c5 100644 --- a/t/test-lib-github-workflow-markup.sh +++ b/t/test-lib-github-workflow-markup.sh @@ -18,7 +18,7 @@ # # The idea is for `test-lib.sh` to source this file when run in GitHub # workflows; these functions will then override (empty) functions -# that are are called at the appropriate times during the test runs. +# that are called at the appropriate times during the test runs. test_skip_test_preamble=t diff --git a/t/test-lib-junit.sh b/t/test-lib-junit.sh index 76cbbd3299d64a..f4994dd9d3183d 100644 --- a/t/test-lib-junit.sh +++ b/t/test-lib-junit.sh @@ -19,7 +19,7 @@ # # The idea is for `test-lib.sh` to source this file when the user asks # for JUnit XML; these functions will then override (empty) functions -# that are are called at the appropriate times during the test runs. +# that are called at the appropriate times during the test runs. start_test_output () { junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out" diff --git a/t/test-lib.sh b/t/test-lib.sh index 4a7357b547e77e..ceefb99bff60e0 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1299,10 +1299,10 @@ test_done () { error "Tests passed but trash directory already removed before test cleanup; aborting" cd "$TRASH_DIRECTORY/.." && - rm -fr "$TRASH_DIRECTORY" || { + rm -fr "$TRASH_DIRECTORY" 2>/dev/null || { # try again in a bit sleep 5; - rm -fr "$TRASH_DIRECTORY" + rm -fr "$TRASH_DIRECTORY" 2>/dev/null } || error "Tests passed but test cleanup failed; aborting" fi @@ -1532,6 +1532,12 @@ then BAIL_OUT 'You need to build test-tool; Run "make t/helper/test-tool" in the source (toplevel) directory' fi +if test -n "$HARNESS_ACTIVE" +then + say "TAP version 13" + say "pragma +strict" +fi + # Are we running this test at all? remove_trash= this_test=${0##*/} diff --git a/tree-walk.h b/tree-walk.h index 29a55328bd94a4..9646c47ac5bce5 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -177,7 +177,7 @@ struct traverse_info { /** * Walk trees starting with "tree_oid" to find the entry for "name", and - * return the the object name and the mode of the found entry via the + * return the object name and the mode of the found entry via the * "oid" and "mode" parameters. Return 0 if the entry is found, and -1 * otherwise. */ diff --git a/unpack-trees.c b/unpack-trees.c index 998a1e6dc70cae..b42020f16b10ae 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1780,14 +1780,14 @@ static int clear_ce_flags(struct index_state *istate, xsnprintf(label, sizeof(label), "clear_ce_flags(0x%08lx,0x%08lx)", (unsigned long)select_mask, (unsigned long)clear_mask); - trace2_region_enter("unpack_trees", label, the_repository); + trace2_region_enter("unpack_trees", label, istate->repo); rval = clear_ce_flags_1(istate, istate->cache, istate->cache_nr, &prefix, select_mask, clear_mask, pl, 0, 0); - trace2_region_leave("unpack_trees", label, the_repository); + trace2_region_leave("unpack_trees", label, istate->repo); stop_progress(&istate->progress); return rval; @@ -1882,7 +1882,7 @@ static int verify_absent(const struct cache_entry *, */ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o) { - struct repository *repo = the_repository; + struct repository *repo = o->src_index->repo; int i, ret; static struct cache_entry *dfc; struct pattern_list pl; @@ -1903,7 +1903,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options BUG("o->df_conflict_entry is an output only field"); trace_performance_enter(); - trace2_region_enter("unpack_trees", "unpack_trees", the_repository); + trace2_region_enter("unpack_trees", "unpack_trees", repo); prepare_repo_settings(repo); if (repo->settings.command_requires_full_index) { @@ -2007,9 +2007,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options } trace_performance_enter(); - trace2_region_enter("unpack_trees", "traverse_trees", the_repository); + trace2_region_enter("unpack_trees", "traverse_trees", repo); ret = traverse_trees(o->src_index, len, t, &info); - trace2_region_leave("unpack_trees", "traverse_trees", the_repository); + trace2_region_leave("unpack_trees", "traverse_trees", repo); trace_performance_leave("traverse_trees"); if (ret < 0) goto return_failed; @@ -2106,7 +2106,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options dir_clear(o->internal.dir); o->internal.dir = NULL; } - trace2_region_leave("unpack_trees", "unpack_trees", the_repository); + trace2_region_leave("unpack_trees", "unpack_trees", repo); trace_performance_leave("unpack_trees"); return ret;