Git development
 help / color / mirror / Atom feed
* How to resolve git stash conflict without adding to index?
From: Sven Bachmann @ 2011-11-08  9:10 UTC (permalink / raw)
  To: git


Hi Git-Group,

from time to time I've got to "git stash" a bunch of files (about 20).
My problem is, sometimes "git stash pop" conflicts and all files are  
added to the index - which is not what I want.

I just want to have the same behavior like "git stash pop" without  
conflict has. Resolving the conflict is okay, but not "git reset HEAD"  
to all other files, which I don't want to commit now.

Is there a possibility that "git stash pop" does not add all files to  
the index when a conflict appears?

I've already asked this question on stackoverflow (  
http://stackoverflow.com/questions/7751555/how-to-resolve-git-stash-conflict-without-commit ) - maybe this helps a bit better to describe the  
problem.

Please add me to CC if possible as I'm not subscribed to this list and  
reading it in the browser.

Thanks a lot in advance!
   Sven

^ permalink raw reply

* [fyi] patches used by git distributors
From: Jonathan Nieder @ 2011-11-08  9:02 UTC (permalink / raw)
  To: git

Hi,

In an ideal world, each patch applied by downstream distributors would
fall into one of two categories: (a) adapting the package to some
esoteric distro-specific requirement (i.e., special-interest patches)
or (b) in the process of being generalized and reviewed for eventual
application upstream, so everyone can benefit from it.  Unfortunately
that takes time.  I should do better --- sorry about that.

As an experiment, here's a quick summary of the patches being used
in Debian, for people curious about that and for people interested in
grabbing useful patches to polish and not knowing where to start.

(Links point to relevant discussion, not necessarily the patch used):

Frédéric Brière (1):
      gitk: Skip over AUTHOR/COMMIT_DATE when searching all fields [1]

Gerrit Pape (1):
      bug#506445: hooks/post-receive-email: set encoding to utf-8 [2]

Jonathan Nieder (12):
      remove shebang line from shell libraries [3]
      pre-rebase hook: capture documentation in a <<here document [4]
      gitk: use symbolic font names "sans" and "monospace"
      transport: expose git_tcp_connect and friends in new tcp.h [5]
      daemon: make host resolution into a separate function [5]
      daemon: move locate_host to tcp.c [5]
      tcp: unify ipv4 and ipv6 code paths [5]
      daemon: check for errors retrieving IP address [5]
      tcp: make dns_resolve return an error code [5]
      transport: optionally honor DNS SRV records [5]
      srv: make errors less quiet [5]
      Makefile: add a knob to turn off hardlinks within same directory [6]

The patches listed above are on the candidate+patches branch of [7].
Questions and improvements can go to git@packages.debian.org.

A few other packaging projects:

 - git://pkgs.fedoraproject.org/git.git master --- 3 patches (using
   SERVER_NAME for home link, reviving vc-git.el, compatibility with
   newer cvsps)
 - http://www.freebsd.org/cgi/cvsweb.cgi/ports/devel/git/files/ ---
   1 patch (capping individual reads and writes at INT_MAX chars)
 - https://build.opensuse.org/package/files?package=git&project=devel%3Atools%3Ascm
   --- 4 patches (a python build fix, making gitweb::prevent_xss
   default to true, turning off hardlinks for builtins at installation
   time, protecting COMP_WORDBREAKS from mangling in the completion
   script)
 - http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/dev-vcs/git/files/
   --- 1 patch (a NO_CVS knob for the makefile).  Very nice.
 - http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/devel/scmgit-base/patches/
   --- 3 patches (putting CFLAGS at the end of ALL_CFLAGS so it can
   override BASIC_CFLAGS, setting INSTALLDIRS=vendor in perl makefile,
   improving tk support on Darwin 8)
 - http://www.openbsd.org/cgi-bin/cvsweb/ports/devel/git/patches/ ---
   8 patches (updating OpenBSD makefile defaults, using raw perlio in
   gitweb blob view, removing "set -e" in t9117, passing --text [well,
   -a] to grep in t9200, avoiding nonportable regex \+ in t9400)
 - ftp://ftp.cygwin.org/pub/cygwin/release/git/git-1.7.5.1-1-src.tar.bz2
   --- 3 patches (tcl 8.4.1 support, updating Cygwin makefile defaults,
   case-insensitive path comparison in makefile, special Windows-specific
   wish script preamble)

[1] http://thread.gmane.org/gmane.comp.version-control.git/142160
[2] http://thread.gmane.org/gmane.comp.version-control.git/181737
[3] http://bugs.debian.org/368792
[4] http://thread.gmane.org/gmane.comp.version-control.git/150737
[5] http://thread.gmane.org/gmane.comp.version-control.git/175106
[6] http://thread.gmane.org/gmane.comp.version-control.git/183361
[7] http://smarden.org/git/git.git
    gitweb: http://repo.or.cz/w/git/debian.org

^ permalink raw reply

* Re: git-apply that handles rejects like merge conflicts
From: Bert Wesarg @ 2011-11-08  8:52 UTC (permalink / raw)
  To: Jeff King; +Cc: Ori Avtalion, git
In-Reply-To: <20111107225508.GB28188@sigill.intra.peff.net>

On Mon, Nov 7, 2011 at 23:55, Jeff King <peff@peff.net> wrote:
> In the general case, you can't represent all failed hunks with conflict
> markers, can you? I'm thinking something where we couldn't find any
> relevant context. You know the lines from the original patch from the
> hunk header, so you can drop the failed content from the patch in the
> right spot. But how do you know how big a conflict marker to make for
> the "current" side? The same number of lines as were in the hunk?
> I think you'd end up with confusing conflict markers.

GNU patch can produce conflict markers with the --merge option.

Bert

>
> -Peff

^ permalink raw reply

* Re: git-receive-pack missing credentials ?
From: François Dagorn @ 2011-11-08  8:26 UTC (permalink / raw)
  To: git
In-Reply-To: <CALUzUxpiOoY3Qy0oXzgioBGkZyBF_vpHV3OHm-DWfChR9pPHHA@mail.gmail.com>

Tay Ray Chuan <rctay89 <at> gmail.com> writes:

> 
> On Mon, Nov 7, 2011 at 11:33 PM, François Dagorn

> 
> Can you update your git installation and try again? v1.7.3.4 sounds
> pretty old (almost a year).
> 


On the server side I'm using the last 1.7.7.2 and 1.7.3.4 is on
the client side used for testing. 

When apache is configured to serve without authentication, everything
is ok !

PS: I don't know where to report but there are mistakes (IMHO) in the
git-http-backend man page : the LocationMatch directive cannot be used 
to restrict access to "receive-pack" because "receive-pack" does not
take part of the URL but only in the QUERY_STRING.


GET /test13/info/refs?service=git-receive-pack
                    ****

Cheers.

François

^ permalink raw reply

* Re: how to merge sub directory or file?
From: Emily Ren @ 2011-11-08  7:08 UTC (permalink / raw)
  To: Konstantin Khomoutov; +Cc: git
In-Reply-To: <20111107193708.6cf2ae81.kostix@domain007.com>

Hi Kon,

Thank you !  I tried that method, it failed on read-tree because
B/dir3 already exists, Cannot bind.

$ git read-tree --prefix=dir3 -u A:dir3
error: Entry 'dir3/file1' overlaps with 'dir3/file1'.  Cannot bind.

And my case is that not all A's sub direcotries are in B.
For example, in A's dir3, there are file1, dir4 and dir5. But in B's
dir3, only file1 and dir4 exist, there's no dir5. How to handle this
case ?

Thanks,
Emily

On Mon, Nov 7, 2011 at 11:37 PM, Konstantin Khomoutov
<flatworm@users.sourceforge.net> wrote:
>
> On Mon, 7 Nov 2011 22:54:18 +0800
> Emily <lingyan.ren@gmail.com> wrote:
>
> > I have two git projects A and B, content of B is subset of A. For
> > example, Project  A and B's tree are as below:
> [...]
> > When there's new changes in project A, how can I merge them to
> > project B without changing B's directory structure?
> >
> > Your help will be highly appreciated.
> Subtree merging maybe?
> See http://progit.org/book/ch6-7.html

^ permalink raw reply

* Re: git-apply that handles rejects like merge conflicts
From: Junio C Hamano @ 2011-11-08  6:15 UTC (permalink / raw)
  To: Jeff King; +Cc: Ori Avtalion, git
In-Reply-To: <20111108054643.GC29643@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> But I think there are two questions:
>
>   1. Should am's 3-way fallback be made more easily available to users
>      of regular "apply"?
>
>   2. Short of doing a 3-way merge, are there better ways to represent
>      failed hunks in the patch target itself, rather than saving ".rej"
>      files?
>
> I'm actually not sure which one Ori was asking about.

Me neither, but if I have to guess it would be the former. If there were a
solution better than ".rej" in 2-way context, surely "patch" would have
implemented it 10 years before we started ;-).

^ permalink raw reply

* Re: pretty placeholders for reflog entries
From: Jeff King @ 2011-11-08  5:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jack Nagel, git
In-Reply-To: <7v8vnr1oww.fsf@alter.siamese.dyndns.org>

On Mon, Nov 07, 2011 at 03:41:19PM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > It would be a little nicer to provide explicit date placeholders, but we
> > can't quite make them match the author-date specifiers, because "gd" is
> > taken.  We could add %gt, %gr, etc. But in the long run, I'd like to
> > move to considering most of %ar, %at, etc to be historical, and have
> > something like "%ad(short)" be the official way of picking different
> > date formats[1]. And then the reflog placeholders could learn
> > "%gt(short)". So making more reflog placeholders right now just feels
> > like cluttering a namespace I'd like to get changed eventually.
> 
> I tend to agree with the direction.
> 
> As we are not adding anything new before the 1.7.8 final, I'd rather ask
> you to hold onto this and other changes in your footnote, instead of
> having me to carry them in 'pu', which is an integration branch even less
> official than it would otherwise be during the freeze period.

Sure. I'll re-send the patch once the release is out. That will also
give Jack and any other interested parties time to comment and test.

-Peff

^ permalink raw reply

* Re: git-apply that handles rejects like merge conflicts
From: Jeff King @ 2011-11-08  5:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ori Avtalion, git
In-Reply-To: <7v4nyf1opf.fsf@alter.siamese.dyndns.org>

On Mon, Nov 07, 2011 at 03:45:48PM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > In the general case, you can't represent all failed hunks with conflict
> > markers, can you?
> 
> Conflict markers come from the use of a 3-way merge, and if you were to do
> a 3-way merge, by definition, you would need some way to tell where the
> preimage of the patch and the target tree you are attempting to apply the
> patch forked from. That's done by fall-back-3way in "am -3".
> 
> You _could_ lift that logic out of "am -3", but I do not think it is worth
> the effort to do so (IOW, I do not see a reason to avoid "am -3").

I think it would purely be "I have a patch produced by git diff, not by
git format-patch". If you want to use "am -3", you would have to dress
up your patch with mail headers.

In practice, this doesn't come up much for me. I think I was using "git
diff >patch" as a poor-man's stash (and I did just stick some fake
headers in, and "git reset HEAD^" afterwards). But maybe other workflows
deal with this more.

But I think there are two questions:

  1. Should am's 3-way fallback be made more easily available to users
     of regular "apply"?

  2. Short of doing a 3-way merge, are there better ways to represent
     failed hunks in the patch target itself, rather than saving ".rej"
     files?

I'm actually not sure which one Ori was asking about.

-Peff

^ permalink raw reply

* Re: Find the size of git push in pre-receive hook
From: Jeff King @ 2011-11-08  5:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Manigandan S, git
In-Reply-To: <7vboso4hf6.fsf@alter.siamese.dyndns.org>

On Sun, Nov 06, 2011 at 09:42:37PM -0800, Junio C Hamano wrote:

> Manigandan S <etc.mani@gmail.com> writes:
> 
> > Let me explain it in detail, if I was not clear.
> 
> Do not top-post on this list.
> 
> You said you wanted to restrict the size of a push, but what you are
> trying is to restrict the size of a repository after a push. If accepting
> this push will result in your repository go over the quota, the push will
> be denied. Otherwise the push will be accepted.
> 
> If that is the case, how much the resulting repository weighs is what you
> are trying to measure, not the size of _this_ push, i.e. the amount of
> additional data this push will introduce, and "du -s" for the repository
> inside pre-receive-hook is the way to do so.

I'm not sure even "du -s" is a good method. That will tell you how big
this push is right _now_, which is at least a maximum. But most commits,
when packed with other commits, will take up a fraction of that space
due to deltas.

So you might receive a 100K thin pack on the network that git will
explode to a 5 megabyte full pack on disk. Next time you repack, it will
only increase the size of your existing packed data by 100K or so.

If receive-pack actually measured the incoming pack bytes in the thin
pack, that would probably be a more accurate guess (but again, it's
still just a guess).

-Peff

^ permalink raw reply

* Re: [PATCH] prune: show progress while marking reachable objects
From: Junio C Hamano @ 2011-11-08  5:40 UTC (permalink / raw)
  To: Jeff King; +Cc: Nguyễn Thái Ngọc Duy, git
In-Reply-To: <20111108053149.GA29643@sigill.intra.peff.net>

Both patches look sensible from a quick glance.

^ permalink raw reply

* Re: [PATCH v2 00/12] Pulling signed/annotated tags
From: Junio C Hamano @ 2011-11-08  5:37 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <CA+55aFyEuuT25m00uakL66YKSpT-zjoiBreymFSbuHmtARq6yw@mail.gmail.com>

Linus Torvalds <torvalds@linux-foundation.org> writes:

> But I don't have any really strong opinions on it. I just think it's a
> good idea to make it easy to parse both mechanically and
> human-visually, and "number of lines" doesn't strike me as being very
> human-friendly.

Here is what I had in mind. An empty line in the tag payload would become
"mergetag \n" and a separate would become "mergetag\n". The consumer of
"cat-file commit" would be able to tell between the two anyway and if a
human _really_ cares, s/he can pipe it to "cat -e" or something.

Honestly, I do not care too much about human readability of "mergetag"
header. We could even store zlib-deflate-and-then-base85 the payload,
which _might_ be a better solution. For one thing, it would protect us
from potential NUL in the tag payload ;-).


 commit.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/commit.c b/commit.c
index 7d471a3..6a5d40e 100644
--- a/commit.c
+++ b/commit.c
@@ -868,6 +868,8 @@ static void handle_signed_tag(struct strbuf *signed_tags, struct commit *parent)
 	 * if (verify_signed_buffer(buf, len, buf + len, size - len, &sig))
 	 *	warn("warning: signed tag unverified.");
 	 */
+	if (signed_tags->len)
+		strbuf_addstr(signed_tags, "mergetag\n");
 	strbuf_add_lines(signed_tags, "mergetag ", buf, size);
 
 free_return:

^ permalink raw reply related

* [PATCH 2/2] reachable: per-object progress
From: Jeff King @ 2011-11-08  5:37 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <20111108053149.GA29643@sigill.intra.peff.net>

The current progress code really just counts commits.
This patch makes it count all objects, giving us a "total"
count close to what a repack would show. This is nice when
using "git gc", which will usually have just repacked the
whole repo.

Signed-off-by: Jeff King <peff@peff.net>
---
This makes the change a lot more invasive, but it is at least confined
to reachable.c. I think matching repack's numbers is worth it. I did a
few basic measurements, and with "& 1023" trick and reasonable
optimizations, it doesn't seem to make prune any slower.

Again, I'd be OK if this is squashed into your original patch.

 reachable.c |   51 +++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/reachable.c b/reachable.c
index 293d37d..bf79706 100644
--- a/reachable.c
+++ b/reachable.c
@@ -9,10 +9,23 @@
 #include "cache-tree.h"
 #include "progress.h"
 
+struct connectivity_progress {
+	struct progress *progress;
+	unsigned long count;
+};
+
+static void update_progress(struct connectivity_progress *cp)
+{
+	cp->count++;
+	if ((cp->count & 1023) == 0)
+		display_progress(cp->progress, cp->count);
+}
+
 static void process_blob(struct blob *blob,
 			 struct object_array *p,
 			 struct name_path *path,
-			 const char *name)
+			 const char *name,
+			 struct connectivity_progress *cp)
 {
 	struct object *obj = &blob->object;
 
@@ -21,6 +34,7 @@ static void process_blob(struct blob *blob,
 	if (obj->flags & SEEN)
 		return;
 	obj->flags |= SEEN;
+	update_progress(cp);
 	/* Nothing to do, really .. The blob lookup was the important part */
 }
 
@@ -35,7 +49,8 @@ static void process_gitlink(const unsigned char *sha1,
 static void process_tree(struct tree *tree,
 			 struct object_array *p,
 			 struct name_path *path,
-			 const char *name)
+			 const char *name,
+			 struct connectivity_progress *cp)
 {
 	struct object *obj = &tree->object;
 	struct tree_desc desc;
@@ -47,6 +62,7 @@ static void process_tree(struct tree *tree,
 	if (obj->flags & SEEN)
 		return;
 	obj->flags |= SEEN;
+	update_progress(cp);
 	if (parse_tree(tree) < 0)
 		die("bad tree object %s", sha1_to_hex(obj->sha1));
 	add_object(obj, p, path, name);
@@ -58,23 +74,25 @@ static void process_tree(struct tree *tree,
 
 	while (tree_entry(&desc, &entry)) {
 		if (S_ISDIR(entry.mode))
-			process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
+			process_tree(lookup_tree(entry.sha1), p, &me, entry.path, cp);
 		else if (S_ISGITLINK(entry.mode))
 			process_gitlink(entry.sha1, p, &me, entry.path);
 		else
-			process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+			process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
 	}
 	free(tree->buffer);
 	tree->buffer = NULL;
 }
 
-static void process_tag(struct tag *tag, struct object_array *p, const char *name)
+static void process_tag(struct tag *tag, struct object_array *p,
+			const char *name, struct connectivity_progress *cp)
 {
 	struct object *obj = &tag->object;
 
 	if (obj->flags & SEEN)
 		return;
 	obj->flags |= SEEN;
+	update_progress(cp);
 
 	if (parse_tag(tag) < 0)
 		die("bad tag object %s", sha1_to_hex(obj->sha1));
@@ -82,17 +100,17 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam
 		add_object(tag->tagged, p, NULL, name);
 }
 
-static void walk_commit_list(struct rev_info *revs, struct progress *progress)
+static void walk_commit_list(struct rev_info *revs,
+			     struct connectivity_progress *cp)
 {
 	int i;
 	struct commit *commit;
 	struct object_array objects = OBJECT_ARRAY_INIT;
-	uint32_t count = 0;
 
 	/* Walk all commits, process their trees */
 	while ((commit = get_revision(revs)) != NULL) {
-		process_tree(commit->tree, &objects, NULL, "");
-		display_progress(progress, ++count);
+		process_tree(commit->tree, &objects, NULL, "", cp);
+		update_progress(cp);
 	}
 
 	/* Then walk all the pending objects, recursively processing them too */
@@ -100,17 +118,16 @@ static void walk_commit_list(struct rev_info *revs, struct progress *progress)
 		struct object_array_entry *pending = revs->pending.objects + i;
 		struct object *obj = pending->item;
 		const char *name = pending->name;
-		display_progress(progress, ++count);
 		if (obj->type == OBJ_TAG) {
-			process_tag((struct tag *) obj, &objects, name);
+			process_tag((struct tag *) obj, &objects, name, cp);
 			continue;
 		}
 		if (obj->type == OBJ_TREE) {
-			process_tree((struct tree *)obj, &objects, NULL, name);
+			process_tree((struct tree *)obj, &objects, NULL, name, cp);
 			continue;
 		}
 		if (obj->type == OBJ_BLOB) {
-			process_blob((struct blob *)obj, &objects, NULL, name);
+			process_blob((struct blob *)obj, &objects, NULL, name, cp);
 			continue;
 		}
 		die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
@@ -199,6 +216,8 @@ static void add_cache_refs(struct rev_info *revs)
 void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
 			    struct progress *progress)
 {
+	struct connectivity_progress cp;
+
 	/*
 	 * Set up revision parsing, and mark us as being interested
 	 * in all object types, not just commits.
@@ -217,11 +236,15 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
 	if (mark_reflog)
 		for_each_reflog(add_one_reflog, revs);
 
+	cp.progress = progress;
+	cp.count = 0;
+
 	/*
 	 * Set up the revision walk - this will move all commits
 	 * from the pending list to the commit walking list.
 	 */
 	if (prepare_revision_walk(revs))
 		die("revision walk setup failed");
-	walk_commit_list(revs, progress);
+	walk_commit_list(revs, &cp);
+	display_progress(cp.progress, cp.count);
 }
-- 
1.7.7.2.7.g9f96f.dirty

^ permalink raw reply related

* [PATCH 1/2] prune: handle --progress/no-progress
From: Jeff King @ 2011-11-08  5:34 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <20111108053149.GA29643@sigill.intra.peff.net>

And have "git gc" pass no-progress when quiet.

Signed-off-by: Jeff King <peff@peff.net>
---
On top of the prune progress patch you sent earlier.

I did these as separate patches so you could see each change, but I'd
also be fine if they are just squashed into your patch.

 builtin/gc.c    |    4 +++-
 builtin/prune.c |   11 +++++++++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 0498094..271376d 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,7 +32,7 @@
 static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
 static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
 static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
-static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
+static const char *argv_prune[] = {"prune", "--expire", NULL, NULL, NULL};
 static const char *argv_rerere[] = {"rerere", "gc", NULL};
 
 static int gc_config(const char *var, const char *value, void *cb)
@@ -243,6 +243,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 
 	if (prune_expire) {
 		argv_prune[2] = prune_expire;
+		if (quiet)
+			argv_prune[3] = "--no-progress";
 		if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
 			return error(FAILED_RUN, argv_prune[0]);
 	}
diff --git a/builtin/prune.c b/builtin/prune.c
index 6b39d3f..58d7cb8 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -15,6 +15,7 @@
 static int show_only;
 static int verbose;
 static unsigned long expire;
+static int show_progress = -1;
 
 static int prune_tmp_object(const char *path, const char *filename)
 {
@@ -125,10 +126,11 @@ static void remove_temporary_files(const char *path)
 int cmd_prune(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
-	struct progress *progress;
+	struct progress *progress = NULL;
 	const struct option options[] = {
 		OPT__DRY_RUN(&show_only, "do not remove, show only"),
 		OPT__VERBOSE(&verbose, "report pruned objects"),
+		OPT_BOOL(0, "progress", &show_progress, "show progress"),
 		OPT_DATE(0, "expire", &expire,
 			 "expire objects older than <time>"),
 		OPT_END()
@@ -154,7 +156,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 		else
 			die("unrecognized argument: %s", name);
 	}
-	progress = start_progress_delay("Checking connectivity", 0, 0, 2);
+
+	if (show_progress == -1)
+		show_progress = isatty(2);
+	if (show_progress)
+		progress = start_progress_delay("Checking connectivity", 0, 0, 2);
+
 	mark_reachable_objects(&revs, 1, progress);
 	stop_progress(&progress);
 	prune_object_dir(get_object_directory());
-- 
1.7.7.2.7.g9f96f.dirty

^ permalink raw reply related

* Re: [PATCH] prune: show progress while marking reachable objects
From: Jeff King @ 2011-11-08  5:31 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <1320494408-6373-1-git-send-email-pclouds@gmail.com>

On Sat, Nov 05, 2011 at 07:00:08PM +0700, Nguyen Thai Ngoc Duy wrote:

> prune already shows progress meter while pruning. The marking part may
> take a few seconds or more, depending on repository size. Show
> progress meter during this time too.

Thanks, this is a nice start. It's missing a few things IMHO:

  1. It actually counts commits, not all objects. I'm tempted to say
     this doesn't matter, as any eye candy is helpful. Except that the
     most common use of prune is as part of "git gc", in which case
     pack-objects will have just done the "counting objects" phase and
     come up with some number. If we count all objects, then our end
     number is the same (modulo any .keep packs, but at least it's
     probably in the same order of magnitude). That gives the user a
     better sense of completion time.

  2. Prune should learn --progress/--no-progress, isatty(2), etc. And
     git-gc should pass --no-progress when it's told to be quiet.

Patches for both in a moment.

-Peff

^ permalink raw reply

* Re: [PATCH v2 00/12] Pulling signed/annotated tags
From: Linus Torvalds @ 2011-11-08  5:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vsjlzyza7.fsf@alter.siamese.dyndns.org>

On Mon, Nov 7, 2011 at 9:10 PM, Junio C Hamano <gitster@pobox.com> wrote:
>
> Eek.
>
> The mergetag stuff is a dump of "cat-file tag" so if you have a line that
> begins with "object " the parsing side (which does not exist yet) would
> have trouble. We would need to devise e.g. adding number of lines at the
> beginning, or something.

Might I suggest making it simpler still to parse?

Change "strbuf_add_lines()" to have two *different* prefixes: one for
the first line, and one for "continuation lines".

Then you can just use the same prefix if you want to - and get the
semantics you have now for that helper.

But instead of just having "mergetag" as the prefix for all the lines
copied from the merge, wouldn't it be nice and easy to have "mergetag"
as the prefix for the *first* line of each copied tag, but then have
some other tag for lines 2..n?

I think that would be *way* easier to parse, and I think something
like that could be a good generic model for any multi-line thing -
have the first line tagged, and the rest have just the continuation
marker. You don't really need to repeat the tag over and over again
each line, it just causes ambiguoity as shown by this example.

But I don't have any really strong opinions on it. I just think it's a
good idea to make it easy to parse both mechanically and
human-visually, and "number of lines" doesn't strike me as being very
human-friendly.

         Linus

^ permalink raw reply

* Re: [PATCH v2 00/12] Pulling signed/annotated tags
From: Junio C Hamano @ 2011-11-08  5:10 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <CA+55aFxVsgNjGv2zAGR1VK34uG59+euJec_3i9JNyQ0VUdjyeA@mail.gmail.com>

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Mon, Nov 7, 2011 at 7:00 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> This is a re-roll of the fourth iteration.
>
> Ok, this all looks fine to me.
>
> Clean series, and everything looks fine.
>
> The one thing I wondered about is what happens when you merge two
> signed tags. Maybe I read the patch wrong, but it *looks* to me like
> the code just appends them all together with nothing in between. Is it
> still parseable?

Eek.

The mergetag stuff is a dump of "cat-file tag" so if you have a line that
begins with "object " the parsing side (which does not exist yet) would
have trouble. We would need to devise e.g. adding number of lines at the
beginning, or something.

^ permalink raw reply

* Re: [PATCH v2 00/12] Pulling signed/annotated tags
From: Linus Torvalds @ 2011-11-08  4:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

On Mon, Nov 7, 2011 at 7:00 PM, Junio C Hamano <gitster@pobox.com> wrote:
> This is a re-roll of the fourth iteration.

Ok, this all looks fine to me.

Clean series, and everything looks fine.

The one thing I wondered about is what happens when you merge two
signed tags. Maybe I read the patch wrong, but it *looks* to me like
the code just appends them all together with nothing in between. Is it
still parseable?

I guess I could just try it out .. ;)

         Linus

^ permalink raw reply

* [PATCH v2 05/12] refs DWIMmery: use the same rule for both "git fetch" and others
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

"git log frotz" can DWIM to "refs/remotes/frotz/HEAD", but in the remote
access context, "git fetch frotz" to fetch what the other side happened to
have fetched from what it calls 'frotz' (which may not have any relation
to what we consider is 'frotz') the last time would not make much sense,
so the fetch rules table did not include "refs/remotes/%.*s/HEAD".

When the user really wants to, "git fetch $there remotes/frotz/HEAD" would
let her do so anyway, so this is not about safety or security; it merely
is about confusion avoidance and discouraging meaningless usage.

Specifically, it is _not_ about ambiguity avoidance. A name that would
become ambiguous if we use the same rules table for both fetch and local
rev-parse would be ambiguous locally at the remote side.

So for the same reason as we added rule to allow "git fetch $there v1.0"
instead of "git fetch $there tags/v1.0" in the previous commit, here is a
bit longer rope for the users, which incidentally simplifies our code.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 cache.h          |    2 +-
 refs.c           |    8 --------
 t/t5510-fetch.sh |    5 ++---
 3 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/cache.h b/cache.h
index be07ec7..26322dd 100644
--- a/cache.h
+++ b/cache.h
@@ -873,7 +873,7 @@ extern int get_sha1_mb(const char *str, unsigned char *sha1);
 
 extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
 extern const char *ref_rev_parse_rules[];
-extern const char *ref_fetch_rules[];
+#define ref_fetch_rules ref_rev_parse_rules
 
 extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
 extern int validate_headref(const char *ref);
diff --git a/refs.c b/refs.c
index ff20eeb..026c7ea 100644
--- a/refs.c
+++ b/refs.c
@@ -995,14 +995,6 @@ const char *ref_rev_parse_rules[] = {
 	NULL
 };
 
-const char *ref_fetch_rules[] = {
-	"%.*s",
-	"refs/%.*s",
-	"refs/tags/%.*s",
-	"refs/heads/%.*s",
-	NULL
-};
-
 int refname_match(const char *abbrev_name, const char *full_name, const char **rules)
 {
 	const char **p;
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 7e433b1..251d138 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -116,7 +116,7 @@ test_expect_success 'fetch must not resolve short tag name' '
 
 '
 
-test_expect_success 'fetch must not resolve short remote name' '
+test_expect_success 'fetch can now resolve short remote name' '
 
 	cd "$D" &&
 	git update-ref refs/remotes/six/HEAD HEAD &&
@@ -125,8 +125,7 @@ test_expect_success 'fetch must not resolve short remote name' '
 	cd six &&
 	git init &&
 
-	test_must_fail git fetch .. six:six
-
+	git fetch .. six:six
 '
 
 test_expect_success 'create bundle 1' '
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 09/12] merge: make usage of commit->util more extensible
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

The merge-recursive code uses the commit->util field directly to annotate
the commit objects given from the command line, i.e. the remote heads to
be merged, with a single string to be used to describe it in its trace
messages and conflict markers.

Correct this short-signtedness by redefining the field to be a pointer to
a structure "struct merge_remote_desc" that later enhancements can add
more information. Store the original objects we were told to merge in a
field "obj" in this struct, so that we can recover the tag we were told to
merge.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/merge.c   |   63 +++++++++++++++++++---------------------------------
 commit.c          |   19 ++++++++++++++++
 commit.h          |   13 +++++++++++
 merge-recursive.c |   13 +++++------
 4 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 48e7f00..8d4eb4e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -406,20 +406,10 @@ static void finish(struct commit *head_commit,
 	strbuf_release(&reflog_message);
 }
 
-static struct object *want_commit(const char *name)
-{
-	struct object *obj;
-	unsigned char sha1[20];
-	if (get_sha1(name, sha1))
-		return NULL;
-	obj = parse_object(sha1);
-	return peel_to_type(name, 0, obj, OBJ_COMMIT);
-}
-
 /* Get the name for the merge commit's message. */
 static void merge_name(const char *remote, struct strbuf *msg)
 {
-	struct object *remote_head;
+	struct commit *remote_head;
 	unsigned char branch_head[20], buf_sha[20];
 	struct strbuf buf = STRBUF_INIT;
 	struct strbuf bname = STRBUF_INIT;
@@ -431,7 +421,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
 	remote = bname.buf;
 
 	memset(branch_head, 0, sizeof(branch_head));
-	remote_head = want_commit(remote);
+	remote_head = get_merge_parent(remote);
 	if (!remote_head)
 		die(_("'%s' does not point to a commit"), remote);
 
@@ -487,7 +477,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
 		if (resolve_ref(truname.buf, buf_sha, 1, NULL)) {
 			strbuf_addf(msg,
 				    "%s\t\tbranch '%s'%s of .\n",
-				    sha1_to_hex(remote_head->sha1),
+				    sha1_to_hex(remote_head->object.sha1),
 				    truname.buf + 11,
 				    (early ? " (early part)" : ""));
 			strbuf_release(&truname);
@@ -515,7 +505,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
 		goto cleanup;
 	}
 	strbuf_addf(msg, "%s\t\tcommit '%s'\n",
-		sha1_to_hex(remote_head->sha1), remote);
+		sha1_to_hex(remote_head->object.sha1), remote);
 cleanup:
 	strbuf_release(&buf);
 	strbuf_release(&bname);
@@ -719,7 +709,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 				die(_("Unknown option for merge-recursive: -X%s"), xopts[x]);
 
 		o.branch1 = head_arg;
-		o.branch2 = remoteheads->item->util;
+		o.branch2 = merge_remote_util(remoteheads->item)->name;
 
 		for (j = common; j; j = j->next)
 			commit_list_insert(j->item, &reversed);
@@ -1190,7 +1180,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		argv += 2;
 		argc -= 2;
 	} else if (!head_commit) {
-		struct object *remote_head;
+		struct commit *remote_head;
 		/*
 		 * If the merged head is a valid one there is no reason
 		 * to forbid "git merge" into a branch yet to be born.
@@ -1204,12 +1194,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		if (!allow_fast_forward)
 			die(_("Non-fast-forward commit does not make sense into "
 			    "an empty head"));
-		remote_head = want_commit(argv[0]);
+		remote_head = get_merge_parent(argv[0]);
 		if (!remote_head)
 			die(_("%s - not something we can merge"), argv[0]);
-		read_empty(remote_head->sha1, 0);
-		update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
-				DIE_ON_ERR);
+		read_empty(remote_head->object.sha1, 0);
+		update_ref("initial pull", "HEAD", remote_head->object.sha1,
+			   NULL, 0, DIE_ON_ERR);
 		return 0;
 	} else {
 		struct strbuf merge_names = STRBUF_INIT;
@@ -1218,12 +1208,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		head_arg = "HEAD";
 
 		/*
-		 * All the rest are the commits being merged;
-		 * prepare the standard merge summary message to
-		 * be appended to the given message.  If remote
-		 * is invalid we will die later in the common
-		 * codepath so we discard the error in this
-		 * loop.
+		 * All the rest are the commits being merged; prepare
+		 * the standard merge summary message to be appended
+		 * to the given message.
 		 */
 		for (i = 0; i < argc; i++)
 			merge_name(argv[i], &merge_names);
@@ -1251,17 +1238,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	strbuf_reset(&buf);
 
 	for (i = 0; i < argc; i++) {
-		struct object *o;
-		struct commit *commit;
-
-		o = want_commit(argv[i]);
-		if (!o)
+		struct commit *commit = get_merge_parent(argv[i]);
+		if (!commit)
 			die(_("%s - not something we can merge"), argv[i]);
-		commit = lookup_commit(o->sha1);
-		commit->util = (void *)argv[i];
 		remotes = &commit_list_insert(commit, remotes)->next;
-
-		strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
+		strbuf_addf(&buf, "GITHEAD_%s",
+			    sha1_to_hex(commit->object.sha1));
 		setenv(buf.buf, argv[i], 1);
 		strbuf_reset(&buf);
 	}
@@ -1307,7 +1289,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			!hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
 		/* Again the most common case of merging one remote. */
 		struct strbuf msg = STRBUF_INIT;
-		struct object *o;
+		struct commit *commit;
 		char hex[41];
 
 		strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
@@ -1321,14 +1303,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		if (have_message)
 			strbuf_addstr(&msg,
 				" (no commit created; -m option ignored)");
-		o = want_commit(sha1_to_hex(remoteheads->item->object.sha1));
-		if (!o)
+		commit = remoteheads->item;
+		if (!commit)
 			return 1;
 
-		if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
+		if (checkout_fast_forward(head_commit->object.sha1,
+					  commit->object.sha1))
 			return 1;
 
-		finish(head_commit, o->sha1, msg.buf);
+		finish(head_commit, commit->object.sha1, msg.buf);
 		drop_save();
 		return 0;
 	} else if (!remoteheads->next && common->next)
diff --git a/commit.c b/commit.c
index 73b7e00..83ff503 100644
--- a/commit.c
+++ b/commit.c
@@ -894,3 +894,22 @@ int commit_tree(const char *msg, unsigned char *tree,
 	strbuf_release(&buffer);
 	return result;
 }
+
+struct commit *get_merge_parent(const char *name)
+{
+	struct object *obj;
+	struct commit *commit;
+	unsigned char sha1[20];
+	if (get_sha1(name, sha1))
+		return NULL;
+	obj = parse_object(sha1);
+	commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+	if (commit && !commit->util) {
+		struct merge_remote_desc *desc;
+		desc = xmalloc(sizeof(*desc));
+		desc->obj = obj;
+		desc->name = strdup(name);
+		commit->util = desc;
+	}
+	return commit;
+}
diff --git a/commit.h b/commit.h
index 009b113..5b57eab 100644
--- a/commit.h
+++ b/commit.h
@@ -185,4 +185,17 @@ extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
 		const char *author);
 
+struct merge_remote_desc {
+	struct object *obj; /* the named object, could be a tag */
+	const char *name;
+};
+#define merge_remote_util(commit) ((struct merge_remote_desc *)((commit)->util))
+
+/*
+ * Given "name" from the command line to merge, find the commit object
+ * and return it, while storing merge_remote_desc in its ->util field,
+ * to allow callers to tell if we are told to merge a tag.
+ */
+struct commit *get_merge_parent(const char *name);
+
 #endif /* COMMIT_H */
diff --git a/merge-recursive.c b/merge-recursive.c
index cc664c3..5a2db29 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -38,16 +38,15 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
 	return lookup_tree(shifted);
 }
 
-/*
- * A virtual commit has (const char *)commit->util set to the name.
- */
-
 static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
 {
 	struct commit *commit = xcalloc(1, sizeof(struct commit));
+	struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
+
+	desc->name = comment;
+	desc->obj = (struct object *)commit;
 	commit->tree = tree;
-	commit->util = (void*)comment;
-	/* avoid warnings */
+	commit->util = desc;
 	commit->object.parsed = 1;
 	return commit;
 }
@@ -184,7 +183,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
 	for (i = o->call_depth; i--;)
 		fputs("  ", stdout);
 	if (commit->util)
-		printf("virtual %s\n", (char *)commit->util);
+		printf("virtual %s\n", merge_remote_util(commit)->name);
 	else {
 		printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 		if (parse_commit(commit) != 0)
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 12/12] merge: force edit mode when merging a tag object
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

Now that we allow pulling a tag from the remote site to validate the
authenticity, we should give the user the final chance to verify and
edit the merge message.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/merge.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 7158e8e..3b3e374 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1253,6 +1253,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			    sha1_to_hex(commit->object.sha1));
 		setenv(buf.buf, argv[i], 1);
 		strbuf_reset(&buf);
+		if (merge_remote_util(commit) &&
+		    merge_remote_util(commit)->obj &&
+		    merge_remote_util(commit)->obj->type == OBJ_TAG)
+			option_edit = 1;
 	}
 
 	if (!use_strategies) {
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 11/12] commit: copy merged signed tags to headers of merge commit
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

Now MERGE_HEAD records the tag objects without peeling, we could record
the result of manual conflict resolution via "git commit" without losing
the tag information.

In hindsight, it would have been better to make "merge --continue" as the
way to continue from such an interrupted merge, not "commit", but this is
a backward compatibility baggage we would need to carry around for now.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/commit.c |   10 +++++-----
 commit.c         |   46 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index c46f2d1..4688a73 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1425,7 +1425,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 			pptr = &commit_list_insert(c->item, pptr)->next;
 	} else if (whence == FROM_MERGE) {
 		struct strbuf m = STRBUF_INIT;
-		struct commit *commit;
 		FILE *fp;
 
 		if (!reflog_msg)
@@ -1436,11 +1435,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 			die_errno(_("could not open '%s' for reading"),
 				  git_path("MERGE_HEAD"));
 		while (strbuf_getline(&m, fp, '\n') != EOF) {
-			unsigned char sha1[20];
-			if (get_sha1_hex(m.buf, sha1) < 0)
+			struct commit *parent;
+
+			parent = get_merge_parent(m.buf);
+			if (!parent)
 				die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
-			commit = lookup_commit_or_die(sha1, "MERGE_HEAD");
-			pptr = &commit_list_insert(commit, pptr)->next;
+			pptr = &commit_list_insert(parent, pptr)->next;
 		}
 		fclose(fp);
 		strbuf_release(&m);
diff --git a/commit.c b/commit.c
index 83ff503..7d471a3 100644
--- a/commit.c
+++ b/commit.c
@@ -840,6 +840,41 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 	return result;
 }
 
+static void handle_signed_tag(struct strbuf *signed_tags, struct commit *parent)
+{
+	struct merge_remote_desc *desc;
+	struct strbuf sig = STRBUF_INIT;
+	char *buf;
+	unsigned long size, len;
+	enum object_type type;
+
+	desc = merge_remote_util(parent);
+	if (!desc || !desc->obj)
+		return;
+	buf = read_sha1_file(desc->obj->sha1, &type, &size);
+	if (!buf || type != OBJ_TAG)
+		goto free_return;
+	len = parse_signature(buf, size);
+	if (size == len)
+		goto free_return;
+	/*
+	 * We could verify this signature again and either omit writing
+	 * the contents of the tag when it does not validate, but the
+	 * integrator may not have the public key of the signer of the
+	 * tag he is merging, while a later auditor may acquire the public
+	 * key while auditing, so let's not run verify-signed-buffer here
+	 * for now...
+	 *
+	 * if (verify_signed_buffer(buf, len, buf + len, size - len, &sig))
+	 *	warn("warning: signed tag unverified.");
+	 */
+	strbuf_add_lines(signed_tags, "mergetag ", buf, size);
+
+free_return:
+	strbuf_release(&sig);
+	free(buf);
+}
+
 static const char commit_utf8_warn[] =
 "Warning: commit message does not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
@@ -852,6 +887,7 @@ int commit_tree(const char *msg, unsigned char *tree,
 	int result;
 	int encoding_is_utf8;
 	struct strbuf buffer;
+	struct strbuf signed_tags = STRBUF_INIT;
 
 	assert_sha1_type(tree, OBJ_TREE);
 
@@ -868,8 +904,11 @@ int commit_tree(const char *msg, unsigned char *tree,
 	 */
 	while (parents) {
 		struct commit_list *next = parents->next;
+		struct commit *parent = parents->item;
+
 		strbuf_addf(&buffer, "parent %s\n",
-			sha1_to_hex(parents->item->object.sha1));
+			    sha1_to_hex(parent->object.sha1));
+		handle_signed_tag(&signed_tags, parent);
 		free(parents);
 		parents = next;
 	}
@@ -881,6 +920,11 @@ int commit_tree(const char *msg, unsigned char *tree,
 	strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
 	if (!encoding_is_utf8)
 		strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
+
+	if (signed_tags.len) {
+		strbuf_addbuf(&buffer, &signed_tags);
+		strbuf_release(&signed_tags);
+	}
 	strbuf_addch(&buffer, '\n');
 
 	/* And add the comment */
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 10/12] merge: record tag objects without peeling in MERGE_HEAD
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

Otherwise, "git commit" wouldn't have a way to tell that we were in the
middle of merging an annotated or signed tag, not a plain commit, after
"git merge" stops to ask the user to resolve conflicts.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/merge.c  |   13 ++++++++++---
 t/t7600-merge.sh |    6 +++++-
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 8d4eb4e..7158e8e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1045,9 +1045,16 @@ static void write_merge_state(void)
 	struct commit_list *j;
 	struct strbuf buf = STRBUF_INIT;
 
-	for (j = remoteheads; j; j = j->next)
-		strbuf_addf(&buf, "%s\n",
-			sha1_to_hex(j->item->object.sha1));
+	for (j = remoteheads; j; j = j->next) {
+		unsigned const char *sha1;
+		struct commit *c = j->item;
+		if (c->util && merge_remote_util(c)->obj) {
+			sha1 = merge_remote_util(c)->obj->sha1;
+		} else {
+			sha1 = c->object.sha1;
+		}
+		strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
+	}
 	fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
 	if (fd < 0)
 		die_errno(_("Could not open '%s' for writing"),
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index b91d022..5d8c428 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -96,7 +96,11 @@ verify_parents () {
 
 verify_mergeheads () {
 	printf '%s\n' "$@" >mergehead.expected &&
-	test_cmp mergehead.expected .git/MERGE_HEAD
+	while read sha1 rest
+	do
+		git rev-parse $sha1
+	done <.git/MERGE_HEAD >mergehead.actual &&
+	test_cmp mergehead.expected mergehead.actual
 }
 
 verify_no_mergehead () {
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 08/12] fmt-merge-msg: Add contents of merged tag in the merge message
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

When a contributor asks the integrator to merge her history, a signed tag
can be a good vehicle to communicate the authenticity of the request while
conveying other information such as the purpose of the topic.

E.g. a signed tag "for-linus" can be created, and the integrator can run:

   $ git pull git://example.com/work.git/ for-linus

This would allow the integrator to run "git verify-tag FETCH_HEAD" to
validate the signed tag.

Update fmt-merge-msg so that it pre-fills the merge message template with
the body (but not signature) of the tag object to help the integrator write
a better merge message, in the same spirit as the existing merge.log summary
lines.

The message that comes from GPG signature validation is also included in
the merge message template to help the integrator verify it, but they are
prefixed with "#" to make them comments.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/fmt-merge-msg.c |   72 +++++++++++++++++++++++++++++++++++++++++++++-
 strbuf.c                |   15 ++++++++++
 strbuf.h                |    8 +++++
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 3ff9564..7dae846 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -5,6 +5,7 @@
 #include "revision.h"
 #include "tag.h"
 #include "string-list.h"
+#include "gpg-interface.h"
 
 static const char * const fmt_merge_msg_usage[] = {
 	"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
@@ -262,6 +263,70 @@ static void fmt_merge_msg_title(struct strbuf *out,
 		strbuf_addf(out, " into %s\n", current_branch);
 }
 
+static void fmt_tag_signature(struct strbuf *tagbuf,
+			      struct strbuf *sig,
+			      const char *buf,
+			      unsigned long len)
+{
+	const char *tag_body = strstr(buf, "\n\n");
+	if (tag_body) {
+		tag_body += 2;
+		strbuf_add(tagbuf, tag_body, buf + len - tag_body);
+	}
+	strbuf_complete_line(tagbuf);
+	strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+}
+
+static void fmt_merge_msg_sigs(struct strbuf *out)
+{
+	int i, tag_number = 0, first_tag = 0;
+	struct strbuf tagbuf = STRBUF_INIT;
+
+	for (i = 0; i < origins.nr; i++) {
+		unsigned char *sha1 = origins.items[i].util;
+		enum object_type type;
+		unsigned long size, len;
+		char *buf = read_sha1_file(sha1, &type, &size);
+		struct strbuf sig = STRBUF_INIT;
+
+		if (!buf || type != OBJ_TAG)
+			goto next;
+		len = parse_signature(buf, size);
+
+		if (size == len)
+			; /* merely annotated */
+		else if (verify_signed_buffer(buf, len, buf + len, size - len, &sig)) {
+			if (!sig.len)
+				strbuf_addstr(&sig, "gpg verification failed.\n");
+		}
+
+		if (!tag_number++) {
+			fmt_tag_signature(&tagbuf, &sig, buf, len);
+			first_tag = i;
+		} else {
+			if (tag_number == 2) {
+				struct strbuf tagline = STRBUF_INIT;
+				strbuf_addf(&tagline, "\n# %s\n",
+					    origins.items[first_tag].string);
+				strbuf_insert(&tagbuf, 0, tagline.buf,
+					      tagline.len);
+				strbuf_release(&tagline);
+			}
+			strbuf_addf(&tagbuf, "\n# %s\n",
+				    origins.items[i].string);
+			fmt_tag_signature(&tagbuf, &sig, buf, len);
+		}
+		strbuf_release(&sig);
+	next:
+		free(buf);
+	}
+	if (tagbuf.len) {
+		strbuf_addch(out, '\n');
+		strbuf_addbuf(out, &tagbuf);
+	}
+	strbuf_release(&tagbuf);
+}
+
 int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 		  struct fmt_merge_msg_opts *opts)
 {
@@ -293,6 +358,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 	if (opts->add_title && srcs.nr)
 		fmt_merge_msg_title(out, current_branch);
 
+	if (origins.nr)
+		fmt_merge_msg_sigs(out);
+
 	if (opts->shortlog_len) {
 		struct commit *head;
 		struct rev_info rev;
@@ -310,8 +378,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 			shortlog(origins.items[i].string, origins.items[i].util,
 				 head, &rev, opts->shortlog_len, out);
 	}
-	if (out->len && out->buf[out->len-1] != '\n')
-		strbuf_addch(out, '\n');
+
+	strbuf_complete_line(out);
 	return 0;
 }
 
diff --git a/strbuf.c b/strbuf.c
index 3ad2cc0..a3c2e84 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -397,3 +397,18 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
 
 	return len;
 }
+
+void strbuf_add_lines(struct strbuf *out, const char *prefix,
+		      const char *buf, size_t size)
+{
+	strbuf_complete_line(out);
+	while (size) {
+		const char *next = memchr(buf, '\n', size);
+		next = next ? (next + 1) : (buf + size);
+		strbuf_addstr(out, prefix);
+		strbuf_add(out, buf, next - buf);
+		size -= next - buf;
+		buf = next;
+	}
+	strbuf_complete_line(out);
+}
diff --git a/strbuf.h b/strbuf.h
index 46a33f8..08fc13d 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -100,6 +100,14 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 __attribute__((format (printf,2,0)))
 extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
+extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
+
+static inline void strbuf_complete_line(struct strbuf *sb)
+{
+	if (sb->len && sb->buf[sb->len - 1] != '\n')
+		strbuf_addch(sb, '\n');
+}
+
 extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 /* XXX: if read fails, any partial read is undone */
 extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 07/12] fmt-merge-msg: package options into a structure
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

This way new features can be added more easily

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin.h               |    8 +++++++-
 builtin/fmt-merge-msg.c |   29 ++++++++++++++---------------
 builtin/merge.c         |    8 ++++++--
 3 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/builtin.h b/builtin.h
index 0e9da90..e94a5dc 100644
--- a/builtin.h
+++ b/builtin.h
@@ -14,8 +14,14 @@ extern const char git_usage_string[];
 extern const char git_more_info_string[];
 
 extern void prune_packed_objects(int);
+
+struct fmt_merge_msg_opts {
+	unsigned add_title:1;
+	int shortlog_len;
+};
+
 extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
-			 int merge_title, int shortlog_len);
+			 struct fmt_merge_msg_opts *);
 extern void commit_notes(struct notes_tree *t, const char *msg);
 
 struct notes_rewrite_cfg {
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 7b492f9..3ff9564 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -209,7 +209,7 @@ static void shortlog(const char *name, unsigned char *sha1,
 	string_list_clear(&subjects, 0);
 }
 
-static void do_fmt_merge_msg_title(struct strbuf *out,
+static void fmt_merge_msg_title(struct strbuf *out,
 	const char *current_branch) {
 	int i = 0;
 	char *sep = "";
@@ -262,8 +262,9 @@ static void do_fmt_merge_msg_title(struct strbuf *out,
 		strbuf_addf(out, " into %s\n", current_branch);
 }
 
-static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
-	struct strbuf *out, int shortlog_len) {
+int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
+		  struct fmt_merge_msg_opts *opts)
+{
 	int i = 0, pos = 0;
 	unsigned char head_sha1[20];
 	const char *current_branch;
@@ -289,10 +290,10 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 			die ("Error in line %d: %.*s", i, len, p);
 	}
 
-	if (merge_title && srcs.nr)
-		do_fmt_merge_msg_title(out, current_branch);
+	if (opts->add_title && srcs.nr)
+		fmt_merge_msg_title(out, current_branch);
 
-	if (shortlog_len) {
+	if (opts->shortlog_len) {
 		struct commit *head;
 		struct rev_info rev;
 
@@ -307,18 +308,13 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 
 		for (i = 0; i < origins.nr; i++)
 			shortlog(origins.items[i].string, origins.items[i].util,
-					head, &rev, shortlog_len, out);
+				 head, &rev, opts->shortlog_len, out);
 	}
 	if (out->len && out->buf[out->len-1] != '\n')
 		strbuf_addch(out, '\n');
 	return 0;
 }
 
-int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
-		  int merge_title, int shortlog_len) {
-	return do_fmt_merge_msg(merge_title, in, out, shortlog_len);
-}
-
 int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 {
 	const char *inpath = NULL;
@@ -340,6 +336,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 	FILE *in = stdin;
 	struct strbuf input = STRBUF_INIT, output = STRBUF_INIT;
 	int ret;
+	struct fmt_merge_msg_opts opts;
 
 	git_config(fmt_merge_msg_config, NULL);
 	argc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage,
@@ -361,10 +358,12 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 
 	if (message)
 		strbuf_addstr(&output, message);
-	ret = fmt_merge_msg(&input, &output,
-			    message ? 0 : 1,
-			    shortlog_len);
 
+	memset(&opts, 0, sizeof(opts));
+	opts.add_title = !message;
+	opts.shortlog_len = shortlog_len;
+
+	ret = fmt_merge_msg(&input, &output, &opts);
 	if (ret)
 		return ret;
 	write_in_full(STDOUT_FILENO, output.buf, output.len);
diff --git a/builtin/merge.c b/builtin/merge.c
index 6a44b6d..48e7f00 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1229,8 +1229,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			merge_name(argv[i], &merge_names);
 
 		if (!have_message || shortlog_len) {
-			fmt_merge_msg(&merge_names, &merge_msg, !have_message,
-				      shortlog_len);
+			struct fmt_merge_msg_opts opts;
+			memset(&opts, 0, sizeof(opts));
+			opts.add_title = !have_message;
+			opts.shortlog_len = shortlog_len;
+
+			fmt_merge_msg(&merge_names, &merge_msg, &opts);
 			if (merge_msg.len)
 				strbuf_setlen(&merge_msg, merge_msg.len - 1);
 		}
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related

* [PATCH v2 06/12] fmt-merge-msg: avoid early returns
From: Junio C Hamano @ 2011-11-08  3:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <1320721245-13223-1-git-send-email-gitster@pobox.com>

In various places in the codepath, the program tries to return early
assuming there is no more work needed. That is generally untrue when
over time new features are added.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/fmt-merge-msg.c |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 7e2f225..7b492f9 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -26,6 +26,7 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 	return 0;
 }
 
+/* merge data per repository where the merged tips came from */
 struct src_data {
 	struct string_list branch, tag, r_branch, generic;
 	int head_status;
@@ -71,6 +72,11 @@ static int handle_line(char *line)
 		line[len - 1] = 0;
 	line += 42;
 
+	/*
+	 * At this point, line points at the beginning of comment e.g.
+	 * "branch 'frotz' of git://that/repository.git".
+	 * Find the repository name and point it with src.
+	 */
 	src = strstr(line, " of ");
 	if (src) {
 		*src = 0;
@@ -283,10 +289,7 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 			die ("Error in line %d: %.*s", i, len, p);
 	}
 
-	if (!srcs.nr)
-		return 0;
-
-	if (merge_title)
+	if (merge_title && srcs.nr)
 		do_fmt_merge_msg_title(out, current_branch);
 
 	if (shortlog_len) {
@@ -306,6 +309,8 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 			shortlog(origins.items[i].string, origins.items[i].util,
 					head, &rev, shortlog_len, out);
 	}
+	if (out->len && out->buf[out->len-1] != '\n')
+		strbuf_addch(out, '\n');
 	return 0;
 }
 
@@ -341,12 +346,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 			     0);
 	if (argc > 0)
 		usage_with_options(fmt_merge_msg_usage, options);
-	if (message && !shortlog_len) {
-		char nl = '\n';
-		write_in_full(STDOUT_FILENO, message, strlen(message));
-		write_in_full(STDOUT_FILENO, &nl, 1);
-		return 0;
-	}
+
 	if (shortlog_len < 0)
 		die("Negative --log=%d", shortlog_len);
 
-- 
1.7.8.rc0.128.g31aa4

^ permalink raw reply related


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