Re: Tracking branch history

From: Shawn Pearce <spearce@spearce.org>
Date: 2006-05-13 17:17:53
Junio C Hamano <junkio@cox.net> wrote:
> Shawn Pearce <spearce@spearce.org> writes:
> 
> > git-udpate-ref.  So just have it append the ref's history to a file:
> >
> > 	.git/log/refs/heads/$branch
> >
> > where the history records are stored as:
> >
> > 	40 byte commit-ish SHA1
> > 	<SP>
> > 	<committer>
> > 	<LF>
> >
> > e.g.:
> >
> > 	cbb6d91d95e523c2b6a6b52577c4be28d18ace83 Shawn O. Pearce <spearce@spearce.org> 1137039378 -0500
> > 	ae8c74e96a1e02bbfb7f1a9669b77d6f8ee6c3cf Shawn O. Pearce <spearce@spearce.org> 1136921470 -0500
> >
> 
> Because the question we often would want to ask is "two days ago
> my tip worked but today it does not", recording the timestamp
> makes sense, but I do not know what the point is for the name
> and e-mail.  If it is in your local repository (i.e. the program
> that updates the tip ref is not receive-pack which is invoked by
> your pushing into a remote repo), it will always be you.  And in
> the receive-pack case, the information is not available to begin
> with (you may have a UNIX UID but that is about it).

Agreed.  Prototype patch below.

While writing this I discovered at least two chunks of GIT which
don't use git-update-ref: fetch.c and upload-pack.c.  fetch.c uses
the APIs in refs.c but upload-pack.c doesn't.  I spent a couple of
hours trying to convert update-ref.c to use the APIs in refs.c so
I could just put the logging change there, but that turned out to
be more difficult than expected for a simple prototype so it all
went out the window.

-- >-
Log ref updates to logs/refs/<refname>

If .git/logs/refs/<refname> exists then append a line to it whenever
git-update-ref <refname> is executed.  Each log line contains the
following information:

  40 byte tree-ish SHA1
  <SP>
  date/time
  <LF>

where date/time is the current date, time and timezone in the
standard GIT date format.  If the caller is unable to append to
the log file and the log file exists then git-update-ref will fail
without updating <refname>.

---

 Documentation/git-update-ref.txt |   15 ++++++++++++++
 update-ref.c                     |   41 +++++++++++++++++++++++++++++++++++---
 2 files changed, 53 insertions(+), 3 deletions(-)

8f1ccd3b0eda9d54eca37af178113c91174e81ca
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 475237f..d314786 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -49,6 +49,21 @@ for reading but not for writing (so we'l
 ref symlink to some other tree, if you have copied a whole
 archive by creating a symlink tree).
 
+Logging Updates
+---------------
+If "$GIT_DIR/logs/<ref>" (possibly dereferencing symbolic refs)
+exists then `git-update-ref` will append a line to the log file
+describing the change in ref value.  Log lines are formatted as:
+
+    . sha1 SP date LF
++
+Where "sha1" is the 40 character hexadecimal value of <newvalue>
+and "date" is the current date/time and timezone in the standard
+GIT date format.
+
+An update will fail (without changing <ref>) if the log file
+exists but the current user is unable to append to the file.
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>.
diff --git a/update-ref.c b/update-ref.c
index fd48742..bffe5f9 100644
--- a/update-ref.c
+++ b/update-ref.c
@@ -20,9 +20,9 @@ int main(int argc, char **argv)
 {
 	char *hex;
 	const char *refname, *value, *oldval, *path;
-	char *lockpath;
+	char *lockpath, *logpath;
 	unsigned char sha1[20], oldsha1[20], currsha1[20];
-	int fd, written;
+	int fd, logfd, written, pfxlen;
 
 	setup_git_directory();
 	git_config(git_default_config);
@@ -38,7 +38,9 @@ int main(int argc, char **argv)
 	if (oldval && get_sha1(oldval, oldsha1))
 		die("%s: not a valid old SHA1", oldval);
 
-	path = resolve_ref(git_path("%s", refname), currsha1, !!oldval);
+	path = git_path("%s", refname);
+	pfxlen = strlen(path) - strlen(refname);
+	path = resolve_ref(path, currsha1, !!oldval);
 	if (!path)
 		die("No such ref: %s", refname);
 
@@ -50,6 +52,17 @@ int main(int argc, char **argv)
 			exit(0);
 	}
 	path = strdup(path);
+
+	/*
+	 * If logging is required make sure we can append to the log.
+	 */
+	logpath = strdup(git_path("logs/%s", path + pfxlen));
+	logfd = open(logpath, O_APPEND | O_WRONLY, 0);
+	if (logfd < 0 && errno != ENOENT)
+		die("Unable to append to log %s", logpath);
+	if (logfd >= 0)
+		setup_ident();
+
 	lockpath = mkpath("%s.lock", path);
 	if (safe_create_leading_directories(lockpath) < 0)
 		die("Unable to create all of %s", lockpath);
@@ -75,6 +88,28 @@ int main(int argc, char **argv)
 	}
 
 	/*
+	 * Write to the log, if it was opened.
+	 */
+	if (logfd >= 0) {
+		char now[50];
+		char logrec[100];
+		unsigned len;
+
+		datestamp(now, sizeof(now));
+		len = snprintf(logrec, sizeof(logrec), "%s %s\n", sha1_to_hex(sha1), now);
+		if (len >= sizeof(logrec)) {
+			unlink(lockpath);
+			die("Internal error formatting log record.");
+		}
+		written = write(logfd, logrec, len);
+		if (written != len) {
+			unlink(lockpath);
+			die("Unable to append to %s", logpath);
+		}
+		close(logfd);
+	}
+
+	/*
 	 * Finally, replace the old ref with the new one
 	 */
 	if (rename(lockpath, path) < 0) {
-- 
1.3.2.g7278

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Received on Sat May 13 17:18:35 2006

This archive was generated by hypermail 2.1.8 : 2006-05-13 17:18:52 EST