diff options
authorJeff King <>2016-08-01 19:37:00 (GMT)
committerJunio C Hamano <>2016-08-01 21:49:41 (GMT)
commit4d9c7e6f45523ce1bf9615689e6c4e13fd82ed5d (patch)
parent0b65a8dbdb38962e700ee16776a3042beb489060 (diff)
am: reset cached ident date for each patch
When we compute the date to go in author/committer lines of commits, or tagger lines of tags, we get the current date once and then cache it for the rest of the program. This is a good thing in some cases, like "git commit", because it means we do not racily assign different times to the author/committer fields of a single commit object. But as more programs start to make many commits in a single process (e.g., the recently builtin "git am"), it means that you'll get long strings of commits with identical committer timestamps (whereas before, we invoked "git commit" many times and got true timestamps). This patch addresses it by letting callers reset the cached time, which means they'll get a fresh time on their next call to git_committer_info() or git_author_info(). The first caller to do so is "git am", which resets the time for each patch it applies. It would be nice if we could just do this automatically before filling in the ident fields of commit and tag objects. Unfortunately, it's hard to know where a particular logical operation begins and ends. For instance, if commit_tree_extended() were to call reset_ident_date() before getting the committer/author ident, that doesn't quite work; sometimes the author info is passed in to us as a parameter, and it may or may not have come from a previous call to ident_default_date(). So in those cases, we lose the property that the committer and the author timestamp always match. You could similarly put a date-reset at the end of commit_tree_extended(). That actually works in the current code base, but it's fragile. It makes the assumption that after commit_tree_extended() finishes, the caller has no other operations that would logically want to fall into the same timestamp. So instead we provide the tool to easily do the reset, and let the high-level callers use it to annotate their own logical operations. There's no automated test, because it would be inherently racy (it depends on whether the program takes multiple seconds to run). But you can see the effect with something like: # make a fake 100-patch series top=$(git rev-parse HEAD) bottom=$(git rev-list --first-parent -100 HEAD | tail -n 1) git log --format=email --reverse --first-parent \ --binary -m -p $bottom..$top >patch # now apply it; this presumably takes multiple seconds git checkout --detach $bottom git am <patch # now count the number of distinct committer times; # prior to this patch, there would only be one, but # now we'd typically see several. git log --format=%ct $bottom.. | sort -u Suggested-by: Linus Torvalds <> Helped-by: Paul Tan <> Signed-off-by: Jeff King <> Signed-off-by: Junio C Hamano <>
3 files changed, 8 insertions, 0 deletions
diff --git a/builtin/am.c b/builtin/am.c
index d003939..8058583 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1840,6 +1840,8 @@ static void am_run(struct am_state *state, int resume)
const char *mail = am_path(state, msgnum(state));
int apply_status;
+ reset_ident_date();
if (!file_exists(mail))
goto next;
diff --git a/cache.h b/cache.h
index 4ff196c..1876e12 100644
--- a/cache.h
+++ b/cache.h
@@ -1256,6 +1256,7 @@ extern const char *ident_default_email(void);
extern const char *git_editor(void);
extern const char *git_pager(int stdout_is_tty);
extern int git_ident_config(const char *, const char *, void *);
+extern void reset_ident_date(void);
struct ident_split {
const char *name_begin;
diff --git a/ident.c b/ident.c
index 4fd82d1..0c78df7 100644
--- a/ident.c
+++ b/ident.c
@@ -186,6 +186,11 @@ static const char *ident_default_date(void)
return git_default_date.buf;
+void reset_ident_date(void)
+ strbuf_reset(&git_default_date);
static int crud(unsigned char c)
return c <= 32 ||