Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Documentation/RelNotes/2.56.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ UI, Workflows & Features
absolute and relative paths for "gitdir" and "commondir", supported by
a new path-formatting helper extracted from "git rev-parse".

* When 'git push origin/main' or 'git branch origin main' is run, the
command is now recognized as a potential typo, and advice has been
added to offer a typo fix.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand Down Expand Up @@ -74,6 +78,16 @@ Performance, Internal Implementation, Development Support etc.
a default limit of at most one reroll per day to give reviewers across
different time zones enough time to participate.

* The lazy priority queue optimization pattern (deferring actual removal
in 'prio_queue_get()' to allow get+put fusion) has been folded
directly into 'prio_queue' itself, speeding up commit traversal
workflows and simplifying callers.

* The 'reprepare()' callback for object database sources has been
generalized into a 'prepare()' callback with an optional flush cache
flag, and a new 'odb_prepare()' wrapper has been introduced to allow
pre-opening object database sources.


Fixes since v2.55
-----------------
Expand Down Expand Up @@ -111,3 +125,18 @@ Fixes since v2.55
test_path_is_missing instead of ! grep on a file that shouldn't
exist in the conflicted state.
(merge eaad121fef sg/t3420-do-not-grep-in-missing-file later to maint).

* The GPG and SSH signature parsing code has been corrected to strip
carriage return characters only when they immediately precede line
feeds, instead of unconditionally stripping all carriage returns.
(merge 5dea8b690b ad/gpg-strip-cr-before-lf later to maint).

* A memory leak in the 'reftable_writer_new()' initialization function
has been fixed by delaying the allocation of 'struct reftable_writer'
until after input options are validated.
(merge c6fb3b9c3e jk/reftable-leakfix later to maint).

* A memory leak in the '--base' handling of 'git format-patch' has been
plugged, and the leak reporting of the test suite when running under a
TAP harness has been improved.
(merge 973a0373ff jk/format-patch-leakfix later to maint).
5 changes: 5 additions & 0 deletions Documentation/config/advice.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ all advice messages.
Shown when linkgit:git-push[1] rejects a forced update of
a branch when its remote-tracking ref has updates that we
do not have locally.
pushRepoLooksLikeRef::
Shown when the repository given to linkgit:git-push[1] is not
a configured remote but looks like a `<remote>/<branch>` ref,
suggesting that the remote and branch be given as separate
arguments.
pushUnqualifiedRefname::
Shown when linkgit:git-push[1] gives up trying to
guess based on the source and destination refs what
Expand Down
1 change: 1 addition & 0 deletions advice.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ static struct {
[ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent" },
[ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching" },
[ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate" },
[ADVICE_PUSH_REPO_LOOKS_LIKE_REF] = { "pushRepoLooksLikeRef" },
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
Expand Down
1 change: 1 addition & 0 deletions advice.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum advice_type {
ADVICE_PUSH_NON_FF_CURRENT,
ADVICE_PUSH_NON_FF_MATCHING,
ADVICE_PUSH_REF_NEEDS_UPDATE,
ADVICE_PUSH_REPO_LOOKS_LIKE_REF,
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
Expand Down
32 changes: 32 additions & 0 deletions builtin/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,29 @@ static int edit_branch_description(const char *branch_name)
return 0;
}

static void die_if_upstream_looks_like_remote(const char *new_upstream, const char *branch_name)
{
struct strbuf remote_ref = STRBUF_INIT;
int code;

if (strchr(new_upstream, '/') ||
!remote_is_configured(remote_get(new_upstream), 0))
return;

strbuf_addf(&remote_ref, "refs/remotes/%s/%s", new_upstream, branch_name);
if (!refs_ref_exists(get_main_ref_store(the_repository), remote_ref.buf)) {
strbuf_release(&remote_ref);
return;
}

code = die_message(_("--set-upstream-to takes a single <remote>/<branch> argument"));
advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
_("Did you mean to use: git branch --set-upstream-to=%s/%s?"),
new_upstream, branch_name);
strbuf_release(&remote_ref);
exit(code);
}

int cmd_branch(int argc,
const char **argv,
const char *prefix,
Expand Down Expand Up @@ -957,6 +980,15 @@ int cmd_branch(int argc,
if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) {
if (!argc || branch_checked_out(branch->refname))
die(_("no commit on branch '%s' yet"), branch->name);
/*
* Check the advice up front to avoid the ref
* lookups when the hint is off. The helper still
* calls advise_if_enabled() so the hint carries the
* standard "disable this message" instructions.
*/
if (argc == 1 &&
advice_enabled(ADVICE_SET_UPSTREAM_FAILURE))
die_if_upstream_looks_like_remote(new_upstream, argv[0]);
die(_("branch '%s' does not exist"), branch->name);
}

Expand Down
70 changes: 16 additions & 54 deletions builtin/describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,56 +251,19 @@ static int compare_pt(const void *a_, const void *b_)
return 0;
}

struct lazy_queue {
struct prio_queue queue;
bool get_pending;
};

#define LAZY_QUEUE_INIT { { compare_commits_by_commit_date }, false }

static void *lazy_queue_get(struct lazy_queue *queue)
{
if (queue->get_pending)
prio_queue_get(&queue->queue);
else
queue->get_pending = true;
return prio_queue_peek(&queue->queue);
}

static void lazy_queue_put(struct lazy_queue *queue, void *thing)
{
if (queue->get_pending)
prio_queue_replace(&queue->queue, thing);
else
prio_queue_put(&queue->queue, thing);
queue->get_pending = false;
}

static bool lazy_queue_empty(const struct lazy_queue *queue)
{
return queue->queue.nr == (queue->get_pending ? 1 : 0);
}

static void lazy_queue_clear(struct lazy_queue *queue)
{
clear_prio_queue(&queue->queue);
queue->get_pending = false;
}

static unsigned long finish_depth_computation(struct lazy_queue *queue,
static unsigned long finish_depth_computation(struct prio_queue *queue,
struct possible_tag *best)
{
unsigned long seen_commits = 0;
struct oidset unflagged = OIDSET_INIT;
struct commit *c;

for (size_t i = queue->get_pending ? 1 : 0; i < queue->queue.nr; i++) {
struct commit *commit = queue->queue.array[i].data;
if (!(commit->object.flags & best->flag_within))
oidset_insert(&unflagged, &commit->object.oid);
prio_queue_for_each(queue, c) {
if (!(c->object.flags & best->flag_within))
oidset_insert(&unflagged, &c->object.oid);
}

while (!lazy_queue_empty(queue)) {
struct commit *c = lazy_queue_get(queue);
while ((c = prio_queue_get(queue))) {
struct commit_list *parents = c->parents;
seen_commits++;
if (c->object.flags & best->flag_within) {
Expand All @@ -316,7 +279,7 @@ static unsigned long finish_depth_computation(struct lazy_queue *queue,
repo_parse_commit(the_repository, p);
seen = p->object.flags & SEEN;
if (!seen)
lazy_queue_put(queue, p);
prio_queue_put(queue, p);
flag_before = p->object.flags & best->flag_within;
p->object.flags |= c->object.flags;
flag_after = p->object.flags & best->flag_within;
Expand Down Expand Up @@ -364,8 +327,8 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf

static void describe_commit(struct commit *cmit, struct strbuf *dst)
{
struct commit *gave_up_on = NULL;
struct lazy_queue queue = LAZY_QUEUE_INIT;
struct commit *c, *gave_up_on = NULL;
struct prio_queue queue = { compare_commits_by_commit_date };
struct commit_name *n;
struct possible_tag all_matches[MAX_TAGS];
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
Expand Down Expand Up @@ -407,9 +370,8 @@ static void describe_commit(struct commit *cmit, struct strbuf *dst)
}

cmit->object.flags = SEEN;
lazy_queue_put(&queue, cmit);
while (!lazy_queue_empty(&queue)) {
struct commit *c = lazy_queue_get(&queue);
prio_queue_put(&queue, cmit);
while ((c = prio_queue_get(&queue))) {
struct commit_list *parents = c->parents;
struct commit_name **slot;

Expand Down Expand Up @@ -443,7 +405,7 @@ static void describe_commit(struct commit *cmit, struct strbuf *dst)
t->depth++;
}
/* Stop if last remaining path already covered by best candidate(s) */
if (annotated_cnt && lazy_queue_empty(&queue)) {
if (annotated_cnt && !prio_queue_size(&queue)) {
int best_depth = INT_MAX;
unsigned best_within = 0;
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
Expand All @@ -466,7 +428,7 @@ static void describe_commit(struct commit *cmit, struct strbuf *dst)
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
lazy_queue_put(&queue, p);
prio_queue_put(&queue, p);
p->object.flags |= c->object.flags;
parents = parents->next;

Expand All @@ -481,7 +443,7 @@ static void describe_commit(struct commit *cmit, struct strbuf *dst)
strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
if (suffix)
strbuf_addstr(dst, suffix);
lazy_queue_clear(&queue);
clear_prio_queue(&queue);
return;
}
if (unannotated_cnt)
Expand All @@ -497,11 +459,11 @@ static void describe_commit(struct commit *cmit, struct strbuf *dst)
QSORT(all_matches, match_cnt, compare_pt);

if (gave_up_on) {
lazy_queue_put(&queue, gave_up_on);
prio_queue_put(&queue, gave_up_on);
seen_commits--;
}
seen_commits += finish_depth_computation(&queue, &all_matches[0]);
lazy_queue_clear(&queue);
clear_prio_queue(&queue);

if (debug) {
static int label_width = -1;
Expand Down
14 changes: 3 additions & 11 deletions builtin/grep.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@
#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
#include "odb/source.h"
#include "oid-array.h"
#include "oidset.h"
#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "promisor-remote.h"
Expand Down Expand Up @@ -1357,15 +1356,8 @@ int cmd_grep(int argc,
if (recurse_submodules)
repo_read_gitmodules(the_repository, 1);

if (startup_info->have_repository) {
struct odb_source *source;

odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
odb_source_packed_prepare(files->packed);
}
}
if (startup_info->have_repository)
odb_prepare(the_repository->objects, 0);

start_threads(&opt);
} else {
Expand Down
7 changes: 3 additions & 4 deletions builtin/last-modified.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ static void process_parent(struct last_modified *lm,
static int last_modified_run(struct last_modified *lm)
{
int max_count, queue_popped = 0;
struct commit *c, *n;
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
struct prio_queue not_queue = { compare_commits_by_gen_then_commit_date };
struct commit_list *list;
Expand Down Expand Up @@ -389,10 +390,9 @@ static int last_modified_run(struct last_modified *lm)
}
}

while (queue.nr) {
while ((c = prio_queue_get(&queue))) {
int parent_i;
struct commit_list *p;
struct commit *c = prio_queue_get(&queue);
struct bitmap *active_c = active_paths_for(lm, c);

if ((0 <= max_count && max_count < ++queue_popped) ||
Expand All @@ -416,9 +416,8 @@ static int last_modified_run(struct last_modified *lm)
*/
repo_parse_commit(lm->rev.repo, c);

while (not_queue.nr) {
while ((n = prio_queue_get(&not_queue))) {
struct commit_list *np;
struct commit *n = prio_queue_get(&not_queue);

repo_parse_commit(lm->rev.repo, n);

Expand Down
1 change: 1 addition & 0 deletions builtin/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,7 @@ static void prepare_bases(struct base_tree_info *bases,
bases->nr_patch_id++;
}
clear_commit_base(&commit_base);
release_revisions(&revs);
}

static void print_bases(struct base_tree_info *bases, FILE *file)
Expand Down
37 changes: 36 additions & 1 deletion builtin/push.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "advice.h"
#include "branch.h"
#include "config.h"
#include "dir.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
Expand Down Expand Up @@ -662,6 +663,29 @@ static int push_multiple(struct string_list *list,
return result;
}

static void die_if_repo_looks_like_ref(const char *repo)
{
const char *slash = strchr(repo, '/');
struct strbuf name = STRBUF_INIT;
int code;

if (!slash || !slash[1] || file_exists(repo))
return;

strbuf_add(&name, repo, slash - repo);
if (!remote_is_configured(remote_get(name.buf), 0)) {
strbuf_release(&name);
return;
}

code = die_message(_("'%s' is not a valid push target"), repo);
advise_if_enabled(ADVICE_PUSH_REPO_LOOKS_LIKE_REF,
_("Did you mean to use: git push %s %s?"),
name.buf, slash + 1);
strbuf_release(&name);
exit(code);
}

int cmd_push(int argc,
const char **argv,
const char *prefix,
Expand Down Expand Up @@ -744,6 +768,17 @@ int cmd_push(int argc,

if (repo) {
if (!add_remote_or_group(repo, &remote_group)) {
struct remote *r;

/*
* Check the advice up front to avoid the remote
* lookup when the hint is off. The helper still
* calls advise_if_enabled() so the hint carries the
* standard "disable this message" instructions.
*/
if (advice_enabled(ADVICE_PUSH_REPO_LOOKS_LIKE_REF))
die_if_repo_looks_like_ref(repo);

/*
* Not a configured remote name or group name.
* Try treating it as a direct URL or path, e.g.
Expand All @@ -753,7 +788,7 @@ int cmd_push(int argc,
* from the URL so the loop below can handle it
* identically to a named remote.
*/
struct remote *r = pushremote_get(repo);
r = pushremote_get(repo);
if (!r)
die(_("bad repository '%s'"), repo);
string_list_append(&remote_group, r->name);
Expand Down
Loading