Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5bd3978
commit-reach: reject cycles in contains walk
tamird Jun 12, 2026
ca96eee
ref-filter: memoize --contains with generations
tamird Jun 12, 2026
ff3ba7d
commit-reach: die on contains walk errors
tamird Jun 12, 2026
de1e62e
Merge branch 'ps/refs-writing-subcommands' into ps/refs-wo-the-reposi…
gitster Jul 9, 2026
641588b
lib-log-graph: move check_graph function
pabloosabaterr Jul 14, 2026
08a0bef
revision: add next_commit_to_show()
pabloosabaterr Jul 14, 2026
bf3c696
graph: add a 2 commit buffer for lookahead
pabloosabaterr Jul 14, 2026
a34c00d
graph: indent visual root in graph
pabloosabaterr Jul 14, 2026
233cc40
graph: wrap cascading commits after 4 columns
pabloosabaterr Jul 14, 2026
f3a0330
graph: move config reading into graph_read_config()
pabloosabaterr Jul 14, 2026
e9b5720
graph: add --[no-]graph-indent and log.graphIndent
pabloosabaterr Jul 14, 2026
88101d3
t3400: restore coverage for note copying with apply backend
phillipwood Jul 15, 2026
1da8592
sequencer: be more careful with external merge
phillipwood Jul 15, 2026
18f5750
sequencer: never reschedule on failed commit
phillipwood Jul 15, 2026
6bb740d
sequencer: remove unnecessary "or" in pick_one_commit()
phillipwood Jul 15, 2026
dc0e2ac
sequencer: simplify handling of fixup with conflicts
phillipwood Jul 15, 2026
871f900
sequencer: remove unnecessary condition in pick_one_commit()
phillipwood Jul 15, 2026
034deee
sequencer: simplify pick_one_commit()
phillipwood Jul 15, 2026
a7dbb3a
sequencer: use an enum to represent result of picking a commit
phillipwood Jul 15, 2026
42554b7
sequencer: do not record dropped commits as rewritten
phillipwood Jul 15, 2026
3279c13
submodule--helper: avoid use of %zu for now
gitster Jul 15, 2026
f749a83
remote-curl: simplify passing of push specs
rscharfe Jul 15, 2026
5abbd7c
refs/packed: de-globalize handling of "core.packedRefsTimeout"
pks-t Jul 16, 2026
af57f73
refs/files: drop `USE_THE_REPOSITORY_VARIABLE`
pks-t Jul 16, 2026
28723da
worktree: refactor code to use available repositories
pks-t Jul 16, 2026
2cec1c9
worktree: pass repository to file-local functions
pks-t Jul 16, 2026
e2533e0
worktree: pass repository to public functions
pks-t Jul 16, 2026
b1296cb
refs: remove remaining uses of `the_repository`
pks-t Jul 16, 2026
991ec27
refspec: group related structures and functions
pks-t Jul 16, 2026
bb71c3f
refspec: let callers pass in hash algorithm when parsing items
pks-t Jul 16, 2026
01f4b61
refspec: stop depending on `the_repository`
pks-t Jul 16, 2026
0717b35
copy: drop dependency on `the_repository`
pks-t Jul 16, 2026
7b2648f
wt-status: avoid repeated insertion for untracked paths
sahitya-chandra Jul 18, 2026
251e7af
hash: initialize context before cloning
bk2204 Jul 19, 2026
fdfcd75
rust: discard hash context when finished
bk2204 Jul 19, 2026
fbf123a
Merge branch 'ps/shift-root-in-graph'
gitster Jul 27, 2026
f931547
Merge branch 'jc/submodule-helper-avoid-zu'
gitster Jul 27, 2026
0c20b08
Merge branch 'ps/refs-wo-the-repository'
gitster Jul 27, 2026
ebc9fb5
Merge branch 'td/ref-filter-memoize-contains'
gitster Jul 27, 2026
f97a43e
Merge branch 'rs/remote-curl-simplify-push-specs'
gitster Jul 27, 2026
4be0a34
Merge branch 'ps/refspec-wo-the-repository'
gitster Jul 27, 2026
7d64c1e
Merge branch 'sc/wt-status-avoid-quadratic-insertion'
gitster Jul 27, 2026
bb8bc69
Merge branch 'ps/copy-wo-the-repository'
gitster Jul 27, 2026
f364885
Merge branch 'pw/rebase-drop-notes-with-commit'
gitster Jul 27, 2026
47ea9e4
Merge branch 'bc/rust-hash-cleanups'
gitster Jul 27, 2026
13c7afe
The 8th batch
gitster Jul 27, 2026
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
51 changes: 51 additions & 0 deletions Documentation/RelNotes/2.56.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ UI, Workflows & Features
standardized to make them consistent with each other and with other
commands.

* 'git log --graph' has been modified to visually distinguish parentless
'root' commits (and commits that become roots due to history
simplification) by indenting them, preventing them from appearing
falsely related to unrelated commits rendered immediately above them.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand Down Expand Up @@ -206,6 +211,36 @@ Performance, Internal Implementation, Development Support etc.
pathspec filtering, which was lost when the streaming walk was
refactored.

* The ref subsystem and the worktree API have been refactored to pass a
repository pointer down the call chain, allowing them to drop
references to the global 'the_repository' variable. As part of this,
the handling of the 'core.packedRefsTimeout' configuration has been
moved into the per-repository ref store structure.

* 'git branch --contains' and 'git for-each-ref --contains' have been
optimized to use the memoized commit traversal previously used only by
'git tag --contains', significantly speeding up connectivity checks
across many candidate refs with shared history.

* The passing of push destination specifications in the 'remote-curl'
helper has been simplified by removing the explicit 'count' parameter
and relying on the NULL-termination of the array.

* The dependency on the global 'the_repository' variable in the
'refspec.c' API has been removed by passing the hash algorithm
explicitly to refspec-parsing functions and storing it in 'struct
refspec'.

* The enumeration of untracked and ignored files in 'git status' has
been optimized by avoiding quadratic complexity when inserting into
string lists, reducing the construction cost from O(n^2) to O(n log
n).

* The copy_file() and copy_file_with_time() functions have been
refactored to take a repository parameter, allowing the removal of the
implicit dependency on the global 'the_repository' variable in
'copy.c'.


Fixes since v2.55
-----------------
Expand Down Expand Up @@ -350,3 +385,19 @@ Fixes since v2.55
'git submodule update' command until it was broken in a modernization
of the option-parsing code, has been restored.
(merge ff1da37f58 dm/submodule-update-i-shorthand later to maint).

* An accidental use of the '%zu' format specifier in 'git
submodule--helper' has been corrected to use 'PRIuMAX' and cast the
value to 'uintmax_t' to avoid portability issues.
(merge 3279c13c00 jc/submodule-helper-avoid-zu later to maint).

* The rebase post-rewrite notes-copying logic has been corrected. When
a commit is dropped during rebase (e.g., because its changes are
already upstream), it is no longer recorded as rewritten, preventing
its notes from being copied to an unrelated commit.
(merge 42554b78fd pw/rebase-drop-notes-with-commit later to maint).

* A few memory problems in the Rust interface to C hash functions have
been corrected. The 'Clone' implementation of 'CryptoHasher' now
properly initializes the context before cloning, and its 'Drop'
implementation now discards the context to prevent leaks.
4 changes: 4 additions & 0 deletions Documentation/config/log.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ This is the same as the `--decorate` option of the `git log`.
A list of colors, separated by commas, that can be used to draw
history lines in `git log --graph`.

`log.graphIndent`::
If `true`, indent visual roots when rendering the graphs with `--graph`.
Set true by default. It can be overriden with `--[no-]graph-indent`.

`log.showRoot`::
If true, the initial commit will be shown as a big creation event.
This is equivalent to a diff against an empty tree.
Expand Down
8 changes: 8 additions & 0 deletions Documentation/rev-list-options.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,14 @@ This implies the `--topo-order` option by default, but the
By default it is set to 0 (no limit), zero and negative values
are ignored and treated as no limit.

`--no-graph-indent`::
`--graph-indent`::
When used with `--graph`, indent visual roots (commits with no parents
or whose parents are not shown) to differentiate them from commits that
are vertically adjacent but unrelated. Enabled by default. Use
`--no-graph-indent` to disable or set `log.graphIndent` to set a
default preference.

ifdef::git-rev-list[]
`--count`::
Print a number stating how many commits would have been
Expand Down
6 changes: 3 additions & 3 deletions branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
*/
int validate_branchname(const char *name, struct strbuf *ref)
{
if (check_branch_ref(ref, name)) {
if (check_branch_ref(the_repository, ref, name)) {
int code = die_message(_("'%s' is not a valid branch name"), name);
advise_if_enabled(ADVICE_REF_SYNTAX,
_("See 'git help check-ref-format'"));
Expand All @@ -394,7 +394,7 @@ static void prepare_checked_out_branches(void)
return;
initialized_checked_out_branches = 1;

worktrees = get_worktrees();
worktrees = get_worktrees(the_repository);

while (worktrees[i]) {
char *old, *wt_gitdir;
Expand Down Expand Up @@ -846,7 +846,7 @@ void remove_branch_state(struct repository *r, int verbose)

void die_if_checked_out(const char *branch, int ignore_current_worktree)
{
struct worktree **worktrees = get_worktrees();
struct worktree **worktrees = get_worktrees(the_repository);

for (int i = 0; worktrees[i]; i++) {
if (worktrees[i]->is_current && ignore_current_worktree)
Expand Down
16 changes: 10 additions & 6 deletions builtin/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
char *target = NULL;
int flags = 0;

copy_branchname(&bname, argv[i], allowed_interpret);
copy_branchname(the_repository, &bname,
argv[i], allowed_interpret);
free(name);
name = mkpathdup(fmt, bname.buf);

Expand Down Expand Up @@ -579,9 +580,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
const char *interpreted_oldname = NULL;
const char *interpreted_newname = NULL;
int recovery = 0, oldref_usage = 0;
struct worktree **worktrees = get_worktrees();
struct worktree **worktrees = get_worktrees(the_repository);

if (check_branch_ref(&oldref, oldname)) {
if (check_branch_ref(the_repository, &oldref, oldname)) {
/*
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
Expand Down Expand Up @@ -921,7 +922,8 @@ int cmd_branch(int argc,
die(_("cannot give description to detached HEAD"));
branch_name = head;
} else if (argc == 1) {
copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
copy_branchname(the_repository, &buf, argv[0],
INTERPRET_BRANCH_LOCAL);
branch_name = buf.buf;
} else {
die(_("cannot edit description of more than one branch"));
Expand Down Expand Up @@ -964,7 +966,8 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
copy_branchname(the_repository, &buf, argv[0],
INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to set new upstream"));
Expand Down Expand Up @@ -1003,7 +1006,8 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
copy_branchname(the_repository, &buf, argv[0],
INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to unset upstream"));
Expand Down
2 changes: 1 addition & 1 deletion builtin/check-ref-format.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static int check_ref_format_branch(const char *arg)
int nongit;

setup_git_directory_gently(the_repository, &nongit);
if (check_branch_ref(&sb, arg) ||
if (check_branch_ref(the_repository, &sb, arg) ||
!skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
printf("%s\n", name);
Expand Down
2 changes: 1 addition & 1 deletion builtin/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ static void setup_branch_path(struct branch_info *branch)
&branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);

copy_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
copy_branchname(the_repository, &buf, branch->name, INTERPRET_BRANCH_LOCAL);
if (strcmp(buf.buf, branch->name)) {
free(branch->name);
branch->name = xstrdup(buf.buf);
Expand Down
2 changes: 1 addition & 1 deletion builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
}
if (copy_file_with_time(dest->buf, src->buf, 0666))
if (copy_file_with_time(the_repository, dest->buf, src->buf, 0666))
die_errno(_("failed to copy file to '%s'"), dest->buf);
}

Expand Down
2 changes: 1 addition & 1 deletion builtin/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ static void location_options_init(struct config_location_options *opts,
opts->source.file = opts->file_to_free = repo_git_path(the_repository, "config");
opts->source.scope = CONFIG_SCOPE_LOCAL;
} else if (opts->use_worktree_config) {
struct worktree **worktrees = get_worktrees();
struct worktree **worktrees = get_worktrees(the_repository);
if (the_repository->repository_format_worktree_config)
opts->source.file = opts->file_to_free =
repo_git_path(the_repository, "config.worktree");
Expand Down
4 changes: 2 additions & 2 deletions builtin/difftool.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ static int run_dir_diff(struct repository *repo,
struct stat st;
if (stat(wtdir.buf, &st))
st.st_mode = 0644;
if (copy_file(rdir.buf, wtdir.buf,
if (copy_file(repo, rdir.buf, wtdir.buf,
st.st_mode)) {
ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
goto finish;
Expand Down Expand Up @@ -658,7 +658,7 @@ static int run_dir_diff(struct repository *repo,
warning("%s", "");
err = 1;
} else if (unlink(wtdir.buf) ||
copy_file(wtdir.buf, rdir.buf, st.st_mode))
copy_file(repo, wtdir.buf, rdir.buf, st.st_mode))
warning_errno(_("could not copy '%s' to '%s'"),
rdir.buf, wtdir.buf);
}
Expand Down
4 changes: 3 additions & 1 deletion builtin/fast-export.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static int show_original_ids;
static int mark_tags;
static struct string_list extra_refs = STRING_LIST_INIT_DUP;
static struct string_list tag_refs = STRING_LIST_INIT_DUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static struct refspec refspecs;
static int anonymize;
static struct hashmap anonymized_seeds;
static struct revision_sources revision_sources;
Expand Down Expand Up @@ -1372,6 +1372,8 @@ int cmd_fast_export(int argc,
/* we handle encodings */
repo_config(the_repository, git_default_config, NULL);

refspec_init_fetch(&refspecs, the_hash_algo);

repo_init_revisions(the_repository, &revs, prefix);
init_revision_sources(&revision_sources);
revs.topo_order = 1;
Expand Down
9 changes: 6 additions & 3 deletions builtin/fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *gtransport;
static struct transport *gsecondary;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct refspec refmap;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_restrict = STRING_LIST_INIT_NODUP;
static struct string_list negotiation_include = STRING_LIST_INIT_NODUP;
Expand Down Expand Up @@ -601,7 +601,8 @@ static struct ref *get_ref_map(struct remote *remote,
struct refspec_item tag_refspec;

/* also fetch all tags */
refspec_item_init_push(&tag_refspec, TAG_REFSPEC);
refspec_item_init_push(&tag_refspec, TAG_REFSPEC,
the_hash_algo);
get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
refspec_item_clear(&tag_refspec);
} else if (tags == TAGS_DEFAULT && *autotags) {
Expand Down Expand Up @@ -2428,7 +2429,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
const struct fetch_config *config,
struct list_objects_filter_options *filter_options)
{
struct refspec rs = REFSPEC_INIT_FETCH;
struct refspec rs = REFSPEC_INIT_FETCH(the_hash_algo);
int i;
int exit_code;
int maybe_prune_tags;
Expand Down Expand Up @@ -2630,6 +2631,8 @@ int cmd_fetch(int argc,

filter_options.allow_auto_filter = 1;

refspec_init_fetch(&refmap, the_hash_algo);

packet_trace_identity("fetch");

/* Record the command line for the reflog */
Expand Down
6 changes: 3 additions & 3 deletions builtin/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ static void snapshot_refs(struct repository *repo,
refs_for_each_ref_ext(get_main_ref_store(repo),
snapshot_ref, &data, &opts);

worktrees = get_worktrees();
worktrees = get_worktrees(repo);
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct strbuf refname = STRBUF_INIT;
Expand Down Expand Up @@ -685,7 +685,7 @@ static void process_refs(struct repository *repo, struct snapshot *snap)
}

if (include_reflogs) {
worktrees = get_worktrees();
worktrees = get_worktrees(repo);
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;

Expand Down Expand Up @@ -1121,7 +1121,7 @@ int cmd_fsck(int argc,
verify_index_checksum = 1;
verify_ce_order = 1;

worktrees = get_worktrees();
worktrees = get_worktrees(repo);
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate =
Expand Down
2 changes: 1 addition & 1 deletion builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ static int worktree_prune_condition(struct gc_config *cfg)
while (limit && (d = readdir_skip_dot_and_dotdot(dir))) {
char *wtpath;
strbuf_reset(&buf);
if (should_prune_worktree(d->d_name, &buf, &wtpath, expiry_date))
if (should_prune_worktree(the_repository, d->d_name, &buf, &wtpath, expiry_date))
limit--;
free(wtpath);
}
Expand Down
2 changes: 1 addition & 1 deletion builtin/merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
char *found_ref = NULL;
int len, early;

copy_branchname(&bname, remote, 0);
copy_branchname(the_repository, &bname, remote, 0);
remote = bname.buf;

oidclr(&branch_head, the_repository->hash_algo);
Expand Down
2 changes: 1 addition & 1 deletion builtin/notes.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ static int merge(int argc, const char **argv, const char *prefix,
"NOTES_MERGE_PARTIAL", &result_oid, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
worktrees = get_worktrees();
worktrees = get_worktrees(the_repository);
wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
notes_ref);
if (wt)
Expand Down
2 changes: 1 addition & 1 deletion builtin/pull.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
const char *spec_src;
const char *merge_branch;

if (!refspec_item_init_fetch(&spec, refspec))
if (!refspec_item_init_fetch(&spec, refspec, the_hash_algo))
die(_("invalid refspec '%s'"), refspec);
spec_src = spec.src;
if (!*spec_src || !strcmp(spec_src, "HEAD"))
Expand Down
6 changes: 4 additions & 2 deletions builtin/push.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static enum transport_family family;

static struct push_cas_option cas;

static struct refspec rs = REFSPEC_INIT_PUSH;
static struct refspec rs;

static struct string_list push_options_config = STRING_LIST_INIT_DUP;

Expand Down Expand Up @@ -749,6 +749,8 @@ int cmd_push(int argc,
: &push_options_config);
set_push_cert_flags(&flags, push_cert);

refspec_init_push(&rs, the_hash_algo);

die_for_incompatible_opt4(deleterefs, "--delete",
tags, "--tags",
flags & TRANSPORT_PUSH_ALL, "--all/--branches",
Expand Down Expand Up @@ -855,7 +857,7 @@ int cmd_push(int argc,
}

refspec_clear(&rs);
rs = (struct refspec) REFSPEC_INIT_PUSH;
rs = (struct refspec) REFSPEC_INIT_PUSH(the_hash_algo);

if (tags)
refspec_append(&rs, "refs/tags/*");
Expand Down
2 changes: 1 addition & 1 deletion builtin/receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct object_id *old_oid = &cmd->old_oid;
struct object_id *new_oid = &cmd->new_oid;
int do_update_worktree = 0;
struct worktree **worktrees = get_worktrees();
struct worktree **worktrees = get_worktrees(the_repository);
const struct worktree *worktree =
find_shared_symref(worktrees, "HEAD", name);

Expand Down
4 changes: 2 additions & 2 deletions builtin/reflog.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
struct string_list_item *item;
struct worktree **worktrees, **p;

worktrees = get_worktrees();
worktrees = get_worktrees(the_repository);
for (p = worktrees; *p; p++) {
if (single_worktree && !(*p)->is_current)
continue;
Expand Down Expand Up @@ -374,7 +374,7 @@ static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
struct string_list_item *item;
struct worktree **worktrees, **p;

worktrees = get_worktrees();
worktrees = get_worktrees(the_repository);
for (p = worktrees; *p; p++) {
if (single_worktree && !(*p)->is_current)
continue;
Expand Down
Loading