Git development
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] Function stripspace now gets a buffer instead file descriptors.
From: Johannes Schindelin @ 2007-07-11 19:17 UTC (permalink / raw)
  To: Carlos Rica; +Cc: git, Junio C Hamano, Kristian Høgsberg
In-Reply-To: <4695267A.7080202@gmail.com>

Hi,

On Wed, 11 Jul 2007, Carlos Rica wrote:

> @@ -28,52 +26,67 @@ static int cleanup(char *line, int len)
>   * Remove empty lines from the beginning and end
>   * and also trailing spaces from every line.
>   *
> + * Note that the buffer will not be null-terminated.
> + *
>   * Turn multiple consecutive empty lines between paragraphs
>   * into just one empty line.
>   *
>   * If the input has only empty lines and spaces,
>   * no output will be produced.
>   *
> + * If last line has a newline at the end, it will be removed.
> + *

Please let me comment about the rationale for both changes: The 
stripspace() function (which this hunk is about) is more useful if it does 
not allocate a new buffer, but works in-place.

And since it knows the new length already, it can just as well return the 
length, and _not_ NUL terminate (which would mean that we have to 
reallocate if we used read_pipe() to get the buffer).

The reason for the missing newline at the end is the same: since we accept 
buffers with a missing newline at the end, we would have to reallocate in 
that case.

So for the sake of simplicity, we neither NUL-terminate, nor \n terminate 
the buffer, and leave that to the callers.

Ciao,
Dscho

^ permalink raw reply

* Re: git-rm isn't the inverse action of git-add
From: Jan Hudec @ 2007-07-11 18:56 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <f72hu8$65g$1@sea.gmane.org>

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

On Wed, Jul 11, 2007 at 14:20:24 +0200, Jakub Narebski wrote:
> Christian Jaeger wrote:
> > I don't per se require undo actions. I just don't understand why git-rm
> > refuses to remove the file from the index, even if I didn't commit it.
> > The index is just an intermediate record of the changes in my
> > understandings, and the rm action would also be intermediate until it's
> > being committed. And a non-committed action being deleted shouldn't need
> > a special confirmation from me, especially not one which is consisting
> > of a combination of two flags (of which one is a destructive one).
> 
> Should git-rm refuse to remove index entry if it is different from working
> directory version or not?

IMHO it should refuse to remove index entry if it is different from both
working-tree version and versions in all parents.

If index matches any of that, but the working tree version does not match any
parent, the index entry should be removed (which currently isn't -- that's
the proposed change), but the file left in wokring tree. That would make
git-add + git-rm get you right back where you started, with nothing in index
and unversioned file in working tree.

-- 
						 Jan 'Bulb' Hudec <bulb@ucw.cz>

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH 2/2] Make git-tag a builtin.
From: Carlos Rica @ 2007-07-11 18:54 UTC (permalink / raw)
  To: git, Junio C Hamano, Johannes Schindelin, Kristian Høgsberg

This replaces the script "git-tag.sh" with "builtin-tag.c".
It is based in a previous work on it from Kristian Høgsberg.

There are some minor changes in the behaviour of "git tag" here:
"git tag -v" now can get more than one tag to verify, like "git tag -d" did,
"git tag" with no arguments prints all tags, more like "git branch" does, and
the template for the edited message adds an empty line, like in "git commit".

The program is now calling to the script "git verify-tag" for verify,
something that should be changed porting it to C and calling its functions
directly from builtin-tag.c.

Signed-off-by: Carlos Rica <jasampler@gmail.com>
---

  As said, "git verify-tag" should be replaced with "git tag" for
  verify tags, since both do the same job.  The builtin "git mktag"
  is another candidate to be replaced with "git tag", however
  it is now an essential part of the "plumbing" family doing
  a neat thing not easily replaceable.

  The function launch_editor is copied and modified from the initial work
  from Kristian on builtin-commit.c, so we expect share that code on
  both builtins when it is finnished.

 Makefile      |    3 +-
 builtin-tag.c |  430 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h     |    1 +
 git-tag.sh    |  205 ---------------------------
 git.c         |    1 +
 5 files changed, 434 insertions(+), 206 deletions(-)
 create mode 100644 builtin-tag.c
 delete mode 100755 git-tag.sh

diff --git a/Makefile b/Makefile
index d7541b4..f0da8f7 100644
--- a/Makefile
+++ b/Makefile
@@ -207,7 +207,7 @@ SCRIPT_SH = \
 	git-pull.sh git-rebase.sh git-rebase--interactive.sh \
 	git-repack.sh git-request-pull.sh git-reset.sh \
 	git-sh-setup.sh \
-	git-tag.sh git-verify-tag.sh \
+	git-verify-tag.sh \
 	git-am.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
 	git-merge-resolve.sh git-merge-ours.sh \
@@ -376,6 +376,7 @@ BUILTIN_OBJS = \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
 	builtin-symbolic-ref.o \
+	builtin-tag.o \
 	builtin-tar-tree.o \
 	builtin-unpack-objects.o \
 	builtin-update-index.o \
diff --git a/builtin-tag.c b/builtin-tag.c
new file mode 100644
index 0000000..1824379
--- /dev/null
+++ b/builtin-tag.c
@@ -0,0 +1,430 @@
+/*
+ * Builtin "git tag"
+ *
+ * Copyright (c) 2007 Kristian HÞgsberg <krh@redhat.com>,
+ *                    Carlos Rica <jasampler@gmail.com>
+ * Based on git-tag.sh and mktag.c by Linus Torvalds.
+ */
+
+#include "cache.h"
+#include "builtin.h"
+#include "refs.h"
+#include "tag.h"
+#include "run-command.h"
+
+static const char builtin_tag_usage[] =
+  "git-tag [-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]";
+
+static char signingkey[1000];
+static int lines;
+
+static void launch_editor(const char *path, char **buffer, unsigned long *len)
+{
+	const char *editor, *terminal;
+	struct child_process child;
+	const char *args[3];
+	int fd;
+
+	editor = getenv("VISUAL");
+	if (!editor)
+		editor = getenv("EDITOR");
+
+	terminal = getenv("TERM");
+	if (!editor && (!terminal || !strcmp(terminal, "dumb"))) {
+		fprintf(stderr,
+		"Terminal is dumb but no VISUAL nor EDITOR defined.\n"
+		"Please supply the message using either -m or -F option.\n");
+		exit(1);
+	}
+
+	if (!editor)
+		editor = "vi";
+
+	memset(&child, 0, sizeof(child));
+	child.argv = args;
+	args[0] = editor;
+	args[1] = path;
+	args[2] = NULL;
+
+	if (run_command(&child))
+		die("could not launch editor %s.", editor);
+
+	fd = open(path, O_RDONLY);
+	if (fd == -1)
+		die("could not read %s.", path);
+	if (read_pipe(fd, buffer, len))
+		die("could not read message file '%s': %s",
+		    path, strerror(errno));
+	close(fd);
+}
+
+#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
+
+static int show_reference(const char *refname, const unsigned char *sha1,
+			  int flag, void *cb_data)
+{
+	const char *pattern = cb_data;
+
+	if (!fnmatch(pattern, refname, 0)) {
+		int i;
+		unsigned long size;
+		enum object_type type;
+		char *buf, *sp, *eol;
+		size_t len;
+
+		if (!lines) {
+			printf("%s\n", refname);
+			return 0;
+		}
+		printf("%-15s ", refname);
+
+		sp = buf = read_sha1_file(sha1, &type, &size);
+		if (!buf || !size)
+			return 0;
+		/* skip header */
+		while (sp + 1 < buf + size &&
+				!(sp[0] == '\n' && sp[1] == '\n'))
+			sp++;
+		/* only take up to "lines" lines, and strip the signature */
+		for (i = 0, sp += 2; i < lines && sp < buf + size &&
+				prefixcmp(sp, PGP_SIGNATURE "\n");
+				i++) {
+			if (i)
+				printf("\n    ");
+			eol = memchr(sp, '\n', size - (sp - buf));
+			len = eol ? eol - sp : size - (sp - buf);
+			fwrite(sp, len, 1, stdout);
+			if (!eol)
+				break;
+			sp = eol + 1;
+		}
+		putchar('\n');
+		free(buf);
+	}
+
+	return 0;
+}
+
+static int list_tags(const char *pattern)
+{
+	char *newpattern;
+
+	if (pattern == NULL)
+		pattern = "";
+
+	/* prepend/append * to the shell pattern: */
+	newpattern = xmalloc(strlen(pattern) + 3);
+	sprintf(newpattern, "*%s*", pattern);
+
+	for_each_tag_ref(show_reference, (void *) newpattern);
+
+	free(newpattern);
+
+	return 0;
+}
+
+
+static int delete_tags(const char **argv)
+{
+	const char **p;
+	char ref[PATH_MAX];
+	int had_error = 0;
+	unsigned char sha1[20];
+
+	for (p = argv; *p; p++) {
+		if (snprintf(ref, sizeof ref, "refs/tags/%s", *p) > sizeof ref)
+			die("tag name '%s' too long.", *p);
+		if (!resolve_ref(ref, sha1, 1, NULL)) {
+			fprintf(stderr, "tag '%s' not found.\n", *p);
+			had_error = 1;
+			continue;
+		}
+
+		if (delete_ref(ref, sha1))
+			had_error = 1;
+		else
+			printf("Deleted tag '%s'\n", *p);
+	}
+
+	return had_error;
+}
+
+static int run_verify_tag_command(unsigned char *sha1)
+{
+	int ret;
+	const char *argv_verify_tag[] = {"git-verify-tag",
+					"-v", "SHA1_HEX", NULL};
+	argv_verify_tag[2] = sha1_to_hex(sha1);
+
+	ret = run_command_v_opt(argv_verify_tag, 0);
+
+	if (ret <= -10000)
+		die("unable to run %s\n", argv_verify_tag[0]);
+	return -ret;
+}
+
+static int verify_tags(const char **argv)
+{
+	const char **p;
+	char ref[PATH_MAX];
+	int had_error = 0;
+	unsigned char sha1[20];
+
+	for (p = argv; *p; p++) {
+		if (snprintf(ref, sizeof ref, "refs/tags/%s", *p) > sizeof ref)
+			die("tag name '%s' too long.", *p);
+
+		if (!resolve_ref(ref, sha1, 1, NULL)) {
+			fprintf(stderr, "tag '%s' not found.\n", *p);
+			had_error = 1;
+			continue;
+		}
+		if (run_verify_tag_command(sha1))
+			had_error = 1;
+	}
+
+	return had_error;
+}
+
+static int do_sign(char *buffer, size_t size, size_t max)
+{
+	struct child_process gpg;
+	const char *args[4];
+	char *bracket;
+	int len;
+
+	if (signingkey[0] == '\0') {
+		strlcpy(signingkey, git_committer_info(1), sizeof signingkey);
+		bracket = strchr(signingkey, '>');
+		if (bracket)
+			bracket[1] = '\0';
+	}
+
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args;
+	gpg.in = -1;
+	gpg.out = -1;
+	args[0] = "gpg";
+	args[1] = "-bsau";
+	args[2] = signingkey;
+	args[3] = NULL;
+
+	if (start_command(&gpg))
+		die("could not run gpg.");
+
+	write_or_die(gpg.in, buffer, size);
+	close(gpg.in);
+	gpg.close_in = 0;
+	len = read_in_full(gpg.out, buffer + size, max - size);
+
+	finish_command(&gpg);
+
+	return size + len;
+}
+
+static const char tag_template[] =
+	"\n"
+	"#\n"
+	"# Write a tag message\n"
+	"#\n";
+
+static int git_tag_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "user.signingkey")) {
+		if (!value)
+			die("user.signingkey without value");
+		strlcpy(signingkey, value, sizeof signingkey);
+		return 0;
+	}
+
+	return git_default_config(var, value);
+}
+
+#define MAX_SIGNATURE_LENGTH 1024
+/* message must be NULL or allocated, it will be reallocated and freed */
+static void create_tag(const unsigned char *object, const char *tag,
+		       char *message, int sign, unsigned char *result)
+{
+	enum object_type type;
+	char header_buf[1024], *buffer;
+	int header_len, max_size;
+	unsigned long size;
+
+	type = sha1_object_info(object, NULL);
+	if (type <= 0)
+	    die("bad object type.");
+
+	header_len = snprintf(header_buf, sizeof header_buf,
+			  "object %s\n"
+			  "type %s\n"
+			  "tag %s\n"
+			  "tagger %s\n\n",
+			  sha1_to_hex(object),
+			  typename(type),
+			  tag,
+			  git_committer_info(1));
+
+	if (header_len >= sizeof header_buf)
+		die("tag header too big.");
+
+	if (!message) {
+		char *path;
+		int fd;
+
+		/* write the template message before editing: */
+		path = xstrdup(git_path("TAG_EDITMSG"));
+		fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+		if (fd < 0)
+			die("could not create file %s.", path);
+		write_or_die(fd, tag_template, strlen(tag_template));
+		close(fd);
+
+		launch_editor(path, &buffer, &size);
+
+		unlink(path);
+		free(path);
+	}
+	else {
+		buffer = message;
+		size = strlen(message);
+	}
+
+	size = stripspace(buffer, size, 1);
+
+	if (!message && !size)
+		die("no tag message?");
+
+	/* insert the header and add the '\n' if needed: */
+	max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
+	buffer = xrealloc(buffer, max_size);
+	if (size)
+		buffer[size++] = '\n';
+	memmove(buffer + header_len, buffer, size);
+	memcpy(buffer, header_buf, header_len);
+	size += header_len;
+
+	if (sign)
+		size = do_sign(buffer, size, max_size);
+
+	if (write_sha1_file(buffer, size, tag_type, result) < 0)
+		die("unable to write tag file");
+	free(buffer);
+}
+
+int cmd_tag(int argc, const char **argv, const char *prefix)
+{
+	unsigned char object[20], prev[20];
+	int annotate = 0, sign = 0, force = 0;
+	char *message = NULL;
+	char ref[PATH_MAX];
+	const char *object_ref, *tag;
+	int i, fd;
+	struct ref_lock *lock;
+
+	git_config(git_tag_config);
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (arg[0] != '-')
+			break;
+		if (!strcmp(arg, "-a")) {
+			annotate = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-s")) {
+			annotate = 1;
+			sign = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-f")) {
+			force = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-n")) {
+			if (i + 1 == argc || *argv[i + 1] == '-')
+				/* no argument */
+				lines = 1;
+			else
+				lines = isdigit(*argv[++i]) ?
+					atoi(argv[i]) : 1;
+			continue;
+		}
+		if (!strcmp(arg, "-m")) {
+			annotate = 1;
+			i++;
+			if  (i == argc)
+				die("option -m needs an argument.");
+			message = xstrdup(argv[i]);
+			continue;
+		}
+		if (!strcmp(arg, "-F")) {
+			unsigned long len;
+			annotate = 1;
+			i++;
+			if  (i == argc)
+				die("option -F needs an argument.");
+
+			fd = open(argv[i], O_RDONLY);
+			if (fd < 0)
+				die("cannot open %s", argv[1]);
+
+			len = 1024;
+			message = xmalloc(len);
+			if (read_pipe(fd, &message, &len))
+				die("cannot read %s", argv[1]);
+			message = xrealloc(message, len + 1);
+			message[len] = '\0';
+			continue;
+		}
+		if (!strcmp(arg, "-u")) {
+			annotate = 1;
+			sign = 1;
+			i++;
+			if  (i == argc)
+				die("option -u needs an argument.");
+			strlcpy(signingkey, argv[i], sizeof signingkey);
+			continue;
+		}
+		if (!strcmp(arg, "-l")) {
+			return list_tags(argv[i + 1]);
+		}
+		if (!strcmp(arg, "-d")) {
+			return delete_tags(argv + i + 1);
+		}
+		if (!strcmp(arg, "-v")) {
+			return verify_tags(argv + i + 1);
+		}
+		usage(builtin_tag_usage);
+	}
+
+	if (i == argc)
+		return list_tags(NULL);
+	tag = argv[i++];
+
+	object_ref = i < argc ? argv[i] : "HEAD";
+
+	if (get_sha1(object_ref, object))
+		die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+	if (snprintf(ref, sizeof ref, "refs/tags/%s", tag) > sizeof ref)
+		die("tag '%s' too long.", tag);
+	if (check_ref_format(ref))
+		die("'%s' is not a valid tag name.", tag);
+
+	if (!resolve_ref(ref, prev, 1, NULL))
+		hashclr(prev);
+	else if (!force)
+		die("tag '%s' already exists", tag);
+
+	if (annotate)
+		create_tag(object, tag, message, sign, object);
+
+	lock = lock_any_ref_for_update(ref, prev, 0);
+	if (!lock)
+		die("%s: cannot lock the ref", ref);
+	if (write_ref_sha1(lock, object, NULL) < 0)
+		die("%s: cannot update the ref", ref);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 4cc228d..ac7417f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -70,6 +70,7 @@ extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_tag(int argc, const char **argv, const char *prefix);
 extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_update_index(int argc, const char **argv, const char *prefix);
diff --git a/git-tag.sh b/git-tag.sh
deleted file mode 100755
index 1c25d88..0000000
--- a/git-tag.sh
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2005 Linus Torvalds
-
-USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-message_given=
-annotate=
-signed=
-force=
-message=
-username=
-list=
-verify=
-LINES=0
-while case "$#" in 0) break ;; esac
-do
-    case "$1" in
-    -a)
-	annotate=1
-	shift
-	;;
-    -s)
-	annotate=1
-	signed=1
-	shift
-	;;
-    -f)
-	force=1
-	shift
-	;;
-    -n)
-        case "$#,$2" in
-	1,* | *,-*)
-		LINES=1 	# no argument
-		;;
-	*)	shift
-		LINES=$(expr "$1" : '\([0-9]*\)')
-		[ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used
-		;;
-	esac
-	shift
-	;;
-    -l)
-	list=1
-	shift
-	case $# in
-	0)	PATTERN=
-		;;
-	*)
-		PATTERN="$1"	# select tags by shell pattern, not re
-		shift
-		;;
-	esac
-	git rev-parse --symbolic --tags | sort |
-	    while read TAG
-	    do
-	        case "$TAG" in
-		*$PATTERN*) ;;
-		*)	    continue ;;
-		esac
-		[ "$LINES" -le 0 ] && { echo "$TAG"; continue ;}
-		OBJTYPE=$(git cat-file -t "$TAG")
-		case $OBJTYPE in
-		tag)
-			ANNOTATION=$(git cat-file tag "$TAG" |
-				sed -e '1,/^$/d' |
-				sed -n -e "
-					/^-----BEGIN PGP SIGNATURE-----\$/q
-					2,\$s/^/    /
-					p
-					${LINES}q
-				")
-			printf "%-15s %s\n" "$TAG" "$ANNOTATION"
-			;;
-		*)      echo "$TAG"
-			;;
-		esac
-	    done
-	;;
-    -m)
-	annotate=1
-	shift
-	message="$1"
-	if test "$#" = "0"; then
-	    die "error: option -m needs an argument"
-	else
-	    message="$1"
-	    message_given=1
-	    shift
-	fi
-	;;
-    -F)
-	annotate=1
-	shift
-	if test "$#" = "0"; then
-	    die "error: option -F needs an argument"
-	else
-	    message="$(cat "$1")"
-	    message_given=1
-	    shift
-	fi
-	;;
-    -u)
-	annotate=1
-	signed=1
-	shift
-	if test "$#" = "0"; then
-	    die "error: option -u needs an argument"
-	else
-	    username="$1"
-	    shift
-	fi
-	;;
-    -d)
-	shift
-	had_error=0
-	for tag
-	do
-		cur=$(git show-ref --verify --hash -- "refs/tags/$tag") || {
-			echo >&2 "Seriously, what tag are you talking about?"
-			had_error=1
-			continue
-		}
-		git update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || {
-			had_error=1
-			continue
-		}
-		echo "Deleted tag $tag."
-	done
-	exit $had_error
-	;;
-    -v)
-	shift
-	tag_name="$1"
-	tag=$(git show-ref --verify --hash -- "refs/tags/$tag_name") ||
-		die "Seriously, what tag are you talking about?"
-	git-verify-tag -v "$tag"
-	exit $?
-	;;
-    -*)
-        usage
-	;;
-    *)
-	break
-	;;
-    esac
-done
-
-[ -n "$list" ] && exit 0
-
-name="$1"
-[ "$name" ] || usage
-prev=0000000000000000000000000000000000000000
-if git show-ref --verify --quiet -- "refs/tags/$name"
-then
-    test -n "$force" || die "tag '$name' already exists"
-    prev=`git rev-parse "refs/tags/$name"`
-fi
-shift
-git check-ref-format "tags/$name" ||
-	die "we do not like '$name' as a tag name."
-
-object=$(git rev-parse --verify --default HEAD "$@") || exit 1
-type=$(git cat-file -t $object) || exit 1
-tagger=$(git-var GIT_COMMITTER_IDENT) || exit 1
-
-test -n "$username" ||
-	username=$(git repo-config user.signingkey) ||
-	username=$(expr "z$tagger" : 'z\(.*>\)')
-
-trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0
-
-if [ "$annotate" ]; then
-    if [ -z "$message_given" ]; then
-        ( echo "#"
-          echo "# Write a tag message"
-          echo "#" ) > "$GIT_DIR"/TAG_EDITMSG
-        ${VISUAL:-${EDITOR:-vi}} "$GIT_DIR"/TAG_EDITMSG || exit
-    else
-        printf '%s\n' "$message" >"$GIT_DIR"/TAG_EDITMSG
-    fi
-
-    grep -v '^#' <"$GIT_DIR"/TAG_EDITMSG |
-    git stripspace >"$GIT_DIR"/TAG_FINALMSG
-
-    [ -s "$GIT_DIR"/TAG_FINALMSG -o -n "$message_given" ] || {
-	echo >&2 "No tag message?"
-	exit 1
-    }
-
-    ( printf 'object %s\ntype %s\ntag %s\ntagger %s\n\n' \
-	"$object" "$type" "$name" "$tagger";
-      cat "$GIT_DIR"/TAG_FINALMSG ) >"$GIT_DIR"/TAG_TMP
-    rm -f "$GIT_DIR"/TAG_TMP.asc "$GIT_DIR"/TAG_FINALMSG
-    if [ "$signed" ]; then
-	gpg -bsa -u "$username" "$GIT_DIR"/TAG_TMP &&
-	cat "$GIT_DIR"/TAG_TMP.asc >>"$GIT_DIR"/TAG_TMP ||
-	die "failed to sign the tag with GPG."
-    fi
-    object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
-fi
-
-git update-ref "refs/tags/$name" "$object" "$prev"
diff --git a/git.c b/git.c
index a647f9c..eb9e5ca 100644
--- a/git.c
+++ b/git.c
@@ -363,6 +363,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
+		{ "tag", cmd_tag, RUN_SETUP },
 		{ "tar-tree", cmd_tar_tree },
 		{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
 		{ "update-index", cmd_update_index, RUN_SETUP },
-- 
1.5.0

^ permalink raw reply related

* [PATCH 1/2] Function stripspace now gets a buffer instead file descriptors.
From: Carlos Rica @ 2007-07-11 18:50 UTC (permalink / raw)
  To: git, Junio C Hamano, Johannes Schindelin, Kristian Høgsberg

An implementation easier to call from builtins. It is designed
to be used from the upcoming builtin-tag.c and builtin-commit.c,
because both need to remove unwanted spaces from messages.

Signed-off-by: Carlos Rica <jasampler@gmail.com>
---

  This new implementation is a response to some Junio's comments
  on the version of builtin-tag.c which Kristian released:
  http://article.gmane.org/gmane.comp.version-control.git/49601

  The aim on not making this function internal yet
  is to be able to test it easily using the extensive
  test suite designed for git-stripspace. Later,
  this function could be in the file named "editor.c",
  along with the "launch_editor" function called when the
  program asks the user for a message not given from
  command-line.

 builtin-stripspace.c |   61 ++++++++++++++++++++++++++++++-------------------
 builtin.h            |    2 +-
 2 files changed, 38 insertions(+), 25 deletions(-)

diff --git a/builtin-stripspace.c b/builtin-stripspace.c
index d8358e2..949b640 100644
--- a/builtin-stripspace.c
+++ b/builtin-stripspace.c
@@ -2,12 +2,11 @@
 #include "cache.h"

 /*
- * Remove trailing spaces from a line.
+ * Returns the length of a line removing trailing spaces.
  *
  * If the line ends with newline, it will be removed too.
- * Returns the new length of the string.
  */
-static int cleanup(char *line, int len)
+static size_t cleanup(char *line, size_t len)
 {
 	if (len) {
 		if (line[len - 1] == '\n')
@@ -19,7 +18,6 @@ static int cleanup(char *line, int len)
 				break;
 			len--;
 		}
-		line[len] = 0;
 	}
 	return len;
 }
@@ -28,52 +26,67 @@ static int cleanup(char *line, int len)
  * Remove empty lines from the beginning and end
  * and also trailing spaces from every line.
  *
+ * Note that the buffer will not be null-terminated.
+ *
  * Turn multiple consecutive empty lines between paragraphs
  * into just one empty line.
  *
  * If the input has only empty lines and spaces,
  * no output will be produced.
  *
+ * If last line has a newline at the end, it will be removed.
+ *
  * Enable skip_comments to skip every line starting with "#".
  */
-void stripspace(FILE *in, FILE *out, int skip_comments)
+size_t stripspace(char *buffer, size_t length, int skip_comments)
 {
 	int empties = -1;
-	int alloc = 1024;
-	char *line = xmalloc(alloc);
+	size_t i, j, len, newlen;
+	char *eol;

-	while (fgets(line, alloc, in)) {
-		int len = strlen(line);
+	for (i = j = 0; i < length; i += len, j += newlen) {
+		eol = memchr(buffer + i, '\n', length - i);
+		len = eol ? eol - (buffer + i) + 1 : length - i;

-		while (len == alloc - 1 && line[len - 1] != '\n') {
-			alloc = alloc_nr(alloc);
-			line = xrealloc(line, alloc);
-			fgets(line + len, alloc - len, in);
-			len += strlen(line + len);
-		}
-
-		if (skip_comments && line[0] == '#')
+		if (skip_comments && len && buffer[i] == '#') {
+			newlen = 0;
 			continue;
-		len = cleanup(line, len);
+		}
+		newlen = cleanup(buffer + i, len);

 		/* Not just an empty line? */
-		if (len) {
+		if (newlen) {
+			if (empties != -1)
+				buffer[j++] = '\n';
 			if (empties > 0)
-				fputc('\n', out);
+				buffer[j++] = '\n';
 			empties = 0;
-			fputs(line, out);
-			fputc('\n', out);
+			memmove(buffer + j, buffer + i, newlen);
 			continue;
 		}
 		if (empties < 0)
 			continue;
 		empties++;
 	}
-	free(line);
+
+	return j;
 }

 int cmd_stripspace(int argc, const char **argv, const char *prefix)
 {
-	stripspace(stdin, stdout, 0);
+	char *buffer;
+	unsigned long size;
+
+	size = 1024;
+	buffer = xmalloc(size);
+	if (read_pipe(0, &buffer, &size))
+		die("could not read the input");
+
+	size = stripspace(buffer, size, 0);
+	write_or_die(1, buffer, size);
+	if (size)
+		putc('\n', stdout);
+
+	free(buffer);
 	return 0;
 }
diff --git a/builtin.h b/builtin.h
index 661a92f..4cc228d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -7,7 +7,7 @@ extern const char git_version_string[];
 extern const char git_usage_string[];

 extern void help_unknown_cmd(const char *cmd);
-extern void stripspace(FILE *in, FILE *out, int skip_comments);
+extern size_t stripspace(char *buffer, size_t length, int skip_comments);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 extern void prune_packed_objects(int);

-- 
1.5.0

^ permalink raw reply related

* Re: mtimes of working files
From: Johannes Schindelin @ 2007-07-11 18:42 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <f36b08ee0707111136t198cf559vc85c561decf9707f@mail.gmail.com>

Hi list,

> > > How difficult is it to have script (or maybe existing git option) 
> > > that would make mtimes of all working files equal to time of last 
> > > commit ?

Now I slowly get really curious.  Does _anybody_ know a scenario where 
this makes sense?

(No, Eric, there are enough corner cases where your example of a clustered 
webserver breaks down, so I am not fully convinced that this is a useful 
case.)

Anybody enlighten me?

Ciao,
Dscho

^ permalink raw reply

* Re: how to combine two clones in a collection
From: Johannes Schindelin @ 2007-07-11 18:37 UTC (permalink / raw)
  To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20070711181301.GA26815@piper.oerlikon.madduck.net>

Hi,

On Wed, 11 Jul 2007, martin f krafft wrote:

> also sprach robin:
> > And the simplest way to create an new indpendent branch:
> 
> > echo ref: refs/heads/newbranch >.git/HEAD
> > Then prepare the content and commit like you used to do.
> 
> I am a little uneasy about touching files in .git with non-git
> tools, but everyone seems to be doing it, so I guess it's okay, and
> it make git a lot more powerful too.

You can achieve the same with

	git symbolic-ref HEAD refs/heads/newbranch

There.  No editing in .git/.

>   piper:~> echo ref: refs/heads/newbranch >| .git/HEAD
>   piper:~> git status
>   # On branch newbranch
>   #
>   # Initial commit
>   #
>   # Changes to be committed:
>   #   (use "git rm --cached <file>..." to unstage)
>   #
>   #       new file: date
>   #

However, this is much easier without Git commands:

	rm .git/index

Of course, you can remove all files one by one, but that is certainly not 
easier:

	git ls-files --cached -z | xargs -0 git rm --cached

But then, you really can learn from both examples: .git/index contains 
references to the objects which are staged (in Git speak: "in the index").  
Git plays nicely when that file is missing, and assumes the index to be 
empty.

With "git ls-files --cached", you can list the files which are in the 
index, and with "git rm --cached", you remove the file _only_ from the 
index, but keep it in the working tree (if it is there).  The options "-z" 
and "-0" are only to separate the names by NUL instead of newlines, to 
allow funny file names, too.

If a few more people ask for that feature, we could enhance the semantics 
of "git branch" and "git checkout" to interpret the empty string 
similar to "git push <repo> :<name>".

Ciao,
Dscho

^ permalink raw reply

* Re: mtimes of working files
From: Yakov Lerner @ 2007-07-11 18:36 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0707111902040.4516@racer.site>

On 7/11/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> On Wed, 11 Jul 2007, Yakov Lerner wrote:
>
> > How difficult is it to have script (or maybe existing git option) that
> > would make mtimes of all working files equal to time of last commit ?
>
> I wonder if there was a secret alien invasion three days ago, with an evil
> mental virus weapon?  It seems that this question has been asked three
> times in the last three days, twice on IRC, and once here.
>
> So now, I really, really, really, (repeat that 97 more times in your head,
> please) want to know why?
>
> There must be some super uber-cool application of that, that people
> _insist_ on having it.  And I do not want to be left out.

I gave you my reason on IRC, you ignored it. And you continued with
"You must defend your reason. Until you defend your reason, I do not give
you the solution, although I know it". That sounded rude. If you are *curious*,
try to speak not from position of "punishing authority", but as curious people
would normally speak.

> P.S.: I know how to do it, too.  And no, it does not help to try insulting
> me (unsuccessfully), even in a private chat.

If modifying mtimes of working file breaks the git, you should have
mentioned that.

I think  it does not break anything in git.  If this is so you should
have said so
and to give the solution (which you said you know).  I am lost in guesses
as to what makes you keep your monopolistic solution secret.
Hope I can figure it without you.

In the chat, you told me that you know the answer but won't tell me.

I have to tell you that demanding from me that I tell you why other
people asked this, and to withhold the answer on the ground that
I must mind-read them and tell you their mind ... I think this is stupid
attitude on yous part.

Yakov

^ permalink raw reply

* Re: Hook after pull ?
From: Alex Riesen @ 2007-07-11 18:33 UTC (permalink / raw)
  To: Claudio Scordino; +Cc: git, Johannes.Schindelin
In-Reply-To: <4694F74F.8050908@gmail.com>

Claudio Scordino, Wed, Jul 11, 2007 17:29:19 +0200:
> >>If no, does exist any easy way of creating such hook ?
> >
> >What for? What do you want to do?
> >
> I just need my script to be called after a pull. My script just sends an 
> email saying that the repository has been pulled (I already did it for the 
> push).

Ach, on _remote_ repo. Where it is _pulled_from_.
There are none. You can catch log output of git-daemon, but...
Isn't it a bit extreme? A fetch (part of a pull) is *very* common
operation, sometime you'll get a *real* lot of mail.

P.S. BTW, there is no hooks for pull in local (where it is pulled
into): it is not needed, you already control everything what happens.
But it is not your situation, as far I understand.

^ permalink raw reply

* Re: [PATCH] gitweb: configurable width for the projects list Description column
From: Jakub Narebski @ 2007-07-11 18:28 UTC (permalink / raw)
  To: git
In-Reply-To: <11835958082458-git-send-email-michael@ndrix.org>

Michael Hendricks wrote:

> This allows gitweb users to set $projects_list_description_width
> in their gitweb.conf to determine how many characters of a project
> description are displayed before being truncated with an ellipsis.

Ack.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: how to combine two clones in a collection
From: martin f krafft @ 2007-07-11 18:13 UTC (permalink / raw)
  To: git discussion list
In-Reply-To: <200707110145.28931.robin.rosenberg.lists@dewire.com>

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

also sprach robin:
> And the simplest way to create an new indpendent branch:

> echo ref: refs/heads/newbranch >.git/HEAD
> Then prepare the content and commit like you used to do.

Hi Robin, thanks for this nice suggestion, which doesn't only
createa a new, independent branch, it also teaches me yet a bit
more about git.

I am a little uneasy about touching files in .git with non-git
tools, but everyone seems to be doing it, so I guess it's okay, and
it make git a lot more powerful too.

Anyway, I tried your method and there is one small problem:

  piper:~> git init-db
  Initialized empty Git repository in .git/
  piper:~> date > date; git add date; git commit -m.
  Created initial commit 2dd8d6f: .
  1 files changed, 1 insertions(+), 0 deletions(-)
  create mode 100644 date
  piper:~> echo ref: refs/heads/newbranch >| .git/HEAD
  piper:~> git status
  # On branch newbranch
  #
  # Initial commit
  #
  # Changes to be committed:
  #   (use "git rm --cached <file>..." to unstage)
  #
  #       new file: date
  #

If I were to run commit now, the file 'date' would become part of
the first commit to newbranch. But it's already in the master
branch.

Is there anyway I can prevent this and start a new branch from
scratch without having to unstage all previous additions?

Thanks,

-- 
martin;              (greetings from the heart of the sun.)
  \____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
 
spamtraps: madduck.bogus@madduck.net
 
"anyone who is capable of getting themselves made president
 should on no account be allowed to do the job"
                                                      -- douglas adams

[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: mtimes of working files
From: Johannes Schindelin @ 2007-07-11 18:05 UTC (permalink / raw)
  To: Yakov Lerner; +Cc: Git Mailing List
In-Reply-To: <f36b08ee0707110808h56ecbc7at9c92727c01cca508@mail.gmail.com>

Hi,

On Wed, 11 Jul 2007, Yakov Lerner wrote:

> How difficult is it to have script (or maybe existing git option) that 
> would make mtimes of all working files equal to time of last commit ?

I wonder if there was a secret alien invasion three days ago, with an evil 
mental virus weapon?  It seems that this question has been asked three 
times in the last three days, twice on IRC, and once here.

So now, I really, really, really, (repeat that 97 more times in your head, 
please) want to know why?

There must be some super uber-cool application of that, that people 
_insist_ on having it.  And I do not want to be left out.  Please tell me 
how I could use that feature to make my workflow better.

Please, please, please.

Ciao,
Dscho

P.S.: I know how to do it, too.  And no, it does not help to try insulting 
me (unsuccessfully), even in a private chat.

^ permalink raw reply

* Re: [PATCH v3] revision: allow selection of commits that do not match a pattern
From: Jeff King @ 2007-07-11 17:42 UTC (permalink / raw)
  To: skimo; +Cc: Johannes Schindelin, Junio C Hamano, git
In-Reply-To: <20070708105719.GH1528MdfPADPa@greensroom.kotnet.org>

On Sun, Jul 08, 2007 at 12:57:20PM +0200, Sven Verdoolaege wrote:

> We do this by maintaining two lists of patterns, one for
> those that should match and one for those that should not match.
> 
> A negative pattern is specified by putting a '!' in front.
> For example, to show the commits of Jakub Narebski that
> are not about gitweb, you'd do a
> 
> 	git log --author='Narebski' --grep='!gitweb' --all-match

I wondered if the usage might be more natural if we could grep in
separate processes, and then build filtering pipelines (like we would
with regular grep).  For example, something like:

git-rev-list HEAD |
  git-revgrep --author=Narebski |
  git-revgrep -v gitweb |
  git-log -

However, my concern was that things might get a lot slower. And they do:

$ time git-rev-list --grep=Jeff.King HEAD >/dev/null
real    0m0.553s
user    0m0.532s
sys     0m0.020s

$ time git-rev-list HEAD | git-revgrep Jeff.King >/dev/null
real    0m0.662s
user    0m1.072s
sys     0m0.036s

(note the user time -- it's a dual-CPU box, so the wall clock time is
deceptive).

So it really does double your time (or triple, if you have a second
revgrep, and so forth (although as you filter out commits the cost of
each successive revgrep goes down)).  So it's probably not worth
pursuing this approach, but I thought I would throw it out there to
document my dead-end.

Quick and dirty git-revgrep code is below.

-Peff

---
diff --git a/Makefile b/Makefile
index d7541b4..baaf4f1 100644
--- a/Makefile
+++ b/Makefile
@@ -384,7 +384,8 @@ BUILTIN_OBJS = \
 	builtin-verify-pack.o \
 	builtin-write-tree.o \
 	builtin-show-ref.o \
-	builtin-pack-refs.o
+	builtin-pack-refs.o \
+	builtin-revgrep.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 EXTLIBS = -lz
diff --git a/builtin-revgrep.c b/builtin-revgrep.c
new file mode 100644
index 0000000..35993c8
--- /dev/null
+++ b/builtin-revgrep.c
@@ -0,0 +1,68 @@
+#include "cache.h"
+#include "commit.h"
+#include "grep.h"
+
+static int revgrep_one(const struct commit *commit, struct grep_opt *opt)
+{
+	return grep_buffer(opt, NULL, commit->buffer, strlen(commit->buffer));
+}
+
+static void revgrep_filter(struct grep_opt *opt)
+{
+	char line[1000];
+	unsigned char sha1[20];
+	struct commit *commit;
+
+	while (fgets(line, sizeof(line), stdin) != NULL) {
+		int len = strlen(line);
+		if (line[len - 1] == '\n')
+			line[--len] = 0;
+		if (!len)
+			break;
+		get_sha1_hex(line, sha1);
+		commit = lookup_commit_reference(sha1);
+		if (!commit)
+			continue;
+		if (revgrep_one(commit, opt))
+			printf("%s\n", line);
+	}
+}
+
+int cmd_revgrep(int argc, const char **argv, const char *prefix)
+{
+	struct grep_opt opt;
+
+	memset(&opt, 0, sizeof(opt));
+	opt.pattern_tail = &opt.pattern_list;
+	opt.status_only = 1;
+
+	while (1 < argc) {
+		const char *arg = argv[1];
+		argc--; argv++;
+
+		if (!strcmp(arg, "-i")) {
+			opt.regflags |= REG_ICASE;
+			continue;
+		}
+		if (!strcmp(arg, "-v")) {
+			opt.invert = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-E")) {
+			opt.regflags |= REG_EXTENDED;
+			continue;
+		}
+
+		append_grep_pattern(&opt, arg, "command line", 0,
+				GREP_PATTERN);
+	}
+
+	if (!opt.pattern_list)
+		die("no pattern given");
+
+	compile_grep_patterns(&opt);
+	revgrep_filter(&opt);
+	free_grep_patterns(&opt);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 661a92f..d185528 100644
--- a/builtin.h
+++ b/builtin.h
@@ -82,5 +82,6 @@ extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
+extern int cmd_revgrep(int argc, const char **argv, const char *prefix);
 
 #endif
diff --git a/git.c b/git.c
index a647f9c..d9ec129 100644
--- a/git.c
+++ b/git.c
@@ -374,6 +374,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "verify-pack", cmd_verify_pack },
 		{ "show-ref", cmd_show_ref, RUN_SETUP },
 		{ "pack-refs", cmd_pack_refs, RUN_SETUP },
+		{ "revgrep", cmd_revgrep, RUN_SETUP },
 	};
 	int i;
 






> 
> As an added bonus, this patch also documents --all-match.
> 
> Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
> ---
>  Documentation/git-rev-list.txt |   17 ++++++++++
>  revision.c                     |   64 +++++++++++++++++++++++++++++++++------
>  revision.h                     |    1 +
>  3 files changed, 72 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
> index 20dcac6..c462f5d 100644
> --- a/Documentation/git-rev-list.txt
> +++ b/Documentation/git-rev-list.txt
> @@ -214,11 +214,19 @@ limiting may be applied.
>  
>  	Limit the commits output to ones with author/committer
>  	header lines that match the specified pattern (regular expression).
> +	A pattern starting with a '!' will show only commits that do
> +	not match the remainder of the pattern.
> +	To match lines starting with '!', escape the initial '!'
> +	with a backslash.
>  
>  --grep='pattern'::
>  
>  	Limit the commits output to ones with log message that
>  	matches the specified pattern (regular expression).
> +	A pattern starting with a '!' will show only commits that do
> +	not match the remainder of the pattern.
> +	To match lines starting with '!', escape the initial '!'
> +	with a backslash.
>  
>  --regexp-ignore-case::
>  
> @@ -229,6 +237,15 @@ limiting may be applied.
>  	Consider the limiting patterns to be extended regular expressions
>  	instead of the default basic regular expressions.
>  
> +--all-match::
> +
> +	Without this option, a commit is shown if any of the
> +	(positive or negative) patterns matches, i.e., there
> +	is at least one positive match or not all of the negative
> +	patterns match.  With this options, a commit is only
> +	shown if all of the patterns match, i.e., all positive
> +	patterns match and no negative pattern matches.
> +
>  --remove-empty::
>  
>  	Stop when a given path disappears from the tree.
> diff --git a/revision.c b/revision.c
> index 5184716..0035d40 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -821,34 +821,50 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
>  	return 0;
>  }
>  
> -static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what)
> +static void add_grep(struct rev_info *revs, const char *ptn,
> +		    enum grep_pat_token what)
>  {
> -	if (!revs->grep_filter) {
> +	int negated = 0;
> +	struct grep_opt **filter;
> +
> +	if (ptn[0] == '\\' && ptn[1] == '!')
> +		ptn++;
> +	if (*ptn == '!') {
> +		negated = 1;
> +		ptn++;
> +	}
> +	filter = negated ? &revs->grep_neg_filter : &revs->grep_filter;
> +	if (!*filter) {
>  		struct grep_opt *opt = xcalloc(1, sizeof(*opt));
>  		opt->status_only = 1;
>  		opt->pattern_tail = &(opt->pattern_list);
>  		opt->regflags = REG_NEWLINE;
> -		revs->grep_filter = opt;
> +		*filter = opt;
>  	}
> -	append_grep_pattern(revs->grep_filter, ptn,
> -			    "command line", 0, what);
> +	append_grep_pattern(*filter, ptn, "command line", 0, what);
>  }
>  
> -static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
> +static void add_header_grep(struct rev_info *revs, const char *field,
> +			    const char *pattern)
>  {
>  	char *pat;
> -	const char *prefix;
> +	const char *prefix, *negated;
>  	int patlen, fldlen;
>  
>  	fldlen = strlen(field);
>  	patlen = strlen(pattern);
>  	pat = xmalloc(patlen + fldlen + 10);
> +	negated = "";
> +	if (*pattern == '!') {
> +		negated = "!";
> +		pattern++;
> +	}
>  	prefix = ".*";
>  	if (*pattern == '^') {
>  		prefix = "";
>  		pattern++;
>  	}
> -	sprintf(pat, "^%s %s%s", field, prefix, pattern);
> +	sprintf(pat, "%s^%s %s%s", negated, field, prefix, pattern);
>  	add_grep(revs, pat, GREP_PATTERN_HEAD);
>  }
>  
> @@ -1212,6 +1228,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
>  	if (revs->grep_filter)
>  		revs->grep_filter->regflags |= regflags;
>  
> +	if (revs->grep_neg_filter)
> +		revs->grep_neg_filter->regflags |= regflags;
> +
>  	if (show_merge)
>  		prepare_show_merge(revs);
>  	if (def && !revs->pending.nr) {
> @@ -1249,6 +1268,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
>  		compile_grep_patterns(revs->grep_filter);
>  	}
>  
> +	if (revs->grep_neg_filter) {
> +		revs->grep_neg_filter->all_match = !all_match;
> +		compile_grep_patterns(revs->grep_neg_filter);
> +	}
> +
>  	return left;
>  }
>  
> @@ -1327,11 +1351,31 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
>  	return 0;
>  }
>  
> +/*
> + * If all_match is set, then a commit matches if all the positive
> + * patterns match and not one of the negative patterns matches.
> + * If all_match is not set, then a commit matches if at least one
> + * of the positive patterns matches or not all of the negative
> + * patterns match.
> + */
>  static int commit_match(struct commit *commit, struct rev_info *opt)
>  {
> -	if (!opt->grep_filter)
> +	int pos_match, all_match;
> +
> +	pos_match = !opt->grep_filter ||
> +		    grep_buffer(opt->grep_filter,
> +			   NULL, /* we say nothing, not even filename */
> +			   commit->buffer, strlen(commit->buffer));
> +	if (!opt->grep_neg_filter)
> +		return pos_match;
> +
> +	all_match = !opt->grep_neg_filter->all_match;
> +	if (!all_match && opt->grep_filter && pos_match)
>  		return 1;
> -	return grep_buffer(opt->grep_filter,
> +	if (all_match && !pos_match)
> +		return 0;
> +
> +	return !grep_buffer(opt->grep_neg_filter,
>  			   NULL, /* we say nothing, not even filename */
>  			   commit->buffer, strlen(commit->buffer));
>  }
> diff --git a/revision.h b/revision.h
> index f46b4d5..9728d4c 100644
> --- a/revision.h
> +++ b/revision.h
> @@ -84,6 +84,7 @@ struct rev_info {
>  
>  	/* Filter by commit log message */
>  	struct grep_opt	*grep_filter;
> +	struct grep_opt	*grep_neg_filter;
>  
>  	/* special limits */
>  	int skip_count;
> -- 
> 1.5.3.rc0.65.ge75d-dirty
> 
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: Installation failure caused by CDPATH environment variable
From: Johannes Schindelin @ 2007-07-11 17:09 UTC (permalink / raw)
  To: Wincent Colaiuta; +Cc: git
In-Reply-To: <9693D8E9-6F11-4AA1-AFCA-7E8456FA6420@wincent.com>

Hi,

On Wed, 11 Jul 2007, Wincent Colaiuta wrote:

> [describes the typical CDPATH problem]

You exported CDPATH.  You're guaranteed to run into problems with that.  I 
doubt that your patch catches all problems in git, and even if we tried to 
avoid breakage, you can only do so much about that.

It is _wrong_ to export CDPATH.

Hth,
Dscho

^ permalink raw reply

* Installation failure caused by CDPATH environment variable
From: Wincent Colaiuta @ 2007-07-11 16:59 UTC (permalink / raw)
  To: git

This week I've installed Git on two different machines and one of  
them mysteriously failed making the "install" target in the  
"templates/Makefile". Specifically, the problem was occuring here:

         (cd blt && $(TAR) cf - .) | \
         (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -)

And the error message was:

tar: This does not look like a tar archive
tar: Skipping to next header
tar: Error exit delayed from previous errors

Upon investigation, I discovered that the cause was that on the  
failing machine, the CDPATH environment variable was set and included  
"." (the current directory). This meant that upon executing:

         (cd blt && $(TAR) cf - .)

The data from tar was getting prepended with garbage because "cd blt"  
was echoing the path to the directory.

The workaround is to "unset CDPATH" or change the value of CDPATH so  
that it doesn't include the "." (although the latter is not very  
feasible because without "." at the front of CDPATH changing into a  
directory relative to the current directory can be quite painful).

What do you think about altering the templates/Makefile to make it  
more robust against this kind of environment?

Here's a possible patch:

 From 057630bdcfeee63b90468d1a69153171b15780c0 Mon Sep 17 00:00:00 2001
From: Wincent Colaiuta <win@wincent.com>
Date: Wed, 11 Jul 2007 18:43:59 +0200

[PATCH] Proof Makefile against possible problems with CDPATH environment

If the CDPATH environment variable is set and contains a period
Bash may echo the current directory name while performing a cd,
and when this extra output is piped to tar as part of template
installation it can cause tar to abort with an error. This patch
avoids this problem by invoking cd as a separate step prior to
invoking tar.

Signed-off-by: Wincent Colaiuta <win@wincent.com>
---
  templates/Makefile |    3 ++-
  1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/templates/Makefile b/templates/Makefile
index aaa39d3..3457ccb 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -46,5 +46,6 @@ clean:

  install: all
         $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(template_dir_SQ)'
-       (cd blt && $(TAR) cf - .) | \
+       cd blt && $(TAR) cf - . | \
         (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -)
+       cd -
-- 
1.5.2.3

^ permalink raw reply related

* Re: [PATCH] Document git-filter-branch
From: Johannes Schindelin @ 2007-07-11 17:03 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Frank Lichtenheld, git
In-Reply-To: <f731u9$1ir$1@sea.gmane.org>

Hi,

On Wed, 11 Jul 2007, Jakub Narebski wrote:

> Johannes Schindelin wrote:
> > On Wed, 4 Jul 2007, Frank Lichtenheld wrote:
> 
> >>> +Note that since this operation is extensively I/O expensive, it might
> >>> +be a good idea to redirect the temporary directory it off-disk, e.g. on
> 
> By the way, could git-filter-branch use git-fast-import to reduce I/O?

That idea has been kicked around.  But since skimo promised that he works 
on rewrite-commits, which will be much faster.  So I do not see any point 
in working on filter-branch any more.

BTW good to see you back on the list!

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Document git-filter-branch
From: Jakub Narebski @ 2007-07-11 16:53 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0707040004200.4071@racer.site>

[Cc: git@vger.kernel.org, Johannes Schindelin <Johannes.Schindelin@gmx.de>,
 Frank Lichtenheld <frank@lichtenheld.de>]

Johannes Schindelin wrote:
> On Wed, 4 Jul 2007, Frank Lichtenheld wrote:

>>> +Note that since this operation is extensively I/O expensive, it might
>>> +be a good idea to redirect the temporary directory it off-disk, e.g. on

By the way, could git-filter-branch use git-fast-import to reduce I/O?

>>> +the id of the commit being rewritten.  The author/committer environment
>>> +variables are set before the first filter is run.
>> 
>> Maybe give the actual names of the environment variables here?
> 
> If you think so:
> 
>       Also, GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, 
>       GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, and GIT_COMMITTER_DATE is 
>       set according to the current commit.

Or

        Also, GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, 
        GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, and GIT_COMMITTER_DATE  
        are filled with data taken from the current commit. 

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Build error with qgit4
From: Aneesh Kumar @ 2007-07-11 16:19 UTC (permalink / raw)
  To: Marco Costalba, Git Mailing List

lude/qt4/QtGui -I/usr/include/qt4 -I../src -I../build -I../build -o
../build/fileview.o fileview.cpp
../build/ui_fileview.h: In member function 'void Ui_TabFile::setupUi(QWidget*)':
../build/ui_fileview.h:63: error: 'class QHBoxLayout' has no member
named 'setLeftMargin'
../build/ui_fileview.h:64: error: 'class QHBoxLayout' has no member
named 'setTopMargin'
../build/ui_fileview.h:65: error: 'class QHBoxLayout' has no member
named 'setRightMargin'
../build/ui_fileview.h:66: error: 'class QHBoxLayout' has no member
named 'setBottomMargin'
../build/ui_fileview.h:71: error: 'class QVBoxLayout' has no member
named 'setLeftMargin'

^ permalink raw reply

* Re: [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Jakub Narebski @ 2007-07-11 15:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Matt McCutchen, git, Petr Baudis, Luben Tuikov
In-Reply-To: <7vir8w6inf.fsf@assigned-by-dhcp.cox.net>

On Sat, 7 Jul 2007, Junio C Hamano wrote:
> Matt McCutchen <hashproduct@gmail.com> writes:

>> +# information about snapshot formats that gitweb is capable of serving
>> +# name => [mime type, filename suffix, --format for git-archive,
>> +#          compressor command suffix]
>> +our %known_snapshot_formats = (
>> +	'tgz'  => ['application/x-gzip' , '.tar.gz' , 'tar', '| gzip' ],
>> +	'tbz2' => ['application/x-bzip2', '.tar.bz2', 'tar', '| bzip2'],
>> +	'zip'  => ['application/zip'    , '.zip'    , 'zip', ''       ],
>> +);

> This is a very nice clean-up, and I agree we should go this
> route in the longer term.

I agree that is a nice cleanup.

I'm not sure if we want to store whole 'application/x-gzip' or only
'x-gzip' part of mime type, and if we want to store compressor as
'| gzip' or simply as 'gzip'.
 
> This however will break people's existing gitweb configuration,
> so if we were to do this it should be post 1.5.3, I would say.

This would break not only existing _gitweb_ configuration (when
gitweb admin installs new gitweb it isn't that hard to correct
gitweb config), but also git _repositories_ config: gitweb.snapshot
no longer work as it worked before, for example neither 'gzip'
nor 'bzip2' values work anymore ('zip' doesn't stop working).

-- 
Jakub Narebski
Poland

^ permalink raw reply

* Re: git-cvsimport newbie question
From: Scott Lamb @ 2007-07-11 15:45 UTC (permalink / raw)
  To: git
In-Reply-To: <469484AA.7040701@slamb.org>

Scott Lamb wrote:
> But from the manpage, it appears I'm reverting to a much older way of
> doing things. Maybe I should be giving the newer way a shot? Was this
> "-r" way meant to be used with cloning the mirrored repository? If so,
> what's the workflow there? maybe I should reset racoon2.git's "master"
> branch to the beginning of time (to avoid confusion), update head to
> point to remotes/wide/master (so simple "git clone" and "git pull"
> commands get CVS HEAD), and then update remote.origin.fetch on each
> cloned repository to pull in other branches as needed? But even after
> doing that, "git remote show origin" on a cloned repository still won't
> give me the list of branches I want. So this seems doesn't seem as good
> as the old way.
> 
> Is there any way to make a repository cloned from a new-style
> cvsimported one show the list of branches? It looks like I can't have a
> remote in one repository refer to a remote in another repository - it
> wants a direct reference. Most things seem to ignore origin's remotes,
> at least unless I explicitly name one like "git pull origin
> refs/remotes/wide/master".

Hmm...I just saw in a git-svn howto [1] this text:

    [FIXME] This is all very important information for people setting
    up central tracking servers. This needs expansion, probably its own
    section. Talk about tracking server symlink tricks
    (eg refs/heads/svn -> ../remotes and
    refs/ttags/svn -> ../remotes/tags)

Maybe I want to be doing something similar with git-cvsimport? I'm sure
there's *some* reason way to take advantage of the my named remote; I
just haven't figured out what it is yet. Could someone please fill in
details on this text?

Best regards,
Scott


[1] - http://utsl.gen.nz/talks/git-svn/intro.html

^ permalink raw reply

* Re: user manual wrong about remote branches?
From: Bradford Smith @ 2007-07-11 15:34 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: git
In-Reply-To: <20070711152816.GB4138@fieldses.org>

OK, the problem was the old version of git (1.4.4.2) I used to do the
original clone.  Cloning with the latest version gives me what the
manual says I should get.

Thanks!

Bradford C. Smith

On 7/11/07, J. Bruce Fields <bfields@fieldses.org> wrote:
> On Wed, Jul 11, 2007 at 11:21:53AM -0400, Bradford Smith wrote:
> > I got the latest git source like this:
> >
> > git clone git://git.kernel.org/pub/scm/git/git.git
>
> What version of git did you do this first clone with?
>
> > Then I did:
> >
> > make prefix=/usr/local all doc
> > make prefix=/usr/local install install-doc
> >
> > So my current version is:
> >
> > git version 1.5.3.rc0.gbaa79
> >
> > Now, Documentation/user-manual.txt says I should be able to see the
> > remote branch I cloned from when I do this in the source directory.
> >
> > git branch -r
> >
> > However, this command gives no output at all.  What gives?  Does this
> > mean git-fetch and git-pull won't work properly to keep me up-to-date
> > with the main repository?
>
> The remote branch setup  is done on the initial clone.  So if you clone
> again with the newly installed version of git, you'll probably see
> what's expected.
>
> --b.
>

^ permalink raw reply

* Re: Hook after pull ?
From: Claudio Scordino @ 2007-07-11 15:29 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git, Johannes.Schindelin
In-Reply-To: <81b0412b0707110751i7947ac5bv819e1c2de4e94621@mail.gmail.com>

Alex Riesen wrote:
> On 7/11/07, Claudio Scordino <cloud.of.andor@gmail.com> wrote:
>> Hi all.
>>
>> Does any hook being called after the pull (that means, after fetch or 
>> merge) ?
>>
> 
> There are some

Which one of those inside the .git/hooks directory is called afret a pull?

> 
>> If no, does exist any easy way of creating such hook ?
>>
> 
> What for? What do you want to do?
> 
I just need my script to be called after a pull. My script just sends an email 
saying that the repository has been pulled (I already did it for the push).

Thanks,

         Claudio

^ permalink raw reply

* Re: user manual wrong about remote branches?
From: J. Bruce Fields @ 2007-07-11 15:28 UTC (permalink / raw)
  To: Bradford Smith; +Cc: git
In-Reply-To: <f158199e0707110821k50a55e66p8fb0b92a3dec9ed2@mail.gmail.com>

On Wed, Jul 11, 2007 at 11:21:53AM -0400, Bradford Smith wrote:
> I got the latest git source like this:
>
> git clone git://git.kernel.org/pub/scm/git/git.git

What version of git did you do this first clone with?

> Then I did:
>
> make prefix=/usr/local all doc
> make prefix=/usr/local install install-doc
>
> So my current version is:
>
> git version 1.5.3.rc0.gbaa79
>
> Now, Documentation/user-manual.txt says I should be able to see the
> remote branch I cloned from when I do this in the source directory.
>
> git branch -r
>
> However, this command gives no output at all.  What gives?  Does this
> mean git-fetch and git-pull won't work properly to keep me up-to-date
> with the main repository?

The remote branch setup  is done on the initial clone.  So if you clone
again with the newly installed version of git, you'll probably see
what's expected.

--b.

^ permalink raw reply

* user manual wrong about remote branches?
From: Bradford Smith @ 2007-07-11 15:21 UTC (permalink / raw)
  To: git

I got the latest git source like this:

git clone git://git.kernel.org/pub/scm/git/git.git

Then I did:

make prefix=/usr/local all doc
make prefix=/usr/local install install-doc

So my current version is:

git version 1.5.3.rc0.gbaa79

Now, Documentation/user-manual.txt says I should be able to see the
remote branch I cloned from when I do this in the source directory.

git branch -r

However, this command gives no output at all.  What gives?  Does this
mean git-fetch and git-pull won't work properly to keep me up-to-date
with the main repository?

Thanks,

Bradford C. Smith

^ permalink raw reply

* mtimes of working files
From: Yakov Lerner @ 2007-07-11 15:08 UTC (permalink / raw)
  To: Git Mailing List

How difficult is it to have script (or maybe existing git option)
that would make mtimes of all working files equal to time of last commit ?

Thanks
Yakov

^ permalink raw reply

* Re: [PATCH] Fix core.sharedRepository = 2
From: martin f krafft @ 2007-07-11 14:52 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster
In-Reply-To: <Pine.LNX.4.64.0707111517050.4516@racer.site>

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

also sprach Johannes Schindelin <Johannes.Schindelin@gmx.de> [2007.07.11.1618 +0200]:
> This patch fixes both issues, and adds a test to prove it.

I also tested it and can confirm.

-- 
martin;              (greetings from the heart of the sun.)
  \____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
 
spamtraps: madduck.bogus@madduck.net
 
"wer ein warum hat, dem ist kein wie zu schwer."
                                                 - friedrich nietzsche

[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ 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