Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsibley/0eb1f9d227b143fb7fe97fc2661eac9a to your computer and use it in GitHub Desktop.
Save tsibley/0eb1f9d227b143fb7fe97fc2661eac9a to your computer and use it in GitHub Desktop.
From c7caebe7d19d43bd8dad98afd28ee703e04ab806 Mon Sep 17 00:00:00 2001
From: Thomas Sibley <tom@zulutango.org>
Date: Fri, 8 Mar 2024 16:42:45 -0800
Subject: [PATCH] wip! status: show when tracking branch was last fetched
<https://metasocial.com/@trs/112062359954735355>
fetch now logs no-ops as "up-to-date" reflog entries to support this
---
builtin/fetch.c | 17 +++++++-----
refs.h | 9 ++++++-
refs/refs-internal.h | 13 +++------
remote.c | 64 +++++++++++++++++++++++++++++++++++---------
4 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 0a7a1a3476..53d1543937 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -638,7 +638,8 @@ static struct ref *get_ref_map(struct remote *remote,
static int s_update_ref(const char *action,
struct ref *ref,
struct ref_transaction *transaction,
- int check_old)
+ int check_old,
+ int log_only)
{
char *msg;
char *rla = getenv("GIT_REFLOG_ACTION");
@@ -667,7 +668,8 @@ static int s_update_ref(const char *action,
ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL,
- 0, msg, &err);
+ log_only ? REF_LOG_ONLY : 0,
+ msg, &err);
if (ret) {
ret = STORE_REF_ERROR_OTHER;
goto out;
@@ -905,6 +907,9 @@ static int update_local_ref(struct ref *ref,
die(_("object %s not found"), oid_to_hex(&ref->new_oid));
if (oideq(&ref->old_oid, &ref->new_oid)) {
+ // XXX FIXME: check rv? do we care? an error will be printed inside
+ // this call if the txn fails...
+ s_update_ref("up-to-date", ref, transaction, 1, 1);
if (verbosity > 0)
display_ref_update(display_state, '=', _("[up to date]"), NULL,
remote_ref->name, ref->name,
@@ -930,7 +935,7 @@ static int update_local_ref(struct ref *ref,
starts_with(ref->name, "refs/tags/")) {
if (force || ref->force) {
int r;
- r = s_update_ref("updating tag", ref, transaction, 0);
+ r = s_update_ref("updating tag", ref, transaction, 0, 0);
display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
r ? _("unable to update local ref") : NULL,
remote_ref->name, ref->name,
@@ -969,7 +974,7 @@ static int update_local_ref(struct ref *ref,
what = _("[new ref]");
}
- r = s_update_ref(msg, ref, transaction, 0);
+ r = s_update_ref(msg, ref, transaction, 0, 0);
display_ref_update(display_state, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
remote_ref->name, ref->name,
@@ -993,7 +998,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "..");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
- r = s_update_ref("fast-forward", ref, transaction, 1);
+ r = s_update_ref("fast-forward", ref, transaction, 1, 0);
display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
remote_ref->name, ref->name,
@@ -1006,7 +1011,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "...");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
- r = s_update_ref("forced-update", ref, transaction, 1);
+ r = s_update_ref("forced-update", ref, transaction, 1, 0);
display_ref_update(display_state, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
remote_ref->name, ref->name,
diff --git a/refs.h b/refs.h
index 298caf6c61..8df2fa9e93 100644
--- a/refs.h
+++ b/refs.h
@@ -683,6 +683,13 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
*/
#define REF_FORCE_CREATE_REFLOG (1 << 1)
+/*
+ * Log a ref update but do not actually perform it. This is used
+ * internally when a symbolic ref update is split up and also when
+ * recording fetches resulting in no-op ("up-to-date" log entries).
+ */
+#define REF_LOG_ONLY (1 << 7)
+
/*
* Blindly write an object_id. This is useful for testing data corruption
* scenarios.
@@ -700,7 +707,7 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
*/
#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \
- REF_SKIP_REFNAME_VERIFICATION)
+ REF_SKIP_REFNAME_VERIFICATION | REF_LOG_ONLY)
/*
* Add a reference update to transaction. `new_oid` is the value that
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 56641aa57a..74ae62ecc9 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -14,9 +14,9 @@ struct ref_transaction;
/*
* The following flags can appear in `ref_update::flags`. Their
- * numerical values must not conflict with those of REF_NO_DEREF and
- * REF_FORCE_CREATE_REFLOG, which are also stored in
- * `ref_update::flags`.
+ * numerical values must not conflict with those of the public flags
+ * (e.g. REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, etc.), which are also
+ * stored in `ref_update::flags`.
*/
/*
@@ -30,13 +30,6 @@ struct ref_transaction;
*/
#define REF_HAVE_OLD (1 << 3)
-/*
- * Used as a flag in ref_update::flags when we want to log a ref
- * update but not actually perform it. This is used when a symbolic
- * ref update is split up.
- */
-#define REF_LOG_ONLY (1 << 7)
-
/*
* Return the length of time to retry acquiring a loose reference lock
* before giving up, in milliseconds:
diff --git a/remote.c b/remote.c
index 9090632e96..167b24866e 100644
--- a/remote.c
+++ b/remote.c
@@ -2259,6 +2259,29 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
return stat_branch_pair(branch->refname, base, num_ours, num_theirs, abf);
}
+/*
+ * Extract timestamp and tz from the first (or last) entry in the reflog. For
+ * use with for_each_reflog_ent() or for_each_reflog_ent_reverse().
+ */
+struct grab_1st_date_cbdata {
+ timestamp_t timestamp;
+ int tz;
+};
+
+static int grab_1st_date(struct object_id *ooid UNUSED,
+ struct object_id *noid UNUSED,
+ const char *email UNUSED,
+ timestamp_t timestamp,
+ int tz,
+ const char *message UNUSED,
+ void *cb_data)
+{
+ struct grab_1st_date_cbdata *cb = cb_data;
+ cb->timestamp = timestamp;
+ cb->tz = tz;
+ return 1;
+}
+
/*
* Return true when there is anything to report, otherwise false.
*/
@@ -2278,6 +2301,21 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
upstream_is_gone = 1;
}
+ // XXX FIXME: should this bit move into stat_tracking_info() instead?
+ // there it could be used by wt_shortstatus_print_tracking() too.
+ struct grab_1st_date_cbdata base_date;
+ const char *as_of;
+
+ if (for_each_reflog_ent_reverse(full_base, grab_1st_date, &base_date)) {
+ // XXX FIXME: someone will probably want this date mode configurable but meh?
+ as_of = show_date(base_date.timestamp, base_date.tz, DATE_MODE(RELATIVE));
+ } else {
+ // XXX FIXME: ok to interpolate a translated string into a larger
+ // translated string? not best practice... but acceptable in this
+ // codebase or not?
+ as_of = _("an unknown date");
+ }
+
base = shorten_unambiguous_ref(full_base, 0);
if (upstream_is_gone) {
strbuf_addf(sb,
@@ -2288,45 +2326,45 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
_(" (use \"git branch --unset-upstream\" to fixup)\n"));
} else if (!sti) {
strbuf_addf(sb,
- _("Your branch is up to date with '%s'.\n"),
- base);
+ _("Your branch is up to date with '%s' (as of %s).\n"),
+ base, as_of);
} else if (abf == AHEAD_BEHIND_QUICK) {
strbuf_addf(sb,
- _("Your branch and '%s' refer to different commits.\n"),
- base);
+ _("Your branch and '%s' (as of %s) refer to different commits.\n"),
+ base, as_of);
if (advice_enabled(ADVICE_STATUS_HINTS))
strbuf_addf(sb, _(" (use \"%s\" for details)\n"),
"git status --ahead-behind");
} else if (!theirs) {
strbuf_addf(sb,
- Q_("Your branch is ahead of '%s' by %d commit.\n",
- "Your branch is ahead of '%s' by %d commits.\n",
+ Q_("Your branch is ahead of '%s' (as of %s) by %d commit.\n",
+ "Your branch is ahead of '%s' (as of %s) by %d commits.\n",
ours),
- base, ours);
+ base, as_of, ours);
if (advice_enabled(ADVICE_STATUS_HINTS))
strbuf_addstr(sb,
_(" (use \"git push\" to publish your local commits)\n"));
} else if (!ours) {
strbuf_addf(sb,
- Q_("Your branch is behind '%s' by %d commit, "
+ Q_("Your branch is behind '%s' (as of %s) by %d commit, "
"and can be fast-forwarded.\n",
- "Your branch is behind '%s' by %d commits, "
+ "Your branch is behind '%s' (as of %s) by %d commits, "
"and can be fast-forwarded.\n",
theirs),
- base, theirs);
+ base, as_of, theirs);
if (advice_enabled(ADVICE_STATUS_HINTS))
strbuf_addstr(sb,
_(" (use \"git pull\" to update your local branch)\n"));
} else {
strbuf_addf(sb,
- Q_("Your branch and '%s' have diverged,\n"
+ Q_("Your branch and '%s' (as of %s) have diverged,\n"
"and have %d and %d different commit each, "
"respectively.\n",
- "Your branch and '%s' have diverged,\n"
+ "Your branch and '%s' (as of %s) have diverged,\n"
"and have %d and %d different commits each, "
"respectively.\n",
ours + theirs),
- base, ours, theirs);
+ base, as_of, ours, theirs);
if (show_divergence_advice &&
advice_enabled(ADVICE_STATUS_HINTS))
strbuf_addstr(sb,
--
2.25.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment