Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2ed34f7
Merge branch 'ps/odb-source-packed' into ps/odb-drop-whence
gitster Jun 24, 2026
ebb4d2f
history: streamline message preparation and plug file stream leak
gitster Jun 29, 2026
7270956
bloom: make bloom-filter slab initialization idempotent
peff Jul 1, 2026
c34573e
revision: avoid leaking bloom keyvecs with multiple traversals
peff Jul 1, 2026
459088e
line-log: drop extra copy of range with bloom filters
peff Jul 1, 2026
ca39c35
read-cache: split out function to drop unmerged entries to stage 0
pks-t Jul 1, 2026
5ce540b
reset: drop `USE_THE_REPOSITORY_VARIABLE`
pks-t Jul 1, 2026
9762e2f
reset: rename `reset_head()`
pks-t Jul 1, 2026
2535b95
reset: modernize flags passed to `reset_working_tree()`
pks-t Jul 1, 2026
8e435d9
reset: introduce dry-run mode
pks-t Jul 1, 2026
11c689b
packfile: thread odb_source_packed through packed_object_info()
pks-t Jul 2, 2026
126076b
odb: make backend-specific fields optional
pks-t Jul 2, 2026
32a95be
odb: add `source` field to struct object_info_source
pks-t Jul 2, 2026
2242f7e
treewide: convert users of `whence` to the new source field
pks-t Jul 2, 2026
aea037e
odb: drop `whence` field from object info
pks-t Jul 2, 2026
8a7ad23
odb: document object info fields
pks-t Jul 2, 2026
10ab1af
meson: restore hook-list.h to builtin_sources
floppym Jul 1, 2026
b2ebb78
reset: introduce ability to skip updating HEAD
pks-t Jul 1, 2026
1280e92
reset: allow the caller to specify the current HEAD object
pks-t Jul 1, 2026
e420d7b
reset: stop assuming that the caller passes in a clean index
pks-t Jul 1, 2026
27717e2
replay: expose `replay_result_queue_update()`
pks-t Jul 1, 2026
46affdb
builtin/history: split handling of ref updates into two phases
pks-t Jul 1, 2026
d11b348
builtin/history: implement "drop" subcommand
pks-t Jul 1, 2026
c3df27f
blame: reserve mark column only if necessary
rscharfe Jul 6, 2026
5a183de
builtin/refs: drop `the_repository`
pks-t Jul 6, 2026
b335599
builtin/refs: add "delete" subcommand
pks-t Jul 6, 2026
2540e35
builtin/refs: add "update" subcommand
pks-t Jul 6, 2026
fa4eefe
builtin/refs: add "create" subcommand
pks-t Jul 6, 2026
002fe67
builtin/refs: add "rename" subcommand
pks-t Jul 6, 2026
7a244d8
Merge branch 'jc/history-message-prep-fix'
gitster Jul 15, 2026
85ba074
Merge branch 'ps/refs-writing-subcommands'
gitster Jul 15, 2026
a9d2d2a
Merge branch 'ps/odb-drop-whence'
gitster Jul 15, 2026
955b276
Merge branch 'ps/history-drop'
gitster Jul 15, 2026
0a4fb31
Merge branch 'jk/bloom-leak-fixes'
gitster Jul 15, 2026
e38e971
Merge branch 'mg/meson-hook-list-buildfix'
gitster Jul 15, 2026
7381be0
Merge branch 'rs/blame-abbrev-marks'
gitster Jul 15, 2026
d35c539
The 3rd batch for Git 2.56
gitster Jul 15, 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
29 changes: 29 additions & 0 deletions Documentation/RelNotes/2.56.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ UI, Workflows & Features
command is now recognized as a potential typo, and advice has been
added to offer a typo fix.

* The 'git refs' toolbox has been extended with new 'create', 'delete',
'update', and 'rename' subcommands to create, delete, update, and
rename references, respectively.

* The experimental 'git history' command has been taught a new 'drop'
subcommand to remove a commit, with its descendants replayed onto its
parent.

* The alignment of commit object name abbreviations in 'git blame'
output has been optimized to reserve a column for marks (caret,
question mark, or asterisk) only when such marks are actually shown.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand Down Expand Up @@ -88,6 +100,14 @@ Performance, Internal Implementation, Development Support etc.
flag, and a new 'odb_prepare()' wrapper has been introduced to allow
pre-opening object database sources.

* The 'whence' field in 'struct object_info' has been removed. The
backend-specific object information retrieval has been refactored into
an opt-in 'struct object_info_source' structure.

* A racy build failure under Meson has been corrected by ensuring that
the generated header file 'hook-list.h' is built before compiling
files in 'builtin_sources' that depend on it.


Fixes since v2.55
-----------------
Expand Down Expand Up @@ -140,3 +160,12 @@ Fixes since v2.55
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).

* A write file stream resource leak has been fixed as part of a code
cleanup.
(merge ebb4d2ffa3 jc/history-message-prep-fix later to maint).

* Various memory leaks in the Bloom-filter code paths that are exposed
when running tests with the 'GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1'
environment variable have been plugged.
(merge 459088ec2e jk/bloom-leak-fixes later to maint).
11 changes: 6 additions & 5 deletions Documentation/git-blame.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ include::blame-options.adoc[]
include::diff-algorithm-option.adoc[]

`--abbrev=<n>`::
Instead of using the default _7+1_ hexadecimal digits as the
abbreviated object name, use _<m>+1_ digits, where _<m>_ is at
least _<n>_ but ensures the commit object names are unique.
Note that 1 column
is used for a caret to mark the boundary commit.
Instead of using the default _7_ hexadecimal digits as the
abbreviated object name, use at least _<n>_ digits, but ensure
the commit object names are unique.
If commits marked with caret (boundary), question mark (ignored)
or asterisk (unblamable) are shown, extend unmarked object names
to align them.


THE DEFAULT FORMAT
Expand Down
38 changes: 37 additions & 1 deletion Documentation/git-history.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ git-history - EXPERIMENTAL: Rewrite history
SYNOPSIS
--------
[synopsis]
git history drop <commit> [--dry-run] [--update-refs=(branches|head)] [--empty=(drop|keep|abort)]
git history fixup <commit> [--dry-run] [--update-refs=(branches|head)] [--reedit-message] [--empty=(drop|keep|abort)]
git history reword <commit> [--dry-run] [--update-refs=(branches|head)]
git history split <commit> [--dry-run] [--update-refs=(branches|head)] [--] [<pathspec>...]
Expand Down Expand Up @@ -51,13 +52,28 @@ be stateful operations. The limitation can be lifted once (if) Git learns about
first-class conflicts.

When using `fixup` with `--empty=drop`, dropping the root commit is not yet
supported.
supported. Likewise, `drop` cannot remove the root commit or a merge commit.

COMMANDS
--------

The following commands are available to rewrite history in different ways:

`drop <commit>`::
Remove the specified commit from the history. All descendants of the
commit are replayed directly onto its parent.
+
The root commit cannot be dropped as that may lead to edge cases where refs
end up with no commits anymore. Merge commits cannot be dropped either; see
LIMITATIONS.
+
If `HEAD` points at a commit that is to be rewritten, the index and working
tree are updated to match the new `HEAD`. The command aborts before any
references are updated in case local modifications would be overwritten.
+
If replaying any descendant would result in a conflict, the command aborts
with an error.

`fixup <commit>`::
Apply the currently staged changes to the specified commit. This is
similar in nature to `git commit --fixup=<commit>` followed by `git
Expand Down Expand Up @@ -170,6 +186,26 @@ The staged addition of `unrelated.txt` has been incorporated into the `first`
commit. All descendant commits have been replayed on top of the rewritten
history.

Drop a commit
~~~~~~~~~~~~~

----------
$ git log --oneline
abc1234 (HEAD -> main) third
def5678 second
ghi9012 first

$ git history drop 'main^{/second}'

$ git log --oneline
jkl3456 (HEAD -> main) third
ghi9012 first
----------

The `second` commit has been removed from the history, and `third` has been
replayed directly on top of `first`. All branches that pointed at the dropped
commit have been moved to its parent.

Split a commit
~~~~~~~~~~~~~~

Expand Down
40 changes: 40 additions & 0 deletions Documentation/git-refs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]
[ --stdin | (<pattern>...)]
git refs exists <ref>
git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
git refs create [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value>
git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]
git refs update [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value> [<old-value>]
git refs rename [--message=<reason>] <old-ref> <new-ref>

DESCRIPTION
-----------
Expand Down Expand Up @@ -51,6 +55,28 @@ optimize::
usage. This subcommand is an alias for linkgit:git-pack-refs[1] and
offers identical functionality.

create::
Create the given reference, which must not already exist, pointing at
`<new-value>`.

delete::
Delete the given reference. This subcommand mirrors `git update-ref -d`
(see linkgit:git-update-ref[1]). When `<old-value>` is given, the
reference is only deleted after verifying that it currently contains
`<old-value>`.

update::
Update the given reference to point at `<new-value>`. If `<old-value>`
is given, the reference is only updated after verifying that it
currently contains `<old-value>`. As a special case, an all-zeroes
`<new-value>` deletes the branch, whereas an all-zeroes `<old-value>`
ensures that the branch does not yet exist.

rename::
Rename the reference `<oldref>` to `<newref>`. The old reference must
exist and the new reference must not yet exist, and both must have a
well-formed name (see linkgit:git-check-ref-format[1]).

OPTIONS
-------

Expand Down Expand Up @@ -90,6 +116,20 @@ The following options are specific to 'git refs optimize':

include::pack-refs-options.adoc[]

The following options are specific to commands which write references:

`--create-reflog`::
Create a reflog for the reference even if one would not ordinarily be
created.

`--message=<reason>`::
Use the given <reason> string for the reflog entry associated with the
update. An empty message is rejected.

`--no-deref`::
Operate on <ref> itself rather than the reference it points to via a
symbolic ref.

KNOWN LIMITATIONS
-----------------

Expand Down
5 changes: 5 additions & 0 deletions bloom.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
define_commit_slab(bloom_filter_slab, struct bloom_filter);

static struct bloom_filter_slab bloom_filters;
static int bloom_filter_slab_initialized;

struct pathmap_hash_entry {
struct hashmap_entry entry;
Expand Down Expand Up @@ -263,7 +264,10 @@ void add_key_to_filter(const struct bloom_key *key,

void init_bloom_filters(void)
{
if (bloom_filter_slab_initialized)
return;
init_bloom_filter_slab(&bloom_filters);
bloom_filter_slab_initialized = 1;
}

static void free_one_bloom_filter(struct bloom_filter *filter)
Expand All @@ -276,6 +280,7 @@ static void free_one_bloom_filter(struct bloom_filter *filter)
void deinit_bloom_filters(void)
{
deep_clear_bloom_filter_slab(&bloom_filters, free_one_bloom_filter);
bloom_filter_slab_initialized = 0;
}

struct bloom_keyvec *bloom_keyvec_new(const char *path, size_t len,
Expand Down
68 changes: 45 additions & 23 deletions builtin/blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,36 @@ static void determine_line_heat(struct commit_info *ci, const char **dest_color)
*dest_color = colorfield[i].col;
}

static inline int maybe_putc(int c, FILE *out)
{
return out ? putc(c, out) : 0;
}

static size_t print_marks(FILE *out, const struct blame_entry *ent, int opt)
{
size_t len = 0;

if ((ent->suspect->commit->object.flags & UNINTERESTING) &&
!blank_boundary && !(opt & OUTPUT_ANNOTATE_COMPAT)) {
maybe_putc('^', out);
len++;
}
if (mark_unblamable_lines && ent->unblamable) {
maybe_putc('*', out);
len++;
}
if (mark_ignored_lines && ent->ignored) {
maybe_putc('?', out);
len++;
}
return len;
}

static size_t count_marks(const struct blame_entry *ent, int opt)
{
return print_marks(NULL, ent, opt);
}

static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent,
int opt, struct blame_entry *prev_ent)
{
Expand Down Expand Up @@ -499,23 +529,10 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent,
if (color)
fputs(color, stdout);

if (suspect->commit->object.flags & UNINTERESTING) {
if (blank_boundary) {
memset(hex, ' ', strlen(hex));
} else if (!(opt & OUTPUT_ANNOTATE_COMPAT)) {
length--;
putchar('^');
}
}

if (mark_unblamable_lines && ent->unblamable) {
length--;
putchar('*');
}
if (mark_ignored_lines && ent->ignored) {
length--;
putchar('?');
}
if ((suspect->commit->object.flags & UNINTERESTING) &&
blank_boundary)
memset(hex, ' ', strlen(hex));
length -= print_marks(stdout, ent, opt);

printf("%.*s", (int)(length < GIT_MAX_HEXSZ ? length : GIT_MAX_HEXSZ), hex);
if (opt & OUTPUT_ANNOTATE_COMPAT) {
Expand Down Expand Up @@ -647,11 +664,15 @@ static void find_alignment(struct blame_scoreboard *sb, int *option)
struct blame_entry *e;
int compute_auto_abbrev = (abbrev < 0);
int auto_abbrev = DEFAULT_ABBREV;
size_t max_marks_count = 0;

for (e = sb->ent; e; e = e->next) {
struct blame_origin *suspect = e->suspect;
int num;
size_t marks_count = count_marks(e, *option);

if (max_marks_count < marks_count)
max_marks_count = marks_count;
if (compute_auto_abbrev)
auto_abbrev = update_auto_abbrev(auto_abbrev, suspect);
if (strcmp(suspect->path, sb->path))
Expand Down Expand Up @@ -685,8 +706,12 @@ static void find_alignment(struct blame_scoreboard *sb, int *option)
max_score_digits = decimal_width(largest_score);

if (compute_auto_abbrev)
/* one more abbrev length is needed for the boundary commit */
abbrev = auto_abbrev + 1;
abbrev = auto_abbrev;
if (abbrev < (int)the_hash_algo->hexsz) {
abbrev += max_marks_count;
if (abbrev > (int)the_hash_algo->hexsz)
abbrev = the_hash_algo->hexsz;
}
}

static void sanity_check_on_fail(struct blame_scoreboard *sb, int baa)
Expand Down Expand Up @@ -1047,10 +1072,7 @@ int cmd_blame(int argc,
} else if (show_progress < 0)
show_progress = isatty(2);

if (0 < abbrev && abbrev < (int)the_hash_algo->hexsz)
/* one more abbrev length is needed for the boundary commit */
abbrev++;
else if (!abbrev)
if (!abbrev)
abbrev = the_hash_algo->hexsz;

if (revs_file && read_ancestry(revs_file))
Expand Down
12 changes: 8 additions & 4 deletions builtin/cat-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ static void batch_object_write(const char *obj_name,
data->info.sizep = &data->size;

if (pack)
ret = packed_object_info(pack, offset, &data->info);
ret = packed_object_info(NULL, pack, offset, &data->info);
else
ret = odb_read_object_info_extended(the_repository->objects,
&data->oid, &data->info,
Expand Down Expand Up @@ -837,8 +837,9 @@ static int batch_one_object_oi(const struct object_id *oid,
void *_payload)
{
struct for_each_object_payload *payload = _payload;
if (oi && oi->whence == OI_PACKED)
return payload->callback(oid, oi->u.packed.pack, oi->u.packed.offset,
if (oi && oi->source_infop->source->type == ODB_SOURCE_PACKED)
return payload->callback(oid, oi->source_infop->u.packed.pack,
oi->source_infop->u.packed.offset,
payload->payload);
return payload->callback(oid, NULL, 0, payload->payload);
}
Expand Down Expand Up @@ -909,7 +910,10 @@ static void batch_each_object(struct batch_options *opt,
&payload, flags);
}
} else {
struct object_info oi = { 0 };
struct odb_source_info source_info;
struct object_info oi = {
.source_infop = &source_info,
};

for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
Expand Down
Loading