Git development
 help / color / mirror / Atom feed
* Re: Database consistency after a successful pull
From: McMullan, Jason @ 2005-06-06 18:30 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, Linus Torvalds, GIT Mailling list
In-Reply-To: <Pine.LNX.4.21.0506061000531.30848-100000@iabervon.org>

[-- Attachment #1: Type: text/plain, Size: 532 bytes --]

On Mon, 2005-06-06 at 12:21 -0400, Daniel Barkalow wrote:
> [snip snip]
>
> My bias is to call a database consistent with only deltas having the
> referents; the rest goes towards completeness, since you have and can read
> everything that you have anything for (but may not be able to do some
> particular operation).

Now, if we had consistent URIs for the .git/branches/* files, we could
do 'lazy-pull' and really have our cake and eat it too.

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: clarifying two tree merge semantics
From: Junio C Hamano @ 2005-06-06 19:59 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506061210490.1876@ppc970.osdl.org>

By the way, there is one case that you need to keep an eye on if
you are making further fixes to "git-read-tree -m $H $M",
especially now we are talking about keeping what we slurp from
stage0 sometimes:

 (1) index has DF (file)
 (2) $H has DF (file); the index matches it.
 (3) $M has DF/DF (file), implicitly making DF a directory.

For path DF, this rule from the earlier matrix applies:

  exists          exists (index=$H)       no such path        *2*
  * path is removed.

For path DF/DF, this rule from the earlier matrix applies:

  no such path    no such path            exists
  * take $M without complaining.

Thanks to *2*, the current code gets it right and we do not end
up with a cache that records both DF and DF/DF at the same time.
I cannot tell if it is by design or by accident :-).

There is a safety valve at the end of write-tree to refuse to
write out such a nonsensical tree but as Pasky argued back then
(a similar problem was discussed and resolved when you were
away, around the beginning of May, involving update-cache), when
that safety valuve was added, the damage has already been done
if we allow such a cache entry to be created in the first place.


^ permalink raw reply

* [PATCH 1/4] Operations on refs
From: Daniel Barkalow @ 2005-06-06 20:31 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0506061616590.30848-100000@iabervon.org>

This patch adds code to read a hash out of a specified file under
{GIT_DIR}/refs/, and to write such files atomically and optionally with an
compare and lock.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

Index: Makefile
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/Makefile  (mode:100644 sha1:a5e7552e10bf50888814d43b1ba1a7276d130ca6)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/Makefile  (mode:100644 sha1:c6e2eae2e68a47cdb88d2b1b7fec2c4cc230d506)
@@ -40,7 +40,7 @@
 	$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
-	 tag.o delta.o date.o index.o diff-delta.o patch-delta.o
+	 tag.o delta.o date.o index.o diff-delta.o patch-delta.o refs.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h
 
Index: cache.h
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/cache.h  (mode:100644 sha1:481f7c787040aadbbea877adbb3b9a4fd5f9b9d0)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/cache.h  (mode:100644 sha1:d2dbb0088b2a540972cd3c896d76b6c8dc1844ab)
@@ -110,6 +110,7 @@
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 
 extern char *get_object_directory(void);
+extern char *get_refs_directory(void);
 extern char *get_index_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
Index: refs.c
===================================================================
--- /dev/null  (tree:2dde8ae2d3300fb95e35facac622b9b54990624e)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/refs.c  (mode:100644 sha1:9973d1fc21e9d14f4cf1d30cb59f55cdfd7fc1e7)
@@ -0,0 +1,173 @@
+#include "refs.h"
+#include "cache.h"
+
+#include <errno.h>
+
+static char *ref_file_name(const char *ref)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int reflen = strlen(ref);
+	char *ret = xmalloc(baselen + 2 + reflen);
+	sprintf(ret, "%s/%s", base, ref);
+	return ret;
+}
+
+static char *ref_lock_file_name(const char *ref)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int reflen = strlen(ref);
+	char *ret = xmalloc(baselen + 7 + reflen);
+	sprintf(ret, "%s/%s.lock", base, ref);
+	return ret;
+}
+
+static int read_ref_file(const char *filename, unsigned char *sha1) {
+	int fd = open(filename, O_RDONLY);
+	char hex[41];
+	if (fd < 0) {
+		return error("Couldn't open %s\n", filename);
+	}
+	if ((read(fd, hex, 41) < 41) ||
+	    (hex[40] != '\n') ||
+	    get_sha1_hex(hex, sha1)) {
+		error("Couldn't read a hash from %s\n", filename);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+int get_ref_sha1(const char *ref, unsigned char *sha1)
+{
+	char *filename;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	retval = read_ref_file(filename, sha1);
+	free(filename);
+	return retval;
+}
+
+static int lock_ref_file(const char *filename, const char *lock_filename,
+			 const unsigned char *old_sha1)
+{
+	int fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	unsigned char current_sha1[20];
+	int retval;
+	if (fd < 0) {
+		return error("Couldn't open lock file for %s: %s",
+			     filename, strerror(errno));
+	}
+	retval = read_ref_file(filename, current_sha1);
+	if (old_sha1) {
+		if (retval) {
+			close(fd);
+			unlink(lock_filename);
+			return error("Could not read the current value of %s",
+				     filename);
+		}
+		if (memcmp(current_sha1, old_sha1, 20)) {
+			close(fd);
+			unlink(lock_filename);
+			error("The current value of %s is %s",
+			      filename, sha1_to_hex(current_sha1));
+			return error("Expected %s",
+				     sha1_to_hex(old_sha1));
+		}
+	} else {
+		if (!retval) {
+			close(fd);
+			unlink(lock_filename);
+			return error("Unexpectedly found a value of %s for %s",
+				     sha1_to_hex(current_sha1), filename);
+		}
+	}
+	return fd;
+}
+
+int lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	retval = lock_ref_file(filename, lock_filename, old_sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
+
+static int write_ref_file(const char *filename,
+			  const char *lock_filename, int fd,
+			  const unsigned char *sha1)
+{
+	char *hex = sha1_to_hex(sha1);
+	char term = '\n';
+	if (write(fd, hex, 40) < 40 ||
+	    write(fd, &term, 1) < 1) {
+		error("Couldn't write %s\n", filename);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	rename(lock_filename, filename);
+	return 0;
+}
+
+int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int retval;
+	if (fd < 0)
+		return -1;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	retval = write_ref_file(filename, lock_filename, fd, sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
+
+int check_ref_format(const char *ref)
+{
+	char *middle;
+	if (ref[0] == '.' || ref[0] == '/')
+		return -1;
+	middle = strchr(ref, '/');
+	if (!middle || !middle[1])
+		return -1;
+	if (strchr(middle + 1, '/'))
+		return -1;
+	return 0;
+}
+
+int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int fd;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		error("Writing %s", lock_filename);
+		perror("Open");
+	}
+	retval = write_ref_file(filename, lock_filename, fd, sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
Index: refs.h
===================================================================
--- /dev/null  (tree:2dde8ae2d3300fb95e35facac622b9b54990624e)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/refs.h  (mode:100644 sha1:60cf48086f61c9206a343425ba9fdae3dce62937)
@@ -0,0 +1,21 @@
+#ifndef REFS_H
+#define REFS_H
+
+/** Reads the refs file specified into sha1 **/
+extern int get_ref_sha1(const char *ref, unsigned char *sha1);
+
+/** Locks ref and returns the fd to give to write_ref_sha1() if the ref
+ * has the given value currently; otherwise, returns -1.
+ **/
+extern int lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
+
+/** Writes sha1 into the refs file specified, locked with the given fd. **/
+extern int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1);
+
+/** Writes sha1 into the refs file specified. **/
+extern int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1);
+
+/** Returns 0 if target has the right format for a ref. **/
+extern int check_ref_format(const char *target);
+
+#endif /* REFS_H */
Index: sha1_file.c
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/sha1_file.c  (mode:100644 sha1:a2ba4c81dba1b55b119d9ec3c42a7e4ce4ca1df5)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/sha1_file.c  (mode:100644 sha1:7cfd43c51ba20ee85fe6056c67bbc88cc90dad81)
@@ -58,7 +58,7 @@
 	return get_sha1_hex(buffer, result);
 }
 
-static char *git_dir, *git_object_dir, *git_index_file;
+static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir;
 static void setup_git_env(void)
 {
 	git_dir = gitenv(GIT_DIR_ENVIRONMENT);
@@ -69,6 +69,8 @@
 		git_object_dir = xmalloc(strlen(git_dir) + 9);
 		sprintf(git_object_dir, "%s/objects", git_dir);
 	}
+	git_refs_dir = xmalloc(strlen(git_dir) + 6);
+	sprintf(git_refs_dir, "%s/refs", git_dir);
 	git_index_file = gitenv(INDEX_ENVIRONMENT);
 	if (!git_index_file) {
 		git_index_file = xmalloc(strlen(git_dir) + 7);
@@ -83,6 +85,13 @@
 	return git_object_dir;
 }
 
+char *get_refs_directory(void)
+{
+	if (!git_refs_dir)
+		setup_git_env();
+	return git_refs_dir;
+}
+
 char *get_index_file(void)
 {
 	if (!git_index_file)


^ permalink raw reply

* [PATCH 2/4] rsh.c environment variable
From: Daniel Barkalow @ 2005-06-06 20:35 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0506061616590.30848-100000@iabervon.org>

rsh.c used to set the environment variable for the object database when
invoking the remote command. Now that there is a GIT_DIR variable, use
that instead.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

Index: rsh.c
===================================================================
--- 5d261be8a54c55542223536a72c53fab564cc28a/rsh.c  (mode:100644 sha1:5d1cb9d578a8e679fc190a9d7d2c842ad811223f)
+++ 2dde8ae2d3300fb95e35facac622b9b54990624e/rsh.c  (mode:100644 sha1:3eb9d9160531de91cbccfc1fdea2e9007a9cbfec)
@@ -36,8 +36,8 @@
 	*(path++) = '\0';
 	/* ssh <host> 'cd /<path>; stdio-pull <arg...> <commit-id>' */
 	snprintf(command, COMMAND_SIZE, 
-		 "cd /%s; %s=objects %s",
-		 path, DB_ENVIRONMENT, remote_prog);
+		 "%s='/%s' %s",
+		 GIT_DIR_ENVIRONMENT, path, remote_prog);
 	posn = command + strlen(command);
 	for (i = 0; i < rmt_argc; i++) {
 		*(posn++) = ' ';


^ permalink raw reply

* [PATCH 0/4] Writing refs in git-ssh-push
From: Daniel Barkalow @ 2005-06-06 20:27 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git

This series adds -w to git-ssh-push (and git-ssh-pull, which is the same).

 - Add code for reading and writing ref files
 - Fix the environment variable for the path in rsh.c
 - Add support for transferring references in pull.c
 - Add support for refs in ssh protocol and options to invoke it

I'll send documentation updates in another patch this evening.

	-Daniel
*This .sig left intentionally blank*



^ permalink raw reply

* [PATCH 3/4] Generic support for pulling refs
From: Daniel Barkalow @ 2005-06-06 20:38 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0506061616590.30848-100000@iabervon.org>

This adds support to pull.c for requesting a reference and writing it to a
file. All of the git-*-pull programs get stubs for now.

Index: http-pull.c
===================================================================
--- 9138b84eb683fc23a285445f7d7fc5a836ba01cb/http-pull.c  (mode:100644 sha1:551663e49234dc9b719ee4abb9f8dc8609d759aa)
+++ 8deba080337c75a41cb456cc8b59000654278e59/http-pull.c  (mode:100644 sha1:4f097e0d0bbd5ae28babf8b685dc3b02747f9f15)
@@ -92,6 +92,11 @@
 	return 0;
 }
 
+int fetch_ref(char *ref, unsigned char *sha1)
+{
+	return -1;
+}
+
 int main(int argc, char **argv)
 {
 	char *commit_id;
Index: local-pull.c
===================================================================
--- 9138b84eb683fc23a285445f7d7fc5a836ba01cb/local-pull.c  (mode:100644 sha1:e5d834ff2f7d6949ca2c7dd2424c65f6431a839b)
+++ 8deba080337c75a41cb456cc8b59000654278e59/local-pull.c  (mode:100644 sha1:867e78dbdd2fc5dacdad3c3e3ab5ef1bfde6ba51)
@@ -73,6 +73,11 @@
 	return -1;
 }
 
+int fetch_ref(char *ref, unsigned char *sha1)
+{
+	return -1;
+}
+
 static const char *local_pull_usage = 
 "git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
 
Index: pull.c
===================================================================
--- 9138b84eb683fc23a285445f7d7fc5a836ba01cb/pull.c  (mode:100644 sha1:cd77738ac62be17e7382bc3b368e686f11f7098d)
+++ 8deba080337c75a41cb456cc8b59000654278e59/pull.c  (mode:100644 sha1:a60f1e49bda1bf12e11e0abccfaf4201130f4303)
@@ -3,6 +3,11 @@
 #include "cache.h"
 #include "commit.h"
 #include "tree.h"
+#include "refs.h"
+
+const char *write_ref = NULL;
+
+const unsigned char *current_ref = NULL;
 
 int get_tree = 0;
 int get_history = 0;
@@ -105,16 +110,42 @@
 	return 0;
 }
 
+static int interpret_target(char *target, unsigned char *sha1)
+{
+	if (!get_sha1_hex(target, sha1))
+		return 0;
+	if (!check_ref_format(target)) {
+		if (!fetch_ref(target, sha1)) {
+			return 0;
+		}
+	}
+	return -1;
+}
+
+
 int pull(char *target)
 {
-	int retval;
 	unsigned char sha1[20];
-	retval = get_sha1_hex(target, sha1);
-	if (retval)
-		return retval;
-	retval = make_sure_we_have_it(commitS, sha1);
-	if (retval)
-		return retval;
-	memcpy(current_commit_sha1, sha1, 20);
-	return process_commit(sha1);
+	int fd = -1;
+
+	if (write_ref && current_ref) {
+		fd = lock_ref_sha1(write_ref, current_ref);
+		if (fd < 0)
+			return -1;
+	}
+
+	if (interpret_target(target, sha1))
+		return error("Could not interpret %s as something to pull",
+			     target);
+	if (process_commit(sha1))
+		return -1;
+	
+	if (write_ref) {
+		if (current_ref) {
+			write_ref_sha1(write_ref, fd, sha1);
+		} else {
+			write_ref_sha1_unlocked(write_ref, sha1);
+		}
+	}
+	return 0;
 }
Index: pull.h
===================================================================
--- 9138b84eb683fc23a285445f7d7fc5a836ba01cb/pull.h  (mode:100644 sha1:3cd14cfb811a755a8770a0d01e8e2f96ba604058)
+++ 8deba080337c75a41cb456cc8b59000654278e59/pull.h  (mode:100644 sha1:83295892d1e401e4719ae26f16de07d6eb61a8d2)
@@ -4,6 +4,14 @@
 /** To be provided by the particular implementation. **/
 extern int fetch(unsigned char *sha1);
 
+extern int fetch_ref(char *ref, unsigned char *sha1);
+
+/** If set, the ref filename to write the target value to. **/
+extern const char *write_ref;
+
+/** If set, the hash that the current value of write_ref must be. **/
+extern const unsigned char *current_ref;
+
 /** Set to fetch the target tree. */
 extern int get_tree;
 
Index: ssh-pull.c
===================================================================
--- 9138b84eb683fc23a285445f7d7fc5a836ba01cb/ssh-pull.c  (mode:100644 sha1:f4ab89836455a40aaab3ff4114396185f6d5655a)
+++ 8deba080337c75a41cb456cc8b59000654278e59/ssh-pull.c  (mode:100644 sha1:c0cee73facbbb3ced2e566789ba1dda57b245f47)
@@ -39,6 +39,11 @@
 	return 0;
 }
 
+int fetch_ref(char *ref, unsigned char *sha1)
+{
+	return -1;
+}
+
 int main(int argc, char **argv)
 {
 	char *commit_id;


^ permalink raw reply

* [PATCH 4/4] -w support for git-ssh-pull/push
From: Daniel Barkalow @ 2005-06-06 20:43 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0506061616590.30848-100000@iabervon.org>

This adds support for -w to git-ssh-pull and git-ssh-push to make
receiving side write the commit that was transferred to a reference file.

Index: ssh-pull.c
===================================================================
--- 8deba080337c75a41cb456cc8b59000654278e59/ssh-pull.c  (mode:100644 sha1:c0cee73facbbb3ced2e566789ba1dda57b245f47)
+++ 8293f31cb78c1c7aaf6e521e99a9d2d2a05fabec/ssh-pull.c  (mode:100644 sha1:3d1ff5ef0107da9f56f5f7024af9e2d02f7eec57)
@@ -2,6 +2,7 @@
 #include "commit.h"
 #include "rsh.h"
 #include "pull.h"
+#include "refs.h"
 
 static int fd_in;
 static int fd_out;
@@ -41,7 +42,15 @@
 
 int fetch_ref(char *ref, unsigned char *sha1)
 {
-	return -1;
+	signed char remote;
+	char type = 'r';
+	write(fd_out, &type, 1);
+	write(fd_out, ref, strlen(ref) + 1);
+	read(fd_in, &remote, 1);
+	if (remote < 0)
+		return remote;
+	read(fd_in, sha1, 20);
+	return 0;
 }
 
 int main(int argc, char **argv)
@@ -63,11 +72,14 @@
 			get_history = 1;
 		} else if (argv[arg][1] == 'v') {
 			get_verbosely = 1;
+		} else if (argv[arg][1] == 'w') {
+			write_ref = argv[arg + 1];
+			arg++;
 		}
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-ssh-pull [-c] [-t] [-a] [-v] [-d] commit-id url");
+		usage("git-ssh-pull [-c] [-t] [-a] [-v] [-d] [-w ref] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
Index: ssh-push.c
===================================================================
--- 8deba080337c75a41cb456cc8b59000654278e59/ssh-push.c  (mode:100644 sha1:bd381ac9d1787dc979b1eba5bd72c1fd644a094b)
+++ 8293f31cb78c1c7aaf6e521e99a9d2d2a05fabec/ssh-push.c  (mode:100644 sha1:79fb6fc05f859a9daa4597296bfe8c1440949833)
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "rsh.h"
-#include <sys/socket.h>
-#include <errno.h>
+#include "refs.h"
 
 unsigned char local_version = 1;
 unsigned char remote_version = 0;
@@ -64,6 +63,27 @@
 	return 0;
 }
 
+int serve_ref(int fd_in, int fd_out)
+{
+	char ref[PATH_MAX];
+	unsigned char sha1[20];
+	int posn = 0;
+	signed char remote = 0;
+	do {
+		if (read(fd_in, ref + posn, 1) < 1)
+			return -1;
+		posn++;
+	} while (ref[posn - 1]);
+	if (get_ref_sha1(ref, sha1))
+		remote = -1;
+	write(fd_out, &remote, 1);
+	if (remote)
+		return 0;
+	write(fd_out, sha1, 20);
+        return 0;
+}
+
+
 void service(int fd_in, int fd_out) {
 	char type;
 	int retval;
@@ -78,6 +98,8 @@
 			return;
 		if (type == 'o' && serve_object(fd_in, fd_out))
 			return;
+		if (type == 'r' && serve_ref(fd_in, fd_out))
+			return;
 	} while (1);
 }
 
@@ -88,10 +110,12 @@
         char *url;
 	int fd_in, fd_out;
 	while (arg < argc && argv[arg][0] == '-') {
+		if (argv[arg][1] == 'w')
+			arg++;
                 arg++;
         }
         if (argc < arg + 2) {
-		usage("git-ssh-push [-c] [-t] [-a] commit-id url");
+		usage("git-ssh-push [-c] [-t] [-a] [-w ref] commit-id url");
                 return 1;
         }
 	commit_id = argv[arg];


^ permalink raw reply

* [PATCH] Make git-diff-tree --pretty
From: Dan Holmsand @ 2005-06-06 21:16 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 191 bytes --]

Make git-diff-tree --pretty[=[short|medium|raw]] work as in
git-rev-list.

Also suppress duplicate newline in 'git-diff-tree -s' output.

Signed-off-by: Dan Holmsand <holmsand@gmail.com>
---

[-- Attachment #2: diff-tree.patch.txt --]
[-- Type: text/plain, Size: 1529 bytes --]

 diff-tree.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/diff-tree.c b/diff-tree.c
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -323,7 +323,8 @@ static char *generate_header(const char 
 	offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
 	if (verbose_header) {
 		offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
-		this_header[offset++] = '\n';
+		if (diff_output_format != DIFF_FORMAT_NO_OUTPUT)
+			this_header[offset++] = '\n';
 		this_header[offset++] = 0;
 	}
 
@@ -400,6 +401,19 @@ static int diff_tree_stdin(char *line)
 static char *diff_tree_usage =
 "git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-S<string>] [-O<orderfile>] [-m] [-s] [-v] [-t] <tree-ish> <tree-ish>";
 
+static enum cmit_fmt get_commit_format(const char *arg)
+{
+	if (!*arg)
+		return CMIT_FMT_DEFAULT;
+	if (!strcmp(arg, "=raw"))
+		return CMIT_FMT_RAW;
+	if (!strcmp(arg, "=medium"))
+		return CMIT_FMT_MEDIUM;
+	if (!strcmp(arg, "=short"))
+		return CMIT_FMT_SHORT;
+	usage(diff_tree_usage);	
+}			
+
 int main(int argc, const char **argv)
 {
 	int nr_sha1;
@@ -492,6 +506,12 @@ int main(int argc, const char **argv)
 			header_prefix = "diff-tree ";
 			continue;
 		}
+		if (!strncmp(arg, "--pretty", 8)) {
+			commit_format = get_commit_format(arg+8);
+			verbose_header = 1;
+			header_prefix = "diff-tree ";
+			continue;
+		}
 		if (!strcmp(arg, "--stdin")) {
 			read_stdin = 1;
 			continue;

^ permalink raw reply

* [PATCH] git-diff-cache: handle pathspec beginning with a dash
From: Jonas Fonseca @ 2005-06-06 21:27 UTC (permalink / raw)
  To: git

Parse everything after '--' as tree name or pathspec.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---

 diff-cache.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -167,13 +167,14 @@ int main(int argc, const char **argv)
 	void *tree;
 	unsigned long size;
 	int ret;
+	int allow_options = 1;
 	int i;
 
 	read_cache();
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
-		if (*arg != '-') {
+		if (!allow_options || *arg != '-') {
 			if (tree_name) {
 				pathspec = argv + i;
 				break;
@@ -182,6 +183,10 @@ int main(int argc, const char **argv)
 			continue;
 		}
 			
+		if (!strcmp(arg, "--")) {
+			allow_options = 0;
+			continue;
+		}
 		if (!strcmp(arg, "-r")) {
 			/* We accept the -r flag just to look like git-diff-tree */
 			continue;
-- 
Jonas Fonseca

^ permalink raw reply

* [PATCH] cg-commit: prefix pathspec argument with --
From: Jonas Fonseca @ 2005-06-06 21:32 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20050606212700.GA3498@diku.dk>

Make cg-commit handle files beginning with dashes.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---

[ Obviously depends on the patch I sent previously. ]

 cg-commit |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/cg-commit b/cg-commit
--- a/cg-commit
+++ b/cg-commit
@@ -110,7 +110,7 @@ if [ "$1" ]; then
 	[ "$ignorecache" ] && die "-C and listing files to commit does not make sense"
 	[ -s $_git/merging ] && die "cannot commit individual files when merging"
 
-	eval commitfiles=($(git-diff-cache -r -m HEAD "$@" | \
+	eval commitfiles=($(git-diff-cache -r -m HEAD -- "$@" | \
 		sed 's/^\([^	]*\)\(.	.*\)\(	.*\)*$/"\2"/'))
 	customfiles=1
 
-- 
Jonas Fonseca

^ permalink raw reply

* duplicate htons() in check_file_directory_conflict()
From: Timo Hirvonen @ 2005-06-06 23:02 UTC (permalink / raw)
  To: git

Hi,

create_ce_flags() macro calls htons() so the htons()s in  
check_file_directory_conflict() should be removed or alternatively htons  
should be removed from the create_ce_flags macro. I noticed the bug when  
compiling cogito with -Wshadow.

read-cache.c:208
        pos = cache_name_pos(pathbuf,
                             htons(create_ce_flags(len, stage)));


read-cache.c:232
        pos = cache_name_pos(path,
                             htons(create_ce_flags(namelen, stage)));

-- 
http://onion.dynserv.net/~timo/



^ permalink raw reply

* Re: duplicate htons() in check_file_directory_conflict()
From: Linus Torvalds @ 2005-06-07  1:59 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: git
In-Reply-To: <1118098966l.5384l.0l@garlic>



On Mon, 6 Jun 2005, Timo Hirvonen wrote:
>
> create_ce_flags() macro calls htons() so the htons()s in  
> check_file_directory_conflict() should be removed or alternatively htons  
> should be removed from the create_ce_flags macro. I noticed the bug when  
> compiling cogito with -Wshadow.

No, but it probably should be a ntohs()..

cache_name_pos() takes a host-order thing, and create_ce_flags creates a 
network order thing. It so happens that on all sane setups, ntohs == 
htons, so..

		Linus

^ permalink raw reply

* [PATCH] Document git-ssh-pull and git-ssh-push
From: Daniel Barkalow @ 2005-06-07  2:30 UTC (permalink / raw)
  To: Linus Torvalds, Junio C Hamano; +Cc: git

This fixes the documentation for git-ssh-push, as called by users (if you
run git-ssh-pull or git-ssh-push on one machine, the other runs on the
other machine, and they transfer data in the specified direction).

This also adds documentation for the -w option and for using filenames for
the commit-id (which does what you'd want: uses the source side's value,
not the value already on the target, even if you're running it on the
target).

It also credits me with the programs and the documentation for
git-ssh-push.

Someone who knows asciidoc should make sure I didn't mess up the
formatting. I'm only sure of the ascii part.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Index: Documentation/git-ssh-pull.txt
===================================================================
--- 8ba05dbc5815b0bc731a93d8353d36ba633d14c4/Documentation/git-ssh-pull.txt  (mode:100644 sha1:a0dade00af24d136eba436987eef083cb7cbc75e)
+++ e5b8562b2821b0d4d4f5bccb2af256f437fa7b63/Documentation/git-ssh-pull.txt  (mode:100644 sha1:3397fba8382955f232356efa5e8c6ae13e992433)
@@ -10,15 +10,21 @@
 
 SYNOPSIS
 --------
-'git-ssh-pull' [-c] [-t] [-a] [-d] [-v] [--recover] commit-id url
+'git-ssh-pull' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
 
 DESCRIPTION
 -----------
-Pulls from a remote repository over ssh connection, invoking git-ssh-push
-on the other end.
+Pulls from a remote repository over ssh connection, invoking
+git-ssh-push on the other end. It functions identically to
+git-ssh-push, aside from which end you run it on.
+
 
 OPTIONS
 -------
+commit-id::
+        Either the hash or the filename under [URL]/refs/ to
+        pull.
+
 -c::
 	Get the commit objects.
 -t::
@@ -34,11 +40,14 @@
 	usual, to recover after earlier pull that was interrupted.
 -v::
 	Report what is downloaded.
+-w::
+        Writes the commit-id into the filename under $GIT_DIR/refs/ on
+        the local end after the transfer is complete.
 
 
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org>
+Written by Daniel Barkalow <barkalow@iabervon.org>
 
 Documentation
 --------------
Index: Documentation/git-ssh-push.txt
===================================================================
--- 8ba05dbc5815b0bc731a93d8353d36ba633d14c4/Documentation/git-ssh-push.txt  (mode:100644 sha1:4fe850869722d9aa5aaa5f6bb7f66a92592419eb)
+++ e5b8562b2821b0d4d4f5bccb2af256f437fa7b63/Documentation/git-ssh-push.txt  (mode:100644 sha1:c55ce7dd6f7308f5057218a8ea412ac490844cb3)
@@ -1,28 +1,53 @@
 git-ssh-push(1)
 ===============
-v0.1, May 2005
+v0.1, Jun 2005
 
 NAME
 ----
-git-ssh-push - Helper "server-side" program used by git-ssh-pull
+git-ssh-push - Pushes to a remote repository over ssh connection
 
 
 SYNOPSIS
 --------
-'git-ssh-push'
+'git-ssh-push' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
 
 DESCRIPTION
 -----------
-Helper "server-side" program used by git-ssh-pull.
-
+Pushes from a remote repository over ssh connection, invoking
+git-ssh-pull on the other end. It functions identically to
+git-ssh-pull, aside from which end you run it on.
+
+OPTIONS
+-------
+commit-id::
+        Either the hash or the filename under $GIT_DIR/refs/ to push.
+
+-c::
+        Get the commit objects.
+-t::
+        Get tree associated with the requested commit object.
+-a::
+        Get all the objects.
+-d::
+        Do not check for delta base objects (use this option
+        only when you know the local repository is not
+        deltified).
+--recover::
+        Check dependency of deltified object more carefully than
+        usual, to recover after earlier push that was interrupted.
+-v::
+        Report what is uploaded.
+-w::
+        Writes the commit-id into the filename under [URL]/refs/ on
+        the remote end after the transfer is complete.
 
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org>
+Written by Daniel Barkalow <barkalow@iabervon.org>
 
 Documentation
 --------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by Daniel Barkalow
 
 GIT
 ---


^ permalink raw reply

* Re: [PATCH 0/4] Writing refs in git-ssh-push
From: Linus Torvalds @ 2005-06-07  3:17 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.21.0506061616590.30848-100000@iabervon.org>



Two comments on git-ssh-push from a quick try-to-use-it-but-fail..

 - hardcoding the name of the command on the other side kind of sucks. 
   Especially when the user may end up having to install his own version
   under his own subdirectory. You really want to have some way of saying 
   "execute /home/user/bin/git-ssh-pull", and since it will depend on the 
   site you're pushing to, it should probably be available as a cmd line 
   option.

   I have a

	PATH=$PATH:~/bin

   in my .bashrc, but sshd at the other end doesn't end up caring..

 - the host/path parsing is pretty simplistic and just silly. Nobody I 
   know uses that ssh://host/path format, people use the shorter host:path 
   format.

Both look pretty simple to fix, but now I'm going to put the kids to bed.

		Linus

^ permalink raw reply

* Re: [PATCH 0/4] Writing refs in git-ssh-push
From: Daniel Barkalow @ 2005-06-07  5:22 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, Git Mailing List, Radoslaw Szkodzinski
In-Reply-To: <Pine.LNX.4.58.0506062008560.2286@ppc970.osdl.org>

On Mon, 6 Jun 2005, Linus Torvalds wrote:

> Two comments on git-ssh-push from a quick try-to-use-it-but-fail..
> 
>  - hardcoding the name of the command on the other side kind of sucks. 
>    Especially when the user may end up having to install his own version
>    under his own subdirectory. You really want to have some way of saying 
>    "execute /home/user/bin/git-ssh-pull", and since it will depend on the 
>    site you're pushing to, it should probably be available as a cmd line 
>    option.
> 
>    I have a
> 
> 	PATH=$PATH:~/bin
> 
>    in my .bashrc, but sshd at the other end doesn't end up caring..

sshd is pretty odd that way; I think ~/.ssh/environment might get you your
local path. I thought it was just my sshd that was strange like that, but
it's probably common if yours does it too. I'm not sure if there's a
standard way to pick up a per-user version of the remote program. It seems
like cvs doesn't do anything clever, and sftp makes it a compile-time
option.

I think an environment variable for the directory to find
git-ssh-(other) in would be easiest to script when needed and would also
reduce the chances of specifying the wrong program on the remote side
(which would generate really confusing errors).

>  - the host/path parsing is pretty simplistic and just silly. Nobody I 
>    know uses that ssh://host/path format, people use the shorter host:path 
>    format.

I was going for uniformity between git-http-pull and git-ssh-pull, and
between git-ssh-pull and git-ssh-push. But user@host:path is probably the
right thing, although Radoslaw (cc:ed) will want to propose something for
SSH on a non-standard port.

> Both look pretty simple to fix, but now I'm going to put the kids to bed.

Yeah, they're usability issues, and I'm too willing to put up with my own
programs being awkward.

	-Daniel
*This .sig left intentionally blank*


^ permalink raw reply

* Re: [PATCH 0/4] Writing refs in git-ssh-push
From: Frank Sorenson @ 2005-06-07  5:54 UTC (permalink / raw)
  To: Daniel Barkalow
  Cc: Linus Torvalds, Junio C Hamano, Git Mailing List,
	Radoslaw Szkodzinski
In-Reply-To: <Pine.LNX.4.21.0506070032410.30848-100000@iabervon.org>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Daniel Barkalow wrote:
> On Mon, 6 Jun 2005, Linus Torvalds wrote:
> 
> 
>>Two comments on git-ssh-push from a quick try-to-use-it-but-fail..
>>
>> - hardcoding the name of the command on the other side kind of sucks. 
>>   Especially when the user may end up having to install his own version
>>   under his own subdirectory. You really want to have some way of saying 
>>   "execute /home/user/bin/git-ssh-pull", and since it will depend on the 
>>   site you're pushing to, it should probably be available as a cmd line 
>>   option.
>>
>>   I have a
>>
>>	PATH=$PATH:~/bin
>>
>>   in my .bashrc, but sshd at the other end doesn't end up caring..
> 
> 
> sshd is pretty odd that way; I think ~/.ssh/environment might get you your
> local path. I thought it was just my sshd that was strange like that, but
> it's probably common if yours does it too. I'm not sure if there's a
> standard way to pick up a per-user version of the remote program. It seems
> like cvs doesn't do anything clever, and sftp makes it a compile-time
> option.
> 
> I think an environment variable for the directory to find
> git-ssh-(other) in would be easiest to script when needed and would also
> reduce the chances of specifying the wrong program on the remote side
> (which would generate really confusing errors).

- From the ssh(1) manpage (openssh):
Additionally, ssh reads $HOME/.ssh/environment, and adds lines of the
format "VARNAME=value" to the environment if the file exists and if
users are allowed to change their environment.  For more information,
see the PermitUserEnvironment option in sshd_config(5).

The default given in sshd_config(5) is not to allow the user-specified
environment, because "Enabling environment processing may enable users
to bypass access restrictions in some configurations using mechanisms
such as LD_PRELOAD."

It looks like something we probably can't count on for sure.

Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
frank@tuxrocks.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFCpTaiaI0dwg4A47wRAhoJAJ9h4MUqGZWsT7+22FHaavd2N4ETqQCfTYR3
4qibBinO4TUgsdTNMrtgaxk=
=Uutj
-----END PGP SIGNATURE-----

^ permalink raw reply

* [PATCH] Add support for --wrt flag to git-rev-list
From: Jon Seymour @ 2005-06-07  6:00 UTC (permalink / raw)
  To: git; +Cc: torvalds, jon.seymour

[PATCH] Add support for --wrt flag to git-rev-list

This patch adds support for a --wrt flag to git-rev-list.

When --wrt=author@domain is specified, --merge-order is implied but 
the linearisation of non-linear epochs is adjusted so that branches
contributed to by author@domain sort after branches contributed by
others. This has effect of presenting a linear history changes as seen
by author@domain's workspace.

For example, given this commit history:

a4 ---
| \   \
|  b4 |
|/ |  |
a3 |  |
|  |  |
a2 |  |
|  |  c3
|  |  |
|  |  c2
|  b3 |
|  | /|
|  b2 |
|  |  c1
|  | /
|  b1    <-- commit authored by author@domain
a1 |
|  |
a0 |
| /
root

--merge-order alone would sort it as follows:

= a4
| c3
| c2
| c1
^ b4
| b3
| b2
| b1
^ a3
| a2
| a1
| a0
= root

however, with --wrt=author@domain, git-rev-list sorts as follows:

= a4
| c3
| c2
| c1
^ b4
| a3
| a2
| a1
| a0
^ b3
| b2
| b1
= root

To support this change, some additional functions were added to commit.c to allow
the extraction of author from the commit header.

Also, --show-breaks, like --wrt now implies --merge-order rather than requires it.

This change also updates Documentation/git-rev-list.txt to include documentation for
--wrt and other git-rev-list options not currently documented.

A test case has been included in t/t6000-rev-list.sh to verify this change works as
expected.

Use of --wrt implies a small overhead (linear with respect to nodes printed) compared with --merge-order.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>

Diverged from ed37b5b2b94398f3ab8312dfdf23cfd25549e3ec by Linus Torvalds <torvalds@ppc970.osdl.org>
---
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -9,13 +9,25 @@ git-rev-list - Lists commit objects in r
 
 SYNOPSIS
 --------
-'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--merge-order* [ *--show-breaks* ] ] <commit>
+'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--pretty* ] [ *--parents* ] [ *--header* ] [ *--merge-order* [ *--show-breaks* ] ] [ *--wrt=author@domain* ] <head-to-include> <head-to-include> ... 
+^<base-to-exclude> 
+^<base-to-exclude> ...
 
 DESCRIPTION
 -----------
-Lists commit objects in reverse chronological order starting at the
-given commit, taking ancestry relationship into account.  This is
-useful to produce human-readable log output.
+
+Lists commit objects in reverse chronological order starting at the commits specified by head-to-include values, 
+taking ancestry relationship into account.  git-rev-list will not print any commits that are reachable 
+by any of the base-to-exclude values. 
+
+If *--pretty* is specified, git-rev-list prints a short summary of each commit on stdout. This can be usefully
+parsed by git-shortlog to produce a short log of changes.
+
+If *--parents* is specified, git-rev-list prints a space separated list of parents on the same line as the
+commit identifier.
+
+If *--header* is specified, git-rev-list prints to stdout, on line after the identifier of each commit, 
+the contents of the commit's header followed by a trailing NUL.
 
 If *--merge-order* is specified, the commit history is decomposed into a unique sequence of minimal, non-linear
 epochs and maximal, linear epochs. Non-linear epochs are then linearised by sorting them into merge order, which 
@@ -42,17 +54,22 @@ Commits marked with (=) represent the bo
 Commits marked with (|) are direct parents of commits immediately preceding the marked commit in the list.
 Commits marked with (^) are not parents of the immediately preceding commit. These "breaks" represent necessary discontinuities implied by trying to represent an arbtirary DAG in a linear form.
 
-*--show-breaks* is only valid if *--merge-order* is also specified.
+*--show-breaks* implies *--merge-order*.
+
+If *--wrt=author@domain* is specified, then --merge-order is implied but git-rev-list sorts commits
+so that contemporaneously parallel commits (w.r.t. author@domain) appear to occur after (that is, sort before) 
+any commits authored by author@domain. This reflects the order in which author@domain's workspace sees contemporaneously
+parallel changes.
 
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
 
-Original *--merge-order* logic by Jon Seymour <jon.seymour@gmail.com>
+Original *--merge-order* and *--wrt* logic by Jon Seymour <jon.seymour@gmail.com>
 
 Documentation
 --------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by David Greaves, Junio C Hamano, Jon Seymour and the git-list <git@vger.kernel.org>.
 
 GIT
 ---
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -302,3 +302,65 @@ int count_parents(struct commit * commit
         return count;
 }
 
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len)
+{
+	char * p = commit->buffer;
+	
+	while (*p) {		
+
+		char * q = header;
+		if (*p == '\n') {
+			break;
+		}
+
+		int matched;
+
+		for (matched = 1; *p != ' ' && *p != '\n'; p++, q++) {
+			matched = matched & (*q==*p);
+		}
+		
+		if (matched && index) {
+			// if we matched but we haven't seen the index'th element yet, 
+			// just decrement the index then pretend we didn't match
+			index--;
+			matched = 0;
+		}
+		
+		if (!matched) {
+			
+			// skip to start of next header line
+			
+			for (;*p!='\n';p++)
+				;
+			p++;
+			
+		} else {
+			
+			int count = 0; // number of characters in value
+			
+			if (*p == ' ') {				
+				p++;
+				
+				for (count = 0; *p != '\n'; p++, count++, len--) {
+					if (len > 0) {
+						*buffer++=*p;				
+					}						
+				}
+								
+			} 
+			
+			if (len > 0) {
+				*buffer = 0;
+			}
+			
+			return (len > 0) ? count+1 : -(count+1);
+			
+		}			
+	}
+	return 0;
+}
+
+int copy_author(struct commit * commit, char * buffer, int len)
+{
+	return copy_commit_header(commit, "author", 0, buffer, len);
+}
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -53,4 +53,17 @@ struct commit *pop_most_recent_commit(st
 struct commit *pop_commit(struct commit_list **stack);
 
 int count_parents(struct commit * commit);
+
+//
+// Copies the value of the (index+1)'th commit header matching the name specified
+// into the buffer supplied and append a trailing NUL.
+//
+// Returns n<0 if the buffer was too short (-n is the required length)
+// Returns 0 if the header doesn't exist.
+// Returns n>0 where n is the length of the copied zero-terminated value, including the terminating zero.
+//
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len);
+
+// Copies the commit's author value into the buffer supplied. Return values as per copy_commit_header.
+int copy_author(struct commit * commit, char * buffer, int len);
 #endif /* COMMIT_H */
diff --git a/epoch.c b/epoch.c
--- a/epoch.c
+++ b/epoch.c
@@ -464,17 +464,21 @@ static void sort_first_epoch(struct comm
 	// so we need to reverse this list to output the oldest (or most "local") commits last.
 	//
 
-	for (parents = head->parents; parents; parents = parents->next)
-		commit_list_insert(parents->item, &reversed_parents);
-
-	//
-	// todo: by sorting the parents in a different order, we can alter the 
-	// merge order to show contemporaneous changes in parallel branches
-	// occurring after "local" changes. This is useful for a developer
-	// when a developer wants to see all changes that were incorporated
-	// into the same merge as her own changes occur after her own
-	// changes.
-	//
+	if (!head->object.util) {	
+		
+		for (parents = head->parents; parents; parents = parents->next)
+			commit_list_insert(parents->item, &reversed_parents);
+			
+	} else {
+		
+		// reverse the locally sorted parents and reset utility pointer to NULL
+		
+		parents = (struct commit_list *)head->object.util;
+		head->object.util = NULL;
+		while (parents) {
+			commit_list_insert(pop_commit(&parents), &reversed_parents);
+		}
+	}			
 
 	while (reversed_parents) {
 
@@ -555,13 +559,82 @@ static int emit_stack(struct commit_list
 }
 
 //
+// Sort a list of commits in local last order. A commit is "local" if any of its ancestors (except the base)
+// causes (*local_test)() to return a non-zero value.
+//
+// The sorted list is returned in *sorted. A side effect of this function is to set each object.util 
+// pointer to a list of parents sorted in local_last order.
+//
+// Does nothing except set *sorted to NULL if either list or local_test are NULL.
+//
+static void sort_list_in_local_last_order(struct commit_list * list, local_test_func local_test, struct commit_list ** sorted)
+{
+	if (!list || !local_test) {
+		*sorted = NULL;
+		return;
+	}
+	
+        struct commit_list * next;
+        
+	for ( next = list ; next; next = next->next) {
+		
+		struct commit * item = next->item;
+		
+		if (item->object.flags & BOUNDARY || item->object.util) {
+			// we have already visited this item or we have
+			// reached the boundary.
+			continue;
+		}
+		
+ 		if ((*local_test)(item)) {
+			item->object.flags |= LOCAL;			
+ 		}			
+		
+		sort_list_in_local_last_order(item->parents, local_test, (struct commit_list **)&item->object.util);		
+		
+		struct commit_list * sorted_parents = (struct commit_list *)&item->object.util;
+		
+		if (sorted_parents && (sorted_parents->item->object.flags & LOCAL)) {
+			item->object.flags |= LOCAL;
+		}					
+	}
+	
+	//
+	// Iterate over the original list and generate two lists - a list of the
+	// non-local parents and list of local parents. Then splice the list
+	// of local parents onto the end of the non-local parents to form
+	// a new list.
+	//
+	
+        struct commit_list * non_local = NULL;
+        struct commit_list * local = NULL;                
+        struct commit_list **p = &local;
+        struct commit_list **q = &non_local;
+        
+	for (next = list; next; next = next->next) {
+		
+		if (next->item->object.flags & LOCAL) { 
+			*p = commit_list_insert(next->item, p);
+			p = &(*p)->next;
+		} else {
+			*q = commit_list_insert(next->item, q);
+			q = &(*q)->next;
+		}
+	}
+	
+	*q = local;	
+	*sorted = non_local;
+	
+}
+
+//
 // Sorts an arbitrary epoch into merge order by sorting each epoch
 // of its epoch sequence into order.
 //
 // Note: this algorithm currently leaves traces of its execution in the
 // object flags of nodes it discovers. This should probably be fixed.
 //
-static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter)
+static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter, local_test_func local_test)
 {
 	struct commit *next = head_of_epoch;
 	int ret = 0;
@@ -602,6 +675,9 @@ static int sort_in_merge_order(struct co
 		} else {
 
 			struct commit_list *stack = NULL;
+
+			sort_list_in_local_last_order(next->parents, local_test, (struct commit_list **)&next->object.util);
+			
 			sort_first_epoch(next, &stack);
 			action = emit_stack(&stack, emitter);
 			next = base;
@@ -623,7 +699,7 @@ static int sort_in_merge_order(struct co
 // subgraph using the sort_first_epoch algorithm. Once we have reached the base
 // we can continue sorting using sort_in_merge_order.
 //
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter)
+int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test)
 {
 	struct commit_list *stack = NULL;
 	struct commit *base;
@@ -631,7 +707,8 @@ int sort_list_in_merge_order(struct comm
 	int ret = 0;
 	int action = CONTINUE;
 
-	struct commit_list *reversed = NULL;
+	struct commit_list *filtered = NULL;
+	struct commit_list **p = &filtered;
 
 	for (; list; list = list->next) {
 
@@ -642,37 +719,50 @@ int sort_list_in_merge_order(struct comm
 				fprintf(stderr, "%s: duplicate commit %s ignored\n", __FUNCTION__, sha1_to_hex(next->object.sha1));
 			} else {
 				next->object.flags |= DUPCHECK;
-				commit_list_insert(list->item, &reversed);
+				*p = commit_list_insert(list->item, p);
+				p = &(*p)->next;
 			}
 		}
 	}
 
-	if (!reversed->next) {
+	if (!filtered->next) {
 
 		// if there is only one element in the list, we can sort it using 
 		// sort_in_merge_order.
 
-		base = reversed->item;
+		base = filtered->item;
 
 	} else {
 
 		// otherwise, we search for the base of the list
 
-		if ((ret = find_base_for_list(reversed, &base)))
+		if ((ret = find_base_for_list(filtered, &base)))
 			return ret;
 
 		if (base) {
 			base->object.flags |= BOUNDARY;
 		}
-
+		
+		struct commit_list * sorted;
+		
+		sort_list_in_local_last_order(filtered, local_test, &sorted);
+		
+		if (!sorted) {
+			sorted = filtered;
+		}
+		
+		struct commit_list * reversed = NULL;
+		while (sorted) 
+			commit_list_insert(pop_commit(&sorted), &reversed);
+		
 		while (reversed) {
 			sort_first_epoch(pop_commit(&reversed), &stack);
 			if (reversed) {
 				//
 				// if we have more commits to push, then the
-				// first push for the next parent may (or may not)
+				// first push for the next commit may (or may not)
 				// represent a discontinuity with respect to the
-				// parent currently on the top of the stack.
+				// commit currently on the top of the stack.
 				//
 				// mark it for checking here, and check it
 				// with the next push...see sort_first_epoch for
@@ -686,8 +776,9 @@ int sort_list_in_merge_order(struct comm
 	}
 
 	if (base && (action != STOP)) {
-		ret = sort_in_merge_order(base, emitter);
+		ret = sort_in_merge_order(base, emitter, local_test);
 	}
 
 	return ret;
 }
+
diff --git a/epoch.h b/epoch.h
--- a/epoch.h
+++ b/epoch.h
@@ -8,13 +8,18 @@
 #define DO       2
 typedef int (*emitter_func) (struct commit *); 
 
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);
+// functions of this type return non-zero if the commit is "local" by some private assessment of
+// what it is for a commit to be local.
+typedef int (*local_test_func) (struct commit *); 
+
+int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test);
 
 #define UNINTERESTING  (1u<<2)
 #define BOUNDARY       (1u<<3)
 #define VISITED        (1u<<4)
 #define DISCONTINUITY  (1u<<5)
 #define DUPCHECK       (1u<<6)
+#define LOCAL          (1u<<7)
 
 
 #endif				/* EPOCH_H */
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -11,8 +11,11 @@ static const char rev_list_usage[] =
 		      "  --max-age=epoch\n"
 		      "  --min-age=epoch\n"
 		      "  --header\n"
+		      "  --parents\n"
 		      "  --pretty\n"
-		      "  --merge-order [ --show-breaks ]";
+		      "  --merge-order\n"
+		      "  --wrt=author@domain\n"
+                      "  --show-breaks ]";
 
 static int verbose_header = 0;
 static int show_parents = 0;
@@ -24,6 +27,7 @@ static int max_count = -1;
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
 static int merge_order = 0;
 static int show_breaks = 0;
+static char * local_author = NULL;
 
 static void show_commit(struct commit *commit)
 {
@@ -147,6 +151,16 @@ static enum cmit_fmt get_commit_format(c
 	usage(rev_list_usage);	
 }			
 
+static int is_local_author(struct commit * commit)
+{
+	static char author[16384];
+	if (copy_author(commit, author, sizeof(author)) > 0) {
+		if (strstr(author, local_author)) {
+			return 1;
+		}
+	}
+	return 0;
+}
 
 int main(int argc, char **argv)
 {
@@ -192,6 +206,13 @@ int main(int argc, char **argv)
 		}
 		if (!strncmp(arg, "--show-breaks", 13)) {
 			show_breaks = 1;
+                        merge_order = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--wrt=", 6)) {
+			local_author=xmalloc(strlen(&arg[6])+3);
+			sprintf(local_author, "<%s>", &arg[6]);
+			merge_order = 1;
 			continue;
 		}
 
@@ -201,7 +222,7 @@ int main(int argc, char **argv)
 			arg++;
 			limited = 1;
 		}
-		if (get_sha1(arg, sha1) || (show_breaks && !merge_order))
+		if (get_sha1(arg, sha1))
 			usage(rev_list_usage);
 		commit = lookup_commit_reference(sha1);
 		if (!commit || parse_commit(commit) < 0)
@@ -221,7 +242,7 @@ int main(int argc, char **argv)
 			
 	} else {
 		
-		if (sort_list_in_merge_order(list, &process_commit)) {
+		if (sort_list_in_merge_order(list, &process_commit, local_author ? &is_local_author : NULL)) {
 			  die("merge order sort failed\n");
 		}
 					

^ permalink raw reply

* Re: [PATCH 0/4] Writing refs in git-ssh-push
From: Thomas Glanzmann @ 2005-06-07  7:30 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Daniel Barkalow, Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506062008560.2286@ppc970.osdl.org>

Hello,

> 	PATH=$PATH:~/bin in my .bashrc,

this should work because ssh executes a *not* login shell when you execute a
remote command. And bash reads .bashrc always and .bash_profile only for login
shell. Is bash your login shell?

For me it works:

(excalibur) [~] cat .bashrc
export PATH=$PATH:~/bin
(excalibur) [~] ssh localhost env | grep PATH
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/cip/adm/sithglan/bin

In university I had to put the following in my .cshrc (because I have tcsh as
login shell and can't change it) to make bk push and stuff working:

(faui00u) [~] cat .cshrc
setenv PATH /opt/csw/bin:/usr/X11R6/bin:/sbin:/usr/bin:/usr/sbin:/local/bin:/bin:/local/bitkeeper/bin

	Thomas

^ permalink raw reply

* Deprecate old environment variable names before 1.0?
From: Junio C Hamano @ 2005-06-07  7:57 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

I am wondering if we want to remove support for deprecated
environment variable names before 1.0.  The big rename happened
on May 9th and it will be about a month now.





^ permalink raw reply

* [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
From: Jon Seymour @ 2005-06-07  9:15 UTC (permalink / raw)
  To: git; +Cc: torvalds, jon.seymour

[PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list

This patch is a complete replacement for:
	[PATCH] Add support for --wrt flag to git-rev-list

This patch adds support for --wrt-author, --exclude-author and --author switches
to git-rev-list.

When --wrt-author is specified, --merge-order is implied but 
the linearisation of non-linear epochs is adjusted so that branches
contributed to by the author sort after branches contributed to by
others. This has the effect of presenting a linear history of changes as seen
by the author's own workspace.

For example, given this commit history:

a4 ---
| \   \
|  b4 |
|/ |  |
a3 |  |
|  |  |
a2 |  |
|  |  c3
|  |  |
|  |  c2
|  b3 |
|  | /|
|  b2 |
|  |  c1
|  | /
|  b1    <-- commit authored by author@domain
a1 |
|  |
a0 |
| /
root

--merge-order alone would sort it as follows:

= a4
| c3
| c2
| c1
^ b4
| b3
| b2
| b1
^ a3
| a2
| a1
| a0
= root

however, with --wrt-author --author=author@domain, git-rev-list sorts as follows:

= a4
| c3
| c2
| c1
^ b4
| a3
| a2
| a1
| a0
^ b3
| b2
| b1
= root

If --exclude-author is specified, then git-rev-list behaves as if a 
^argument had been added for each commit authored by the author.

The --exclude-author option allows an author to see a brief summary of 
changes since they last made a contribution to the commit graph. For example:

      git-rev-list --exclude-author --pretty HEAD 

To configure which author git-rev-list uses when processing the --wrt-author 
and --exclude-author switches, use the --author=author@domain option. If this 
option is not specified, git-rev-list uses GIT_AUTHOR_EMAIL or a value
derived from the local user, host and domain names (per git-commit-tree's algorithm)

To support this change, some additional functions were added to commit.c to allow
the extraction of author from the commit header.

Also, --show-breaks, like --wrt-author now implies --merge-order rather than requires it.

This change also updates Documentation/git-rev-list.txt to include documentation for
--wrt-author and other git-rev-list options not currently documented.

A test case has been included in t/t6000-rev-list.sh to verify this change works as
expected.

Use of --wrt-author implies a small overhead (linear with respect to nodes printed) compared with --merge-order.

This change extracts real email id formatting functions from commit-tree.c into user.c and user.h.

NOTE TO REVIEWERS: please pay special attention to get_real_identity() 
which was extracted from commit-tree.c and placed into user.c. It was essentially 
a cut and paste, but since this has the potential to affect the operation of git-commit-tree, 
it would be worth being very careful about checking this change.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>

Diverged from ed37b5b2b94398f3ab8312dfdf23cfd25549e3ec by Linus Torvalds <torvalds@ppc970.osdl.org>
---
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -9,13 +9,25 @@ git-rev-list - Lists commit objects in r
 
 SYNOPSIS
 --------
-'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--merge-order* [ *--show-breaks* ] ] <commit>
+'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--pretty* ] [ *--parents* ] [ *--header* ] [ *--merge-order* ] [ *--show-breaks* ] [ *--wrt-author* ] [ *--exclude-author* ] [ *--author=author@domain* ]  <head-to-include> <head-to-include> ... 
+^<base-to-exclude> 
+^<base-to-exclude> ...
 
 DESCRIPTION
 -----------
-Lists commit objects in reverse chronological order starting at the
-given commit, taking ancestry relationship into account.  This is
-useful to produce human-readable log output.
+
+Lists commit objects in reverse chronological order starting at the commits specified by head-to-include values, 
+taking ancestry relationship into account.  git-rev-list will not print any commits that are reachable 
+by any of the base-to-exclude values. 
+
+If *--pretty* is specified, git-rev-list prints a short summary of each commit on stdout. This can be usefully
+parsed by git-shortlog to produce a short log of changes.
+
+If *--parents* is specified, git-rev-list prints a space separated list of parents on the same line as the
+commit identifier.
+
+If *--header* is specified, git-rev-list prints to stdout, on line after the identifier of each commit, 
+the contents of the commit's header followed by a trailing NUL.
 
 If *--merge-order* is specified, the commit history is decomposed into a unique sequence of minimal, non-linear
 epochs and maximal, linear epochs. Non-linear epochs are then linearised by sorting them into merge order, which 
@@ -42,17 +54,30 @@ Commits marked with (=) represent the bo
 Commits marked with (|) are direct parents of commits immediately preceding the marked commit in the list.
 Commits marked with (^) are not parents of the immediately preceding commit. These "breaks" represent necessary discontinuities implied by trying to represent an arbtirary DAG in a linear form.
 
-*--show-breaks* is only valid if *--merge-order* is also specified.
+The *--author* option is used to specify the author used by the *--wrt-author* and *--exclude-author* switches. If 
+an *--author* option is not specified, the author used is derived from GIT_AUTHOR_EMAIL or, ultimately, 
+from the local user, host and domain names as per the logic used by git-commit-tree.
+
+If *--wrt=author* is specified, then git-rev-list sorts commits so that contemporaneously 
+developed commits appear to occur after (that is, sort before) any commits authored by the 
+author specified by *--author*. This reflects the order in which that author 
+sees contemporaneously developed commits appear in her own workspace.
+
+If *--exclude-author* is specified, then any commit authored by the author is marked as uninteresting as if it 
+had been specified with ^ on the command line. This option restricts git-rev-list's to just the changes since 
+the author contributed a change. 
+
+Use of *--show-breaks*, *--exclude-author* or *--wrt-author* implies *--merge-order*.
 
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
 
-Original *--merge-order* logic by Jon Seymour <jon.seymour@gmail.com>
+Original *--merge-order*, *--wrt-author* and *--exclude-author* logic by Jon Seymour <jon.seymour@gmail.com>
 
 Documentation
 --------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by David Greaves, Junio C Hamano, Jon Seymour and the git-list <git@vger.kernel.org>.
 
 GIT
 ---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -41,9 +41,9 @@ install: $(PROG) $(SCRIPTS)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o delta.o date.o index.o diff-delta.o patch-delta.o entry.o \
-	 epoch.o refs.o
+	 epoch.o refs.o user.o
 LIB_FILE=libgit.a
-LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h
+LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h user.h
 
 LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
@@ -138,6 +138,7 @@ diffcore-pickaxe.o : $(LIB_H) diffcore.h
 diffcore-break.o : $(LIB_H) diffcore.h
 diffcore-order.o : $(LIB_H) diffcore.h
 epoch.o: $(LIB_H)
+user.o: $(LIB_H)
 
 test: all
 	$(MAKE) -C t/ all
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -4,10 +4,11 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
+#include "user.h"
 
-#include <pwd.h>
 #include <time.h>
 #include <ctype.h>
+#include <pwd.h>
 
 #define BLOCKING (1ul << 14)
 
@@ -100,17 +101,16 @@ static char *commit_tree_usage = "git-co
 
 int main(int argc, char **argv)
 {
-	int i, len;
+	int i;
 	int parents = 0;
 	unsigned char tree_sha1[20];
 	unsigned char parent_sha1[MAXPARENT][20];
 	unsigned char commit_sha1[20];
 	char *gecos, *realgecos, *commitgecos;
-	char *email, *commitemail, realemail[1000];
+	char *email, *commitemail, *realemail;
 	char date[50], realdate[50];
 	char *audate, *cmdate;
 	char comment[1000];
-	struct passwd *pw;
 	char *buffer;
 	unsigned int size;
 
@@ -128,18 +128,8 @@ int main(int argc, char **argv)
 	}
 	if (!parents)
 		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
-	pw = getpwuid(getuid());
-	if (!pw)
-		die("You don't exist. Go away!");
-	realgecos = pw->pw_gecos;
-	len = strlen(pw->pw_name);
-	memcpy(realemail, pw->pw_name, len);
-	realemail[len] = '@';
-	gethostname(realemail+len+1, sizeof(realemail)-len-1);
-	if (!strchr(realemail+len+1, '.')) {
-		strcat(realemail, ".");
-		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
-	}
+
+        get_real_identity(&realemail, &realgecos);
 
 	datestamp(realdate, sizeof(realdate));
 	strcpy(date, realdate);
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -302,3 +302,65 @@ int count_parents(struct commit * commit
         return count;
 }
 
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len)
+{
+	char * p = commit->buffer;
+	
+	while (*p) {		
+
+		char * q = header;
+		if (*p == '\n') {
+			break;
+		}
+
+		int matched;
+
+		for (matched = 1; *p != ' ' && *p != '\n'; p++, q++) {
+			matched = matched & (*q==*p);
+		}
+		
+		if (matched && index) {
+			// if we matched but we haven't seen the index'th element yet, 
+			// just decrement the index then pretend we didn't match
+			index--;
+			matched = 0;
+		}
+		
+		if (!matched) {
+			
+			// skip to start of next header line
+			
+			for (;*p!='\n';p++)
+				;
+			p++;
+			
+		} else {
+			
+			int count = 0; // number of characters in value
+			
+			if (*p == ' ') {				
+				p++;
+				
+				for (count = 0; *p != '\n'; p++, count++, len--) {
+					if (len > 0) {
+						*buffer++=*p;				
+					}						
+				}
+								
+			} 
+			
+			if (len > 0) {
+				*buffer = 0;
+			}
+			
+			return (len > 0) ? count+1 : -(count+1);
+			
+		}			
+	}
+	return 0;
+}
+
+int copy_author(struct commit * commit, char * buffer, int len)
+{
+	return copy_commit_header(commit, "author", 0, buffer, len);
+}
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -53,4 +53,17 @@ struct commit *pop_most_recent_commit(st
 struct commit *pop_commit(struct commit_list **stack);
 
 int count_parents(struct commit * commit);
+
+//
+// Copies the value of the (index+1)'th commit header matching the name specified
+// into the buffer supplied and append a trailing NUL.
+//
+// Returns n<0 if the buffer was too short (-n is the required length)
+// Returns 0 if the header doesn't exist.
+// Returns n>0 where n is the length of the copied zero-terminated value, including the terminating zero.
+//
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len);
+
+// Copies the commit's author value into the buffer supplied. Return values as per copy_commit_header.
+int copy_author(struct commit * commit, char * buffer, int len);
 #endif /* COMMIT_H */
diff --git a/epoch.c b/epoch.c
--- a/epoch.c
+++ b/epoch.c
@@ -450,11 +450,15 @@ static void mark_ancestors_uninteresting
 // Sorts the nodes of the first epoch of the epoch sequence of the epoch headed at head
 // into merge order.
 //
-static void sort_first_epoch(struct commit *head, struct commit_list **stack)
+static void sort_first_epoch(struct commit *head, struct commit_list **stack, marker_func marker)
 {
 	struct commit_list *parents;
 	struct commit_list *reversed_parents = NULL;
 
+        if (marker) {
+	        (*marker)(head);
+        }
+
 	head->object.flags |= VISITED;
 
 	//
@@ -464,17 +468,21 @@ static void sort_first_epoch(struct comm
 	// so we need to reverse this list to output the oldest (or most "local") commits last.
 	//
 
-	for (parents = head->parents; parents; parents = parents->next)
-		commit_list_insert(parents->item, &reversed_parents);
-
-	//
-	// todo: by sorting the parents in a different order, we can alter the 
-	// merge order to show contemporaneous changes in parallel branches
-	// occurring after "local" changes. This is useful for a developer
-	// when a developer wants to see all changes that were incorporated
-	// into the same merge as her own changes occur after her own
-	// changes.
-	//
+	if (!head->object.util) {	
+		
+		for (parents = head->parents; parents; parents = parents->next)
+			commit_list_insert(parents->item, &reversed_parents);
+			
+	} else {
+		
+		// reverse the locally sorted parents and reset utility pointer to NULL
+		
+		parents = (struct commit_list *)head->object.util;
+		head->object.util = NULL;
+		while (parents) {
+			commit_list_insert(pop_commit(&parents), &reversed_parents);
+		}
+	}			
 
 	while (reversed_parents) {
 
@@ -502,7 +510,7 @@ static void sort_first_epoch(struct comm
 
 			} else {
 
-				sort_first_epoch(parent, stack);
+				sort_first_epoch(parent, stack, marker);
 
 				if (reversed_parents) {
 					//
@@ -555,13 +563,82 @@ static int emit_stack(struct commit_list
 }
 
 //
+// Sort a list of commits in local last order. A commit is "local" if any of its ancestors (except the base)
+// causes (*local_test)() to return a non-zero value.
+//
+// The sorted list is returned in *sorted. A side effect of this function is to set each object.util 
+// pointer to a list of parents sorted in local_last order.
+//
+// Does nothing except set *sorted to NULL if either list or local_test are NULL.
+//
+static void sort_list_in_local_last_order(struct commit_list * list, local_test_func local_test, struct commit_list ** sorted)
+{
+	if (!list || !local_test) {
+		*sorted = NULL;
+		return;
+	}
+	
+        struct commit_list * next;
+        
+	for ( next = list ; next; next = next->next) {
+		
+		struct commit * item = next->item;
+		
+		if (item->object.flags & BOUNDARY || item->object.util) {
+			// we have already visited this item or we have
+			// reached the boundary.
+			continue;
+		}
+		
+ 		if ((*local_test)(item)) {
+			item->object.flags |= LOCAL;			
+ 		}			
+		
+		sort_list_in_local_last_order(item->parents, local_test, (struct commit_list **)&item->object.util);		
+		
+		struct commit_list * sorted_parents = (struct commit_list *)&item->object.util;
+		
+		if (sorted_parents && (sorted_parents->item->object.flags & LOCAL)) {
+			item->object.flags |= LOCAL;
+		}					
+	}
+	
+	//
+	// Iterate over the original list and generate two lists - a list of the
+	// non-local parents and list of local parents. Then splice the list
+	// of local parents onto the end of the non-local parents to form
+	// a new list.
+	//
+	
+        struct commit_list * non_local = NULL;
+        struct commit_list * local = NULL;                
+        struct commit_list **p = &local;
+        struct commit_list **q = &non_local;
+        
+	for (next = list; next; next = next->next) {
+		
+		if (next->item->object.flags & LOCAL) { 
+			*p = commit_list_insert(next->item, p);
+			p = &(*p)->next;
+		} else {
+			*q = commit_list_insert(next->item, q);
+			q = &(*q)->next;
+		}
+	}
+	
+	*q = local;	
+	*sorted = non_local;
+	
+}
+
+//
 // Sorts an arbitrary epoch into merge order by sorting each epoch
 // of its epoch sequence into order.
 //
 // Note: this algorithm currently leaves traces of its execution in the
 // object flags of nodes it discovers. This should probably be fixed.
 //
-static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter)
+static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter, local_test_func local_test, marker_func marker)
 {
 	struct commit *next = head_of_epoch;
 	int ret = 0;
@@ -586,6 +663,10 @@ static int sort_in_merge_order(struct co
 			while (HAS_EXACTLY_ONE_PARENT(next)
 			       && (action != STOP)
 			       && !ret) {
+                                
+			        if (marker) {
+				         (*marker)(next);
+                                }
 
 				if (next->object.flags & UNINTERESTING) {
 					action = STOP;
@@ -602,7 +683,10 @@ static int sort_in_merge_order(struct co
 		} else {
 
 			struct commit_list *stack = NULL;
-			sort_first_epoch(next, &stack);
+
+			sort_list_in_local_last_order(next->parents, local_test, (struct commit_list **)&next->object.util);
+			
+			sort_first_epoch(next, &stack, marker);
 			action = emit_stack(&stack, emitter);
 			next = base;
 
@@ -623,7 +707,7 @@ static int sort_in_merge_order(struct co
 // subgraph using the sort_first_epoch algorithm. Once we have reached the base
 // we can continue sorting using sort_in_merge_order.
 //
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter)
+int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test, marker_func marker)
 {
 	struct commit_list *stack = NULL;
 	struct commit *base;
@@ -631,7 +715,8 @@ int sort_list_in_merge_order(struct comm
 	int ret = 0;
 	int action = CONTINUE;
 
-	struct commit_list *reversed = NULL;
+	struct commit_list *filtered = NULL;
+	struct commit_list **p = &filtered;
 
 	for (; list; list = list->next) {
 
@@ -642,37 +727,50 @@ int sort_list_in_merge_order(struct comm
 				fprintf(stderr, "%s: duplicate commit %s ignored\n", __FUNCTION__, sha1_to_hex(next->object.sha1));
 			} else {
 				next->object.flags |= DUPCHECK;
-				commit_list_insert(list->item, &reversed);
+				*p = commit_list_insert(list->item, p);
+				p = &(*p)->next;
 			}
 		}
 	}
 
-	if (!reversed->next) {
+	if (!filtered->next) {
 
 		// if there is only one element in the list, we can sort it using 
 		// sort_in_merge_order.
 
-		base = reversed->item;
+		base = filtered->item;
 
 	} else {
 
 		// otherwise, we search for the base of the list
 
-		if ((ret = find_base_for_list(reversed, &base)))
+		if ((ret = find_base_for_list(filtered, &base)))
 			return ret;
 
 		if (base) {
 			base->object.flags |= BOUNDARY;
 		}
-
+		
+		struct commit_list * sorted;
+		
+		sort_list_in_local_last_order(filtered, local_test, &sorted);
+		
+		if (!sorted) {
+			sorted = filtered;
+		}
+		
+		struct commit_list * reversed = NULL;
+		while (sorted) 
+			commit_list_insert(pop_commit(&sorted), &reversed);
+		
 		while (reversed) {
-			sort_first_epoch(pop_commit(&reversed), &stack);
+			sort_first_epoch(pop_commit(&reversed), &stack, marker);
 			if (reversed) {
 				//
 				// if we have more commits to push, then the
-				// first push for the next parent may (or may not)
+				// first push for the next commit may (or may not)
 				// represent a discontinuity with respect to the
-				// parent currently on the top of the stack.
+				// commit currently on the top of the stack.
 				//
 				// mark it for checking here, and check it
 				// with the next push...see sort_first_epoch for
@@ -686,8 +784,9 @@ int sort_list_in_merge_order(struct comm
 	}
 
 	if (base && (action != STOP)) {
-		ret = sort_in_merge_order(base, emitter);
+		ret = sort_in_merge_order(base, emitter, local_test, marker);
 	}
 
 	return ret;
 }
+
diff --git a/epoch.h b/epoch.h
--- a/epoch.h
+++ b/epoch.h
@@ -8,13 +8,19 @@
 #define DO       2
 typedef int (*emitter_func) (struct commit *); 
 
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);
+// functions of this type return non-zero if the commit is "local" by some private assessment of
+// what it is for a commit to be local.
+typedef int (*local_test_func) (struct commit *); 
+typedef void (*marker_func) (struct commit *); 
+
+extern int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test, marker_func marker);
 
 #define UNINTERESTING  (1u<<2)
 #define BOUNDARY       (1u<<3)
 #define VISITED        (1u<<4)
 #define DISCONTINUITY  (1u<<5)
 #define DUPCHECK       (1u<<6)
+#define LOCAL          (1u<<7)
 
 
 #endif				/* EPOCH_H */
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "epoch.h"
+#include "user.h"
 
 #define SEEN		(1u << 0)
 #define INTERESTING	(1u << 1)
@@ -11,8 +12,13 @@ static const char rev_list_usage[] =
 		      "  --max-age=epoch\n"
 		      "  --min-age=epoch\n"
 		      "  --header\n"
+		      "  --parents\n"
 		      "  --pretty\n"
-		      "  --merge-order [ --show-breaks ]";
+		      "  --merge-order\n"
+		      "  --wrt-author\n"
+                      "  --exclude-author\n"
+                      "  --author author@domain\n"
+                      "  --show-breaks ]";
 
 static int verbose_header = 0;
 static int show_parents = 0;
@@ -24,6 +30,9 @@ static int max_count = -1;
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
 static int merge_order = 0;
 static int show_breaks = 0;
+static char * local_author = NULL;
+static int exclude_author = 0;
+static int wrt_author = 0;
 
 static void show_commit(struct commit *commit)
 {
@@ -147,6 +156,23 @@ static enum cmit_fmt get_commit_format(c
 	usage(rev_list_usage);	
 }			
 
+static int is_local_author(struct commit * commit)
+{
+	static char author[16384];
+	if (copy_author(commit, author, sizeof(author)) > 0) {
+		if (strstr(author, local_author)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void mark_authors_own_uninteresting(struct commit * commit)
+{
+        if (is_local_author(commit)) {
+		commit->object.flags |= UNINTERESTING;
+        }
+}
 
 int main(int argc, char **argv)
 {
@@ -192,6 +218,19 @@ int main(int argc, char **argv)
 		}
 		if (!strncmp(arg, "--show-breaks", 13)) {
 			show_breaks = 1;
+                        merge_order = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--author=", 9)) {
+                        local_author=strdup(&arg[9]);
+			continue;
+		}
+		if (!strncmp(arg, "--wrt-author", 6)) {
+		        wrt_author = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--exclude-author", 16)) {
+		        exclude_author = 1;
 			continue;
 		}
 
@@ -201,7 +240,7 @@ int main(int argc, char **argv)
 			arg++;
 			limited = 1;
 		}
-		if (get_sha1(arg, sha1) || (show_breaks && !merge_order))
+		if (get_sha1(arg, sha1))
 			usage(rev_list_usage);
 		commit = lookup_commit_reference(sha1);
 		if (!commit || parse_commit(commit) < 0)
@@ -213,6 +252,8 @@ int main(int argc, char **argv)
 	if (!list)
 		usage(rev_list_usage);
 
+        merge_order = merge_order || wrt_author || exclude_author || show_breaks;
+
 	if (!merge_order) {		
 	
 	        if (limited) 
@@ -220,11 +261,31 @@ int main(int argc, char **argv)
 		show_commit_list(list);
 			
 	} else {
+
+	        if ((exclude_author|wrt_author) && !local_author) {
+		        local_author = strdup(gitenv("GIT_AUTHOR_EMAIL")) ? : NULL;
+                        if (!local_author) {
+			         get_real_identity(&local_author, NULL);
+                        }
+	        }
 		
-		if (sort_list_in_merge_order(list, &process_commit)) {
-			  die("merge order sort failed\n");
+		if (local_author) {
+		        // add delimiters to improve accuracy of match
+		        char * tmp=xmalloc(strlen(local_author)+3);
+		        sprintf(tmp, "<%s>", local_author);
+                        free(local_author);
+                        local_author = tmp;
+                }
+
+		if (sort_list_in_merge_order(
+			list, 
+			&process_commit, 
+			local_author ? &is_local_author : NULL, 
+			exclude_author ? &mark_authors_own_uninteresting : NULL)
+		    ) {
+	      		die("merge order sort failed\n");
 		}
-					
+
 	}
 
 	return 0;
diff --git a/user.c b/user.c
new file mode 100644
--- /dev/null
+++ b/user.c
@@ -0,0 +1,32 @@
+#include "cache.h"
+#include "user.h"
+#include <string.h>
+#include <pwd.h>
+
+void get_real_identity(char **email, char **gecos)
+{
+	static char buffer[1000];
+	struct passwd *pw;
+	int len;
+
+	pw = getpwuid(getuid());
+	if (!pw)
+		die("You don't exist. Go away!");
+
+	len = strlen(pw->pw_name);
+	memcpy(buffer, pw->pw_name, len);
+	buffer[len] = '@';
+	gethostname(buffer + len + 1, sizeof(buffer) - len - 1);
+	if (!strchr(buffer + len + 1, '.')) {
+		strcat(buffer, ".");
+		getdomainname(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer) - 1);
+	}
+
+	if (gecos) {
+		*gecos = strdup(pw->pw_gecos);
+	}
+
+	if (email) {
+		*email = strdup(buffer);
+	}
+}
diff --git a/user.h b/user.h
new file mode 100644
--- /dev/null
+++ b/user.h
@@ -0,0 +1,8 @@
+#ifndef USER_H
+#define USER_H
+//
+// Allocates two new strings to contain the real email and
+// name of the current user.
+//
+extern void get_real_identity(char **email, char **gecos);
+#endif

^ permalink raw reply

* Re: [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
From: Jon Seymour @ 2005-06-07  9:30 UTC (permalink / raw)
  To: git; +Cc: torvalds, jon.seymour
In-Reply-To: <20050607091523.14051.qmail@blackcubes.dyndns.org>

A small update to the patch which corrects a couple of documentation typos and a
slight correction to git-rev-list options processing has been posted
here. The update has been tested with a complete apply+build from the
base commit.

http://blackcubes.dyndns.org/epoch/wrt-patch.patch

Regards,

jon.

^ permalink raw reply

* Re: [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
From: Petr Baudis @ 2005-06-07  9:49 UTC (permalink / raw)
  To: Jon Seymour; +Cc: git, torvalds
In-Reply-To: <20050607091523.14051.qmail@blackcubes.dyndns.org>

Dear diary, on Tue, Jun 07, 2005 at 11:15:23AM CEST, I got a letter
where Jon Seymour <jon.seymour@gmail.com> told me that...
> [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
> 
> This patch is a complete replacement for:
> 	[PATCH] Add support for --wrt flag to git-rev-list
> 
> This patch adds support for --wrt-author, --exclude-author and --author switches
> to git-rev-list.

I'd prefer just --wrt-author and --exclude-author to take an argument on
their own.

(Note that I don't endorse this patch and the --wrt-author behaviour in
particular seems strange. I don't have enough time to comment on it
sensibly now, though. I'm just focusing on style here since I'd like to
still be able to read git's source code few weeks from now on.)

> Diverged from ed37b5b2b94398f3ab8312dfdf23cfd25549e3ec by Linus Torvalds <torvalds@ppc970.osdl.org>
> ---
> diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
> --- a/Documentation/git-rev-list.txt
> +++ b/Documentation/git-rev-list.txt
> @@ -9,13 +9,25 @@ git-rev-list - Lists commit objects in r
>  
>  SYNOPSIS
>  --------
> -'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--merge-order* [ *--show-breaks* ] ] <commit>
> +'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--pretty* ] [ *--parents* ] [ *--header* ] [ *--merge-order* ] [ *--show-breaks* ] [ *--wrt-author* ] [ *--exclude-author* ] [ *--author=author@domain* ]  <head-to-include> <head-to-include> ... 
> +^<base-to-exclude> 
> +^<base-to-exclude> ...
>  
>  DESCRIPTION
>  -----------
> -Lists commit objects in reverse chronological order starting at the
> -given commit, taking ancestry relationship into account.  This is
> -useful to produce human-readable log output.
> +
> +Lists commit objects in reverse chronological order starting at the commits specified by head-to-include values, 
> +taking ancestry relationship into account.  git-rev-list will not print any commits that are reachable 
> +by any of the base-to-exclude values. 

Could you please break your lines somewhere before the 80th column?
This applies to the code too (actually it applies more to the code,
comments in particular).

> diff --git a/commit-tree.c b/commit-tree.c
> --- a/commit-tree.c
> +++ b/commit-tree.c
> @@ -128,18 +128,8 @@ int main(int argc, char **argv)
>  	}
>  	if (!parents)
>  		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
> -	pw = getpwuid(getuid());
> -	if (!pw)
> -		die("You don't exist. Go away!");
> -	realgecos = pw->pw_gecos;
> -	len = strlen(pw->pw_name);
> -	memcpy(realemail, pw->pw_name, len);
> -	realemail[len] = '@';
> -	gethostname(realemail+len+1, sizeof(realemail)-len-1);
> -	if (!strchr(realemail+len+1, '.')) {
> -		strcat(realemail, ".");
> -		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
> -	}
> +
> +        get_real_identity(&realemail, &realgecos);

Whitespace police emergency.

>  
>  	datestamp(realdate, sizeof(realdate));
>  	strcpy(date, realdate);
> diff --git a/commit.c b/commit.c
> --- a/commit.c
> +++ b/commit.c
> @@ -302,3 +302,65 @@ int count_parents(struct commit * commit
>          return count;
>  }
>  
> +int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len)
> +{
> +	char * p = commit->buffer;
> +	
> +	while (*p) {		
> +
> +		char * q = header;
> +		if (*p == '\n') {
> +			break;
> +		}
> +
> +		int matched;
> +
> +		for (matched = 1; *p != ' ' && *p != '\n'; p++, q++) {
> +			matched = matched & (*q==*p);
> +		}
> +		
> +		if (matched && index) {
> +			// if we matched but we haven't seen the index'th element yet, 
> +			// just decrement the index then pretend we didn't match
> +			index--;
> +			matched = 0;
> +		}
> +		
> +		if (!matched) {
> +			
> +			// skip to start of next header line
> +			
> +			for (;*p!='\n';p++)
> +				;
> +			p++;
> +			
> +		} else {
> +			
> +			int count = 0; // number of characters in value
> +			
> +			if (*p == ' ') {				
> +				p++;
> +				
> +				for (count = 0; *p != '\n'; p++, count++, len--) {
> +					if (len > 0) {
> +						*buffer++=*p;				
> +					}						
> +				}
> +								
> +			} 
> +			
> +			if (len > 0) {
> +				*buffer = 0;
> +			}
> +			
> +			return (len > 0) ? count+1 : -(count+1);
> +			
> +		}			
> +	}
> +	return 0;
> +}

Another style comment - I think the code is way too diffused, suffering
by hyperemptylineosis, which subsequently causes unreadability. Do you
think you could dense it down a little, please?

> diff --git a/epoch.c b/epoch.c
> --- a/epoch.c
> +++ b/epoch.c
> @@ -450,11 +450,15 @@ static void mark_ancestors_uninteresting
>  // Sorts the nodes of the first epoch of the epoch sequence of the epoch headed at head
>  // into merge order.
>  //
> -static void sort_first_epoch(struct commit *head, struct commit_list **stack)
> +static void sort_first_epoch(struct commit *head, struct commit_list **stack, marker_func marker)
>  {
>  	struct commit_list *parents;
>  	struct commit_list *reversed_parents = NULL;
>  
> +        if (marker) {
> +	        (*marker)(head);
> +        }
> +
>  	head->object.flags |= VISITED;

These whitespaces seem quite strange too. Check your editor settings.
;-)

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

^ permalink raw reply

* Re: [PATCH 3/4] Generic support for pulling refs
From: McMullan, Jason @ 2005-06-07 13:18 UTC (permalink / raw)
  To: Daniel Barkalow
  Cc: Linus Torvalds, Petr Baudis, Junio C Hamano, GIT Mailling list
In-Reply-To: <Pine.LNX.4.21.0506061635070.30848-100000@iabervon.org>

[-- Attachment #1: Type: text/plain, Size: 531 bytes --]

On Mon, 2005-06-06 at 16:38 -0400, Daniel Barkalow wrote:
> This adds support to pull.c for requesting a reference and writing it to a
> file. All of the git-*-pull programs get stubs for now.
>
> [snip snip]

Well, looks like you beat me to the punch, Daniel!

I hereby concede the Deathmatch to git-ssh-pu{sh,ll}, and withdraw
git-sync from consideration.

Way to go Daniel!

"Welcome to Git Thunderdome. Two codes enter, one code leaves."

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH] Add missing Documentation/*
From: Jason McMullan @ 2005-06-07 14:17 UTC (permalink / raw)
  To: torvalds, git

Id: e774aa5641ca2267e7aba7338da3f7e355b7fb78
tree e42cf7a8ae0e05eb383ad41bc43d6e7d1245441f
parent 63aff4fed94355889be98ad44371e29942ff70e4
author Jason McMullan <jason.mcmullan@gmail.com> 1118153523 -0400
committer Jason McMullan <jason.mcmullan@gmail.com> 1118153523 -0400

Add: Additional missing documentation


======== diff against 63aff4fed94355889be98ad44371e29942ff70e4 ========
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-apply.txt
@@ -0,0 +1,36 @@
+git-apply(1)
+============
+v0.1, May 2005
+
+NAME
+----
+git-apply - Apply a patch against the current index cache/working directory
+
+
+SYNOPSIS
+--------
+'git-apply' [--check] [--stat] [--show-file] <patch>
+
+DESCRIPTION
+-----------
+This applies patches on top of some (arbitrary) version of the SCM.
+
+NOTE! It does all its work in the index file, and only cares about
+the files in the working directory if you tell it to "merge" the
+patch apply.
+
+Even when merging it always takes the source from the index, and
+uses the working tree as a "branch" for a 3-way merge.
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-commit-script.txt b/Documentation/git-commit-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-commit-script.txt
@@ -0,0 +1,29 @@
+git-commit-script(1)
+====================
+v0.1, May 2005
+
+NAME
+----
+git-commit-script - Commit working directory
+
+
+SYNOPSIS
+--------
+'git-commit-script' 
+
+DESCRIPTION
+-----------
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-deltafy-script.txt b/Documentation/git-deltafy-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-deltafy-script.txt
@@ -0,0 +1,51 @@
+git-deltafy-script(1)
+=====================
+v0.1, May 2005
+
+NAME
+----
+git-deltafy-script - Convery repository into delta format
+
+
+SYNOPSIS
+--------
+'git-deltafy-script'
+
+DESCRIPTION
+-----------
+Script to deltafy an entire GIT repository based on the commit list.
+The most recent version of a file is the reference and previous versions
+are made delta against the best earlier version available. And so on for
+successive versions going back in time.  This way the increasing delta
+overhead is pushed towards older versions of any given file.
+
+The -d argument allows to provide a limit on the delta chain depth.
+If 0 is passed then everything is undeltafied.  Limiting the delta
+depth is meaningful for subsequent access performance to old revisions.
+A value of 16 might be a good compromize between performance and good
+space saving.  Current default is unbounded.
+
+The --max-behind=30 argument is passed to git-mkdelta so to keep
+combinations and memory usage bounded a bit.  If you have lots of memory
+and CPU power you may remove it (or set to 0) to let git-mkdelta find the
+best delta match regardless of the number of revisions for a given file.
+You can also make the value smaller to make it faster and less
+memory hungry.  A value of 5 ought to still give pretty good results.
+When set to 0 or ommitted then look behind is unbounded.  Note that
+git-mkdelta might die with a segmentation fault in that case if it
+runs out of memory.  Note that the GIT repository will still be consistent
+even if git-mkdelta dies unexpectedly.
+
+
+Author
+------
+Written by Nicolas Pitre <nico@cam.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-fetch-script.txt b/Documentation/git-fetch-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-fetch-script.txt
@@ -0,0 +1,29 @@
+git-fetch-script(1)
+===================
+v0.1, May 2005
+
+NAME
+----
+git-fetch-script - Fetch an object from a remote repository
+
+
+SYNOPSIS
+--------
+'git-fetch-script' <sha1>
+
+DESCRIPTION
+-----------
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-get-tar-commit-id.txt b/Documentation/git-get-tar-commit-id.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-get-tar-commit-id.txt
@@ -0,0 +1,29 @@
+git-get-tar-commit-id(1)
+========================
+v0.1, May 2005
+
+NAME
+----
+git-get-tar-commit-id - Show the commit ID embedded in a git-tar-tree file.
+
+
+SYNOPSIS
+--------
+'git-get-tar-commit-id' <tar-file.tar>
+
+DESCRIPTION
+-----------
+This shows the commit ID embedded in a git-tar-tree generated file.
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-log-script.txt b/Documentation/git-log-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-log-script.txt
@@ -0,0 +1,29 @@
+git-log-script(1)
+=================
+v0.1, May 2005
+
+NAME
+----
+git-log-script - Prettified version of git-rev-list
+
+
+SYNOPSIS
+--------
+'git-log-script' 
+
+DESCRIPTION
+-----------
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-shortlog.txt
@@ -0,0 +1,29 @@
+git-shortlog(1)
+===============
+v0.1, May 2005
+
+NAME
+----
+git-status - Show status of working directory files
+
+
+SYNOPSIS
+--------
+'git-log-script' | 'git-shortlog' 
+
+DESCRIPTION
+-----------
+Summarize the output of 'git-log-script'
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-status-script.txt b/Documentation/git-status-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-status-script.txt
@@ -0,0 +1,29 @@
+git-status-script(1)
+====================
+v0.1, May 2005
+
+NAME
+----
+git-status-script - Show status of working directory files
+
+
+SYNOPSIS
+--------
+'git-status-script' 
+
+DESCRIPTION
+-----------
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-stripspace.txt
@@ -0,0 +1,31 @@
+git-stripspace(1)
+=================
+v0.1, May 2005
+
+NAME
+----
+git-stripspace - Strip space from stdin
+
+
+SYNOPSIS
+--------
+'git-stripspace' <stream
+
+DESCRIPTION
+-----------
+Remove empty lines from the beginning and end.
+
+Turn multiple consecutive empty lines into just one empty line.
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-whatchanged.txt
@@ -0,0 +1,29 @@
+git-whatchanged(1)
+==================
+v0.1, May 2005
+
+NAME
+----
+git-whatchanged - Find out what changed
+
+
+SYNOPSIS
+--------
+'git-whatchanged' 
+
+DESCRIPTION
+-----------
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
======== end ========


^ permalink raw reply

* [PATCH] Add git-help-script
From: Jason McMullan @ 2005-06-07 14:19 UTC (permalink / raw)
  To: torvalds, git

Id: 13d680c11f5403f3b1b48e71416e36770cd0aecf
tree 91e05412806336f2c9d989b8d9a2eccb21281efe
parent e774aa5641ca2267e7aba7338da3f7e355b7fb78
author Jason McMullan <jason.mcmullan@gmail.com> 1118153648 -0400
committer Jason McMullan <jason.mcmullan@gmail.com> 1118153648 -0400

Add: 'git help' aka 'git-help-script', built from Documentation/* information


======== diff against e774aa5641ca2267e7aba7338da3f7e355b7fb78 ========
diff --git a/Documentation/git-help-script.txt b/Documentation/git-help-script.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-help-script.txt
@@ -0,0 +1,29 @@
+git-help-script(1)
+==================
+v0.1, May 2005
+
+NAME
+----
+git-help-script - Short help of all the git commands and scripts
+
+
+SYNOPSIS
+--------
+'git-help-script' 
+
+DESCRIPTION
+-----------
+Shows a brief summary of all the git-* commands.
+
+Author
+------
+Written by Jason McMullan <jason.mcmullan@timesys.com>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ INSTALL=install
 SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \
 	git-pull-script git-tag-script git-resolve-script git-whatchanged \
 	git-deltafy-script git-fetch-script git-status-script git-commit-script \
-	git-log-script git-shortlog
+	git-log-script git-shortlog git-help-script
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
@@ -84,6 +84,26 @@ test-delta: test-delta.c diff-delta.o pa
 git-%: %.c $(LIB_FILE)
 	$(CC) $(CFLAGS) -o $@ $(filter %.c,$^) $(LIBS)
 
+git-help-script: Makefile $(patsubst %,Documentation/%.txt,$(SCRIPTS) $(PROG))
+	echo "#!/bin/sh" >git-help-script
+	echo "cat <<EOF" >>git-help-script
+	echo "Commands:" >>git-help-script
+	echo >>git-help-script
+	for cmd in $(sort $(SCRIPTS)) $(sort $(PROG)); do \
+	  doc="Documentation/$$cmd.txt"; \
+	  if [ ! -e "$$doc" ]; then \
+	    echo "MISSING: $$doc" 1>&2; \
+	    rm -f git-help-script; \
+	    exit 1; \
+	  fi; \
+	  desc=`grep "^$$cmd - " $$doc | cut -d' ' -f3-` ; \
+	  desc=`echo "$$desc" | sed -e 's/\(.\{40\}\) /\1\n                        /g'` ; \
+	  cmd=`echo $$cmd | sed -e 's/^git-\(.*\)-script$$/git \1/'`; \
+	  printf "    %-20s%s\n" "$$cmd" "$$desc" >>git-help-script; \
+	done
+	echo "EOF" >>git-help-script
+	echo "exit 1" >>git-help-script
+
 git-update-cache: update-cache.c
 git-diff-files: diff-files.c
 git-init-db: init-db.c
@@ -143,7 +163,7 @@ test: all
 	$(MAKE) -C t/ all
 
 clean:
-	rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROG) $(LIB_FILE)
+	rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROG) $(LIB_FILE) git-help-script
 	$(MAKE) -C Documentation/ clean
 
 backup: clean
diff --git a/git b/git
--- a/git
+++ b/git
@@ -1,4 +1,8 @@
 #!/bin/sh
-cmd="git-$1-script"
+
+cmd="$1"
+
+[ -z "$cmd" -o "$cmd" = "-h" -o "$cmd" = "--help" ] && cmd="help"
+cmd="git-$cmd-script"
 shift
 exec $cmd "$@"
======== end ========


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox