diff --git a/commit-reach.c b/commit-reach.c index 5df471a313cf6b..708798a39b2d8e 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -108,11 +108,14 @@ static int paint_down_to_common(struct repository *r, { compare_commits_by_gen_then_commit_date } }; int i; + int gen_ordered = 1; timestamp_t last_gen = GENERATION_NUMBER_INFINITY; struct commit_list **tail = result; - if (!min_generation && !corrected_commit_dates_enabled(r)) + if (!min_generation && !corrected_commit_dates_enabled(r)) { queue.pq.compare = compare_commits_by_commit_date; + gen_ordered = 0; + } one->object.flags |= PARENT1; if (!n) { @@ -147,11 +150,12 @@ static int paint_down_to_common(struct repository *r, commit->object.flags |= RESULT; tail = commit_list_append(commit, tail); /* - * The queue is generation-ordered; no - * remaining common ancestor can be a + * When the queue is generation-ordered, + * no remaining common ancestor can be a * descendant of this one. */ if (!(mb_flags & MERGE_BASE_FIND_ALL) && + gen_ordered && generation < GENERATION_NUMBER_INFINITY) break; } diff --git a/git.c b/git.c index fd0637fd7d4983..ac2ac587cd73e0 100644 --- a/git.c +++ b/git.c @@ -528,9 +528,12 @@ static int run_post_command_hook(struct repository *r) /* * Only run post_command if pre_command succeeded in this process + * and we haven't attempted post_command yet. */ if (!run_post_hook) return 0; + run_post_hook = 0; + lock = getenv("COMMAND_HOOK_LOCK"); if (!lock || strcmp(lock, "true")) return 0; @@ -539,8 +542,6 @@ static int run_post_command_hook(struct repository *r) strvec_pushf(&opt.args, "--exit_code=%u", exit_code); ret = run_hooks_opt(r, "post-command", &opt); - run_post_hook = 0; - errno = saved_errno; strvec_clear(&sargv); strvec_clear(&opt.args); diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh index b5b314e57068f9..0ff41381ff3c52 100755 --- a/t/t6600-test-reach.sh +++ b/t/t6600-test-reach.sh @@ -49,6 +49,42 @@ test_expect_success 'setup' ' git tag -a -m "$x-$i" tag-$x-$i commit-$x-$i || return 1 done done && + # Build a topology with clock skew to test the !FIND_ALL early + # exit in paint_down_to_common(). M2 is the correct merge base + # of P1 and P2, but its ancestor M1 has a higher committer date + # due to clock skew. With date-only ordering (v1 commit graph + # without corrected commit dates), M1 pops from the queue first, + # gets both paint sides, and the early exit fires before M2 is + # ever visited. + # + # P1 P2 @7000 + # | / \ + # A B D @6000 + # / \ | | + # | M2--+ | @2000 (correct merge base) + # \ | | + # M1--------+ @5000 (clock skew: date > M2) + # | + # root @1000 + # + git checkout --orphan skew-orphan && + skew_tree=$(git mktree expect && + merge_base_all_modes skew-P1 skew-P2 +' + test_done diff --git a/trace2/tr2_tbuf.c b/trace2/tr2_tbuf.c index c3b3822ed7e4af..ef57376f3c3e24 100644 --- a/trace2/tr2_tbuf.c +++ b/trace2/tr2_tbuf.c @@ -3,45 +3,64 @@ void tr2_tbuf_local_time(struct tr2_tbuf *tb) { - struct timeval tv; - struct tm tm; + struct timeval tv = { 0 }; + struct tm tm = { 0 }; time_t secs; + int len; gettimeofday(&tv, NULL); secs = tv.tv_sec; localtime_r(&secs, &tm); - xsnprintf(tb->buf, sizeof(tb->buf), "%02d:%02d:%02d.%06ld", tm.tm_hour, - tm.tm_min, tm.tm_sec, (long)tv.tv_usec); + len = snprintf(tb->buf, sizeof(tb->buf), "%02d:%02d:%02d.%06ld", + tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec); + + if (len < 0 || (size_t)len >= sizeof(tb->buf)) { + const char *blank = "00:00:00.000000"; + strlcpy(tb->buf, blank, sizeof(tb->buf)); + } } void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb) { - struct timeval tv; - struct tm tm; + struct timeval tv = { 0 }; + struct tm tm = { 0 }; time_t secs; + int len; gettimeofday(&tv, NULL); secs = tv.tv_sec; gmtime_r(&secs, &tm); - xsnprintf(tb->buf, sizeof(tb->buf), - "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", tm.tm_year + 1900, - tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - (long)tv.tv_usec); + len = snprintf(tb->buf, sizeof(tb->buf), + "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec); + + if (len < 0 || (size_t)len >= sizeof(tb->buf)) { + const char *blank = "1900-00-00T00:00:00.000000Z"; + strlcpy(tb->buf, blank, sizeof(tb->buf)); + } } void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb) { - struct timeval tv; - struct tm tm; + struct timeval tv = { 0 }; + struct tm tm = { 0 }; time_t secs; + int len; gettimeofday(&tv, NULL); secs = tv.tv_sec; gmtime_r(&secs, &tm); - xsnprintf(tb->buf, sizeof(tb->buf), "%4d%02d%02dT%02d%02d%02d.%06ldZ", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec, (long)tv.tv_usec); + len = snprintf(tb->buf, sizeof(tb->buf), + "%4d%02d%02dT%02d%02d%02d.%06ldZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec); + + if (len < 0 || (size_t)len >= sizeof(tb->buf)) { + const char *blank = "19000000T000000.000000Z"; + strlcpy(tb->buf, blank, sizeof(tb->buf)); + } }