Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9077923
reftable/writer: fix type used for number of records
pks-t Aug 12, 2025
d4a2159
reftable/writer: drop Git-specific `QSORT()` macro
pks-t Aug 12, 2025
5ed5f5d
reftable/stack: reorder code to avoid forward declarations
pks-t Aug 12, 2025
6fb1d81
reftable/stack: fix compiler warning due to missing braces
pks-t Aug 12, 2025
178c588
reftable/stack: allow passing flags to `reftable_stack_add()`
pks-t Aug 12, 2025
54d25de
reftable/stack: handle outdated stacks when compacting
pks-t Aug 12, 2025
8fd7a0e
reftable: don't second-guess errors from flock interface
pks-t Aug 12, 2025
16684b6
refs/reftable: always reload stacks when creating lock
pks-t Aug 12, 2025
e715f77
describe: pass oid struct by const pointer
peff Aug 18, 2025
db2664b
describe: error if blob not found
peff Aug 18, 2025
c647871
describe: catch unborn branch in describe_blob()
peff Aug 18, 2025
c4cf8ca
t/t1517: mark tests that fail with GIT_TEST_INSTALLED
me-and Aug 19, 2025
217e4a2
t5510: make confusing config cleanup more explicit
peff Aug 19, 2025
1de2903
t5510: stop changing top-level working directory
peff Aug 19, 2025
f1c2a42
t5510: prefer "git -C" to subshell for followRemoteHEAD tests
peff Aug 19, 2025
450fc2b
refs: do not clobber dangling symrefs
peff Aug 19, 2025
bcb20dd
doc/gitk: update reference to the external project
j6t Aug 20, 2025
8cfd4ac
describe: handle blob traversal with no commits
peff Aug 20, 2025
7c10e48
describe: pass commit to describe_commit()
peff Aug 18, 2025
716d342
doc: add discord to ways of getting help
DanieleSassoli Aug 20, 2025
96a04c4
Merge branch 'ad/t1517-short-help-tests-fix'
gitster Aug 29, 2025
00c2c50
Merge branch 'ps/reftable-libgit2-cleanup'
gitster Aug 29, 2025
040f05e
Merge branch 'ds/doc-community-discord'
gitster Aug 29, 2025
fea9d18
Merge branch 'jk/no-clobber-dangling-symref-with-fetch'
gitster Aug 29, 2025
c64ec66
Merge branch 'jk/describe-blob'
gitster Aug 29, 2025
7f09275
Merge branch 'js/doc-gitk-history'
gitster Aug 29, 2025
6ad8021
The fifth batch
gitster Aug 29, 2025
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
9 changes: 9 additions & 0 deletions Documentation/MyFirstContribution.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ respond to you. It's better to ask your questions in the channel so that you
can be answered if you disconnect and so that others can learn from the
conversation.

==== https://discord.gg/GRFVkzgxRd[#discord] on Discord
This is an unofficial Git Discord server for everyone, from people just
starting out with Git to those who develop it. It's a great place to ask
questions, share tips, and connect with the broader Git community in real time.

The server has channels for general discussions and specific channels for those
who use Git and those who develop it. The server's search functionality also
allows you to find previous conversations and answers to common questions.

[[getting-started]]
== Getting Started

Expand Down
16 changes: 16 additions & 0 deletions Documentation/RelNotes/2.52.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ Performance, Internal Implementation, Development Support etc.
* Remove dependency on the_repository and other globals from the
commit-graph code, and other changes unrelated to de-globaling.

* Discord has been added to the first contribution documentation as
another way to ask for help.


Fixes since v2.51
-----------------
Expand Down Expand Up @@ -110,6 +113,18 @@ including security updates, are included in this release.
been corrected.
(merge 8f32a5a6c0 jk/fetch-check-graph-objects-fix later to maint).

* "git fetch" can clobber a symref that is dangling when the
remote-tracking HEAD is set to auto update, which has been
corrected.

* "git describe <blob>" misbehaves and/or crashes in some corner
cases, which has been taught to exit with failure gracefully.
(merge 7c10e48e81 jk/describe-blob later to maint).

* Manual page for "gitk" is updated with the current maintainer's
name.
(merge bcb20dda83 js/doc-gitk-history later to maint).

* Other code cleanup, docfix, build fix, etc.
(merge 823d537fa7 kh/doc-git-log-markup-fix later to maint).
(merge cf7efa4f33 rj/t6137-cygwin-fix later to maint).
Expand All @@ -118,3 +133,4 @@ including security updates, are included in this release.
(merge 741f36c7d9 kr/clone-synopsis-fix later to maint).
(merge a60203a015 dk/t7005-editor-updates later to maint).
(merge 7d4a5fef7d ds/doc-count-objects-fix later to maint).
(merge 16684b6fae ps/reftable-libgit2-cleanup later to maint).
8 changes: 4 additions & 4 deletions Documentation/gitk.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,16 @@ used by default. If '$XDG_CONFIG_HOME' is not set it defaults to

History
-------
Gitk was the first graphical repository browser. It's written in
tcl/tk.
Gitk was the first graphical repository browser, written by
Paul Mackerras in Tcl/Tk.

'gitk' is actually maintained as an independent project, but stable
versions are distributed as part of the Git suite for the convenience
of end users.

gitk-git/ comes from Paul Mackerras's gitk project:
`gitk-git/` comes from Johannes Sixt's gitk project:

git://ozlabs.org/~paulus/gitk
https://github.com/j6t/gitk

SEE ALSO
--------
Expand Down
41 changes: 25 additions & 16 deletions builtin/describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,26 +352,24 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
repo_find_unique_abbrev(the_repository, oid, abbrev));
}

static void describe_commit(struct object_id *oid, struct strbuf *dst)
static void describe_commit(struct commit *cmit, struct strbuf *dst)
{
struct commit *cmit, *gave_up_on = NULL;
struct commit *gave_up_on = NULL;
struct lazy_queue queue = LAZY_QUEUE_INIT;
struct commit_name *n;
struct possible_tag all_matches[MAX_TAGS];
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;

cmit = lookup_commit_reference(the_repository, oid);

n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
/*
* Exact match to an existing ref.
*/
append_name(n, dst);
if (n->misnamed || longformat)
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : &cmit->object.oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
return;
Expand Down Expand Up @@ -528,39 +526,47 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}

struct process_commit_data {
struct object_id current_commit;
struct object_id looking_for;
struct commit *current_commit;
const struct object_id *looking_for;
struct strbuf *dst;
struct rev_info *revs;
};

static void process_commit(struct commit *commit, void *data)
{
struct process_commit_data *pcd = data;
pcd->current_commit = commit->object.oid;
pcd->current_commit = commit;
}

static void process_object(struct object *obj, const char *path, void *data)
{
struct process_commit_data *pcd = data;

if (oideq(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
if (oideq(pcd->looking_for, &obj->oid) && !pcd->dst->len) {
reset_revision_walk();
describe_commit(&pcd->current_commit, pcd->dst);
strbuf_addf(pcd->dst, ":%s", path);
if (pcd->current_commit) {
describe_commit(pcd->current_commit, pcd->dst);
strbuf_addf(pcd->dst, ":%s", path);
}
free_commit_list(pcd->revs->commits);
pcd->revs->commits = NULL;
}
}

static void describe_blob(struct object_id oid, struct strbuf *dst)
static void describe_blob(const struct object_id *oid, struct strbuf *dst)
{
struct rev_info revs;
struct strvec args = STRVEC_INIT;
struct process_commit_data pcd = { *null_oid(the_hash_algo), oid, dst, &revs};
struct object_id head_oid;
struct process_commit_data pcd = { NULL, oid, dst, &revs};

if (repo_get_oid(the_repository, "HEAD", &head_oid))
die(_("cannot search for blob '%s' on an unborn branch"),
oid_to_hex(oid));

strvec_pushl(&args, "internal: The first arg is not parsed",
"--objects", "--in-commit-order", "--reverse", "HEAD",
"--objects", "--in-commit-order", "--reverse",
oid_to_hex(&head_oid),
NULL);

repo_init_revisions(the_repository, &revs, NULL);
Expand All @@ -574,6 +580,9 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
reset_revision_walk();
release_revisions(&revs);
strvec_clear(&args);

if (!dst->len)
die(_("blob '%s' not reachable from HEAD"), oid_to_hex(oid));
}

static void describe(const char *arg, int last_one)
Expand All @@ -590,10 +599,10 @@ static void describe(const char *arg, int last_one)
cmit = lookup_commit_reference_gently(the_repository, &oid, 1);

if (cmit)
describe_commit(&oid, &sb);
describe_commit(cmit, &sb);
else if (odb_read_object_info(the_repository->objects,
&oid, NULL) == OBJ_BLOB)
describe_blob(oid, &sb);
describe_blob(&oid, &sb);
else
die(_("%s is neither a commit nor blob"), arg);

Expand Down
34 changes: 30 additions & 4 deletions refs/files-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -2515,13 +2515,37 @@ static enum ref_transaction_error split_symref_update(struct ref_update *update,
*/
static enum ref_transaction_error check_old_oid(struct ref_update *update,
struct object_id *oid,
struct strbuf *referent,
struct strbuf *err)
{
if (update->flags & REF_LOG_ONLY ||
!(update->flags & REF_HAVE_OLD) ||
oideq(oid, &update->old_oid))
!(update->flags & REF_HAVE_OLD))
return 0;

if (oideq(oid, &update->old_oid)) {
/*
* Normally matching the expected old oid is enough. Either we
* found the ref at the expected state, or we are creating and
* expect the null oid (and likewise found nothing).
*
* But there is one exception for the null oid: if we found a
* symref pointing to nothing we'll also get the null oid. In
* regular recursive mode, that's good (we'll write to what the
* symref points to, which doesn't exist). But in no-deref
* mode, it means we'll clobber the symref, even though the
* caller asked for this to be a creation event. So flag
* that case to preserve the dangling symref.
*/
if ((update->flags & REF_NO_DEREF) && referent->len &&
is_null_oid(oid)) {
strbuf_addf(err, "cannot lock ref '%s': "
"dangling symref already exists",
ref_update_original_update_refname(update));
return REF_TRANSACTION_ERROR_CREATE_EXISTS;
}
return 0;
}

if (is_null_oid(&update->old_oid)) {
strbuf_addf(err, "cannot lock ref '%s': "
"reference already exists",
Expand Down Expand Up @@ -2661,7 +2685,8 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
if (update->old_target)
ret = ref_update_check_old_target(referent.buf, update, err);
else
ret = check_old_oid(update, &lock->old_oid, err);
ret = check_old_oid(update, &lock->old_oid,
&referent, err);
if (ret)
goto out;
} else {
Expand Down Expand Up @@ -2693,7 +2718,8 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
ret = REF_TRANSACTION_ERROR_EXPECTED_SYMREF;
goto out;
} else {
ret = check_old_oid(update, &lock->old_oid, err);
ret = check_old_oid(update, &lock->old_oid,
&referent, err);
if (ret) {
goto out;
}
Expand Down
53 changes: 39 additions & 14 deletions refs/reftable-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,10 +1012,6 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
if (!arg) {
struct reftable_addition *addition;

ret = reftable_stack_reload(be->stack);
if (ret)
return ret;

ret = reftable_stack_new_addition(&addition, be->stack,
REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret) {
Expand Down Expand Up @@ -1278,9 +1274,33 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
ret = ref_update_check_old_target(referent->buf, u, err);
if (ret)
return ret;
} else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD &&
!oideq(&current_oid, &u->old_oid)) {
if (is_null_oid(&u->old_oid)) {
} else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD) {
if (oideq(&current_oid, &u->old_oid)) {
/*
* Normally matching the expected old oid is enough. Either we
* found the ref at the expected state, or we are creating and
* expect the null oid (and likewise found nothing).
*
* But there is one exception for the null oid: if we found a
* symref pointing to nothing we'll also get the null oid. In
* regular recursive mode, that's good (we'll write to what the
* symref points to, which doesn't exist). But in no-deref
* mode, it means we'll clobber the symref, even though the
* caller asked for this to be a creation event. So flag
* that case to preserve the dangling symref.
*
* Everything else is OK and we can fall through to the
* end of the conditional chain.
*/
if ((u->flags & REF_NO_DEREF) &&
referent->len &&
is_null_oid(&u->old_oid)) {
strbuf_addf(err, _("cannot lock ref '%s': "
"dangling symref already exists"),
ref_update_original_update_refname(u));
return REF_TRANSACTION_ERROR_CREATE_EXISTS;
}
} else if (is_null_oid(&u->old_oid)) {
strbuf_addf(err, _("cannot lock ref '%s': "
"reference already exists"),
ref_update_original_update_refname(u));
Expand Down Expand Up @@ -1974,7 +1994,8 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
REFTABLE_STACK_NEW_ADDITION_RELOAD);

done:
assert(ret != REFTABLE_API_ERROR);
Expand Down Expand Up @@ -2003,7 +2024,8 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
REFTABLE_STACK_NEW_ADDITION_RELOAD);

done:
assert(ret != REFTABLE_API_ERROR);
Expand Down Expand Up @@ -2375,7 +2397,8 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
goto done;
arg.stack = be->stack;

ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg);
ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
REFTABLE_STACK_NEW_ADDITION_RELOAD);

done:
return ret;
Expand Down Expand Up @@ -2446,7 +2469,8 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
return ret;
arg.stack = be->stack;

ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg);
ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
REFTABLE_STACK_NEW_ADDITION_RELOAD);

assert(ret != REFTABLE_API_ERROR);
return ret;
Expand Down Expand Up @@ -2567,15 +2591,16 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;

ret = reftable_stack_init_log_iterator(be->stack, &it);
ret = reftable_stack_new_addition(&add, be->stack,
REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret < 0)
goto done;

ret = reftable_iterator_seek_log(&it, refname);
ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;

ret = reftable_stack_new_addition(&add, be->stack, 0);
ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)
goto done;

Expand Down
9 changes: 6 additions & 3 deletions reftable/reftable-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,15 @@ int reftable_addition_commit(struct reftable_addition *add);
* transaction. Releases the lock if held. */
void reftable_addition_destroy(struct reftable_addition *add);

/* add a new table to the stack. The write_table function must call
* reftable_writer_set_limits, add refs and return an error value. */
/*
* Add a new table to the stack. The write_table function must call
* reftable_writer_set_limits, add refs and return an error value.
* The flags are passed through to `reftable_stack_new_addition()`.
*/
int reftable_stack_add(struct reftable_stack *st,
int (*write_table)(struct reftable_writer *wr,
void *write_arg),
void *write_arg);
void *write_arg, unsigned flags);

struct reftable_iterator;

Expand Down
4 changes: 2 additions & 2 deletions reftable/reftable-writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ int reftable_writer_add_ref(struct reftable_writer *w,
the records before adding them, reordering the records array passed in.
*/
int reftable_writer_add_refs(struct reftable_writer *w,
struct reftable_ref_record *refs, int n);
struct reftable_ref_record *refs, size_t n);

/*
adds reftable_log_records. Log records are keyed by (refname, decreasing
Expand All @@ -171,7 +171,7 @@ int reftable_writer_add_log(struct reftable_writer *w,
the records before adding them, reordering records array passed in.
*/
int reftable_writer_add_logs(struct reftable_writer *w,
struct reftable_log_record *logs, int n);
struct reftable_log_record *logs, size_t n);

/* reftable_writer_close finalizes the reftable. The writer is retained so
* statistics can be inspected. */
Expand Down
Loading