Git development
 help / color / mirror / Atom feed
* Re: [RFC/PATCH] show tracking branches with their associated branch names
From: Santhosh @ 2011-12-12 14:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Vincent van Ravesteijn, git
In-Reply-To: <7vsjkq5h0i.fsf@alter.siamese.dyndns.org>

On Mon, Dec 12, 2011 at 12:44 PM, Junio C Hamano <gitster@pobox.com> wrote:
>
> It makes sense to make the various information available, but it does not
> mean it makes sense to add it by default for everybody at all. Given that
> against all common sense, many newbie web-tips and third-party documents
> suggest "git branch | sed -ne 's/^\* //p'" as a way to find the current
> branch in scripts, I am sure such a change will cause trouble to many
> while only helping a few.
>

You certainly have a point.

> I wouldn't mind a new option --verbose-format=... that takes various
> formatting letters similar to how --pretty=format:... does, though.
>

I will explore this option and see if it is worth the trouble.
Probably I can accomplish this locally with an alias.

~Santhosh.

^ permalink raw reply

* Re: [PATCH] tag deletions not rejected with receive.denyDeletes= true
From: Jerome DE VIVIE @ 2011-12-12 14:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <6271653.2751323698446271.JavaMail.root@promailix.prometil.com>


Junio C Hamano <gitster@pobox.com> writes :
> Our documentation can also use some updates, as it dates to the days back
> when we more liberally used "refs" and "branches" interchangeably.

Ok, I have turned the patch below for documentation.

For protecting tags, I can do it with triggers but its painful with lots of repositories. I propose to extend receive.denyDeletes with these values:
- "false"/"none" (existing behavior)
- "true"/"branches" (existing behavior)
- "tags": protect tags only
- "all": protect both tags and branches

Your opinion ?

BR
Jérôme


Signed-off-by: Jerome de Vivie <jedevivie-ext@airfrance.fr>
---
 Documentation/config.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da..9c7c7fe 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1642,7 +1642,7 @@ receive.unpackLimit::
 
 receive.denyDeletes::
 	If set to true, git-receive-pack will deny a ref update that deletes
-	the ref. Use this to prevent such a ref deletion via a push.
+	a branch. Use this to prevent such a branch deletion via a push.
 
 receive.denyDeleteCurrent::
 	If set to true, git-receive-pack will deny a ref update that
-- 
1.7.6.msysgit.0

^ permalink raw reply related

* Re: [PATCH v2 08/51] is_dup_ref(): extract function from sort_ref_array()
From: Michael Haggerty @ 2011-12-12 11:44 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, git, Drew Northup, Jakub Narebski, Heiko Voigt,
	Johan Herland, Julian Phillips
In-Reply-To: <20111212083345.GA16106@sigill.intra.peff.net>

On 12/12/2011 09:33 AM, Jeff King wrote:
> On Mon, Dec 12, 2011 at 06:38:15AM +0100, mhagger@alum.mit.edu wrote:
> 
>> +/*
>> + * Emit a warning and return true iff ref1 and ref2 have the same name
>> + * and the same sha1.  Die if they have the same name but different
>> + * sha1s.
>> + */
>> +static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
>> +{
>> +	if (!strcmp(ref1->name, ref2->name)) {
>> +		/* Duplicate name; make sure that the SHA1s match: */
>> +		if (hashcmp(ref1->sha1, ref2->sha1))
>> +			die("Duplicated ref, and SHA1s don't match: %s",
>> +			    ref1->name);
>> +		warning("Duplicated ref: %s", ref1->name);
>> +		return 1;
>> +	} else {
>> +		return 0;
>> +	}
>> +}
> 
> As a user, I'm not sure what this message means. If I understand the
> context right, this happens when you have duplicate entries in your
> packed-refs file?

It could be caused by dups in any of the three ref caches: packed refs,
loose refs, or extra refs.

Duplicates in the packed-refs file could be caused by any garden-variety
data corruption external to git.  Or they could be caused by a bug in
git that caused it to write duplicates.  But the code that writes packed
refs iterates over the refs right after they are sorted, and sorting
eliminates duplicates, so this would be an unlikely bug the way the code
is currently organized.  I suppose they could also be caused by the
simultaneous writing of the packed-refs file by another process that
doesn't respect git's lock file; perhaps an ill-timed rsync or something.

Normally there should be no duplicate loose refs, because their names
are taken directly from the filesystem and duplicate filenames are not
allowed.  (Though I don't know if readdir() guarantees an atomic
snapshot of a directory; if not, then a dup could perhaps be created by
having another process add and remove files while git is reading a loose
ref directory.)

Extra refs are created locally by other git code that I am not familiar
with, so duplicate extra refs could only be created by a bug in git.

So in summary, duplicates could be caused by a git bug, by a corrupt
packed-refs file, or conceivably by a race condition with another
process that is mutating the packed-refs file or the loose reference
directories.

> This would indicate a bug in git, so should this perhaps say "BUG:" in
> front, or maybe give some more context so that a user understands it is
> not their error, or even a random error on this run, but that git has
> accidentally corrupted the packed-refs file (and their best bet is
> probably to report the bug to us).
> 
> This is obviously not an issue introduced by your patch, as you are
> just moving these error messages around. But maybe while the topic is
> fresh in your mind it is a good time to improve it. I dunno. AFAICT
> nobody has ever actually hit this message, so maybe it doesn't matter.
> :)

The first of Google search results for the fatal error message only
shows one instance where the error was observed [1].  This was a case of
cloning using the rsync protocol, which I believe is now deprecated
(probably for exactly this reason).

I think that the gold-plated way to improve the error message would be
to pass the error back to the caller, who would have more context to
decide the most likely cause of the duplicate and give an appropriate
warning or error message.  But I think we can afford to wait until more
error reports appear before bothering with this.

Michael

[1] http://kerneltrap.org/mailarchive/git/2008/12/17/4438764

-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/

^ permalink raw reply

* [PATCH 4/4] Rename resolve_ref() to resolve_ref_unsafe()
From: Nguyễn Thái Ngọc Duy @ 2011-12-12 11:20 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <1323688832-32016-1-git-send-email-pclouds@gmail.com>

resolve_ref() may return a pointer to a shared buffer and can be
overwritten by the next resolve_ref() calls. Callers need to
pay attention, not to keep the pointer when the next call happens.

Rename with "_unsafe" suffix to warn developers (or reviewers) before
introducing new call sites.

This patch is generated using the following command

git grep -l 'resolve_ref(' -- '*.[ch]'|xargs sed -i 's/resolve_ref(/resolve_ref_unsafe(/g'

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 branch.c               |    2 +-
 builtin/branch.c       |    2 +-
 builtin/commit.c       |    2 +-
 builtin/fsck.c         |    2 +-
 builtin/log.c          |    4 ++--
 builtin/receive-pack.c |    2 +-
 builtin/remote.c       |    2 +-
 builtin/show-branch.c  |    2 +-
 builtin/symbolic-ref.c |    2 +-
 cache.h                |    2 +-
 refs.c                 |   20 ++++++++++----------
 remote.c               |    6 +++---
 test-resolve-ref.c     |    4 ++--
 transport.c            |    2 +-
 14 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/branch.c b/branch.c
index d91a099..772a4c2 100644
--- a/branch.c
+++ b/branch.c
@@ -182,7 +182,7 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
 		const char *head;
 		unsigned char sha1[20];
 
-		head = resolve_ref("HEAD", sha1, 0, NULL);
+		head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
 		if (!is_bare_repository() && head && !strcmp(head, ref->buf))
 			die("Cannot force update the current branch.");
 	}
diff --git a/builtin/branch.c b/builtin/branch.c
index 72c4c31..641bee1 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -251,7 +251,7 @@ static char *resolve_symref(const char *src, const char *prefix)
 	int flag;
 	const char *dst, *cp;
 
-	dst = resolve_ref(src, sha1, 0, &flag);
+	dst = resolve_ref_unsafe(src, sha1, 0, &flag);
 	if (!(dst && (flag & REF_ISSYMREF)))
 		return NULL;
 	if (prefix && (cp = skip_prefix(dst, prefix)))
diff --git a/builtin/commit.c b/builtin/commit.c
index e36e9ad..4d39d25 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1304,7 +1304,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 	rev.diffopt.break_opt = 0;
 	diff_setup_done(&rev.diffopt);
 
-	head = resolve_ref("HEAD", junk_sha1, 0, NULL);
+	head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
 	printf("[%s%s ",
 		!prefixcmp(head, "refs/heads/") ?
 			head + 11 :
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 30d0dc8..8c479a7 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -563,7 +563,7 @@ static int fsck_head_link(void)
 	if (verbose)
 		fprintf(stderr, "Checking HEAD link\n");
 
-	head_points_at = resolve_ref("HEAD", head_sha1, 0, &flag);
+	head_points_at = resolve_ref_unsafe("HEAD", head_sha1, 0, &flag);
 	if (!head_points_at)
 		return error("Invalid HEAD");
 	if (!strcmp(head_points_at, "HEAD"))
diff --git a/builtin/log.c b/builtin/log.c
index 4395f3e..89d0cc0 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1040,7 +1040,7 @@ static char *find_branch_name(struct rev_info *rev)
 	if (positive < 0)
 		return NULL;
 	strbuf_addf(&buf, "refs/heads/%s", rev->cmdline.rev[positive].name);
-	branch = resolve_ref(buf.buf, branch_sha1, 1, NULL);
+	branch = resolve_ref_unsafe(buf.buf, branch_sha1, 1, NULL);
 	if (!branch ||
 	    prefixcmp(branch, "refs/heads/") ||
 	    hashcmp(rev->cmdline.rev[positive].item->sha1, branch_sha1))
@@ -1268,7 +1268,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
 			rev.pending.objects[0].item->flags |= UNINTERESTING;
 			add_head_to_pending(&rev);
-			ref = resolve_ref("HEAD", sha1, 1, NULL);
+			ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
 			if (ref && !prefixcmp(ref, "refs/heads/"))
 				branch_name = xstrdup(ref + strlen("refs/heads/"));
 			else
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 5cd6fc7..a1a4b09 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -571,7 +571,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
 	int flag;
 
 	strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
-	dst_name = resolve_ref(buf.buf, sha1, 0, &flag);
+	dst_name = resolve_ref_unsafe(buf.buf, sha1, 0, &flag);
 	strbuf_release(&buf);
 
 	if (!(flag & REF_ISSYMREF))
diff --git a/builtin/remote.c b/builtin/remote.c
index 407abfb..583eec9 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -573,7 +573,7 @@ static int read_remote_branches(const char *refname,
 	strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
 	if (!prefixcmp(refname, buf.buf)) {
 		item = string_list_append(rename->remote_branches, xstrdup(refname));
-		symref = resolve_ref(refname, orig_sha1, 1, &flag);
+		symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag);
 		if (flag & REF_ISSYMREF)
 			item->util = xstrdup(symref);
 		else
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index a1f148e..a59e088 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -789,7 +789,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 		}
 	}
 
-	head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
+	head_p = resolve_ref_unsafe("HEAD", head_sha1, 1, NULL);
 	if (head_p) {
 		head_len = strlen(head_p);
 		memcpy(head, head_p, head_len + 1);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index dea849c..2ef5962 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -12,7 +12,7 @@ static void check_symref(const char *HEAD, int quiet)
 {
 	unsigned char sha1[20];
 	int flag;
-	const char *refs_heads_master = resolve_ref(HEAD, sha1, 0, &flag);
+	const char *refs_heads_master = resolve_ref_unsafe(HEAD, sha1, 0, &flag);
 
 	if (!refs_heads_master)
 		die("No such ref: %s", HEAD);
diff --git a/cache.h b/cache.h
index ba5e911..051e7ee 100644
--- a/cache.h
+++ b/cache.h
@@ -865,7 +865,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
  *
  * errno is sometimes set on errors, but not always.
  */
-#define resolve_ref(ref, sha1, reading, flag) resolve_ref_real(ref, sha1, reading, flag, __FILE__, __LINE__)
+#define resolve_ref_unsafe(ref, sha1, reading, flag) resolve_ref_real(ref, sha1, reading, flag, __FILE__, __LINE__)
 extern const char *resolve_ref_real(const char *ref, unsigned char *sha1, int reading, int *flag, const char *file, int line);
 extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
 
diff --git a/refs.c b/refs.c
index cf8dfcc..010bb72 100644
--- a/refs.c
+++ b/refs.c
@@ -361,7 +361,7 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
 	if (!(flags & REF_ISSYMREF))
 		return 0;
 
-	resolves_to = resolve_ref(refname, junk, 0, NULL);
+	resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL);
 	if (!resolves_to || strcmp(resolves_to, d->refname))
 		return 0;
 
@@ -616,7 +616,7 @@ const char *resolve_ref_real(const char *ref, unsigned char *sha1,
 
 char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
 {
-	const char *ret = resolve_ref(ref, sha1, reading, flag);
+	const char *ret = resolve_ref_unsafe(ref, sha1, reading, flag);
 	return ret ? xstrdup(ret) : NULL;
 }
 
@@ -629,7 +629,7 @@ struct ref_filter {
 
 int read_ref_full(const char *ref, unsigned char *sha1, int reading, int *flags)
 {
-	if (resolve_ref(ref, sha1, reading, flags))
+	if (resolve_ref_unsafe(ref, sha1, reading, flags))
 		return 0;
 	return -1;
 }
@@ -1126,7 +1126,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
 
 		this_result = refs_found ? sha1_from_ref : sha1;
 		mksnpath(fullref, sizeof(fullref), *p, len, str);
-		r = resolve_ref(fullref, this_result, 1, &flag);
+		r = resolve_ref_unsafe(fullref, this_result, 1, &flag);
 		if (r) {
 			if (!refs_found++)
 				*ref = xstrdup(r);
@@ -1156,7 +1156,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 		const char *ref, *it;
 
 		mksnpath(path, sizeof(path), *p, len, str);
-		ref = resolve_ref(path, hash, 1, NULL);
+		ref = resolve_ref_unsafe(path, hash, 1, NULL);
 		if (!ref)
 			continue;
 		if (!stat(git_path("logs/%s", path), &st) &&
@@ -1192,7 +1192,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 	lock = xcalloc(1, sizeof(struct ref_lock));
 	lock->lock_fd = -1;
 
-	ref = resolve_ref(ref, lock->old_sha1, mustexist, &type);
+	ref = resolve_ref_unsafe(ref, lock->old_sha1, mustexist, &type);
 	if (!ref && errno == EISDIR) {
 		/* we are trying to lock foo but we used to
 		 * have foo/bar which now does not exist;
@@ -1205,7 +1205,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 			error("there are still refs under '%s'", orig_ref);
 			goto error_return;
 		}
-		ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, &type);
+		ref = resolve_ref_unsafe(orig_ref, lock->old_sha1, mustexist, &type);
 	}
 	if (type_p)
 	    *type_p = type;
@@ -1368,7 +1368,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
 	if (log && S_ISLNK(loginfo.st_mode))
 		return error("reflog for %s is a symlink", oldref);
 
-	symref = resolve_ref(oldref, orig_sha1, 1, &flag);
+	symref = resolve_ref_unsafe(oldref, orig_sha1, 1, &flag);
 	if (flag & REF_ISSYMREF)
 		return error("refname %s is a symbolic ref, renaming it is not supported",
 			oldref);
@@ -1657,7 +1657,7 @@ int write_ref_sha1(struct ref_lock *lock,
 		unsigned char head_sha1[20];
 		int head_flag;
 		const char *head_ref;
-		head_ref = resolve_ref("HEAD", head_sha1, 1, &head_flag);
+		head_ref = resolve_ref_unsafe("HEAD", head_sha1, 1, &head_flag);
 		if (head_ref && (head_flag & REF_ISSYMREF) &&
 		    !strcmp(head_ref, lock->ref_name))
 			log_ref_write("HEAD", lock->old_sha1, sha1, logmsg);
@@ -1994,7 +1994,7 @@ int update_ref(const char *action, const char *refname,
 int ref_exists(const char *refname)
 {
 	unsigned char sha1[20];
-	return !!resolve_ref(refname, sha1, 1, NULL);
+	return !!resolve_ref_unsafe(refname, sha1, 1, NULL);
 }
 
 struct ref *find_ref_by_name(const struct ref *list, const char *name)
diff --git a/remote.c b/remote.c
index 6655bb0..73a3809 100644
--- a/remote.c
+++ b/remote.c
@@ -482,7 +482,7 @@ static void read_config(void)
 		return;
 	default_remote_name = xstrdup("origin");
 	current_branch = NULL;
-	head_ref = resolve_ref("HEAD", sha1, 0, &flag);
+	head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
 	if (head_ref && (flag & REF_ISSYMREF) &&
 	    !prefixcmp(head_ref, "refs/heads/")) {
 		current_branch =
@@ -1007,7 +1007,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 	struct strbuf buf = STRBUF_INIT;
 	unsigned char sha1[20];
 
-	const char *r = resolve_ref(peer->name, sha1, 1, NULL);
+	const char *r = resolve_ref_unsafe(peer->name, sha1, 1, NULL);
 	if (!r)
 		return NULL;
 
@@ -1058,7 +1058,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		unsigned char sha1[20];
 		int flag;
 
-		dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
+		dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag);
 		if (!dst_value ||
 		    ((flag & REF_ISSYMREF) &&
 		     prefixcmp(dst_value, "refs/heads/")))
diff --git a/test-resolve-ref.c b/test-resolve-ref.c
index b772038..59d04e0 100644
--- a/test-resolve-ref.c
+++ b/test-resolve-ref.c
@@ -11,8 +11,8 @@ int main(int argc, char **argv)
 	 * function returns a shared buffer, so by the time the second
 	 * call is made, ref1 must _not_ be accessed any more.
 	 */
-	ref1 = resolve_ref("HEAD", sha1, 0, NULL);
-	ref2 = resolve_ref("HEAD", sha1, 0, NULL);
+	ref1 = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
+	ref2 = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
 	printf("ref1 = %s\nref2 = %s\n", ref1, ref2);
 	return 0;
 }
diff --git a/transport.c b/transport.c
index 51814b5..e9797c0 100644
--- a/transport.c
+++ b/transport.c
@@ -163,7 +163,7 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
 		/* Follow symbolic refs (mainly for HEAD). */
 		localname = ref->peer_ref->name;
 		remotename = ref->name;
-		tmp = resolve_ref(localname, sha, 1, &flag);
+		tmp = resolve_ref_unsafe(localname, sha, 1, &flag);
 		if (tmp && flag & REF_ISSYMREF &&
 			!prefixcmp(tmp, "refs/heads/"))
 			localname = tmp;
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH 3/4] Guard memory overwriting in resolve_ref's static buffer
From: Nguyễn Thái Ngọc Duy @ 2011-12-12 11:20 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <1323688832-32016-1-git-send-email-pclouds@gmail.com>

There is a potential problem with resolve_ref() and some other
functions in git. The return value returned by resolve_ref() may
be changed when the function is called again. Callers must make sure the
next call won't happen as long as the value is still being used.

It's usually hard to track down this kind of problem.  Michael Haggerty
has an idea [1] that, instead of passing the same static buffer to
caller every time the function is called, we free the old buffer and
allocate the new one. This way access to the old (now invalid) buffer
may be caught.

This patch applies the same principle for resolve_ref() with a
few modifications:

 - This behavior is enabled when GIT_DEBUG_MEMCHECK is set. The ability
   is always available. We may be able to ask users to rerun with this
   flag on in suspicious cases.

 - Rely on mmap/mprotect to catch illegal access. We need valgrind or
   some other memory tracking tool to reliably catch this in Michael's
   approach.

 - Because mprotect is used instead of munmap, we definitely leak
   memory. Hopefully callers will not put resolve_ref() in a
   loop that runs 1 million times.

 - Save caller location in the allocated buffer so we know who made this
   call in the core dump.

Also introduce a new target, "make memcheck", that runs tests with this
flag on.

[1] http://comments.gmane.org/gmane.comp.version-control.git/182209

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Changes include:

  - __FUNCTION__ to __FILE__ for compiler compatibility
  - x{malloc,free}_mmap() now put call site information in a struct,
    it's clearer this way and hopefully will avoid platform issues
  - update t0071 to follow '&&' convention
  - add notes where to get caller site info in git-compat-util.h

 .gitignore          |    1 +
 Makefile            |    4 ++++
 cache.h             |    3 ++-
 git-compat-util.h   |   20 ++++++++++++++++++++
 refs.c              |   13 +++++++++++--
 t/t0071-memcheck.sh |   11 +++++++++++
 test-resolve-ref.c  |   18 ++++++++++++++++++
 wrapper.c           |   27 +++++++++++++++++++++++++++
 8 files changed, 94 insertions(+), 3 deletions(-)
 create mode 100755 t/t0071-memcheck.sh
 create mode 100644 test-resolve-ref.c

diff --git a/.gitignore b/.gitignore
index 8572c8c..470e452 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,6 +179,7 @@
 /test-obj-pool
 /test-parse-options
 /test-path-utils
+/test-resolve-ref
 /test-run-command
 /test-sha1
 /test-sigchain
diff --git a/Makefile b/Makefile
index ed82320..d71cf04 100644
--- a/Makefile
+++ b/Makefile
@@ -444,6 +444,7 @@ TEST_PROGRAMS_NEED_X += test-obj-pool
 TEST_PROGRAMS_NEED_X += test-parse-options
 TEST_PROGRAMS_NEED_X += test-path-utils
 TEST_PROGRAMS_NEED_X += test-run-command
+TEST_PROGRAMS_NEED_X += test-resolve-ref
 TEST_PROGRAMS_NEED_X += test-sha1
 TEST_PROGRAMS_NEED_X += test-sigchain
 TEST_PROGRAMS_NEED_X += test-string-pool
@@ -2241,6 +2242,9 @@ export NO_SVN_TESTS
 test: all
 	$(MAKE) -C t/ all
 
+memcheck: all
+	GIT_DEBUG_MEMCHECK=1 $(MAKE) -C t/ all
+
 test-ctype$X: ctype.o
 
 test-date$X: date.o ctype.o
diff --git a/cache.h b/cache.h
index 4887a3e..ba5e911 100644
--- a/cache.h
+++ b/cache.h
@@ -865,7 +865,8 @@ extern int read_ref(const char *filename, unsigned char *sha1);
  *
  * errno is sometimes set on errors, but not always.
  */
-extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
+#define resolve_ref(ref, sha1, reading, flag) resolve_ref_real(ref, sha1, reading, flag, __FILE__, __LINE__)
+extern const char *resolve_ref_real(const char *ref, unsigned char *sha1, int reading, int *flag, const char *file, int line);
 extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
 
 extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
diff --git a/git-compat-util.h b/git-compat-util.h
index 77062ed..0cb6e34 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -433,6 +433,26 @@ extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size);
 extern void *xcalloc(size_t nmemb, size_t size);
 extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
+
+/*
+ * These functions are used to allocate new memory blocks and catch
+ * invalid use after they are released (though the memory is never
+ * returned to system, so do not allocate too much this way).
+ *
+ * mprotect() is used to remove all access to memory when xfree_mmap()
+ * is called. Invalid access will cause sigsegv. The memory block is
+ * preceded by struct alloc_header, describing where it is
+ * allocated. This information can be found in the core dump.
+ */
+struct alloc_header {
+	const char *file;
+	int line;
+	int size;
+	char buf[FLEX_ARRAY];
+};
+extern void *xmalloc_mmap(size_t, const char *file, int line);
+extern void xfree_mmap(void *);
+
 extern ssize_t xread(int fd, void *buf, size_t len);
 extern ssize_t xwrite(int fd, const void *buf, size_t len);
 extern int xdup(int fd);
diff --git a/refs.c b/refs.c
index 8ffb32f..cf8dfcc 100644
--- a/refs.c
+++ b/refs.c
@@ -497,12 +497,21 @@ static int get_packed_ref(const char *ref, unsigned char *sha1)
 	return -1;
 }
 
-const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
+const char *resolve_ref_real(const char *ref, unsigned char *sha1,
+			     int reading, int *flag, const char *file, int line)
 {
 	int depth = MAXDEPTH;
 	ssize_t len;
 	char buffer[256];
-	static char ref_buffer[256];
+	static char real_ref_buffer[256];
+	static char *ref_buffer;
+
+	if (!ref_buffer && !getenv("GIT_DEBUG_MEMCHECK"))
+		ref_buffer = real_ref_buffer;
+	if (ref_buffer != real_ref_buffer) {
+		xfree_mmap(ref_buffer);
+		ref_buffer = xmalloc_mmap(256, file, line);
+	}
 
 	if (flag)
 		*flag = 0;
diff --git a/t/t0071-memcheck.sh b/t/t0071-memcheck.sh
new file mode 100755
index 0000000..8904369
--- /dev/null
+++ b/t/t0071-memcheck.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+test_description='test that GIT_DEBUG_MEMCHECK works correctly'
+. ./test-lib.sh
+
+test_expect_success 'test-resolve-ref must crash' '
+	test-resolve-ref &&
+	GIT_DEBUG_MEMCHECK=1 test_expect_code 139 test-resolve-ref
+'
+
+test_done
diff --git a/test-resolve-ref.c b/test-resolve-ref.c
new file mode 100644
index 0000000..b772038
--- /dev/null
+++ b/test-resolve-ref.c
@@ -0,0 +1,18 @@
+#include "cache.h"
+
+int main(int argc, char **argv)
+{
+	unsigned char sha1[20];
+	const char *ref1, *ref2;
+	setup_git_directory();
+
+	/*
+	 * This is an invalid use of resolve_ref_unsafe(). This
+	 * function returns a shared buffer, so by the time the second
+	 * call is made, ref1 must _not_ be accessed any more.
+	 */
+	ref1 = resolve_ref("HEAD", sha1, 0, NULL);
+	ref2 = resolve_ref("HEAD", sha1, 0, NULL);
+	printf("ref1 = %s\nref2 = %s\n", ref1, ref2);
+	return 0;
+}
diff --git a/wrapper.c b/wrapper.c
index 85f09df..02b6c81 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -60,6 +60,33 @@ void *xmallocz(size_t size)
 	return ret;
 }
 
+void *xmalloc_mmap(size_t size, const char *file, int line)
+{
+	struct alloc_header *block;
+	size += offsetof(struct alloc_header,buf);
+	block = mmap(NULL, size, PROT_READ | PROT_WRITE,
+		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	if (block == (struct alloc_header*)-1)
+		die_errno("unable to mmap %lu bytes anonymously",
+			  (unsigned long)size);
+
+	block->file = file;
+	block->line = line;
+	block->size = size;
+	return block->buf;
+}
+
+void xfree_mmap(void *p)
+{
+	struct alloc_header *block;
+
+	if (!p)
+		return;
+	block = (struct alloc_header *)((char*)p - offsetof(struct alloc_header,buf));
+	if (mprotect(block, block->size, PROT_NONE) == -1)
+		die_errno("unable to remove memory access");
+}
+
 /*
  * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
  * "data" to the allocated memory, zero terminates the allocated memory,
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH 2/4] Convert resolve_ref+xstrdup to new resolve_refdup function
From: Nguyễn Thái Ngọc Duy @ 2011-12-12 11:20 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <1323688832-32016-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/branch.c        |   11 ++++-------
 builtin/checkout.c      |   15 +++++++--------
 builtin/fmt-merge-msg.c |    6 +++---
 builtin/for-each-ref.c  |    7 ++-----
 builtin/merge.c         |   12 +++++-------
 builtin/notes.c         |    6 +++---
 builtin/receive-pack.c  |    8 +++-----
 builtin/show-branch.c   |    4 +---
 cache.h                 |    1 +
 reflog-walk.c           |   13 ++++++-------
 refs.c                  |    6 ++++++
 wt-status.c             |    4 +---
 12 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index e1e486e..72c4c31 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -103,7 +103,7 @@ static int branch_merged(int kind, const char *name,
 	 * safely to HEAD (or the other branch).
 	 */
 	struct commit *reference_rev = NULL;
-	const char *reference_name = NULL;
+	char *reference_name = NULL;
 	int merged;
 
 	if (kind == REF_LOCAL_BRANCH) {
@@ -115,10 +115,8 @@ static int branch_merged(int kind, const char *name,
 		    branch->merge[0] &&
 		    branch->merge[0]->dst &&
 		    (reference_name =
-		     resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) {
-			reference_name = xstrdup(reference_name);
+		     resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
 			reference_rev = lookup_commit_reference(sha1);
-		}
 	}
 	if (!reference_rev)
 		reference_rev = head_rev;
@@ -143,7 +141,7 @@ static int branch_merged(int kind, const char *name,
 				"         '%s', even though it is merged to HEAD."),
 				name, reference_name);
 	}
-	free((char *)reference_name);
+	free(reference_name);
 	return merged;
 }
 
@@ -731,10 +729,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
 	track = git_branch_track;
 
-	head = resolve_ref("HEAD", head_sha1, 0, NULL);
+	head = resolve_refdup("HEAD", head_sha1, 0, NULL);
 	if (!head)
 		die(_("Failed to resolve HEAD as a valid ref."));
-	head = xstrdup(head);
 	if (!strcmp(head, "HEAD")) {
 		detached = 1;
 	} else {
diff --git a/builtin/checkout.c b/builtin/checkout.c
index b7c6302..a66d3eb 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -696,17 +696,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 {
 	int ret = 0;
 	struct branch_info old;
+	char *path;
 	unsigned char rev[20];
 	int flag;
 	memset(&old, 0, sizeof(old));
-	old.path = resolve_ref("HEAD", rev, 0, &flag);
-	if (old.path)
-		old.path = xstrdup(old.path);
+	old.path = path = resolve_refdup("HEAD", rev, 0, &flag);
 	old.commit = lookup_commit_reference_gently(rev, 1);
-	if (!(flag & REF_ISSYMREF)) {
-		free((char *)old.path);
+	if (!(flag & REF_ISSYMREF))
 		old.path = NULL;
-	}
 
 	if (old.path && !prefixcmp(old.path, "refs/heads/"))
 		old.name = old.path + strlen("refs/heads/");
@@ -720,8 +717,10 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	}
 
 	ret = merge_working_tree(opts, &old, new);
-	if (ret)
+	if (ret) {
+		free(path);
 		return ret;
+	}
 
 	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 		orphaned_commit_warning(old.commit);
@@ -729,7 +728,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	update_refs_for_switch(opts, &old, new);
 
 	ret = post_checkout_hook(old.commit, new->commit, 1);
-	free((char *)old.path);
+	free(path);
 	return ret || opts->writeout_error;
 }
 
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index bdfa0ea..a27efcd 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -372,14 +372,14 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 	int i = 0, pos = 0;
 	unsigned char head_sha1[20];
 	const char *current_branch;
+	char *ref;
 
 	/* get current branch */
-	current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
+	current_branch = ref = resolve_refdup("HEAD", head_sha1, 1, NULL);
 	if (!current_branch)
 		die("No current branch");
 	if (!prefixcmp(current_branch, "refs/heads/"))
 		current_branch += 11;
-	current_branch = xstrdup(current_branch);
 
 	/* get a line */
 	while (pos < in->len) {
@@ -421,7 +421,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 	}
 
 	strbuf_complete_line(out);
-	free((char *)current_branch);
+	free(ref);
 	return 0;
 }
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index d90e5d2..b01d76a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -628,11 +628,8 @@ static void populate_value(struct refinfo *ref)
 
 	if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
 		unsigned char unused1[20];
-		const char *symref;
-		symref = resolve_ref(ref->refname, unused1, 1, NULL);
-		if (symref)
-			ref->symref = xstrdup(symref);
-		else
+		ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL);
+		if (!ref->symref)
 			ref->symref = "";
 	}
 
diff --git a/builtin/merge.c b/builtin/merge.c
index a1c8534..6437db2 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1096,6 +1096,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	struct commit_list *common = NULL;
 	const char *best_strategy = NULL, *wt_strategy = NULL;
 	struct commit_list **remotes = &remoteheads;
+	char *branch_ref;
 
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_merge_usage, builtin_merge_options);
@@ -1104,12 +1105,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	 * Check if we are _not_ on a detached HEAD, i.e. if there is a
 	 * current branch.
 	 */
-	branch = resolve_ref("HEAD", head_sha1, 0, &flag);
-	if (branch) {
-		if (!prefixcmp(branch, "refs/heads/"))
-			branch += 11;
-		branch = xstrdup(branch);
-	}
+	branch = branch_ref = resolve_refdup("HEAD", head_sha1, 0, &flag);
+	if (branch && !prefixcmp(branch, "refs/heads/"))
+		branch += 11;
 	if (!branch || is_null_sha1(head_sha1))
 		head_commit = NULL;
 	else
@@ -1520,6 +1518,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		ret = suggest_conflicts(option_renormalize);
 
 done:
-	free((char *)branch);
+	free(branch_ref);
 	return ret;
 }
diff --git a/builtin/notes.c b/builtin/notes.c
index 10b8bc7..816c998 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -804,6 +804,7 @@ static int merge_commit(struct notes_merge_options *o)
 	struct notes_tree *t;
 	struct commit *partial;
 	struct pretty_print_context pretty_ctx;
+	char *ref;
 	int ret;
 
 	/*
@@ -826,10 +827,9 @@ static int merge_commit(struct notes_merge_options *o)
 	t = xcalloc(1, sizeof(struct notes_tree));
 	init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
-	o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
+	o->local_ref = ref = resolve_refdup("NOTES_MERGE_REF", sha1, 0, NULL);
 	if (!o->local_ref)
 		die("Failed to resolve NOTES_MERGE_REF");
-	o->local_ref = xstrdup(o->local_ref);
 
 	if (notes_merge_commit(o, t, partial, sha1))
 		die("Failed to finalize notes merge");
@@ -846,7 +846,7 @@ static int merge_commit(struct notes_merge_options *o)
 	free_notes(t);
 	strbuf_release(&msg);
 	ret = merge_abort(o);
-	free((char *)o->local_ref);
+	free(ref);
 	return ret;
 }
 
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b6d957c..5cd6fc7 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -36,7 +36,7 @@ static int use_sideband;
 static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
 static int auto_gc = 1;
-static const char *head_name;
+static char *head_name;
 static int sent_capabilities;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
@@ -695,10 +695,8 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
 
 	check_aliased_updates(commands);
 
-	free((char *)head_name);
-	head_name = resolve_ref("HEAD", sha1, 0, NULL);
-	if (head_name)
-		head_name = xstrdup(head_name);
+	free(head_name);
+	head_name = resolve_refdup("HEAD", sha1, 0, NULL);
 
 	for (cmd = commands; cmd; cmd = cmd->next)
 		if (!cmd->skip_update)
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 4b480d7..a1f148e 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -726,10 +726,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
 		if (ac == 0) {
 			static const char *fake_av[2];
-			const char *refname;
 
-			refname = resolve_ref("HEAD", sha1, 1, NULL);
-			fake_av[0] = xstrdup(refname);
+			fake_av[0] = resolve_refdup("HEAD", sha1, 1, NULL);
 			fake_av[1] = NULL;
 			av = fake_av;
 			ac = 1;
diff --git a/cache.h b/cache.h
index 8c98d05..4887a3e 100644
--- a/cache.h
+++ b/cache.h
@@ -866,6 +866,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
  * errno is sometimes set on errors, but not always.
  */
 extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
+extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
 
 extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
diff --git a/reflog-walk.c b/reflog-walk.c
index da71a85..5572b42 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -50,11 +50,10 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
 	for_each_reflog_ent(ref, read_one_reflog, reflogs);
 	if (reflogs->nr == 0) {
 		unsigned char sha1[20];
-		const char *name = resolve_ref(ref, sha1, 1, NULL);
+		char *name = resolve_refdup(ref, sha1, 1, NULL);
 		if (name) {
-			name = xstrdup(name);
 			for_each_reflog_ent(name, read_one_reflog, reflogs);
-			free((char *)name);
+			free(name);
 		}
 	}
 	if (reflogs->nr == 0) {
@@ -171,11 +170,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 	else {
 		if (*branch == '\0') {
 			unsigned char sha1[20];
-			const char *head = resolve_ref("HEAD", sha1, 0, NULL);
-			if (!head)
-				die ("No current branch");
 			free(branch);
-			branch = xstrdup(head);
+			branch = resolve_refdup("HEAD", sha1, 0, NULL);
+			if (!branch)
+				die ("No current branch");
+
 		}
 		reflogs = read_complete_reflog(branch);
 		if (!reflogs || reflogs->nr == 0) {
diff --git a/refs.c b/refs.c
index f5cb297..8ffb32f 100644
--- a/refs.c
+++ b/refs.c
@@ -605,6 +605,12 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 	return ref;
 }
 
+char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
+{
+	const char *ret = resolve_ref(ref, sha1, reading, flag);
+	return ret ? xstrdup(ret) : NULL;
+}
+
 /* The argument to filter_refs */
 struct ref_filter {
 	const char *pattern;
diff --git a/wt-status.c b/wt-status.c
index 70fdb76..9ffc535 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -111,7 +111,6 @@ void status_printf_more(struct wt_status *s, const char *color,
 void wt_status_prepare(struct wt_status *s)
 {
 	unsigned char sha1[20];
-	const char *head;
 
 	memset(s, 0, sizeof(*s));
 	memcpy(s->color_palette, default_wt_status_colors,
@@ -119,8 +118,7 @@ void wt_status_prepare(struct wt_status *s)
 	s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 	s->use_color = -1;
 	s->relative_paths = 1;
-	head = resolve_ref("HEAD", sha1, 0, NULL);
-	s->branch = head ? xstrdup(head) : NULL;
+	s->branch = resolve_refdup("HEAD", sha1, 0, NULL);
 	s->reference = "HEAD";
 	s->fp = stdout;
 	s->index_file = get_index_file();
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH 1/4] revert: convert resolve_ref() to read_ref_full()
From: Nguyễn Thái Ngọc Duy @ 2011-12-12 11:20 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy

This is the follow up of c689332 (Convert many resolve_ref() calls to
read_ref*() and ref_exists() - 2011-11-13). See the said commit for
rationale.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/revert.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/builtin/revert.c b/builtin/revert.c
index 1ea525c..0c52a83 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -901,7 +901,7 @@ static int rollback_single_pick(void)
 	if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
 	    !file_exists(git_path("REVERT_HEAD")))
 		return error(_("no cherry-pick or revert in progress"));
-	if (!resolve_ref("HEAD", head_sha1, 0, NULL))
+	if (read_ref_full("HEAD", head_sha1, 0, NULL))
 		return error(_("cannot resolve HEAD"));
 	if (is_null_sha1(head_sha1))
 		return error(_("cannot abort from a branch yet to be born"));
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* Re: Breakage (?) in configure and git_vsnprintf()
From: Michael Haggerty @ 2011-12-12 10:25 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, git discussion list, Michal Rokos, Brandon Casey
In-Reply-To: <20111212064305.GA16511@sigill.intra.peff.net>

On 12/12/2011 07:43 AM, Jeff King wrote:
> On Sun, Dec 11, 2011 at 07:42:03PM +0100, Michael Haggerty wrote:
>> 2. The configure problem causes git_vsnprintf() to be wrapped around the
>> C library version.  This leads to many failures in the test suite.  I
>> suppose that git_vsnprintf() is broken in some way.
> 
> I enabled SNPRINTF_RETURNS_BOGUS manually and was able to see the test
> suite failures. Very oddly, I could get them while running the full
> suite in parallel, but when I ran individual scripts, the problem went
> away. Which makes no sense to me at all.
> 
> However, I peeked at the git_vsnprintf function, and one obvious error
> is that it calls vsnprintf multiple times on the same va_list.

Thanks for the quick response!  Yes, I think you've hit the nail on the
head.  (Though I think Andreas is correct that va_end() needs to be
called on the copies.)  Either with or without va_end(), your patch
fixes the test suite failures for me.

> I'll leave the issue of "-std=c89" triggering SNPRINTF_RETURNS_BOGUS to
> people who know and care about autoconf. My gut is to say "don't do
> that". Git is not actually pure c89. [...]

OK, I can live with that.  Poor Junio will probably be stuck correcting
my non-c89isms again, though :-(

Michael

-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Gelonida N @ 2011-12-12 10:24 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <4EE5D3CD.6020604@gmail.com>

I forgot one other use case:

- wanting to pull from tracking branches without fastforwarding is not
such a smart idea.

of course I can do
git merge from  remotes/origin/branch
but this is more to type and would vary depending on whether 'd like to
pull from an unpushed tracking branch or from a freshly fetched tracking
branch.


On 12/12/2011 11:13 AM, Gelonida N wrote:
> Thanks for this rather long answer,
> 
> On 12/12/2011 09:09 AM, Junio C Hamano wrote:
>> Gelonida N <gelonida@gmail.com> writes:
>>
>>> What is the best way to fastforward all fastforwardable tracking
>>> branches after a git fetch?
>>
>> This lacks context and invites too many tangents, so I'll only touch a few
>> of them.
>>
>> First of all, why do you want to do this?
>>
> 
> To explain the scenario:
> - small project
> - every person works on master and multiple topic branches
>    and might alternate rather often
> - sometimes several persons work on the same topic branch
>   but most of the time not in parallel.
> - one person is working from several machines (starting work on
>   one and continuing on another)
> - additionally we do many pushed in order to be sure,
>   that our data is backed up in case of disk failures.
> - sometimes I just want to 'build' from a branch, that I am not
>    working on. but there I create mostly not even a tracking branch
> 
> before changing a machine I want to be sure to have pushed everything. I
> wanted to get rid of the warning, that some branches cannot be pushed,
> because they aren't fastforwarded
> 
> when checking out a branch I want to avoid, that I have to pull manually.
> 
> 
> 
>> In other words, wouldn't a post-checkout hook be a better place to do
>> this kind of thing, perhaps like this (completely untested)? 
>>
>>     #!/bin/sh
>>     old=$1 new=$2 kind=$3
>>
>>     # did we checkout a branch?
>>     test "$kind" = 1 || exit 0
>>
>>     # what did we check out?
>>     branch=$(git symbolic-ref HEAD 2>/dev/null) || exit 0
>>
>>     # does it track anything? otherwise nothing needs to be done
>>     upstream=$(git for-each-ref --format='%(upstream)' "$branch")
>>     test -z "$upstream" || exit 0
>>
>>     # are we up-to-date? if so no need to do anything
>>     test 0 = $(git rev-list "..$upstream" | wc -l) && exit 0
>>
>>     # do we have something we made? if so no point trying to fast-forward
>>     test 0 = $(git rev-list "$upstream.." | wc -l) || exit 0
>>
>>     # attempt a fast-forward merge with it
>>     git merge --ff-only @{upstream}
>>
> 
> This is a solution, I wouldn't get rid of the warnings though when
> running git push.
> 

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Gelonida N @ 2011-12-12 10:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmxay5h0g.fsf@alter.siamese.dyndns.org>

Thanks for this rather long answer,

On 12/12/2011 09:09 AM, Junio C Hamano wrote:
> Gelonida N <gelonida@gmail.com> writes:
> 
>> What is the best way to fastforward all fastforwardable tracking
>> branches after a git fetch?
> 
> This lacks context and invites too many tangents, so I'll only touch a few
> of them.
> 
> First of all, why do you want to do this?
> 

To explain the scenario:
- small project
- every person works on master and multiple topic branches
   and might alternate rather often
- sometimes several persons work on the same topic branch
  but most of the time not in parallel.
- one person is working from several machines (starting work on
  one and continuing on another)
- additionally we do many pushed in order to be sure,
  that our data is backed up in case of disk failures.
- sometimes I just want to 'build' from a branch, that I am not
   working on. but there I create mostly not even a tracking branch

before changing a machine I want to be sure to have pushed everything. I
wanted to get rid of the warning, that some branches cannot be pushed,
because they aren't fastforwarded

when checking out a branch I want to avoid, that I have to pull manually.



> In other words, wouldn't a post-checkout hook be a better place to do
> this kind of thing, perhaps like this (completely untested)? 
> 
>     #!/bin/sh
>     old=$1 new=$2 kind=$3
> 
>     # did we checkout a branch?
>     test "$kind" = 1 || exit 0
> 
>     # what did we check out?
>     branch=$(git symbolic-ref HEAD 2>/dev/null) || exit 0
> 
>     # does it track anything? otherwise nothing needs to be done
>     upstream=$(git for-each-ref --format='%(upstream)' "$branch")
>     test -z "$upstream" || exit 0
> 
>     # are we up-to-date? if so no need to do anything
>     test 0 = $(git rev-list "..$upstream" | wc -l) && exit 0
> 
>     # do we have something we made? if so no point trying to fast-forward
>     test 0 = $(git rev-list "$upstream.." | wc -l) || exit 0
> 
>     # attempt a fast-forward merge with it
>     git merge --ff-only @{upstream}
> 

This is a solution, I wouldn't get rid of the warnings though when
running git push.

^ permalink raw reply

* Re: Breakage (?) in configure and git_vsnprintf()
From: Andreas Schwab @ 2011-12-12  9:30 UTC (permalink / raw)
  To: Jeff King
  Cc: Michael Haggerty, Junio C Hamano, git discussion list,
	Michal Rokos, Brandon Casey
In-Reply-To: <20111212064305.GA16511@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

>  	if (maxsize > 0) {
> -		ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
> +		va_copy(cp, ap);
> +		ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);

You also need to call va_end on the copy.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply

* Re: Access to git repository through squid proxy: The remote end hung up unexpectedly
From: Mathieu Peltier @ 2011-12-12  9:25 UTC (permalink / raw)
  To: Konstantin Khomoutov; +Cc: git
In-Reply-To: <20111210225818.GM2525@localhost.localdomain>

> Looks like either your socat supplies incorrect credentials or proxy
> does not ask socat to actually authenticate and just denies the request.

The problem is solved. Sorry in fact it was just a problem with the
proxy configuration: the squid proxy was configured to use another
proxy server which was denying to use HTTP connect on 9418 port...
Thanks for you help.
Mathieu

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Stefan Haller @ 2011-12-12  9:19 UTC (permalink / raw)
  To: Jeff King; +Cc: Hallvard B Furuseth, Gelonida N, git
In-Reply-To: <20111212082526.GC16511@sigill.intra.peff.net>

Jeff King <peff@peff.net> wrote:

> On Mon, Dec 12, 2011 at 08:33:15AM +0100, Stefan Haller wrote:
> 
> > > Local branches can track each other.  So the script needs to toposort
> > > the branches, or to loop until either nothing was done or an error
> > > happened.  (The latter to prevent an eternal loop on error.)
> > 
> > Is this just theoretical, or are there real use cases for this? What
> > would be a workflow with such a local tracking branch?
> 
> I use this all the time.
> 
> In git.git, we use a topic branch workflow (i.e., every feature gets its
> own topic branch, and topics graduate independently to master as they
> are deemed stable). And we use a patch-submission workflow, which means
> it's OK for me to rebase my topics locally, because the end-product is a
> series of patches sent to the list.
> 
> Typically I branch off of "origin/master", so the topic is independent
> of anything else. For example, the "jk/credentials" branch in my git
> repo is branched from "origin/master" (Junio's master).  But sometimes
> there is a topic that depends on another topic, but should not be part
> of the same series (because the the first topic can graduate to master,
> but the second one may still need more time for discussion and cooking).
> In that case, I'll set the upstream to the other local topic branch. An
> example of this is the "jk/prompt" series, which depends on
> "jk/credentials" for infrastructure, but is really a separate issue.
> 
> Having the upstream set is convenient, because I can get _just_ the
> commits in jk/prompt with "git log @{u}..". Or I can rebase _just_ the
> commits in that topic with "git rebase -i". If my upstream were set to
> origin, I would accidentally also rebase all of the commits pulled in
> from jk/credentials, too.

I see, thanks.  For my script, I'm wondering then if the most sensible
thing to do is to just skip any branch whose upstream doesn't start with
refs/remotes/.

For a future "git pull --all" feature, it would probably only work on
those branches whose upstream is on the remote being pulled from,
anyway.


-- 
Stefan Haller
Berlin, Germany
http://www.haller-berlin.de/

^ permalink raw reply

* Re: Question about commit message wrapping
From: Frans Klaver @ 2011-12-12  8:41 UTC (permalink / raw)
  To: Andrew Ardill; +Cc: Jakub Narebski, Sidney San Martín, git
In-Reply-To: <CAH5451kGn72tLAwdvQFBjSyHSL0rUmaPZrbL7Z-KfHWN-HAuCQ@mail.gmail.com>

On Sun, Dec 11, 2011 at 11:00 PM, Andrew Ardill <andrew.ardill@gmail.com> wrote:

>> Additional and the more serious problem with wrapping on output is
>> related to backward compatibility.  If you have commit message that is
>> wrapped e.g. to 80 characters, and you wrap on output to 72 characters,
>> you would get ugly and nigh unreadable ragged output
>
> For what it's worth, I do a lot of reading emails on my phone, which
> force wraps line-length to the width of the display (not a set number
> of characters).
> This is always less than 80.

Good point.

>
> Emails on this list are almost exclusively sent pre-wrapped to 80
> character line lengths.
> The result is exactly the kind of ragged output you used in your
> example. Changing this behaviour may break backwards compatibility,
> but it is already broken for 'future' compatibility.

I am starting to think that we need to somehow keep the current
behavior, but override at smaller widths. Maybe even use format=flowed
in format-patch. On the other hand, the fundamental use with git is to
communicate code, and I'm not sure how that [cw]ould be handled.

^ permalink raw reply

* Re: [PATCH v2 08/51] is_dup_ref(): extract function from sort_ref_array()
From: Jeff King @ 2011-12-12  8:33 UTC (permalink / raw)
  To: mhagger
  Cc: Junio C Hamano, git, Drew Northup, Jakub Narebski, Heiko Voigt,
	Johan Herland, Julian Phillips
In-Reply-To: <1323668338-1764-9-git-send-email-mhagger@alum.mit.edu>

On Mon, Dec 12, 2011 at 06:38:15AM +0100, mhagger@alum.mit.edu wrote:

> +/*
> + * Emit a warning and return true iff ref1 and ref2 have the same name
> + * and the same sha1.  Die if they have the same name but different
> + * sha1s.
> + */
> +static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
> +{
> +	if (!strcmp(ref1->name, ref2->name)) {
> +		/* Duplicate name; make sure that the SHA1s match: */
> +		if (hashcmp(ref1->sha1, ref2->sha1))
> +			die("Duplicated ref, and SHA1s don't match: %s",
> +			    ref1->name);
> +		warning("Duplicated ref: %s", ref1->name);
> +		return 1;
> +	} else {
> +		return 0;
> +	}
> +}

As a user, I'm not sure what this message means. If I understand the
context right, this happens when you have duplicate entries in your
packed-refs file?

This would indicate a bug in git, so should this perhaps say "BUG:" in
front, or maybe give some more context so that a user understands it is
not their error, or even a random error on this run, but that git has
accidentally corrupted the packed-refs file (and their best bet is
probably to report the bug to us).

This is obviously not an issue introduced by your patch, as you are
just moving these error messages around. But maybe while the topic is
fresh in your mind it is a good time to improve it. I dunno. AFAICT
nobody has ever actually hit this message, so maybe it doesn't matter.
:)

-Peff

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Junio C Hamano @ 2011-12-12  8:28 UTC (permalink / raw)
  To: Hallvard B Furuseth; +Cc: Stefan Haller, Gelonida N, git
In-Reply-To: <hbf.20111211x512@bombur.uio.no>

Hallvard B Furuseth <h.b.furuseth@usit.uio.no> writes:

> Local branches can track each other.  So the script needs to toposort
> the branches, or to loop until either nothing was done or an error
> happened.  (The latter to prevent an eternal loop on error.)

If you have branches A that forked from B that in turn forked from C, and
if after updating C you want to and can successfully update both B and A
by fast-forwarding, that would only mean that neither A nor B had their
own change since they were forked from their upstream, regardless of local
or remote.

What use do these empty branches have in the first place?

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Junio C Hamano @ 2011-12-12  8:09 UTC (permalink / raw)
  To: Gelonida N; +Cc: git
In-Reply-To: <jbvj5o$skt$1@dough.gmane.org>

Gelonida N <gelonida@gmail.com> writes:

> What is the best way to fastforward all fastforwardable tracking
> branches after a git fetch?

This lacks context and invites too many tangents, so I'll only touch a few
of them.

First of all, why do you want to do this?

You have many local branches that are forked from remote tracking branches
and can be fast-forwarded to their counterparts, iow, these local branches
are often behind their upstream and you do not have your own development
in this repository. Because you can by definition have only one branch
checked out in your working tree, after a fetch from your origin, they
will further fall behind their counterparts.

Coming from that background, I can see you may want these branches that
are not checked out fast-forwarded to their remote counterparts to keep
them stay current, but I first question that background. Why have these
local branches to begin with, if they always are supposed to match their
remote counterpart?

One possible reason (this is one tangent) is that you want to build and
install tips of many branches fetched from the upstream without doing any
local development in this repository (the "upstream" could be your primary
repository and the changes fed to this repository may be your own
development, so this is different from saying that you as a person is only
following other people's work. It is just that nothing is done to the
history in THIS repository). It could be solved by directly checking out
the remote tracking branches into detached head state, e.g.

    $ for branch in maint master next
      do
        git checkout origin/$branch &&
        make prefix=$HOME/git-$branch all test install || break
      done

and the reason why you want local branches instead may be because your
build infrastructure (i.e. instead of "make" you have a custom script,
just like I use 'Make' script in my 'todo' branch) the does customization
depending on the name of the current branch, and might be more cumbersome
to get the same information for a detached head state (i.e. "the tip of
which remote tracking branch is the current commit?") than asking "git
symbolic-ref" the name of the current branch. But then it is easy to find
out which remote branch was checked out from the reflog for the HEAD (and
it is easier for your script that builds the origin/$branch to use that
information internally when the script calls your 'Make' equivalent). In
any case, it is largely your build customization's problem if this is the
case.

Another tangent. Perhaps the reason why you want these local branches but
they can often be fast-forwarded is because your workflow looks like this:

 (1) you fork a topic from origin/master;
 (2) you develop a bit;
 (3) you push the topic back to origin/master;
 (4) time passes, others push to origin/master, while you work on other
     branches of yours;
 (5) from time to time, you fetch from origin;
 (6) you decide to continue working on the topic, so you check it out,
     and before continuing, you wish it is already up-to-date.

But then after fast-forwarding the topic in (6), your topic's history
contains commits other than those you made to work toward the goal of your
topic, namely, other commits made by others during (4) for random purposes
that do not have anything to do with achieving the goal of the topic of
yours. Your branch is no longer about what you wanted to accomplish on
your topic. This invites two tangents.

One is a question. If you knew that the topic is not cooked fully and
needs further work after step (6), why did you push it back to the
origin/master in the first place at step (3), contaminating the history
everybody else bases their further work on with the contents of your
"half-done" topic?

Another tangent. Perhaps the fork is not made from origin/master but you
are collaboratively working on the same topic with others, and you handed
off the work up to what you have done at step (3), and others continued to
further the goal of the shared topic during (4). If that is the case,
wouldn't it make more sense to delete the topic after you push it back,
and forking at the point when you actually decide to get back into action?

Yet another. Even if you keep the (stale) topic branch that you already
have pushed out to the remote, because you can work on one topic at a time
in a single working tree anyway, perhaps it makes more sense to delay this
fast-forwarding until you actually check out the topic branch? After all,
your wishing to fast-forward "all branches" imply you have many of them,
and it wouldn't be far-fetched for me to imagine that you will check one
of them out a lot less often than you run "git fetch".

In other words, wouldn't a post-checkout hook be a better place to do
this kind of thing, perhaps like this (completely untested)? 

    #!/bin/sh
    old=$1 new=$2 kind=$3

    # did we checkout a branch?
    test "$kind" = 1 || exit 0

    # what did we check out?
    branch=$(git symbolic-ref HEAD 2>/dev/null) || exit 0

    # does it track anything? otherwise nothing needs to be done
    upstream=$(git for-each-ref --format='%(upstream)' "$branch")
    test -z "$upstream" || exit 0

    # are we up-to-date? if so no need to do anything
    test 0 = $(git rev-list "..$upstream" | wc -l) && exit 0

    # do we have something we made? if so no point trying to fast-forward
    test 0 = $(git rev-list "$upstream.." | wc -l) || exit 0

    # attempt a fast-forward merge with it
    git merge --ff-only @{upstream}

That is, of course, assuming that it makes sense to keep these local
branches in the first place.

^ permalink raw reply

* Re: [RFC/PATCH] show tracking branches with their associated branch names
From: Junio C Hamano @ 2011-12-12  7:14 UTC (permalink / raw)
  To: Santhosh Kumar Mani; +Cc: Vincent van Ravesteijn, git
In-Reply-To: <1323516226.1698.80.camel@sdesktop>

Santhosh Kumar Mani <santhoshmani@gmail.com> writes:

> Of course, I could get this information in different ways. But it makes
> sense to have this information displayed by default.

It makes sense to make the various information available, but it does not
mean it makes sense to add it by default for everybody at all. Given that
against all common sense, many newbie web-tips and third-party documents
suggest "git branch | sed -ne 's/^\* //p'" as a way to find the current
branch in scripts, I am sure such a change will cause trouble to many
while only helping a few.

I wouldn't mind a new option --verbose-format=... that takes various
formatting letters similar to how --pretty=format:... does, though.

^ permalink raw reply

* Re: [PATCH] Update documentation for stripspace
From: Junio C Hamano @ 2011-12-12  6:41 UTC (permalink / raw)
  To: Conrad Irwin; +Cc: git
In-Reply-To: <1323655158-5075-1-git-send-email-conrad.irwin@gmail.com>

Conrad Irwin <conrad.irwin@gmail.com> writes:

> Tell the user what this command is intended for, and expand the
> description of what it does.

Thanks.

> Stop referring to the input as <stream>, as this command reads the
> entire input into memory before processing it.

Which can change to stream, but calling it as input would not invalidate
the new wording, so "input" is fine. From the caller's point of view, the
current implementation (or streaming implementation) can read from an
unseekable input stream (i.e. pipe), so the original wording is equally
valid, by the way.

So in that sense, it does not make any difference either way to me (it is
not even worth rerolling this patch to only remove this part of the
change).

> Signed-off-by: Conrad Irwin <conrad.irwin@gmail.com>
> ---
>  Documentation/git-stripspace.txt |   26 ++++++++++++++++++++------
>  builtin/stripspace.c             |    2 +-
>  2 files changed, 21 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
> index b78f031..6667d25 100644
> --- a/Documentation/git-stripspace.txt
> +++ b/Documentation/git-stripspace.txt
> @@ -3,26 +3,40 @@ git-stripspace(1)
>  
>  NAME
>  ----
> -git-stripspace - Filter out empty lines
> +git-stripspace - Remove unnecessary whitespace
>  
>  
>  SYNOPSIS
>  --------
>  [verse]
> -'git stripspace' [-s | --strip-comments] < <stream>
> +'git stripspace' [-s | --strip-comments] < input
>  
>  DESCRIPTION
>  -----------
> -Remove multiple empty lines, and empty lines at beginning and end.
> +
> +Normalizes input in the manner used by 'git' for user-provided metadata such
> +as commit messages, notes, tags and branch descriptions.

The original says "remove" and new one says "normalize*s*". I think we
tend to say things in imperative mood (i.e. without the trailing "s").

I do not think 'user-provided metadata' is a good wording. This is just a
simple text clean-up filter and you can use it to clean your text files
that you mean to store in the repository as well.

> +When run with no arguments this:
> +
> +- removes trailing whitespace from all lines
> +- collapses multiple consecutive empty lines into one empty line
> +- removes blank lines from the beginning and end of the input
> +- ensures the last line ends with exactly one '\n'.

Thanks for a nicely written bulleted list. It clarifies what the command
does quite a bit.

The last one is a bit funny, though.

By definition, you cannot end the last line with more than one '\n' (upon
seeing the second '\n', you would realize immediately that the line you
saw was _not_ the last line). I think you meant the file does not end with
an incomplete line, i.e. "ensures the output does not end with an
incomplete line by adding '\n' at the end if needed".

> +In the case where the input consists entirely of whitespace characters, no
> +output will be produced.
> +
> +*NOTE*: This is intended for cleaning metadata, prefer the `--whitespace=fix`
> +mode of linkgit:git-apply[1] for correcting whitespace of patches or files in
> +the repository.

I can tell that these three lines were the _primary_ thing you wanted to
add with this patch, having never seen anybody got confused between the
whitespace breakage fix and text cleaning, I wonder if this is adding
clarity or giving users an impression that git can do too many things than
they can wrap their mind around and forcing them to wonder if they have to
learn everything git can do for them.

>  OPTIONS
>  -------
>  -s::
>  --strip-comments::
> -	In addition to empty lines, also strip lines starting with '#'.
> +	Also remove all lines starting with '#'.

With the resulting text (with the rules clarified with your above 4-bullet
points) of this manual page, can a user tell what the command does to this
input (I added line numbers, vertical bars and dollar signs to show where
the beginning and the end of lines are):

    1 | $
    2 |a b c$
    3 |$
    4 |# comment line$
    5 |$
    6 |d e f$
    
The original text at least allows the user to guess correctly, as it hints
that a comment line is treated pretty much like an empty line, and the
"consecutive empty lines are squashed into one" in your bulleted list
would mean that ll 3-5 will become a single blank line.

The new text however gives a wrong hint by saying "Also"; it can be read
as if all the rules in the bullted list are applied first to leave blank
lines at 3 and 5 and then comment line is removed from the result, which
would leave two blank lines in the result.

If I were touching this description, I probably would say something like
"Treat lines starting with a '#' as if they are empty lines".

^ permalink raw reply

* Re: [bug?] checkout -m doesn't work without a base version
From: Junio C Hamano @ 2011-12-12  5:29 UTC (permalink / raw)
  To: Pete Harlan; +Cc: git
In-Reply-To: <4EE55D5E.1090908@pcharlan.com>

Thanks, will queue.

^ permalink raw reply

* Re: [PATCH 0/4] git-p4: paths for p4
From: Junio C Hamano @ 2011-12-12  5:14 UTC (permalink / raw)
  To: Pete Wyckoff; +Cc: git, Gary Gibbons
In-Reply-To: <1323474497-14339-1-git-send-email-pw@padd.com>

Thanks; will queue directly to 'master'.

^ permalink raw reply

* Re: best way to fastforward all tracking branches after a fetch
From: Jeff King @ 2011-12-12  8:25 UTC (permalink / raw)
  To: Stefan Haller; +Cc: Hallvard B Furuseth, Gelonida N, git
In-Reply-To: <1kc5m38.m71ik21ytxkhbM%lists@haller-berlin.de>

On Mon, Dec 12, 2011 at 08:33:15AM +0100, Stefan Haller wrote:

> > Local branches can track each other.  So the script needs to toposort
> > the branches, or to loop until either nothing was done or an error
> > happened.  (The latter to prevent an eternal loop on error.)
> 
> Is this just theoretical, or are there real use cases for this? What
> would be a workflow with such a local tracking branch?

I use this all the time.

In git.git, we use a topic branch workflow (i.e., every feature gets its
own topic branch, and topics graduate independently to master as they
are deemed stable). And we use a patch-submission workflow, which means
it's OK for me to rebase my topics locally, because the end-product is a
series of patches sent to the list.

Typically I branch off of "origin/master", so the topic is independent
of anything else. For example, the "jk/credentials" branch in my git
repo is branched from "origin/master" (Junio's master).  But sometimes
there is a topic that depends on another topic, but should not be part
of the same series (because the the first topic can graduate to master,
but the second one may still need more time for discussion and cooking).
In that case, I'll set the upstream to the other local topic branch. An
example of this is the "jk/prompt" series, which depends on
"jk/credentials" for infrastructure, but is really a separate issue.

Having the upstream set is convenient, because I can get _just_ the
commits in jk/prompt with "git log @{u}..". Or I can rebase _just_ the
commits in that topic with "git rebase -i". If my upstream were set to
origin, I would accidentally also rebase all of the commits pulled in
from jk/credentials, too.

While my topics are still in development (i.e., before they have even
hit "next"), I tend to rebase them aggressively (so that I keep them up
to date with git development), using a script that is something like[1]:

  for i in `topics`; do
    git rebase $i@{u} $i
  done

And I do topo-sort my topics for exactly the reason mentioned.

-Peff

[1] https://github.com/peff/git/blob/meta/rebase

^ permalink raw reply

* Re: [PATCH v2 00/51] ref-api-C and ref-api-D re-roll
From: Junio C Hamano @ 2011-12-12  8:24 UTC (permalink / raw)
  To: mhagger
  Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
	Johan Herland, Julian Phillips
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>

Thanks for a re-roll. Will take a look early this week.

^ permalink raw reply

* Re: Breakage (?) in configure and git_vsnprintf()
From: Junio C Hamano @ 2011-12-12  8:23 UTC (permalink / raw)
  To: Jeff King
  Cc: Michael Haggerty, Junio C Hamano, git discussion list,
	Michal Rokos, Brandon Casey
In-Reply-To: <20111212064305.GA16511@sigill.intra.peff.net>

Good analysis; thanks.

Back when c4582f9 (Add compat/snprintf.c for systems that return bogus,
2008-03-05) was done we didn't have va_copy emulation available in
git-compat-util.h but now we do, so I agree that this is an Obviously
Correct thing to do.

^ permalink raw reply

* Re: [RFC/PATCH 0/7] some sequencer loose ends (Re: Fix revert --abort on Windows)
From: Junio C Hamano @ 2011-12-12  8:15 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Johannes Sixt, Ramkumar Ramachandra, git, Christian Couder,
	Martin von Zweigbergk, Jay Soffian
In-Reply-To: <20111211195836.GA25482@elie.hsd1.il.comcast.net>

Jonathan Nieder <jrnieder@gmail.com> writes:

> How did we ever let this in?  "git reset" already has well defined
> semantics that have nothing to do with this.  Patches 6/7 and 7/7
> would help us forget this UI mistake (and I believe it was a mistake)
> ever happened.

Thanks for catching this. Let's review this quickly and queue it for
maintenance track as necessary.

^ 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