Git development
 help / color / mirror / Atom feed
* Re: rsync update appears broken now
From: Junio C Hamano @ 2005-10-21  0:26 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0510201645450.10477@g5.osdl.org>

Linus Torvalds <torvalds <at> osdl.org> writes:

> The latest one I have is ea5a65a59916503d2a14369c46b1023384d51645, but if 
> you had more pushed out at some point that I just didn't happen to pick 
> up, that may not be the top-most (A).

I am reasonably sure that the screw-up was only rewinding one commit too much.
I've done the merge so things should look better once mirrors catch up.

Thanks for your help.

^ permalink raw reply

* Re: rsync update appears broken now
From: Petr Baudis @ 2005-10-21  0:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Johannes Schindelin, Junio Hamano, junkio, git
In-Reply-To: <Pine.LNX.4.64.0510201717100.10477@g5.osdl.org>

Dear diary, on Fri, Oct 21, 2005 at 02:19:42AM CEST, I got a letter
where Linus Torvalds <torvalds@osdl.org> told me that...
> On Fri, 21 Oct 2005, Johannes Schindelin wrote:
> > It does not have to be a fast-forward. After all, what is another merge? 
> > Since that merge does not have Junio as committer, close inspection of 
> > the commit will reveal that.
> 
> It _does_ have to be a fast-forward, if you expect the tree to have the 
> same content as Junio's.
> 
> Even if it merges everything automatically, if the history is different, 
> it could in theory at least merge _differently_ than what Junio had. Plus 
> you'll have a really ugly version history for no good reason.

And if Junio will want to merge with many of those people, you will
better have to get a dualhead for your gitk.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* Re: Strange differences in cogito on SPARC and i386
From: Petr Baudis @ 2005-10-21  0:44 UTC (permalink / raw)
  To: Horst von Brand; +Cc: git
In-Reply-To: <200510171906.j9HJ6AQr015777@laptop11.inf.utfsm.cl>

Dear diary, on Mon, Oct 17, 2005 at 09:06:10PM CEST, I got a letter
where Horst von Brand <vonbrand@inf.utfsm.cl> told me that...
> git, cogito up to date everywhere.

Does that mean the latest development trees or the latest release
vesions? If the latter, could you try the former, please?

>    [vonbrand@pincoya linux-2.6.git]$ cg-update
>    Recovering from a previously interrupted fetch...
>    15:04:56 URL:http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/HEAD [41/41] -> "refs/heads/.origin-fetching" [1]
>    Getting alternates list
>    progress: 10 objects, 24166 bytes
>    error: Empty reply from server (curl_result = 52, http_code = 0, sha1 = 0801ec7bf4953784f0f3279c1a80258ad29094d6)
>    Getting pack list
>    progress: 11 objects, 24873 bytes
>    error: Unable to find 0801ec7bf4953784f0f3279c1a80258ad29094d6 under http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/
> 
> Just started again each time, seems to work fine. On i386 the download goes
> smoothly, no hickups. And there are /no/ updates while SPARC is working its
> head off getting updates...
> 
> Then again, today on the SPARC it is getting several thousand objects (!),
> while on i386 it was only a few dozen.
> 
> Some stupid pilot error? Got different mirrors between machines? Sounds
> unlikely, as repeating the command (and presumably rotating between DNS
> entries) makes no difference.

Well, can you repeat the bug using git pull? (Try just "git pull".) If
so, and if you will slightly modify the subject in your reply, you
should hopefully get some interested debuggers who know this stuff
better. ;-) But I've seen those reports before, and it seems something
is rotten in the realm of fetching...

> Just finished SPARCwise. Almost 10K objects for changes to 4 files?! Yes,
> the files changed are the same on both machines.

This might be because of the interrupted merge - if it says the
"recovering" message, it will try to make sure you really have all the
objects, and depending on your exact git version, I can imagine it might
re-fetch some of them for some reason.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* Re: [PATCH] Do not send "want" lines for complete objects
From: Junio C Hamano @ 2005-10-21  0:43 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.63.0510210114370.10503@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin <at> gmx.de> writes:

> ... I did not use it originally, because lines 
> 24-25 of commit.h say
> 
> 	/** Internal only **/
> 	struct object *lookup_object(const unsigned char *sha1);
> 
> Is this obsolete?

For this particular application, it should be OK, because:

 - it checks if we already have that object, and returns a pointer to it;
 - if we haven't seen that object, we get a NULL back;

and

 - what we care about is to see if we have checked and verified if it is
   reachable from our refs.  We do not want the check to actively go read
   and parse that object.

-jc

^ permalink raw reply

* Re: LCA2006 Git/Cogito tutorial
From: Petr Baudis @ 2005-10-21  0:51 UTC (permalink / raw)
  To: Martin Langhoff (CatalystIT); +Cc: git
In-Reply-To: <4352F4C9.1040703@catalyst.net.nz>

Dear diary, on Mon, Oct 17, 2005 at 02:48:09AM CEST, I got a letter
where "Martin Langhoff (CatalystIT)" <martin@catalyst.net.nz> told me that...
> Petr Baudis hinted earlier that he might be coming, as did Linus (but
> he was hoping for a sponsor, I'm not sure whether he'll be there or
> not). Speak up if you'll be there!

I'm sorry but I will not be there - it is too far away from my little
country. :-(

> I'll post my slides and presentation plan beforehand to the list, to
> avoid spreading misinfirmation/bad practices. They will probably be
> based on a recent talk I gave @ Wellington Perl Mongers about
> swtiching to Git/Cogito:
> 
>    http://wellington.pm.org/archive/200510/git/

(i) You might want to say "cg-export" instead of "git-tar-tree" (*shrug*)

(ii) You say:

	- Very fast stupid merge
	    ... and very smart, slow merges when stupid won't do

  What are you explicitly referring to? I don't think any kind of merge
in GIT (unless something totally missed me) can be called "very smart".
If it's a three-way merge, it's never "very smart".

(iii) I have only one major problem with your file:

	emacs .gitignore

  This should be obviously:

	vim .gitignore

;-)

> ps: lately, about 30% of my emails to git@vger from gmail have been 
> dropped on the floor. This is starting to get annoying, is anyone seeing 
> similar issues?

Not me. Perhaps I'm in some VIP class. :^)

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* Re: rsync update appears broken now
From: Linus Torvalds @ 2005-10-21  0:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <loom.20051021T022509-63@post.gmane.org>



On Fri, 21 Oct 2005, Junio C Hamano wrote:
> 
> I am reasonably sure that the screw-up was only rewinding one commit too much.
> I've done the merge so things should look better once mirrors catch up.

Yup, works at least for me. Thx,

		Linus

^ permalink raw reply

* Re: Revamping the git protocol
From: Petr Baudis @ 2005-10-21  1:04 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Junio C Hamano, git
In-Reply-To: <4357BCBC.1020706@zytor.com>

Dear diary, on Thu, Oct 20, 2005 at 05:50:20PM CEST, I got a letter
where "H. Peter Anvin" <hpa@zytor.com> told me that...
> Another issue is that currently there is no error information propagated 
> back to the client; the server logs an error in its own logs, but the 
> client is simply disconnected.

Yes. I agree that while it seems quite complex compared to what we have
now, your proposal has good points. But if we are going with the
challenge-response at all and if we are going with the simple form,
I was merely trying to make sure that it is as compatible as possible.

> Anyone noticed that either of those schemes aren't actually 
> backward-compatible in any way (old client talking to new server will be 
> disconnected), and that unfortunately is the best thing one can do with 
> the current setup, exactly because there is no option negotiation phase?

Yes, option negotiation would solve this for us. But my scheme _is_
backwards-compatible in the way that new client taking to old server
will not be disconnected, so it's 50% better than the original proposal.

But I think that considering the long run, we should either not do this
challenge-response thing at all, and fix the problem by other (Linus')
means, or go for the "complex" scheme. I'd prefer the latter - sending
the error messages to the client alone is a huge improvement.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* Re: [PATCH Cogito] Fix README asciidoc formatting
From: Petr Baudis @ 2005-10-21  1:18 UTC (permalink / raw)
  To: Jonas Fonseca; +Cc: git
In-Reply-To: <20051012142223.GA29333@diku.dk>

Dear diary, on Wed, Oct 12, 2005 at 04:22:23PM CEST, I got a letter
where Jonas Fonseca <fonseca@diku.dk> told me that...
> Petr Baudis <pasky@suse.cz> wrote Tue, Oct 11, 2005:
> > Dear diary, on Sun, Oct 02, 2005 at 12:56:01PM CEST, I got a letter
> > where Jonas Fonseca <fonseca@diku.dk> told me that...
> > > BTW, what about adding some notatation info for those boxes? It looks
> > > very creative for an introduction document.
> > 
> > What do you mean by "notation info"?
> 
> I mean some kind of explanatory caption accompanying the ASCII
> illustrations. At least I lack an explanation of what you mean
> by '<' in
> 
> 	+--------+
> 	$ branch <
> 	+--------+
> 
> If you could please "massage that gently into my frontal cortex" I would
> be very happy.

'<' denotes the head, it might be possible to deduce from

		+--------+
		|  master<
		$  origin<
		$ r-unoji<
		$upmirror|
		+--------+

	Note that 'upmirror' has no head associated, it has just the
	"remote branch" ...

but I added explicit explanation.

> Also you use '<-M-' for merging? Why not use '<-U- for updating instead
> of '< < < <'.

Good point, changed that to <-F- (it's a fetch).

Thanks,

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* [PATCH] Fix git-daemon argument-parsing bug
From: H. Peter Anvin @ 2005-10-21  1:34 UTC (permalink / raw)
  To: Git Mailing List

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

Fix stupid bug in parsing the --init-timeout option.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>

[-- Attachment #2: diff --]
[-- Type: text/plain, Size: 351 bytes --]

diff --git a/daemon.c b/daemon.c
--- a/daemon.c
+++ b/daemon.c
@@ -612,7 +612,7 @@ int main(int argc, char **argv)
 		if (!strncmp(arg, "--timeout=", 10)) {
 			timeout = atoi(arg+10);
 		}
-		if (!strncmp(arg, "--init-timeout=", 10)) {
+		if (!strncmp(arg, "--init-timeout=", 15)) {
 			init_timeout = atoi(arg+15);
 		}
 		if (!strcmp(arg, "--")) {

^ permalink raw reply

* [PATCH] Use sensible domain name (the DNS one) when guessing ident information
From: Petr Baudis @ 2005-10-21  1:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Currently, the code would use getdomainname() call, which however returns
something usually unset and not necessarily related at all to the DNS
domain name (it seems to be mostly some scary NIS/YP thing).

This patch changes the code to actually use the DNS domain name, which is
also what tends to be used in emails, and we aim at emails with our ident
code.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 ident.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/ident.c b/ident.c
index 06d0e6c..bc89e1d 100644
--- a/ident.c
+++ b/ident.c
@@ -8,6 +8,7 @@
 #include "cache.h"
 
 #include <pwd.h>
+#include <netdb.h>
 
 static char git_default_date[50];
 
@@ -64,9 +65,16 @@ int setup_ident(void)
 	git_default_email[len++] = '@';
 	gethostname(git_default_email + len, sizeof(git_default_email) - len);
 	if (!strchr(git_default_email+len, '.')) {
+		struct hostent *he = gethostbyname(git_default_email + len);
+		char *domainname;
+
 		len = strlen(git_default_email);
 		git_default_email[len++] = '.';
-		getdomainname(git_default_email+len, sizeof(git_default_email)-len);
+		if (he && (domainname = strchr(he->h_name, '.')))
+			strncpy(git_default_email + len, domainname + 1, sizeof(git_default_email) - len);
+		else
+			strncpy(git_default_email + len, "(none)", sizeof(git_default_email) - len);
+		git_default_email[sizeof(git_default_email) - 1] = 0;
 	}
 	/* And set the default date */
 	datestamp(git_default_date, sizeof(git_default_date));

^ permalink raw reply related

* [PATCH] Do not call git-rev-list from git-fetch-pack
From: Johannes Schindelin @ 2005-10-21  2:15 UTC (permalink / raw)
  To: git, junkio

It is much easier to avoid sending unneeded data when putting the rev list
together in a customized manner. In particular, the tips of the local
branches are sent first, and only then their ancestors.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	This supersedes my earlier attempt. SHA1s of tags are no longer
	sent via "have" lines. This makes the code much simpler. Also,
	it does not buy us much to send them:

	Either we have the tag object already, pointed to by a ref (thus 
	not "want"ing it in the first place), or we fetch at most
	a couple of tag objects we already have.

 fetch-pack.c |  139 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 106 insertions(+), 33 deletions(-)

diff --git a/fetch-pack.c b/fetch-pack.c
index 8566ab1..260de90 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -13,18 +13,102 @@ static const char fetch_pack_usage[] =
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE	(1U << 0)
+#define COMMON		(1U << 1)
+#define COMMON_REF	(1U << 2)
+#define SEEN		(1U << 3)
+
+struct commit_list *rev_list = NULL;
+
+static int rev_list_insert(const char *path, const unsigned char *sha1)
+{
+	struct object *o = deref_tag(parse_object(sha1));
+
+	/*
+	   The real problem is that find_common will stop very soon
+	   after seeing a common revision.
+
+	   However, that does not always make sense. Example:
+
+	   Branch1 has 40 commits since it last merged with branch2,
+	   and branch2 has 2 more commits since then.
+
+	   On the other end, branch1 is up-to-date, but branch2 is not.
+	   When fetching branch1, the 40 commits get sent, the first
+	   is acknowledged as common, and the local head of branch2
+	   never gets sent.
+
+	   As a consequence, the whole history of branch2
+	   (git-rev-list branch2 ^branch1) gets packed and transmitted.
+
+	   The workaround is to pretend that the tips of the local
+	   branches are 10 years younger, so that they are sent before
+	   everything else.
+	*/
+
+	if (o->type == commit_type && !(o->flags & SEEN)) {
+		struct commit *commit = (struct commit *)o;
+		o->flags |= SEEN;
+		/* The head's tips get handled before everything else. */
+		commit->date += 10*365*86400;
+		insert_by_date(commit, &rev_list);
+	}
+
+	return 0;
+}
+
+/*
+  Get the next rev to send, ignoring the common.
+*/
+
+static const unsigned char* get_rev()
+{
+	struct commit *commit = NULL;
+
+	while (commit == NULL) {
+		unsigned int mark;
+
+		if (rev_list == NULL)
+			return NULL;
+
+		commit = rev_list->item;
+
+		if (commit->object.flags & COMMON) {
+			/* do not send "have", and ignore ancestors */
+			commit = NULL;
+			mark = COMMON | SEEN;
+		} else if (commit->object.flags & COMMON_REF)
+			/* send "have", and ignore ancestors */
+			mark = COMMON | SEEN;
+		else
+			/* send "have", also for its ancestors */
+			mark = SEEN;
+
+		pop_most_recent_commit(&rev_list, mark);
+	}
+
+	return commit->object.sha1;
+}
+
+static void mark_common(const unsigned char* sha1)
+{
+	struct object *o = lookup_object(sha1);
+
+	if (o != NULL && !(o->flags & COMMON)) {
+		o->flags |= COMMON;
+		if (o->type == commit_type)
+			insert_by_date((struct commit *)o, &rev_list);
+	}
+}
 
 static int find_common(int fd[2], unsigned char *result_sha1,
 		       struct ref *refs)
 {
 	int fetching;
-	static char line[1000];
-	static char rev_command[1024];
-	int count = 0, flushes = 0, retval, rev_command_len;
-	FILE *revs;
+	int count = 0, flushes = 0, retval;
+	const unsigned char *sha1;
+
+	for_each_ref(rev_list_insert);
 
-	strcpy(rev_command, "git-rev-list $(git-rev-parse --all)");
-	rev_command_len = strlen(rev_command);
 	fetching = 0;
 	for ( ; refs ; refs = refs->next) {
 		unsigned char *remote = refs->old_sha1;
@@ -42,25 +126,17 @@ static int find_common(int fd[2], unsign
 		 */
 		if (((o = lookup_object(remote)) != NULL) &&
 		    (o->flags & COMPLETE)) {
-			struct commit_list *p;
-			struct commit *commit =
-				(struct commit *) (o = deref_tag(o));
-			if (!o)
-				goto repair;
-			if (o->type != commit_type)
-				continue;
-			p = commit->parents;
-			while (p &&
-			       rev_command_len + 44 < sizeof(rev_command)) {
-				snprintf(rev_command + rev_command_len, 44,
-					 " ^%s",
-					 sha1_to_hex(p->item->object.sha1));
-				rev_command_len += 43;
-				p = p->next;
+			o = deref_tag(o);
+			o->flags |= COMMON_REF;
+
+			if (o->type == commit_type && !(o->flags & SEEN)) {
+				o->flags |= SEEN;
+				insert_by_date((struct commit *)o, &rev_list);
 			}
+
 			continue;
 		}
-	repair:
+
 		packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
 		fetching++;
 	}
@@ -68,21 +144,16 @@ static int find_common(int fd[2], unsign
 	if (!fetching)
 		return 1;
 
-	revs = popen(rev_command, "r");
-	if (!revs)
-		die("unable to run 'git-rev-list'");
-
 	flushes = 1;
 	retval = -1;
-	while (fgets(line, sizeof(line), revs) != NULL) {
-		unsigned char sha1[20];
-		if (get_sha1_hex(line, sha1))
-			die("git-fetch-pack: expected object name, got crud");
+	while ((sha1 = get_rev())) {
 		packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
 		if (verbose)
 			fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
 		if (!(31 & ++count)) {
 			packet_flush(fd[1]);
+			if (verbose)
+				fprintf(stderr, "flush\n");
 			flushes++;
 
 			/*
@@ -92,16 +163,17 @@ static int find_common(int fd[2], unsign
 			if (count == 32)
 				continue;
 			if (get_ack(fd[0], result_sha1)) {
+				mark_common(result_sha1);
 				flushes = 0;
 				retval = 0;
 				if (verbose)
-					fprintf(stderr, "got ack\n");
+					fprintf(stderr, "got ack %s\n",
+						sha1_to_hex(result_sha1));
 				break;
 			}
 			flushes--;
 		}
 	}
-	pclose(revs);
 	packet_write(fd[1], "done\n");
 	if (verbose)
 		fprintf(stderr, "done\n");
@@ -109,7 +181,8 @@ static int find_common(int fd[2], unsign
 		flushes--;
 		if (get_ack(fd[0], result_sha1)) {
 			if (verbose)
-				fprintf(stderr, "got ack\n");
+				fprintf(stderr, "got ack %s\n",
+					sha1_to_hex(result_sha1));
 			return 0;
 		}
 	}

^ permalink raw reply related

* Re: LCA2006 Git/Cogito tutorial
From: Dmitry Torokhov @ 2005-10-21  2:37 UTC (permalink / raw)
  To: git; +Cc: Petr Baudis, Martin Langhoff (CatalystIT)
In-Reply-To: <20051021005145.GB30889@pasky.or.cz>

On Thursday 20 October 2005 19:51, Petr Baudis wrote:
> (ii) You say:
> 
>         - Very fast stupid merge
>             ... and very smart, slow merges when stupid won't do
> 

He might be referring to manual merge which is indeed as smart as it gets :)

-- 
Dmitry

^ permalink raw reply

* How to create a new branch based on a tag?
From: Ben Lau @ 2005-10-21 14:57 UTC (permalink / raw)
  To: git

Hi,

   I would like to create a branch of my own work based on a specific 
kernel version(i.e
v2.6.11). I tried with:

 > git-branch my2.6.11 v2.6.11
error: Object 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c is a tree, not a 
commit
fatal: Needed a single revision

  As v2.6.11 is a tree object(tag), git-checkout and git-branch could 
not process it. The
only way I know is using git-read-tree to fetch v2.6.11 content into 
current index and start
a branch based on it. Is there any simpler method?

Thanks!

^ permalink raw reply

* Re: LCA2006 Git/Cogito tutorial
From: Martin Langhoff (CatalystIT) @ 2005-10-21  2:59 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: git, Petr Baudis
In-Reply-To: <200510202137.22311.dtor_core@ameritech.net>

Dmitry Torokhov wrote:
> On Thursday 20 October 2005 19:51, Petr Baudis wrote:
> 
>>(ii) You say:
>>
>>        - Very fast stupid merge
>>            ... and very smart, slow merges when stupid won't do
> 
> He might be referring to manual merge which is indeed as smart as it gets :)

Almost. No, truly, I'm very impressed with git-merge.sh, which first 
does the simple git-read-tree -m, and it can then try several merger 
scripts to resolve the index. The "smartest" merge resolver we have 
follows renames, but we could have language-specific and 
project-specific resolvers, for instance.

If you combine the coolness of git-merge.sh with the fact that cg-merge 
right now is buggy[*]... I'm starting to rely on doing cg-fetch and 
running git-merge.sh by hand.

* I just merged your latest fixes, knowing that they'd conflict on 
cg-fetch, but the merge didn't say a thing a bout cg-fetch, and only 
complained like this:

    MERGE ERROR: : Not handling case  ->  ->

But there were no conflicts at all in the tree! It seems to be that it's 
dropping the upstream changes it doesn't like.

cheers,


martin
-- 
-----------------------------------------------------------------------
Martin @ Catalyst .Net .NZ  Ltd, PO Box 11-053, Manners St,  Wellington
WEB: http://catalyst.net.nz/           PHYS: Level 2, 150-154 Willis St
OFFICE: +64(4)916-7224                              MOB: +64(21)364-017
       Make things as simple as possible, but no simpler - Einstein
-----------------------------------------------------------------------

^ permalink raw reply

* Re: LCA2006 Git/Cogito tutorial
From: Martin Langhoff (CatalystIT) @ 2005-10-21  3:02 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20051021005145.GB30889@pasky.or.cz>

Petr Baudis wrote:

> Dear diary, on Mon, Oct 17, 2005 at 02:48:09AM CEST, I got a letter
> where "Martin Langhoff (CatalystIT)" <martin@catalyst.net.nz> told me that...
> 
>>Petr Baudis hinted earlier that he might be coming, as did Linus (but
>>he was hoping for a sponsor, I'm not sure whether he'll be there or
>>not). Speak up if you'll be there!
> 
> 
> I'm sorry but I will not be there - it is too far away from my little
> country. :-(

Sad to hear that. I'll be soon in Europe, though, but not in CZ, 
unfortunately!

> (i) You might want to say "cg-export" instead of "git-tar-tree" (*shrug*)

You're right! I hadn't seen that.

> (ii) You say:
> 
> 	- Very fast stupid merge
> 	    ... and very smart, slow merges when stupid won't do
> 
>   What are you explicitly referring to? I don't think any kind of merge
> in GIT (unless something totally missed me) can be called "very smart".
> If it's a three-way merge, it's never "very smart".

See latest developments on git-merge.sh -- we should really revamp 
cg-merge ;)

> 	vim .gitignore

Then it'd be a bug, not a feature ;)

>>ps: lately, about 30% of my emails to git@vger from gmail have been 
>>dropped on the floor. This is starting to get annoying, is anyone seeing 
>>similar issues?
> 
> 
> Not me. Perhaps I'm in some VIP class. :^)

Oh, I figured that out! Gmail's "utf-8" mode encodes everything in 
base64. Awful sh*t. Reverted to ascii and life is good.



martin
-- 
-----------------------------------------------------------------------
Martin @ Catalyst .Net .NZ  Ltd, PO Box 11-053, Manners St,  Wellington
WEB: http://catalyst.net.nz/           PHYS: Level 2, 150-154 Willis St
OFFICE: +64(4)916-7224                              MOB: +64(21)364-017
       Make things as simple as possible, but no simpler - Einstein
-----------------------------------------------------------------------

^ permalink raw reply

* Re: How do I clear the directory cache
From: eschvoca @ 2005-10-21  3:23 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20051020085931.GW30889@pasky.or.cz>

Yes, "cg-reset --adds-removals" is what I want (how do I do this with
pure git?).

I would like to clear/reset the index because I've screwed it all up. 
I don't think I can do as you suggested because of the way I got into
this mess.

I'm using git/cogito to version control my hard drive and I've been
gradually adding more entries into the .gitignore file because some
files change too frequently or I don't want them backed up.  The OS
modified a bunch of files, I cg-rm'd 1/4 of them, then I changed my
mind and added them back, also did some genuine cg-adds, etc. and now
I'm all confused (it's a whole hard drive).  If other people are
interested in doing this I can pass on the lessons I learned.

What I found it git is amazingly fast!  cg-status only takes a few
seconds.  I think there are some problems if you try to do:

cd /
cg-add -r usr
cg-commit -m "take a long break"

It seems that cg-add-ing and cg-commit-ing smaller chunks is faster
than one big chunk.

I think commands for the following should be added to cogito:

cg-status -<status_flag>  # list files with given status flag (without
status flag in column 1)
  git-ls-files [--others|--deleted|etc] --exclude-per-directory=/.gitignore

cg-add [-r] -<status_flag> # add files with a given status flag
  git-ls-files [--others|--deleted|etc]
--exclude-per-directory=/.gitignore | while read i; do cg-add "$i;
done

cg-rm [-r] -<status_flag> # you get the idea.

cg-addremove  # recursively add new files, remove deleted files

I use "while read i" so it will work with spaces in filenames.

^ permalink raw reply

* Re: How to create a new branch based on a tag?
From: Martin Langhoff @ 2005-10-21  3:37 UTC (permalink / raw)
  To: Ben Lau; +Cc: git
In-Reply-To: <435901F7.9020509@ust.hk>

On 10/22/05, Ben Lau <benlau@ust.hk> wrote:
> Hi,
>
>    I would like to create a branch of my own work based on a specific
> kernel version(i.e
> v2.6.11). I tried with:
>
>  > git-branch my2.6.11 v2.6.11
> error: Object 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c is a tree, not a
> commit
> fatal: Needed a single revision

What you're after is

   git-rev-parse --verify <tagname>^0  > .refs/heads/mynewbranch

"branches" are very lightweight -- it's a ref containing the SHA1 of
the commit you want it to be at. So if you find the SHA1 of the commit
in gitk or wherever, just

  echo SHA1 > .refs/heads/mynewbranch

and you're sorted. Do git-checkout to switch to it.

cheers,


martin

^ permalink raw reply

* Re: How to create a new branch based on a tag?
From: Junio C Hamano @ 2005-10-21  3:50 UTC (permalink / raw)
  To: Ben Lau; +Cc: git
In-Reply-To: <435901F7.9020509@ust.hk>

Ben Lau <benlau@ust.hk> writes:

> As v2.6.11 is a tree object(tag), git-checkout and git-branch could 
> not process it. The
> only way I know is using git-read-tree to fetch v2.6.11 content into 
> current index and start
> a branch based on it. Is there any simpler method?

The way you know is as good as it gets.  v2.6.11-tree case is
really an unfortunate special case.

^ permalink raw reply

* Split up tree diff functions into tree-diff.c library
From: Linus Torvalds @ 2005-10-21  4:05 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This makes the tree diff functionality independent of the "git-diff-tree" 
program, by splitting the core functionality up into a library file.

This will be needed for when we teach git-rev-list to only follow a 
specified set of pathnames, rather than the global revision history.

Most of it is a fairly straightforward code move, but it also involves 
some calling convention cleanup, and moving some of the static variables 
from diff-tree.c into the options structure.

The actual tree change callback routines also become paramterized by the 
diff_options structure, allowing the library functionality to do something 
else than just show the diff on stdout.

Right now the only user of this functionality remains git-diff-tree 
itself.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

NOTE! I think I did everything right, and things still seem to work, but 
this is worth having a few people look at more closely. git-diff-tree is 
some pretty damn core functionality.

The next email will contain a first cut at changing git-rev-list to take 
advantage of the new library interface.


diff --git a/Makefile b/Makefile
index 5ee72bc..95f8c57 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ LIB_H = \
 
 DIFF_OBJS = \
 	diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
-	diffcore-pickaxe.o diffcore-rename.o
+	diffcore-pickaxe.o diffcore-rename.o tree-diff.o
 
 LIB_OBJS = \
 	blob.o commit.o connect.o count-delta.o csum-file.o \
diff --git a/diff-tree.c b/diff-tree.c
index 8517220..382011a 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -5,256 +5,13 @@
 static int show_root_diff = 0;
 static int verbose_header = 0;
 static int ignore_merges = 1;
-static int recursive = 0;
-static int show_tree_entry_in_recursive = 0;
 static int read_stdin = 0;
 
-static struct diff_options diff_options;
-
 static const char *header = NULL;
 static const char *header_prefix = "";
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
 
-// What paths are we interested in?
-static int nr_paths = 0;
-static const char **paths = NULL;
-static int *pathlens = NULL;
-
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
-
-static void update_tree_entry(void **bufp, unsigned long *sizep)
-{
-	void *buf = *bufp;
-	unsigned long size = *sizep;
-	int len = strlen(buf) + 1 + 20;
-
-	if (size < len)
-		die("corrupt tree file");
-	*bufp = buf + len;
-	*sizep = size - len;
-}
-
-static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep)
-{
-	int len = strlen(tree)+1;
-	const unsigned char *sha1 = tree + len;
-	const char *path = strchr(tree, ' ');
-	unsigned int mode;
-
-	if (!path || size < len + 20 || sscanf(tree, "%o", &mode) != 1)
-		die("corrupt tree file");
-	*pathp = path+1;
-	*modep = DIFF_FILE_CANON_MODE(mode);
-	return sha1;
-}
-
-static char *malloc_base(const char *base, const char *path, int pathlen)
-{
-	int baselen = strlen(base);
-	char *newbase = xmalloc(baselen + pathlen + 2);
-	memcpy(newbase, base, baselen);
-	memcpy(newbase + baselen, path, pathlen);
-	memcpy(newbase + baselen + pathlen, "/", 2);
-	return newbase;
-}
-
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base);
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base);
-
-/* A file entry went away or appeared */
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
-{
-	unsigned mode;
-	const char *path;
-	const unsigned char *sha1 = extract(tree, size, &path, &mode);
-
-	if (recursive && S_ISDIR(mode)) {
-		char type[20];
-		unsigned long size;
-		char *newbase = malloc_base(base, path, strlen(path));
-		void *tree;
-
-		tree = read_sha1_file(sha1, type, &size);
-		if (!tree || strcmp(type, "tree"))
-			die("corrupt tree sha %s", sha1_to_hex(sha1));
-
-		show_tree(prefix, tree, size, newbase);
-
-		free(tree);
-		free(newbase);
-		return;
-	}
-
-	diff_addremove(&diff_options, prefix[0], mode, sha1, base, path);
-}
-
-static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
-{
-	unsigned mode1, mode2;
-	const char *path1, *path2;
-	const unsigned char *sha1, *sha2;
-	int cmp, pathlen1, pathlen2;
-
-	sha1 = extract(tree1, size1, &path1, &mode1);
-	sha2 = extract(tree2, size2, &path2, &mode2);
-
-	pathlen1 = strlen(path1);
-	pathlen2 = strlen(path2);
-	cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
-	if (cmp < 0) {
-		show_file("-", tree1, size1, base);
-		return -1;
-	}
-	if (cmp > 0) {
-		show_file("+", tree2, size2, base);
-		return 1;
-	}
-	if (!diff_options.find_copies_harder &&
-	    !memcmp(sha1, sha2, 20) && mode1 == mode2)
-		return 0;
-
-	/*
-	 * If the filemode has changed to/from a directory from/to a regular
-	 * file, we need to consider it a remove and an add.
-	 */
-	if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-		show_file("-", tree1, size1, base);
-		show_file("+", tree2, size2, base);
-		return 0;
-	}
-
-	if (recursive && S_ISDIR(mode1)) {
-		int retval;
-		char *newbase = malloc_base(base, path1, pathlen1);
-		if (show_tree_entry_in_recursive)
-			diff_change(&diff_options, mode1, mode2,
-				    sha1, sha2, base, path1);
-		retval = diff_tree_sha1(sha1, sha2, newbase);
-		free(newbase);
-		return retval;
-	}
-
-	diff_change(&diff_options, mode1, mode2, sha1, sha2, base, path1);
-	return 0;
-}
-
-static int interesting(void *tree, unsigned long size, const char *base)
-{
-	const char *path;
-	unsigned mode;
-	int i;
-	int baselen, pathlen;
-
-	if (!nr_paths)
-		return 1;
-
-	(void)extract(tree, size, &path, &mode);
-
-	pathlen = strlen(path);
-	baselen = strlen(base);
-
-	for (i=0; i < nr_paths; i++) {
-		const char *match = paths[i];
-		int matchlen = pathlens[i];
-
-		if (baselen >= matchlen) {
-			/* If it doesn't match, move along... */
-			if (strncmp(base, match, matchlen))
-				continue;
-
-			/* The base is a subdirectory of a path which was specified. */
-			return 1;
-		}
-
-		/* Does the base match? */
-		if (strncmp(base, match, baselen))
-			continue;
-
-		match += baselen;
-		matchlen -= baselen;
-
-		if (pathlen > matchlen)
-			continue;
-
-		if (matchlen > pathlen) {
-			if (match[pathlen] != '/')
-				continue;
-			if (!S_ISDIR(mode))
-				continue;
-		}
-
-		if (strncmp(path, match, pathlen))
-			continue;
-
-		return 1;
-	}
-	return 0; /* No matches */
-}
-
-/* A whole sub-tree went away or appeared */
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base)
-{
-	while (size) {
-		if (interesting(tree, size, base))
-			show_file(prefix, tree, size, base);
-		update_tree_entry(&tree, &size);
-	}
-}
-
-static int diff_tree(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
-{
-	while (size1 | size2) {
-		if (nr_paths && size1 && !interesting(tree1, size1, base)) {
-			update_tree_entry(&tree1, &size1);
-			continue;
-		}
-		if (nr_paths && size2 && !interesting(tree2, size2, base)) {
-			update_tree_entry(&tree2, &size2);
-			continue;
-		}
-		if (!size1) {
-			show_file("+", tree2, size2, base);
-			update_tree_entry(&tree2, &size2);
-			continue;
-		}
-		if (!size2) {
-			show_file("-", tree1, size1, base);
-			update_tree_entry(&tree1, &size1);
-			continue;
-		}
-		switch (compare_tree_entry(tree1, size1, tree2, size2, base)) {
-		case -1:
-			update_tree_entry(&tree1, &size1);
-			continue;
-		case 0:
-			update_tree_entry(&tree1, &size1);
-			/* Fallthrough */
-		case 1:
-			update_tree_entry(&tree2, &size2);
-			continue;
-		}
-		die("git-diff-tree: internal error");
-	}
-	return 0;
-}
-
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base)
-{
-	void *tree1, *tree2;
-	unsigned long size1, size2;
-	int retval;
-
-	tree1 = read_object_with_reference(old, "tree", &size1, NULL);
-	if (!tree1)
-		die("unable to read source tree (%s)", sha1_to_hex(old));
-	tree2 = read_object_with_reference(new, "tree", &size2, NULL);
-	if (!tree2)
-		die("unable to read destination tree (%s)", sha1_to_hex(new));
-	retval = diff_tree(tree1, size1, tree2, size2, base);
-	free(tree1);
-	free(tree2);
-	return retval;
-}
+static struct diff_options diff_options;
 
 static void call_diff_setup_done(void)
 {
@@ -285,7 +42,7 @@ static int diff_tree_sha1_top(const unsi
 	int ret;
 
 	call_diff_setup_done();
-	ret = diff_tree_sha1(old, new, base);
+	ret = diff_tree_sha1(old, new, base, &diff_options);
 	call_diff_flush();
 	return ret;
 }
@@ -294,13 +51,17 @@ static int diff_root_tree(const unsigned
 {
 	int retval;
 	void *tree;
-	unsigned long size;
+	struct tree_desc empty, real;
 
 	call_diff_setup_done();
-	tree = read_object_with_reference(new, "tree", &size, NULL);
+	tree = read_object_with_reference(new, "tree", &real.size, NULL);
 	if (!tree)
 		die("unable to read root tree (%s)", sha1_to_hex(new));
-	retval = diff_tree("", 0, tree, size, base);
+	real.buf = tree;
+
+	empty.buf = "";
+	empty.size = 0;
+	retval = diff_tree(&empty, &real, base, &diff_options);
 	free(tree);
 	call_diff_flush();
 	return retval;
@@ -387,14 +148,6 @@ static int diff_tree_stdin(char *line)
 	return diff_tree_commit(commit, line);
 }
 
-static int count_paths(const char **paths)
-{
-	int i = 0;
-	while (*paths++)
-		i++;
-	return i;
-}
-
 static const char diff_tree_usage[] =
 "git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] "
 "[<common diff options>] <tree-ish> <tree-ish>"
@@ -445,11 +198,12 @@ int main(int argc, const char **argv)
 			break;
 		}
 		if (!strcmp(arg, "-r")) {
-			recursive = 1;
+			diff_options.recursive = 1;
 			continue;
 		}
 		if (!strcmp(arg, "-t")) {
-			recursive = show_tree_entry_in_recursive = 1;
+			diff_options.recursive = 1;
+			diff_options.tree_in_recursive = 1;
 			continue;
 		}
 		if (!strcmp(arg, "-m")) {
@@ -478,17 +232,9 @@ int main(int argc, const char **argv)
 		usage(diff_tree_usage);
 	}
 	if (diff_options.output_format == DIFF_FORMAT_PATCH)
-		recursive = 1;
+		diff_options.recursive = 1;
 
-	paths = get_pathspec(prefix, argv);
-	if (paths) {
-		int i;
-
-		nr_paths = count_paths(paths);
-		pathlens = xmalloc(nr_paths * sizeof(int));
-		for (i=0; i<nr_paths; i++)
-			pathlens[i] = strlen(paths[i]);
-	}
+	diff_tree_setup_paths(get_pathspec(prefix, argv));
 
 	switch (nr_sha1) {
 	case 0:
diff --git a/diff.c b/diff.c
index 306bcd9..ec94a96 100644
--- a/diff.c
+++ b/diff.c
@@ -754,6 +754,9 @@ void diff_setup(struct diff_options *opt
 	options->line_termination = '\n';
 	options->break_opt = -1;
 	options->rename_limit = -1;
+
+	options->change = diff_change;
+	options->add_remove = diff_addremove;
 }
 
 int diff_setup_done(struct diff_options *options)
diff --git a/diff.h b/diff.h
index 2f4a7b4..5115547 100644
--- a/diff.h
+++ b/diff.h
@@ -8,11 +8,31 @@
 	(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
 	S_ISLNK(mode) ? S_IFLNK : S_IFDIR)
 
+struct tree_desc {
+	void *buf;
+	unsigned long size;
+};
+
+struct diff_options;
+
+typedef void (*change_fn_t)(struct diff_options *options,
+		 unsigned old_mode, unsigned new_mode,
+		 const unsigned char *old_sha1,
+		 const unsigned char *new_sha1,
+		 const char *base, const char *path);
+
+typedef void (*add_remove_fn_t)(struct diff_options *options,
+		    int addremove, unsigned mode,
+		    const unsigned char *sha1,
+		    const char *base, const char *path);
+
 struct diff_options {
 	const char **paths;
 	const char *filter;
 	const char *orderfile;
 	const char *pickaxe;
+	unsigned recursive:1,
+		 tree_in_recursive:1;
 	int break_opt;
 	int detect_rename;
 	int find_copies_harder;
@@ -23,8 +43,17 @@ struct diff_options {
 	int reverse_diff;
 	int rename_limit;
 	int setup;
+
+	change_fn_t change;
+	add_remove_fn_t add_remove;
 };
 
+extern void diff_tree_setup_paths(const char **paths);
+extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
+		     const char *base, struct diff_options *opt);
+extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
+			  const char *base, struct diff_options *opt);
+
 extern void diff_addremove(struct diff_options *,
 			   int addremove,
 			   unsigned mode,
diff --git a/tree-diff.c b/tree-diff.c
new file mode 100644
index 0000000..0ef06a9
--- /dev/null
+++ b/tree-diff.c
@@ -0,0 +1,270 @@
+/*
+ * Helper functions for tree diff generation
+ */
+#include "cache.h"
+#include "diff.h"
+
+// What paths are we interested in?
+static int nr_paths = 0;
+static const char **paths = NULL;
+static int *pathlens = NULL;
+
+static void update_tree_entry(struct tree_desc *desc)
+{
+	void *buf = desc->buf;
+	unsigned long size = desc->size;
+	int len = strlen(buf) + 1 + 20;
+
+	if (size < len)
+		die("corrupt tree file");
+	desc->buf = buf + len;
+	desc->size = size - len;
+}
+
+static const unsigned char *extract(struct tree_desc *desc, const char **pathp, unsigned int *modep)
+{
+	void *tree = desc->buf;
+	unsigned long size = desc->size;
+	int len = strlen(tree)+1;
+	const unsigned char *sha1 = tree + len;
+	const char *path = strchr(tree, ' ');
+	unsigned int mode;
+
+	if (!path || size < len + 20 || sscanf(tree, "%o", &mode) != 1)
+		die("corrupt tree file");
+	*pathp = path+1;
+	*modep = DIFF_FILE_CANON_MODE(mode);
+	return sha1;
+}
+
+static char *malloc_base(const char *base, const char *path, int pathlen)
+{
+	int baselen = strlen(base);
+	char *newbase = xmalloc(baselen + pathlen + 2);
+	memcpy(newbase, base, baselen);
+	memcpy(newbase + baselen, path, pathlen);
+	memcpy(newbase + baselen + pathlen, "/", 2);
+	return newbase;
+}
+
+static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base);
+
+static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+{
+	unsigned mode1, mode2;
+	const char *path1, *path2;
+	const unsigned char *sha1, *sha2;
+	int cmp, pathlen1, pathlen2;
+
+	sha1 = extract(t1, &path1, &mode1);
+	sha2 = extract(t2, &path2, &mode2);
+
+	pathlen1 = strlen(path1);
+	pathlen2 = strlen(path2);
+	cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
+	if (cmp < 0) {
+		show_entry(opt, "-", t1, base);
+		return -1;
+	}
+	if (cmp > 0) {
+		show_entry(opt, "+", t2, base);
+		return 1;
+	}
+	if (!opt->find_copies_harder &&
+	    !memcmp(sha1, sha2, 20) && mode1 == mode2)
+		return 0;
+
+	/*
+	 * If the filemode has changed to/from a directory from/to a regular
+	 * file, we need to consider it a remove and an add.
+	 */
+	if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
+		show_entry(opt, "-", t1, base);
+		show_entry(opt, "+", t2, base);
+		return 0;
+	}
+
+	if (opt->recursive && S_ISDIR(mode1)) {
+		int retval;
+		char *newbase = malloc_base(base, path1, pathlen1);
+		if (opt->tree_in_recursive)
+			opt->change(opt, mode1, mode2,
+				    sha1, sha2, base, path1);
+		retval = diff_tree_sha1(sha1, sha2, newbase, opt);
+		free(newbase);
+		return retval;
+	}
+
+	opt->change(opt, mode1, mode2, sha1, sha2, base, path1);
+	return 0;
+}
+
+static int interesting(struct tree_desc *desc, const char *base)
+{
+	const char *path;
+	unsigned mode;
+	int i;
+	int baselen, pathlen;
+
+	if (!nr_paths)
+		return 1;
+
+	(void)extract(desc, &path, &mode);
+
+	pathlen = strlen(path);
+	baselen = strlen(base);
+
+	for (i=0; i < nr_paths; i++) {
+		const char *match = paths[i];
+		int matchlen = pathlens[i];
+
+		if (baselen >= matchlen) {
+			/* If it doesn't match, move along... */
+			if (strncmp(base, match, matchlen))
+				continue;
+
+			/* The base is a subdirectory of a path which was specified. */
+			return 1;
+		}
+
+		/* Does the base match? */
+		if (strncmp(base, match, baselen))
+			continue;
+
+		match += baselen;
+		matchlen -= baselen;
+
+		if (pathlen > matchlen)
+			continue;
+
+		if (matchlen > pathlen) {
+			if (match[pathlen] != '/')
+				continue;
+			if (!S_ISDIR(mode))
+				continue;
+		}
+
+		if (strncmp(path, match, pathlen))
+			continue;
+
+		return 1;
+	}
+	return 0; /* No matches */
+}
+
+/* A whole sub-tree went away or appeared */
+static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base)
+{
+	while (desc->size) {
+		if (interesting(desc, base))
+			show_entry(opt, prefix, desc, base);
+		update_tree_entry(desc);
+	}
+}
+
+/* A file entry went away or appeared */
+static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base)
+{
+	unsigned mode;
+	const char *path;
+	const unsigned char *sha1 = extract(desc, &path, &mode);
+
+	if (opt->recursive && S_ISDIR(mode)) {
+		char type[20];
+		char *newbase = malloc_base(base, path, strlen(path));
+		struct tree_desc inner;
+		void *tree;
+
+		tree = read_sha1_file(sha1, type, &inner.size);
+		if (!tree || strcmp(type, "tree"))
+			die("corrupt tree sha %s", sha1_to_hex(sha1));
+
+		inner.buf = tree;
+		show_tree(opt, prefix, &inner, newbase);
+
+		free(tree);
+		free(newbase);
+		return 0;
+	}
+
+	opt->add_remove(opt, prefix[0], mode, sha1, base, path);
+	return 0;
+}
+
+int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+{
+	while (t1->size | t2->size) {
+		if (nr_paths && t1->size && !interesting(t1, base)) {
+			update_tree_entry(t1);
+			continue;
+		}
+		if (nr_paths && t2->size && !interesting(t2, base)) {
+			update_tree_entry(t2);
+			continue;
+		}
+		if (!t1->size) {
+			show_entry(opt, "+", t2, base);
+			update_tree_entry(t2);
+			continue;
+		}
+		if (!t2->size) {
+			show_entry(opt, "-", t1, base);
+			update_tree_entry(t1);
+			continue;
+		}
+		switch (compare_tree_entry(t1, t2, base, opt)) {
+		case -1:
+			update_tree_entry(t1);
+			continue;
+		case 0:
+			update_tree_entry(t1);
+			/* Fallthrough */
+		case 1:
+			update_tree_entry(t2);
+			continue;
+		}
+		die("git-diff-tree: internal error");
+	}
+	return 0;
+}
+
+int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
+{
+	void *tree1, *tree2;
+	struct tree_desc t1, t2;
+	int retval;
+
+	tree1 = read_object_with_reference(old, "tree", &t1.size, NULL);
+	if (!tree1)
+		die("unable to read source tree (%s)", sha1_to_hex(old));
+	tree2 = read_object_with_reference(new, "tree", &t2.size, NULL);
+	if (!tree2)
+		die("unable to read destination tree (%s)", sha1_to_hex(new));
+	t1.buf = tree1;
+	t2.buf = tree2;
+	retval = diff_tree(&t1, &t2, base, opt);
+	free(tree1);
+	free(tree2);
+	return retval;
+}
+
+static int count_paths(const char **paths)
+{
+	int i = 0;
+	while (*paths++)
+		i++;
+	return i;
+}
+
+void diff_tree_setup_paths(const char **p)
+{
+	if (p) {
+		int i;
+
+		paths = p;
+		nr_paths = count_paths(paths);
+		pathlens = xmalloc(nr_paths * sizeof(int));
+		for (i=0; i<nr_paths; i++)
+			pathlens[i] = strlen(paths[i]);
+	}
+}

^ permalink raw reply related

* Re: How do I clear the directory cache
From: Junio C Hamano @ 2005-10-21  4:09 UTC (permalink / raw)
  To: eschvoca; +Cc: git
In-Reply-To: <2b05065b0510202023i62ab7c03uea1381d76535dcc7@mail.gmail.com>

eschvoca <eschvoca@gmail.com> writes:

> Yes, ... is what I want (how do I do this with pure git?).

How do you do *what* with pure git is something not clear to me,
so let me try to rephrase you and see if I understood what you
want correctly, in pure git terms:

 0. Your last commit (.git/HEAD), your index file (.git/index)
    and the files in your working tree are in sync to begin
    with.

 1. Then you do random changes in the working tree (add, modify,
    remove) and do git-update-index on them without making a
    commit.  If your index file is fully in sync with your
    working tree, git-diff-files would say nothing after this.
    If you did git-update-index on some but not all, then
    git-diff-files would report unrecorded changes.

 2. But you want to revert these changes to the index file.  By
    "clearing the directory cache", you mean you want the index
    file to have what it had in step 0, but you want to keep
    what is on the filesystem intact.

If that is what you want, then:

	$ git-read-tree HEAD
        $ git-update-index --refresh >/dev/null

would reset the index to the tree recorded in your last commit.
You can see that

	$ git diff --name-status --cached HEAD

does not report any difference between HEAD and your index, while

	$ git diff --name-status

shows the differences between your index and your working tree.

HOWEVER, the index file does not record "intent to add", so you
would not see files you added in step 1. mentioned in the output
of the last command.

^ permalink raw reply

* Re: How to create a new branch based on a tag?
From: Ben Lau @ 2005-10-21 16:15 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git
In-Reply-To: <46a038f90510202037l7dd40271qcc0634295e092068@mail.gmail.com>

Martin Langhoff wrote:

>On 10/22/05, Ben Lau <benlau@ust.hk> wrote:
>  
>
>>Hi,
>>
>>   I would like to create a branch of my own work based on a specific
>>kernel version(i.e
>>v2.6.11). I tried with:
>>
>> > git-branch my2.6.11 v2.6.11
>>error: Object 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c is a tree, not a
>>commit
>>fatal: Needed a single revision
>>    
>>
>
>What you're after is
>
>   git-rev-parse --verify <tagname>^0  > .refs/heads/mynewbranch
>
>"branches" are very lightweight -- it's a ref containing the SHA1 of
>the commit you want it to be at. So if you find the SHA1 of the commit
>in gitk or wherever, just
>
>  echo SHA1 > .refs/heads/mynewbranch
>
>and you're sorted. Do git-checkout to switch to it.
>
>cheers,
>
>
>martin
>  
>
The command complains:

   >git-rev-parse --verify v2.6.11^
   error: Object 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c is a tree, not 
a commit
   fatal: Needed a single revision

I think it need another way to convert a tag/tree object into a commit ?

^ permalink raw reply

* git-rev-parse: one more fix for "--"
From: Linus Torvalds @ 2005-10-21  4:17 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


My previous "--" fixup case missed one case: it would print any default 
revision after the "--" rather than before.

Trivially fixed.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Gaah. If you haven't applied the previous patch yet, just combine the two 
diffs into one.

diff --git a/rev-parse.c b/rev-parse.c
index 9ae2512..243f89f 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -174,6 +174,7 @@ int main(int argc, char **argv)
 		if (*arg == '-') {
 			if (!strcmp(arg, "--")) {
 				as_is = 1;
+				show_default();
 				/* Pass on the "--" if we show anything but files.. */
 				if (filter & (DO_FLAGS | DO_REVS))
 					show_file(arg);

^ permalink raw reply related

* Re: How to create a new branch based on a tag?
From: Ben Lau @ 2005-10-21 16:23 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vsluv5y0p.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

>Ben Lau <benlau@ust.hk> writes:
>
>  
>
>>As v2.6.11 is a tree object(tag), git-checkout and git-branch could 
>>not process it. The
>>only way I know is using git-read-tree to fetch v2.6.11 content into 
>>current index and start
>>a branch based on it. Is there any simpler method?
>>    
>>
>
>The way you know is as good as it gets.  v2.6.11-tree case is
>really an unfortunate special case.
>
>  
>
What is wrong with the v2.6.11-tree? I just thought it is a duplicate tag
of v2.6.11.

^ permalink raw reply

* Teach git-rev-list to follow just a specified set of files
From: Linus Torvalds @ 2005-10-21  4:25 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This is the first cut at a git-rev-list that knows to ignore commits that 
don't change a certain file (or set of files).

NOTE! For now it only prunes _merge_ commits, and follows the parent where 
there are no differences in the set of files specified. In the long run, 
I'd like to make it re-write the straight-line history too, but for now 
the merge simplification is much more fundamentally important (the 
rewriting of straight-line history is largely a separate simplification 
phase, but the merge simplification needs to happen early if we want to 
optimize away unnecessary commit parsing).

If all parents of a merge change some of the files, the merge is left as 
is, so the end result is in no way guaranteed to be a linear history, but 
it will often be a lot /more/ linear than the full tree, since it prunes 
out parents that didn't matter for that set of files.

As an example from the current kernel:

	[torvalds@g5 linux]$ git-rev-list HEAD | wc -l
	9885
	[torvalds@g5 linux]$ git-rev-list HEAD -- Makefile | wc -l
	4084
	[torvalds@g5 linux]$ git-rev-list HEAD -- drivers/usb | wc -l
	5206

and you can also use 'gitk' to more visually see the pruning of the 
history tree, with something like

	gitk -- drivers/usb

showing a simplified history that tries to follow the first parent in a 
merge that is the parent that fully defines drivers/usb/.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

This should make it much more efficient to do something like a 
git-annotate. The merges are the expensive part. Normal straigh-line 
commits that don't change something is pretty easy.

NOTE! For that "gitk" command line to work, you need to have applied both 
of my rev-list.c patches from earlier today..

NOTE 2! At least for now, git-rev-list requires the "--" between the revs 
and the filenames. That's actually very inconsistent: all the other git 
tools that take filenames will just assume that something that isn't a rev 
and isn't a flag must be a filename.

I'd actually like to make git-rev-list work that way too (it would make 
the syntax for gitk etc much more natural), but I chickened out 
(git-rev-list used to error out when it didn't recognize a rev, and this 
ugly syntax keeps that as an error case. Whether it's for a good reason or 
not, I don't know).

NOTE 3! I've tested this, and it all _seems_ to work. But hey, this is 
even more "core" than git-diff-tree, so buyer beware!

diff --git a/rev-list.c b/rev-list.c
index 3a32e40..b5dbb9f 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -5,6 +5,7 @@
 #include "tree.h"
 #include "blob.h"
 #include "epoch.h"
+#include "diff.h"
 
 #define SEEN		(1u << 0)
 #define INTERESTING	(1u << 1)
@@ -44,6 +45,7 @@ static int show_breaks = 0;
 static int stop_traversal = 0;
 static int topo_order = 0;
 static int no_merges = 0;
+static const char **paths = NULL;
 
 static void show_commit(struct commit *commit)
 {
@@ -377,18 +379,129 @@ static void mark_edges_uninteresting(str
 	}
 }
 
+static int is_different = 0;
+
+static void file_add_remove(struct diff_options *options,
+		    int addremove, unsigned mode,
+		    const unsigned char *sha1,
+		    const char *base, const char *path)
+{
+	is_different = 1;
+}
+
+static void file_change(struct diff_options *options,
+		 unsigned old_mode, unsigned new_mode,
+		 const unsigned char *old_sha1,
+		 const unsigned char *new_sha1,
+		 const char *base, const char *path)
+{
+	is_different = 1;
+}
+
+static struct diff_options diff_opt = {
+	.recursive = 1,
+	.add_remove = file_add_remove,
+	.change = file_change,
+};
+
+static struct commit *try_to_simplify_merge(struct commit *commit, struct commit_list *parent)
+{
+	if (!commit->tree)
+		return NULL;
+
+	while (parent) {
+		struct commit *p = parent->item;
+		parent = parent->next;
+		parse_commit(p);
+		if (!p->tree)
+			continue;
+		is_different = 0;
+		if (diff_tree_sha1(commit->tree->object.sha1,
+				   p->tree->object.sha1, "", &diff_opt) < 0)
+			continue;
+		if (!is_different)
+			return p;
+	}
+	return NULL;
+}
+
+static void add_parents_to_list(struct commit *commit, struct commit_list **list)
+{
+	struct commit_list *parent = commit->parents;
+
+	/*
+	 * If the commit is uninteresting, don't try to
+	 * prune parents - we want the maximal uninteresting
+	 * set.
+	 *
+	 * Normally we haven't parsed the parent
+	 * yet, so we won't have a parent of a parent
+	 * here. However, it may turn out that we've
+	 * reached this commit some other way (where it
+	 * wasn't uninteresting), in which case we need
+	 * to mark its parents recursively too..
+	 */
+	if (commit->object.flags & UNINTERESTING) {
+		while (parent) {
+			struct commit *p = parent->item;
+			parent = parent->next;
+			parse_commit(p);
+			p->object.flags |= UNINTERESTING;
+			if (p->parents)
+				mark_parents_uninteresting(p);
+			if (p->object.flags & SEEN)
+				continue;
+			p->object.flags |= SEEN;
+			insert_by_date(p, list);
+		}
+		return;
+	}
+
+	/*
+	 * Ok, the commit wasn't uninteresting. If it
+	 * is a merge, try to find the parent that has
+	 * no differences in the path set if one exists.
+	 */
+	if (paths && parent && parent->next) {
+		struct commit *preferred;
+
+		preferred = try_to_simplify_merge(commit, parent);
+		if (preferred) {
+			parent->item = preferred;
+			parent->next = NULL;
+		}
+	}
+
+	while (parent) {
+		struct commit *p = parent->item;
+
+		parent = parent->next;
+
+		parse_commit(p);
+		if (p->object.flags & SEEN)
+			continue;
+		p->object.flags |= SEEN;
+		insert_by_date(p, list);
+	}
+}
+
 static struct commit_list *limit_list(struct commit_list *list)
 {
 	struct commit_list *newlist = NULL;
 	struct commit_list **p = &newlist;
 	while (list) {
-		struct commit *commit = pop_most_recent_commit(&list, SEEN);
+		struct commit_list *entry = list;
+		struct commit *commit = list->item;
 		struct object *obj = &commit->object;
 
+		list = list->next;
+		free(entry);
+
 		if (max_age != -1 && (commit->date < max_age))
 			obj->flags |= UNINTERESTING;
 		if (unpacked && has_sha1_pack(obj->sha1))
 			obj->flags |= UNINTERESTING;
+		add_parents_to_list(commit, &list);
 		if (obj->flags & UNINTERESTING) {
 			mark_parents_uninteresting(commit);
 			if (everybody_uninteresting(list))
@@ -507,15 +620,15 @@ static void handle_all(struct commit_lis
 	global_lst = NULL;
 }
 
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
+	const char *prefix = setup_git_directory();
 	struct commit_list *list = NULL;
 	int i, limited = 0;
 
-	setup_git_directory();
 	for (i = 1 ; i < argc; i++) {
 		int flags;
-		char *arg = argv[i];
+		const char *arg = argv[i];
 		char *dotdot;
 		struct commit *commit;
 
@@ -587,6 +700,14 @@ int main(int argc, char **argv)
 		        limited = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--")) {
+			paths = get_pathspec(prefix, argv + i + 1);
+			if (paths) {
+				limited = 1;
+				diff_tree_setup_paths(paths);
+			}
+			break;
+		}
 
 		if (show_breaks && !merge_order)
 			usage(rev_list_usage);

^ permalink raw reply related

* Re: How to create a new branch based on a tag?
From: Junio C Hamano @ 2005-10-21  5:08 UTC (permalink / raw)
  To: Ben Lau; +Cc: git
In-Reply-To: <4359161B.5000808@ust.hk>

Ben Lau <benlau@ust.hk> writes:

>>The way you know is as good as it gets.  v2.6.11-tree case is
>>really an unfortunate special case.
>>
> What is wrong with the v2.6.11-tree? I just thought it is a duplicate tag
> of v2.6.11.

They are not *wrong* per-se.  They are tags to tree objects
without any associated commit history -- that makes them
inappropriate to be used as branch heads.

Linus or somebody authoritative could do:

    $ commit=$(echo v2.6.11 | \
      git-commit-tree c39ae07f393806ccf406ef966e9a15afc43cc36a)
    $ git-tag -s -m 'v2.6.11 canonical "fake" commit' v2.6.11fake $commit

and tell everybody interested to have:

1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 xxxxxxxxxx

(where xxxxx... is the value of $commit above) in their
info/grafts file.  Then we *could* pretend that v2.6.12-rc2's
parent is v2.6.11.  You could branch off from v2.6.11fake commit
and base your development, and later you could merge that into
later development history (say, v2.6.14-rc5) if you wanted to.

If Linus does something like the above, the graft probably be
better done between the current v2.6.12-rc2 based commit history
and the corresponding commit in the history resurrected from
BKCVS (torvalds/old-2.6-bkcvs.git).  Then you could even base
your development on top of v2.4.0 ;-).

Funnily, v2.6.12-rc2 commit in the current history and BKCVS
v2.6.12-rc2 commit in the resurrected history have different
tree IDs.

I am however not quite sure how useful the above would be,
though.  EVen between 2.6.11 and 2.6.12-rc2 much have happened,
so unless the changes you are making apply to the part that did
not change between those two, merge conflict resolution might be
quite a chore.

^ 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