Git development
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] Add a few more words to the glossary.
From: Jon Loeliger @ 2006-05-04 13:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vu0868h7a.fsf@assigned-by-dhcp.cox.net>

So, like, the other day Junio C Hamano mumbled:
> Jon Loeliger <jdl@jdl.com> writes:
> 
> >  ref::
> > -	A 40-byte hex representation of a SHA1 pointing to a particular
> > -	object. These may be stored in `$GIT_DIR/refs/`.
> > +	A 40-byte hex representation of a SHA1 or a name that denotes
> > +	a particular object. These may be stored in `$GIT_DIR/refs/`.
> >  
 
> Uum.  Not very clear.  Do we use that word that often?

Well, I was mystified a bit too, and I tried to clean it up some...
"ref" gets used as half a <refspec>, from pull-fetch-param.txt:

	A parameter <ref> without a colon is equivalent to <ref>: when
	pulling/fetching, so it merges <ref> into the current branch
	without storing the remote branch anywhere locally

So maybe I was confused here.

> > +symbolic ref::
> > +	See "ref".
>
> I think I used that term to differenciate between HEAD symlink
> pointing at refs/heads/master and HEAD being a regular file that
> stores a line "ref: refs/heads/master\n"; the latter is the
> modern style "textual symref", so in that context it is not
> about 40-byte hex at all.  And at that level it is really a
> jargon to talk about one small implementation detail of HEAD, so
> I am not sure it deserves to be in the glossary.

Given "git-symbolic-ref <name> [<ref>]", clearly I just botched it.
You were right to drop my confused "symbolic ref" entry. :-(

> >  tracking branch::
> > -	A regular git branch that is used to follow changes from
> > +	A regular git branch that is used to follow changes frompointing
> >  	another repository.  A tracking branch should not contain
> 
> I think this is a typo?

Yes.  Thanks for noticing and cleaning.

jdl

^ permalink raw reply

* cg-commit path handling problem
From: Christian Jaeger @ 2006-05-04 15:12 UTC (permalink / raw)
  To: git

Hello

I did create a repository from a directory containing, amongst other 
stuff, files starting with a $ sign. E.g.

$ find
./foo
./bar
./var/cache
./var/cache/$foo
./var/cache/$foo::bar
./var/cache/$baz

$ cg-init
...

Now I realized that I didn't want the var directory in the repository and did

$ cg-rm -r var
$ cg-commit var

which worked without warning, but:

$ cg-status
..
D var/cache/$foo
D var/cache/$foo::bar
D var/cache/$baz

So I try again:

$ cg-commit var

will open the editor with the $.. files in the CG: part, I enter a 
commit message, exit the editor, it sayys "Refusing to make an empty 
commit".

$ cg-commit -f var

says "committed as ....", but cg-status will still show the same files as D

As per suggestion from #git, I did the equivalent of

find var -name '$*' |xargs git commit -m please_go_away --

which worked.

So I guess that the cg-commit shell script isn't protecting file 
paths against variable substitution somewhere.

This is cogito-0.17.2 and git 1.2.6 (from Debian unstable rebuilt on Sarge).

Thanks for caring,
Christian.

^ permalink raw reply

* Re: Unresolved issues #2
From: Pavel Roskin @ 2006-05-04 15:45 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Junio C Hamano, git, mj
In-Reply-To: <20060504095827.GW27689@pasky.or.cz>

Hello, Petr!

On Thu, 2006-05-04 at 11:58 +0200, Petr Baudis wrote:

> Oh, my holey memory. In Cogito, I have just implemented a solution
> suggested by Martin Mares, which is pretty simple, non-obtrusive
> and will work equally fine with remotes as well as remote branches:
> 
> 	if [ $branch != master ] && [ -s .git/branches/$branch-origin ]
> 		origin=.git/branches/$branch-origin
> 	else
> 		origin=.git/branches/origin
> 	fi

Isn't ".git/branches" obsolete, at least in git?  I'm surprised it's
still referenced in git sources.

What is the future of ".git/branches"?  Is it becoming a Cogito specific
branch database?  Or is it now a database or branch dependencies?

I would prefer to have one single standard for branch origins that could
be used by git, StGIT and Cogito.  Using a location that is obsolete
outside Cogito is probably the worst possible approach.  I'd rather have
a separate directory, e.g. .git/origins or something.

Alternatively, we could reuse .git/refs by having files with "Pull:" but
without "URI:", e.g.

$ cat .git/refs/branch
Pull: branch-origin:branch

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: [PATCH] Be elaborate when specifying the debs on the download page.
From: Jakub Narebski @ 2006-05-04 15:45 UTC (permalink / raw)
  To: git
In-Reply-To: <20060504133232.GX27689@pasky.or.cz>

Petr Baudis wrote:

> It would be helpful if you could please at least cc' me on the website
> patches, I sometimes do not read all mails on git@ with [PATCH] in
> subject...

Perhaps it would be nice to mark non-git patches in subject: [web],
[gitweb], [StGIT], [Cogito], etc.

-- 
Jakub Narebski
Warsaw, Poland

^ permalink raw reply

* Re: Unresolved issues #2 (shallow clone again)
From: Carl Worth @ 2006-05-04 17:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4q065hq0.fsf@assigned-by-dhcp.cox.net>

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

On Thu, 04 May 2006 01:15:03 -0700, Junio C Hamano wrote:
> * #irc 2006-04-10
>   Shallow clones (Carl Worth).
> 
>   The experiment last round did not work out very well, but as
>   existing repositories get bigger, and more projects being
>   migrated from foreign SCM systems, this would become a
>   must-have from would-be-nice-to-have.
> 
>   I am beginning to think using "graft" to cauterize history
>   for this, while it technically would work, would not be so
>   helpful to users, so the design needs to be worked out again.

I've been meaning to follow up with some thoughts on this topic, so
thanks for the tickler.

For the one use case I had, (track latest tree), I had thrown out the
idea of using "faked", parent-less commit objects to point to the tree
of interest. Junio pointed out that there's no protocol to learn the
name of a remote commit's tree from the name of the commit. I worked
around that by simply making the parent-less commit object on the
server side, (branch name of "master-shallow", say).

That seemed to work just fine, and if someone really wanted to do
this, they could use a hook to maintain the master-shallow branch,
and no change to git itself would be needed. But there's a very
minimal amount of interesting functionality in this, and it's not
clear that it's much better than git-tar-tree. So I'm considering that
idea dead.

Meanwhile, a more general ability to use shallow clones would still be
very useful. I think what I'd like to be able to do is to pass
rev-list limiting options (--max-count, --max-age via --since,
etc.). That would limit the expansion of the WANT commits, and then
the existing logic to compute the necessary objects needed to satisfy
the list of desired commits should do the right thing.

Then, in order for this to actually be useful, when returning objects
from a limited fetch like this, the server should provide a list of
commits that should be noted as cauterized, (whether through the
existing grafts mechanism or otherwise).

Additionally, when doing a fetch into a tree that has any such
cauterized commits, the client must also provide its list of
cauterized commits. So the conversation changes from "I WANT
<fetch-heads> and I HAVE <heads>" to one of "I WANT <fetch-heads>, and
I HAVE <heads>, except that I'm MISSING <cauterized-commits>".

Finally, whenever a fetch receives an commit object that is in its
list of cauterized commits, it should remove that commit from the
list. This allows a shallow clone to be naturally migrated to
something unshallow. And the user can do this as incrementally as
desired based on the need to see more history:

get a bit:
	git fetch somewhere --since=2.weeks.ago

then a bit more:
	git fetch somewhere --since=1.year.ago

then get it all:
	git fetch somewhere

Maybe that's no different from Junio's original proposal. If not, what
do you see in the above that wouldn't work?

-Carl

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

^ permalink raw reply

* [PATCH] cg-admin-rewritehist: fix reappearing files with --filter-tree.
From: Johannes Sixt @ 2006-05-04 19:36 UTC (permalink / raw)
  To: git, Petr Baudis

With --filter-tree a working copy is checked out for each commit.
However, if a file is removed by a commit, the file is _not_ removed
from the working copy by git-checkout-index. This must be done explicitly,
otherwise the file becomes added back again.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

---

I'm posting this again, because I haven't received any feedback nor has
the patch been applied.

 cg-admin-rewritehist |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

26bb71a2d3d583d9eee10f4e950ff1b7d400e975
diff --git a/cg-admin-rewritehist b/cg-admin-rewritehist
index 7dd83cf..13ffb5d 100755
--- a/cg-admin-rewritehist
+++ b/cg-admin-rewritehist
@@ -213,10 +213,13 @@ while read commit; do
 
 	if [ "$filter_tree" ]; then
 		git-checkout-index -f -u -a
+		# files that $commit removed are now still in the working tree;
+		# remove them, else they would be added again
+		git-ls-files -z --others | xargs -0 rm -f
 		eval "$filter_tree"
 		git-diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
 			xargs -0 git-update-index --add --replace --remove
-		git-ls-files --others | tr '\n' '\0' | \
+		git-ls-files -z --others | \
 			xargs -0 git-update-index --add --replace --remove
 	fi
 
-- 
1.3.1.gaa6b

^ permalink raw reply related

* [PATCH] cg-admin-rewritehist: Seed the commit map with the parents specified with -r.
From: Johannes Sixt @ 2006-05-04 19:36 UTC (permalink / raw)
  To: git, Petr Baudis

When the first commit is manufactured, its parents are looked up in the
commit map. However, without this patch the map is always empty at that time.
If the entire history is rewritten, this is no problem because the first
commit does not have any parents anyway. However, if -r is used to constrain
rewriting to only part of the history, this first commit is manufactured
incorrectly without parents because 'cat' fails.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

---

I'm posting this again, because I haven't received any feedback nor has
the patch been applied.

 cg-admin-rewritehist |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

977fc81815877a1e72040355b221fe8d62593eb7
diff --git a/cg-admin-rewritehist b/cg-admin-rewritehist
index 9fa4c2a..7dd83cf 100755
--- a/cg-admin-rewritehist
+++ b/cg-admin-rewritehist
@@ -141,6 +141,7 @@ _git_requires_root=1
 
 tempdir=.git-rewrite
 startrev=
+startrevparents=
 filter_env=
 filter_tree=
 filter_index=
@@ -152,6 +153,7 @@ while optparse; do
 		tempdir="$OPTARG"
 	elif optparse -r=; then
 		startrev="^$OPTARG^ $OPTARG $startrev"
+		startrevparents="$OPTARG^ $startrevparents"
 	elif optparse --env-filter=; then
 		filter_env="$OPTARG"
 	elif optparse --tree-filter=; then
@@ -186,6 +188,12 @@ ret=0
 
 mkdir ../map # map old->new commit ids for rewriting parents
 
+# seed with identity mappings for the parents where we start off
+for commit in $startrevparents; do
+	commit="$(git-rev-parse $commit)"
+	echo $commit > ../map/$commit
+done
+
 git-rev-list --topo-order HEAD $startrev | tac >../revs
 commits=$(cat ../revs | wc -l)
 
-- 
1.3.1.gaa6b

^ permalink raw reply related

* Re: Unresolved issues #2
From: Daniel Barkalow @ 2006-05-04 20:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4q065hq0.fsf@assigned-by-dhcp.cox.net>

On Thu, 4 May 2006, Junio C Hamano wrote:

> * Message-ID: <Pine.LNX.4.63.0604301524080.2646@wbgn013.biozentrum.uni-wuerzburg.de>
> 
>   An optional "git fetch --store newname URL refspecs..." to
>   create an equivalent of remotes file so newname can then be
>   used as a short-hand.  I still have somewhat negative reaction
>   to it, but I am willing to apply it if there are enough people
>   who want this.

I was just about to suggest something for this general use. It's currently 
kind of a pain to deal with the situation where you've got stuff on your 
workstation that you want to version control in a shared repository on a 
server.

I think it shouldn't be on fetch, though; I think a "git remote" command 
for describing, creating, and modifying remotes would be better, since you 
also sometimes want to add a "Push:" line.

Maybe:

 git remote <name>: Print info about <name>
 git remote add <name> <URL> [<direction> ...]: create a remote
 git remote <name> <direction> ...: modify a remote

 where <direction> is either:
  pull <remote> <local> or
  push <local> <remote>

	-Daniel
*This .sig left intentionally blank*

^ permalink raw reply

* [PATCH] builtin-push: --all and --tags _are_ explicit refspecs
From: Johannes Schindelin @ 2006-05-04 21:18 UTC (permalink / raw)
  To: git, junkio


... so do not get refspecs from remotes/* or the config if one of them
was specified.

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

---

 builtin-push.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

42859edd0156479786e5bc4184e462a0307a67eb
diff --git a/builtin-push.c b/builtin-push.c
index 06d06ff..e530022 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -72,7 +72,7 @@ static int get_remotes_uri(const char *r
 {
 	int n = 0;
 	FILE *f = fopen(git_path("remotes/%s", repo), "r");
-	int has_explicit_refspec = refspec_nr;
+	int has_explicit_refspec = refspec_nr || all || tags;
 
 	if (!f)
 		return -1;
@@ -144,7 +144,7 @@ static int get_config_remotes_uri(const 
 	config_repo = repo;
 	config_current_uri = 0;
 	config_uri = uri;
-	config_get_refspecs = !refspec_nr;
+	config_get_refspecs = !(refspec_nr || all || tags);
 
 	git_config(get_remote_config);
 	return config_current_uri;
-- 
1.3.2.gec86-dirty

^ permalink raw reply related

* Re: Unresolved issues #2
From: Linus Torvalds @ 2006-05-04 21:33 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0605041627310.6713@iabervon.org>



On Thu, 4 May 2006, Daniel Barkalow wrote:
> 
> I think it shouldn't be on fetch, though; I think a "git remote" command 
> for describing, creating, and modifying remotes would be better, since you 
> also sometimes want to add a "Push:" line.

I don't think this is wrong, but I think it's more important to try to 
decide on how we want to represent this information first, and stabilize 
that.

I realize that git has gotten a lot more porcelainish over time, but at 
the same time, now you're really starting to argue about syntax that 
really ends up being often a feature of the development environment. If 
you did development using an IDE that knows about git, I think the 
"remote" information ends up being not necessarily a git command at all, 
but really an interface in the IDE.

I'm actually growing pretty fond of the config file interfaces that Dscho 
is pushing. I really like the idea of "git pull" doing different things 
depending on which branch is active at the time, because different 
branches really can have different sources they come from.

Always pulling from the same default source seems wrong, and having to 
remember whose source some branch is associated with is just not all that 
user-friendly, but perhaps more importantly, it's also going to result in 
people making mistakes, pulling from the wrong branch (because they didn't 
think about where they were), and then having strange merges that they 
might not notice were wrong until it's too late and they pushed the result 
out.

So Johannes' patches seem to move into that direction, and having it all 
in the config file actually seems to be quite readable.

And that, in turn, may mean that a lot of porcelains really only care 
about that syntax, and then they may update the config file any way they 
please (whether by hand, or by using "git repo-config" or by using "git 
remote").

So I'd argue that (a) yes, we do want to have the "proto porcelain" that 
sets remote branch information without the user having to know the magic 
"git repo-config" incantation, or know which file in .git/remotes/ to 
edit, but that (b) it's even more important to try to decide on what the 
remote description format _is_.

I personally have just two preferences:

 - I'd like each branch I'm on to have a "default source" for pulling (and 
   _maybe_ for pushing too). I'd like to just say "git pull", and it would 
   automatically select the appropriate thing to pull from.

 - maybe the same per-branch thing for "push", but more importantly for 
   me, I like to push to multiple destinations, and I'd like the 
   description format to be sane. I think it may already be sane in the 
   form it is in now (supporting both config file _and_ .git/remotes/ 
   formats), I'd just like us to decide on exactly what the meaning is, 
   and hopefully get to the point where we can tell porcelain how to use 
   that meaning to their advantage (and not change it)

Others may disagree, or (equally importantly), may have additional 
preferences. We should try to find something that works for everybody, and 
that is easy to work with.

		Linus

^ permalink raw reply

* [PATCH] Fix linking with OpenSSL
From: Alexey Dobriyan @ 2006-05-04 22:25 UTC (permalink / raw)
  To: git

For those who put it into interesting (read: default) place.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>

--- a/Makefile
+++ b/Makefile
@@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
 
 git-rev-list$X: rev-list.o $(LIB_FILE)
 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-		$(LIBS) $(OPENSSL_LIBSSL)
+		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
 
 init-db.o: init-db.c
 	$(CC) -c $(ALL_CFLAGS) \

^ permalink raw reply

* Re: [PATCH] Fix linking with OpenSSL
From: Junio C Hamano @ 2006-05-04 22:38 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: git
In-Reply-To: <20060504222550.GA7236@mipter.zuzino.mipt.ru>

Alexey Dobriyan <adobriyan@gmail.com> writes:

> For those who put it into interesting (read: default) place.
>
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
>
> --- a/Makefile
> +++ b/Makefile
> @@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
>  
>  git-rev-list$X: rev-list.o $(LIB_FILE)
>  	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
> -		$(LIBS) $(OPENSSL_LIBSSL)
> +		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
>  
>  init-db.o: init-db.c
>  	$(CC) -c $(ALL_CFLAGS) \

We used to depend on bignum from openssl for rev-list
(merge-order), and if I remember correctly that was the only
reason built recipe for rev-list is different from other
programs.  I wonder if we can just get rid of this thing, and
have it built with git-%$X rule like everybody else.

Can somebody try that out and report what happens?

^ permalink raw reply

* Re: [PATCH] Fix linking with OpenSSL
From: Junio C Hamano @ 2006-05-04 23:00 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: git
In-Reply-To: <7vwtd12z6h.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> Alexey Dobriyan <adobriyan@gmail.com> writes:
>
>> For those who put it into interesting (read: default) place.
>>
>> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
>>
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
>>  
>>  git-rev-list$X: rev-list.o $(LIB_FILE)
>>  	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
>> -		$(LIBS) $(OPENSSL_LIBSSL)
>> +		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
>>  
>>  init-db.o: init-db.c
>>  	$(CC) -c $(ALL_CFLAGS) \
>
> We used to depend on bignum from openssl for rev-list
> (merge-order), and if I remember correctly that was the only
> reason built recipe for rev-list is different from other
> programs.  I wonder if we can just get rid of this thing, and
> have it built with git-%$X rule like everybody else.
>
> Can somebody try that out and report what happens?

Well, I did.  Alexey, does this work for you?

-- >8 --

diff --git a/Makefile b/Makefile
index a3f7e92..814010d 100644
--- a/Makefile
+++ b/Makefile
@@ -564,10 +564,6 @@ git-http-push$X: revision.o http.o http-
 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
-git-rev-list$X: rev-list.o $(LIB_FILE)
-	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-		$(LIBS) $(OPENSSL_LIBSSL)
-
 init-db.o: init-db.c
 	$(CC) -c $(ALL_CFLAGS) \
 		-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c

^ permalink raw reply related

* [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:07 UTC (permalink / raw)
  To: git, junkio


When called with "--stdout", it still writes to standard output.

Notable differences to git-format-patch:

	- since fmt-patch uses the standardized logging machinery, it is
	  no longer "From nobody", but "From <commit_sha1>",

	- the empty lines before and after the "---" just before the
	  diffstat are no longer there,

	- git-format-patch outputs the commit_sha1 just before the first
	  diff, which fmt-patch does not,

	- the file names are no longer output to stdout, but to stderr
	  (since stdout is freopen()ed all the time), and

	- "git fmt-patch HEAD^" does not work as expected: it outputs
	  *all* commits reachable from HEAD^!

The last one is possibly a showstopper. At least I used to call that
command quite often...

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
 builtin-log.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index a39aed6..a75a37f 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -69,12 +69,54 @@ int cmd_log(int argc, const char **argv,
 	return cmd_log_wc(argc, argv, envp, &rev);
 }
 
+static int istitlechar(char c)
+{
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+		(c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void reopen_stdout(struct commit *commit, int nr)
+{
+	char filename[1024];
+	char *sol;
+	int len;
+
+
+	sprintf(filename, "%04d", nr);
+	len = strlen(filename);
+
+	sol = strstr(commit->buffer, "\n\n");
+	if (sol) {
+		int j, space = 1;
+
+		sol += 2;
+		for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
+			if (istitlechar(sol[j])) {
+				if (space) {
+					filename[len++] = '-';
+					space = 0;
+				}
+				filename[len++] = sol[j];
+				if (sol[j] == '.')
+					while (sol[++j] == '.');
+			} else
+				space = 1;
+		}
+		while (filename[len - 1] == '.')
+			len--;
+	}
+	strcpy(filename + len, ".txt");
+	fprintf(stderr, "%s\n", filename);
+	freopen(filename, "w", stdout);
+}
+
 int cmd_format_patch(int argc, const char **argv, char **envp)
 {
 	struct commit *commit;
 	struct commit **list = NULL;
 	struct rev_info rev;
-	int nr = 0;
+	int nr = 0, total;
+	int use_stdout = 0;
 
 	init_revisions(&rev);
 	rev.commit_format = CMIT_FMT_EMAIL;
@@ -87,20 +129,37 @@ int cmd_format_patch(int argc, const cha
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 	argc = setup_revisions(argc, argv, &rev, "HEAD");
 
+	while (argc > 1) {
+		if (!strcmp(argv[1], "--stdout"))
+			use_stdout = 1;
+		else
+			die ("unrecognized argument: %s", argv[1]);
+		argc--;
+		argv++;
+	}
+
 	prepare_revision_walk(&rev);
 	while ((commit = get_revision(&rev)) != NULL) {
+		/* ignore merges */
+		if (commit->parents && commit->parents->next)
+			continue;
 		nr++;
 		list = realloc(list, nr * sizeof(list[0]));
 		list[nr - 1] = commit;
 	}
+	total = nr;
 	while (0 <= --nr) {
 		int shown;
 		commit = list[nr];
+		if (!use_stdout)
+			reopen_stdout(commit, total - nr);
 		shown = log_tree_commit(&rev, commit);
 		free(commit->buffer);
 		commit->buffer = NULL;
 		if (shown)
 			printf("-- \n%s\n\n", git_version_string);
+		if (!use_stdout)
+			fclose(stdout);
 	}
 	free(list);
 	return 0;
-- 
1.3.1.g42859-dirty

^ permalink raw reply related

* Re: [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:15 UTC (permalink / raw)
  To: git, junkio
In-Reply-To: <Pine.LNX.4.63.0605050106180.12713@wbgn013.biozentrum.uni-wuerzburg.de>

Hi,

this patch is faulty. I'll send a fixed patch in one minute.

Sorry,
Dscho

^ permalink raw reply

* [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:16 UTC (permalink / raw)
  To: git, junkio


When called with "--stdout", it still writes to standard output.

Notable differences to git-format-patch:

	- since fmt-patch uses the standardized logging machinery, it is
	  no longer "From nobody", but "From <commit_sha1>",

	- the empty lines before and after the "---" just before the
	  diffstat are no longer there,

	- git-format-patch outputs the commit_sha1 just before the first
	  diff, which fmt-patch does not,

	- the file names are no longer output to stdout, but to stderr
	  (since stdout is freopen()ed all the time), and

	- "git fmt-patch HEAD^" does not work as expected: it outputs
	  *all* commits reachable from HEAD^!

The last one is possibly a showstopper. At least I used to call that
command quite often...

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

	I forgot to "git-update-index builtin-log.c"...

 builtin-log.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 71 insertions(+), 1 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index a39aed6..576703c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -69,12 +69,65 @@ int cmd_log(int argc, const char **argv,
 	return cmd_log_wc(argc, argv, envp, &rev);
 }
 
+static int istitlechar(char c)
+{
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+		(c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void reopen_stdout(struct commit *commit, int nr)
+{
+	char filename[1024];
+	char *sol;
+	int len;
+
+
+	sprintf(filename, "%04d", nr);
+	len = strlen(filename);
+
+	sol = strstr(commit->buffer, "\n\n");
+	if (sol) {
+		int j, space = 1;
+
+		sol += 2;
+		/* strip [PATCH] or [PATCH blabla] */
+		if (!strncmp(sol, "[PATCH", 6)) {
+			char *eos = strchr(sol + 6, ']');
+			if (eos) {
+				while (isspace(*eos))
+					eos++;
+				sol = eos;
+			}
+		}
+
+		for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
+			if (istitlechar(sol[j])) {
+				if (space) {
+					filename[len++] = '-';
+					space = 0;
+				}
+				filename[len++] = sol[j];
+				if (sol[j] == '.')
+					while (sol[j + 1] == '.')
+						j++;
+			} else
+				space = 1;
+		}
+		while (filename[len - 1] == '.' || filename[len - 1] == '-')
+			len--;
+	}
+	strcpy(filename + len, ".txt");
+	fprintf(stderr, "%s\n", filename);
+	freopen(filename, "w", stdout);
+}
+
 int cmd_format_patch(int argc, const char **argv, char **envp)
 {
 	struct commit *commit;
 	struct commit **list = NULL;
 	struct rev_info rev;
-	int nr = 0;
+	int nr = 0, total;
+	int use_stdout = 0;
 
 	init_revisions(&rev);
 	rev.commit_format = CMIT_FMT_EMAIL;
@@ -87,20 +140,37 @@ int cmd_format_patch(int argc, const cha
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 	argc = setup_revisions(argc, argv, &rev, "HEAD");
 
+	while (argc > 1) {
+		if (!strcmp(argv[1], "--stdout"))
+			use_stdout = 1;
+		else
+			die ("unrecognized argument: %s", argv[1]);
+		argc--;
+		argv++;
+	}
+
 	prepare_revision_walk(&rev);
 	while ((commit = get_revision(&rev)) != NULL) {
+		/* ignore merges */
+		if (commit->parents && commit->parents->next)
+			continue;
 		nr++;
 		list = realloc(list, nr * sizeof(list[0]));
 		list[nr - 1] = commit;
 	}
+	total = nr;
 	while (0 <= --nr) {
 		int shown;
 		commit = list[nr];
+		if (!use_stdout)
+			reopen_stdout(commit, total - nr);
 		shown = log_tree_commit(&rev, commit);
 		free(commit->buffer);
 		commit->buffer = NULL;
 		if (shown)
 			printf("-- \n%s\n\n", git_version_string);
+		if (!use_stdout)
+			fclose(stdout);
 	}
 	free(list);
 	return 0;
-- 
1.3.1.g42859-dirty

^ permalink raw reply related

* [PATCH] binary patch.
From: Junio C Hamano @ 2006-05-04 23:52 UTC (permalink / raw)
  To: git

This adds "binary patch" to the diff output and teaches apply
what to do with them.

On the diff generation side, traditionally, we said "Binary
files differ\n" without giving anything other than the preimage
and postimage object name on the index line.  This was good
enough for applying a patch generated from your own repository
(very useful while rebasing), because the postimage would be
available in such a case.  However, this was not useful when the
recipient of such a patch via e-mail were to apply it, even if
the preimage was available.

This patch allows the diff to generate "binary" patch when
operating under --full-index option.  The binary patch follows
the usual extended git diff headers, and looks like this:

	"GIT binary patch\n"
	<length byte><data>"\n"
	...
	"\n"

Each line is prefixed with a "length-byte", whose value is upper
or lowercase alphabet that encodes number of bytes that the data
on the line decodes to (1..52 -- 'A' means 1, 'B' means 2, ...,
'Z' means 26, 'a' means 27, ...).  <data> is 1 or more groups of
5-byte sequence, each of which encodes up to 4 bytes in base85
encoding.  Because 52 / 4 * 5 = 65 and we have the length byte,
an output line is capped to 66 characters.  The payload is the
same diff-delta as we use in the packfiles.

On the consumption side, git-apply now can decode and apply the
binary patch when --allow-binary-replacement is given, the diff
was generated with --full-index, and the receiving repository
has the preimage blob, which is the same condition as it always
required when accepting an "Binary files differ\n" patch.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Makefile |    2 -
 apply.c  |  232 ++++++++++++++++++++++++++++++++++++++++++++++----------------
 cache.h  |    3 +
 diff.c   |  106 ++++++++++++++++++++++++++--
 4 files changed, 275 insertions(+), 68 deletions(-)

diff --git a/Makefile b/Makefile
index a3f7e92..b6be520 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ DIFF_OBJS = \
 	diffcore-delta.o log-tree.o
 
 LIB_OBJS = \
-	blob.o commit.o connect.o csum-file.o \
+	blob.o commit.o connect.o csum-file.o base85.o \
 	date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
diff --git a/apply.c b/apply.c
index 269210a..e37c4eb 100644
--- a/apply.c
+++ b/apply.c
@@ -10,6 +10,7 @@ #include <fnmatch.h>
 #include "cache.h"
 #include "quote.h"
 #include "blob.h"
+#include "delta.h"
 
 //  --check turns on checking that the working tree matches the
 //    files that are being modified, but doesn't apply the patch
@@ -966,6 +967,70 @@ static inline int metadata_changes(struc
 		 patch->old_mode != patch->new_mode);
 }
 
+static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+{
+	/* We have read "GIT binary patch\n"; what follows is a
+	 * sequence of 'length-byte' followed by base-85 encoded
+	 * delta data.
+	 *
+	 * Each 5-byte sequence of base-85 encodes up to 4 bytes,
+	 * and we would limit the patch line to 66 characters,
+	 * so one line can fit up to 13 groups that would decode
+	 * to 52 bytes max.  The length byte 'A'-'Z' corresponds
+	 * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
+	 * The end of binary is signalled with an empty line.
+	 */
+	int llen, used;
+	struct fragment *fragment;
+	char *delta = NULL;
+
+	patch->is_binary = 1;
+	patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
+	used = 0;
+	while (1) {
+		int byte_length, max_byte_length, newsize;
+		llen = linelen(buffer, size);
+		used += llen;
+		linenr++;
+		if (llen == 1)
+			break;
+		/* Minimum line is "A00000\n" which is 7-byte long,
+		 * and the line length must be multiple of 5 plus 2.
+		 */
+		if ((llen < 7) || (llen-2) % 5)
+			goto corrupt;
+		max_byte_length = (llen - 2) / 5 * 4;
+		byte_length = *buffer;
+		if ('A' <= byte_length && byte_length <= 'Z')
+			byte_length = byte_length - 'A' + 1;
+		else if ('a' <= byte_length && byte_length <= 'z')
+			byte_length = byte_length - 'a' + 27;
+		else
+			goto corrupt;
+		/* if the input length was not multiple of 4, we would
+		 * have filler at the end but the filler should never
+		 * exceed 3 bytes
+		 */
+		if (max_byte_length < byte_length ||
+		    byte_length <= max_byte_length - 4)
+			goto corrupt;
+		newsize = fragment->size + byte_length;
+		delta = xrealloc(delta, newsize);
+		if (decode_85(delta + fragment->size,
+			      buffer + 1,
+			      byte_length))
+			goto corrupt;
+		fragment->size = newsize;
+		buffer += llen;
+		size -= llen;
+	}
+	fragment->patch = delta;
+	return used;
+ corrupt:
+	return error("corrupt binary patch at line %d: %.*s",
+		     linenr-1, llen-1, buffer);
+}
+
 static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
 {
 	int hdrsize, patchsize;
@@ -982,19 +1047,34 @@ static int parse_chunk(char *buffer, uns
 			"Files ",
 			NULL,
 		};
+		static const char git_binary[] = "GIT binary patch\n";
 		int i;
 		int hd = hdrsize + offset;
 		unsigned long llen = linelen(buffer + hd, size - hd);
 
-		if (!memcmp(" differ\n", buffer + hd + llen - 8, 8))
+		if (llen == sizeof(git_binary) - 1 &&
+		    !memcmp(git_binary, buffer + hd, llen)) {
+			int used;
+			linenr++;
+			used = parse_binary(buffer + hd + llen,
+					    size - hd - llen, patch);
+			if (used)
+				patchsize = used + llen;
+			else
+				patchsize = 0;
+		}
+		else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
 			for (i = 0; binhdr[i]; i++) {
 				int len = strlen(binhdr[i]);
 				if (len < size - hd &&
 				    !memcmp(binhdr[i], buffer + hd, len)) {
+					linenr++;
 					patch->is_binary = 1;
+					patchsize = llen;
 					break;
 				}
 			}
+		}
 
 		/* Empty patch cannot be applied if:
 		 * - it is a binary patch and we do not do binary_replace, or
@@ -1345,76 +1425,108 @@ #endif
 	return offset;
 }
 
-static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
+static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 {
-	struct fragment *frag = patch->fragments;
 	const char *name = patch->old_name ? patch->old_name : patch->new_name;
+	unsigned char sha1[20];
+	unsigned char hdr[50];
+	int hdrlen;
 
-	if (patch->is_binary) {
-		unsigned char sha1[20];
+	if (!allow_binary_replacement)
+		return error("cannot apply binary patch to '%s' "
+			     "without --allow-binary-replacement",
+			     name);
 
-		if (!allow_binary_replacement)
-			return error("cannot apply binary patch to '%s' "
-				     "without --allow-binary-replacement",
-				     name);
+	/* For safety, we require patch index line to contain
+	 * full 40-byte textual SHA1 for old and new, at least for now.
+	 */
+	if (strlen(patch->old_sha1_prefix) != 40 ||
+	    strlen(patch->new_sha1_prefix) != 40 ||
+	    get_sha1_hex(patch->old_sha1_prefix, sha1) ||
+	    get_sha1_hex(patch->new_sha1_prefix, sha1))
+		return error("cannot apply binary patch to '%s' "
+			     "without full index line", name);
 
-		/* For safety, we require patch index line to contain
-		 * full 40-byte textual SHA1 for old and new, at least for now.
+	if (patch->old_name) {
+		/* See if the old one matches what the patch
+		 * applies to.
 		 */
-		if (strlen(patch->old_sha1_prefix) != 40 ||
-		    strlen(patch->new_sha1_prefix) != 40 ||
-		    get_sha1_hex(patch->old_sha1_prefix, sha1) ||
-		    get_sha1_hex(patch->new_sha1_prefix, sha1))
-			return error("cannot apply binary patch to '%s' "
-				     "without full index line", name);
-
-		if (patch->old_name) {
-			unsigned char hdr[50];
-			int hdrlen;
-
-			/* See if the old one matches what the patch
-			 * applies to.
-			 */
-			write_sha1_file_prepare(desc->buffer, desc->size,
-						blob_type, sha1, hdr, &hdrlen);
-			if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
-				return error("the patch applies to '%s' (%s), "
-					     "which does not match the "
-					     "current contents.",
-					     name, sha1_to_hex(sha1));
-		}
-		else {
-			/* Otherwise, the old one must be empty. */
-			if (desc->size)
-				return error("the patch applies to an empty "
-					     "'%s' but it is not empty", name);
-		}
+		write_sha1_file_prepare(desc->buffer, desc->size,
+					blob_type, sha1, hdr, &hdrlen);
+		if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
+			return error("the patch applies to '%s' (%s), "
+				     "which does not match the "
+				     "current contents.",
+				     name, sha1_to_hex(sha1));
+	}
+	else {
+		/* Otherwise, the old one must be empty. */
+		if (desc->size)
+			return error("the patch applies to an empty "
+				     "'%s' but it is not empty", name);
+	}
+
+	if (desc->buffer) {
+		free(desc->buffer);
+		desc->alloc = desc->size = 0;
+	}
+	get_sha1_hex(patch->new_sha1_prefix, sha1);
+	if (!memcmp(sha1, null_sha1, 20))
+		return 0; /* deletion patch */
+
+	if (has_sha1_file(sha1)) {
+		char type[10];
+		unsigned long size;
 
-		/* For now, we do not record post-image data in the patch,
-		 * and require the object already present in the recipient's
-		 * object database.
+		desc->buffer = read_sha1_file(sha1, type, &size);
+		if (!desc->buffer)
+			return error("the necessary postimage %s for "
+				     "'%s' cannot be read",
+				     patch->new_sha1_prefix, name);
+		desc->alloc = desc->size = size;
+	}
+	else {
+		char type[10];
+		unsigned long src_size, dst_size;
+		void *src;
+
+		get_sha1_hex(patch->old_sha1_prefix, sha1);
+		src = read_sha1_file(sha1, type, &src_size);
+		if (!src)
+			return error("the necessary preimage %s for "
+				     "'%s' cannot be read",
+				     patch->old_sha1_prefix, name);
+
+		/* patch->fragment->patch has the delta data and
+		 * we should apply it to the preimage.
 		 */
-		if (desc->buffer) {
-			free(desc->buffer);
-			desc->alloc = desc->size = 0;
-		}
-		get_sha1_hex(patch->new_sha1_prefix, sha1);
-
-		if (memcmp(sha1, null_sha1, 20)) {
-			char type[10];
-			unsigned long size;
-
-			desc->buffer = read_sha1_file(sha1, type, &size);
-			if (!desc->buffer)
-				return error("the necessary postimage %s for "
-					     "'%s' does not exist",
-					     patch->new_sha1_prefix, name);
-			desc->alloc = desc->size = size;
-		}
+		desc->buffer = patch_delta(src, src_size,
+					   (void*) patch->fragments->patch,
+					   patch->fragments->size,
+					   &dst_size);
+		if (!desc->buffer)
+			return error("binary patch does not apply to '%s'",
+				     name);
+		desc->size = desc->alloc = dst_size;
 
-		return 0;
+		/* verify that the result matches */
+		write_sha1_file_prepare(desc->buffer, desc->size, blob_type,
+					sha1, hdr, &hdrlen);
+		if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
+			return error("binary patch to '%s' creates incorrect result", name);
 	}
 
+	return 0;
+}
+
+static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
+{
+	struct fragment *frag = patch->fragments;
+	const char *name = patch->old_name ? patch->old_name : patch->new_name;
+
+	if (patch->is_binary)
+		return apply_binary(desc, patch);
+
 	while (frag) {
 		if (apply_one_fragment(desc, frag) < 0)
 			return error("patch failed: %s:%ld",
diff --git a/cache.h b/cache.h
index 9d0ddcf..2f32f3d 100644
--- a/cache.h
+++ b/cache.h
@@ -363,4 +363,7 @@ extern int receive_keep_pack(int fd[2], 
 /* pager.c */
 extern void setup_pager(void);
 
+/* base85 */
+int decode_85(char *dst, char *line, int linelen);
+
 #endif /* CACHE_H */
diff --git a/diff.c b/diff.c
index c845c87..b14d897 100644
--- a/diff.c
+++ b/diff.c
@@ -8,6 +8,7 @@ #include "cache.h"
 #include "quote.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "delta.h"
 #include "xdiff-interface.h"
 
 static int use_size_cache;
@@ -391,6 +392,90 @@ static void show_stats(struct diffstat_t
 			total_files, adds, dels);
 }
 
+static void *encode_delta_size(void *data, unsigned long size)
+{
+	unsigned char *cp = data;
+	*cp++ = size;
+	size >>= 7;
+	while (size) {
+		cp[-1] |= 0x80;
+		*cp++ = size;
+		size >>= 7;
+	}
+	return cp;
+}
+
+static void *safe_diff_delta(const unsigned char *src, unsigned long src_size,
+			     const unsigned char *dst, unsigned long dst_size,
+			     unsigned long *delta_size)
+{
+	unsigned long bufsize;
+	unsigned char *data;
+	unsigned char *cp;
+
+	if (src_size && dst_size)
+		return diff_delta(src, src_size, dst, dst_size, delta_size, 0);
+
+	/* diff-delta does not like to do delta with empty, so
+	 * we do that by hand here.  Sigh...
+	 */
+
+	if (!src_size)
+		/* literal copy can be done only 127-byte at a time.
+		 */
+		bufsize = dst_size + (dst_size / 127) + 40;
+	else
+		bufsize = 40;
+	data = xmalloc(bufsize);
+	cp = encode_delta_size(data, src_size);
+	cp = encode_delta_size(cp, dst_size);
+
+	if (dst_size) {
+		/* copy out literally */
+		while (dst_size) {
+			int sz = (127 < dst_size) ? 127 : dst_size;
+			*cp++ = sz;
+			dst_size -= sz;
+			while (sz) {
+				*cp++ = *dst++;
+				sz--;
+			}
+		}
+	}
+	*delta_size = (cp - data);
+	return data;
+}
+
+static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
+{
+	void *delta, *cp;
+	unsigned long delta_size;
+
+	printf("GIT binary patch\n");
+	delta = safe_diff_delta(one->ptr, one->size,
+				two->ptr, two->size,
+				&delta_size);
+	if (!delta)
+		die("unable to generate binary diff");
+
+	/* emit delta encoded in base85 */
+	cp = delta;
+	while (delta_size) {
+		int bytes = (52 < delta_size) ? 52 : delta_size;
+		char line[70];
+		delta_size -= bytes;
+		if (bytes <= 26)
+			line[0] = bytes + 'A' - 1;
+		else
+			line[0] = bytes - 26 + 'a' - 1;
+		encode_85(line + 1, cp, bytes);
+		cp += bytes;
+		puts(line);
+	}
+	printf("\n");
+	free(delta);
+}
+
 #define FIRST_FEW_BYTES 8000
 static int mmfile_is_binary(mmfile_t *mf)
 {
@@ -407,6 +492,7 @@ static void builtin_diff(const char *nam
 			 struct diff_filespec *one,
 			 struct diff_filespec *two,
 			 const char *xfrm_msg,
+			 struct diff_options *o,
 			 int complete_rewrite)
 {
 	mmfile_t mf1, mf2;
@@ -451,8 +537,13 @@ static void builtin_diff(const char *nam
 	if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
 		die("unable to read files to diff");
 
-	if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))
-		printf("Binary files %s and %s differ\n", lbl[0], lbl[1]);
+	if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) {
+		if (o->full_index)
+			emit_binary_diff(&mf1, &mf2);
+		else
+			printf("Binary files %s and %s differ\n",
+			       lbl[0], lbl[1]);
+	}
 	else {
 		/* Crazy xdl interfaces.. */
 		const char *diffopts = getenv("GIT_DIFF_OPTS");
@@ -928,6 +1019,7 @@ static void run_diff_cmd(const char *pgm
 			 struct diff_filespec *one,
 			 struct diff_filespec *two,
 			 const char *xfrm_msg,
+			 struct diff_options *o,
 			 int complete_rewrite)
 {
 	if (pgm) {
@@ -937,7 +1029,7 @@ static void run_diff_cmd(const char *pgm
 	}
 	if (one && two)
 		builtin_diff(name, other ? other : name,
-			     one, two, xfrm_msg, complete_rewrite);
+			     one, two, xfrm_msg, o, complete_rewrite);
 	else
 		printf("* Unmerged path %s\n", name);
 }
@@ -971,7 +1063,7 @@ static void run_diff(struct diff_filepai
 
 	if (DIFF_PAIR_UNMERGED(p)) {
 		/* unmerged */
-		run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, 0);
+		run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
 		return;
 	}
 
@@ -1041,14 +1133,14 @@ static void run_diff(struct diff_filepai
 		 * needs to be split into deletion and creation.
 		 */
 		struct diff_filespec *null = alloc_filespec(two->path);
-		run_diff_cmd(NULL, name, other, one, null, xfrm_msg, 0);
+		run_diff_cmd(NULL, name, other, one, null, xfrm_msg, o, 0);
 		free(null);
 		null = alloc_filespec(one->path);
-		run_diff_cmd(NULL, name, other, null, two, xfrm_msg, 0);
+		run_diff_cmd(NULL, name, other, null, two, xfrm_msg, o, 0);
 		free(null);
 	}
 	else
-		run_diff_cmd(pgm, name, other, one, two, xfrm_msg,
+		run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
 			     complete_rewrite);
 
 	free(name_munged);
-- 
1.3.1.g25a9

^ permalink raw reply related

* Bad error message
From: Robin Rosenberg (list subscriber) @ 2006-05-04 23:57 UTC (permalink / raw)
  To: git

Hi, 

While playing with git I got the following "impossible" error message:

$ git commit --amend
fatal: Ref HEAD is at 3cec3036287d6b24f7ad7f724f8bb9d4032fb1a3 but expected 
3cec3036287d6b24f7ad7f724f8bb9d4032fb1a3

Since impossible things happen rarely, I was somewhat puzzled and it turned 
out not to be so impossible after all, but a rather typical C bug. Since I 
fixed my working directory using git-reset, I'm not sure how to verify the 
code (suggestions welcome), but I'm not sure if that's important since the 
code being replaced by  this patch probably wasn't tested either. :/

Maybe someone could explain what might have been wrong with my work space (git
status turned up nothing wrong or missing).

-- robin

--- git-1.3.1.orig/update-ref.c 2006-04-25 08:07:54.000000000 +0200
+++ git-1.3.1/update-ref.c      2006-05-04 16:30:04.000000000 +0200
@@ -43,8 +43,13 @@
                die("No such ref: %s", refname);

        if (oldval) {
-               if (memcmp(currsha1, oldsha1, 20))
-                       die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
+               if (memcmp(currsha1, oldsha1, 20)) {
+                       char sha1str1[41];
+                       char sha1str2[41];
+                       strcpy(sha1str1, sha1_to_hex(currsha1));
+                       strcpy(sha1str2, sha1_to_hex(oldsha1));
+                       die("Ref %s is at %s but expected %s", refname, sha1str1, sha1str2);
+               }
                /* Nothing to do? */
                if (!memcmp(oldsha1, sha1, 20))
                        exit(0);

^ permalink raw reply

* Re: [PATCH] Teach fmt-patch to write individual files.
From: Junio C Hamano @ 2006-05-05  0:09 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0605050115440.12795@wbgn013.biozentrum.uni-wuerzburg.de>

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

> When called with "--stdout", it still writes to standard output.
>
> Notable differences to git-format-patch:
>
> 	- since fmt-patch uses the standardized logging machinery, it is
> 	  no longer "From nobody", but "From <commit_sha1>",

Yes, and the date on that UNIX-From line has been updated ;-).

> 	- the empty lines before and after the "---" just before the
> 	  diffstat are no longer there,

Personally, I find this the most annoying myself.  I am not
complaining to you because as you know you inherited this
behaviour from my code.

> 	- git-format-patch outputs the commit_sha1 just before the first
> 	  diff, which fmt-patch does not,

Which should be fine.

> 	- the file names are no longer output to stdout, but to stderr
> 	  (since stdout is freopen()ed all the time), and

Which might be a bigger deal; I suspect people capture that while
dumping patches into individual files, and do their
postprocessing using the list of filenames.

> 	- "git fmt-patch HEAD^" does not work as expected: it outputs
> 	  *all* commits reachable from HEAD^!

If we really wanted to handle this, you could do something like
what builtin-diff does before letting the revision machinery
start walking the revision tree.  Look at pending objects, and
if you find only one UNINTERESTING commit, add_object the
current HEAD there as well.  Personally I do not think it is
worth it; rather we would probably want to standardize on rev-list
syntax.

Two major differences you forgot to mention.

One is that it does not do the "git cherry" filtering.  It is
not a big deal for me personally, but some people may be
depending on it.  I dunno.

Another is -o outdir, which should be trivial to add once you
have implemented output switching with freopen().

Anyhow, thanks for starting this.

^ permalink raw reply

* Re: Bad error message
From: Junio C Hamano @ 2006-05-05  0:20 UTC (permalink / raw)
  To: Robin Rosenberg (list subscriber); +Cc: git
In-Reply-To: <200605041957.26194.robin.rosenberg.lists@dewire.com>

"Robin Rosenberg (list subscriber)"  <robin.rosenberg.lists@dewire.com> writes:

> @@ -43,8 +43,13 @@
>                 die("No such ref: %s", refname);
>
>         if (oldval) {
> -               if (memcmp(currsha1, oldsha1, 20))
> -                       die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
> +               if (memcmp(currsha1, oldsha1, 20)) {
> +                       char sha1str1[41];
> +                       char sha1str2[41];
> +                       strcpy(sha1str1, sha1_to_hex(currsha1));
> +                       strcpy(sha1str2, sha1_to_hex(oldsha1));
> +                       die("Ref %s is at %s but expected %s", refname, sha1str1, sha1str2);
> +               }

Your patch looks correct, but probably is made unnecessary with
the "you can use up to 4 sha1_to_hex() safely" patch Linus did.

We have it in "master" and my plan is to cherry-pick it to
"maint" branch and included it in the next stale release 1.3.3,
along with core.prefersymlinkrefs patch also only in "master",
if we do not hear somebody scream in the next few days.

^ permalink raw reply

* Re: Unresolved issues #2 (shallow clone again)
From: Junio C Hamano @ 2006-05-05  0:25 UTC (permalink / raw)
  To: Carl Worth; +Cc: git
In-Reply-To: <87mzdx7mh9.wl%cworth@cworth.org>

Carl Worth <cworth@cworth.org> writes:

> ... So the conversation changes from "I WANT
> <fetch-heads> and I HAVE <heads>" to one of "I WANT <fetch-heads>, and
> I HAVE <heads>, except that I'm MISSING <cauterized-commits>".
>
> Finally, whenever a fetch receives an commit object that is in its
> list of cauterized commits, it should remove that commit from the
> list. This allows a shallow clone to be naturally migrated to
> something unshallow. And the user can do this as incrementally as
> desired based on the need to see more history:
>
> get a bit:
> 	git fetch somewhere --since=2.weeks.ago
>
> then a bit more:
> 	git fetch somewhere --since=1.year.ago
>
> then get it all:
> 	git fetch somewhere
>
> Maybe that's no different from Junio's original proposal. If not, what
> do you see in the above that wouldn't work?

Lack of actual code to do all that ;-)

Jokes aside, I think listing the updated conversation elements
like you did above is a good step forward.

The vocabulary we would want from the requestor side is probably
(at least):

	I WANT to have these
        I HAVE these
        I'm MISSING these
        Don't bother with these this time around (--since, ^v2.6.16, ...)

I am not sure how we would want to encode the last one and have
it used by rev-list on the upload-pack end safely and sanely.

And the responder side needs to be able to say, "Now you are
MISSING these, remember it and tell me you are missing them next
time you make a request".  That would be, in the simplest case,
a list of commit IDs to cauterize, but I am not sure what is the
right way to come up with that list.  Especially I do not know
if --boundary would/should work with --objects.

^ permalink raw reply

* Re: [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-05  0:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vhd452uzn.fsf@assigned-by-dhcp.cox.net>

Hi,

On Thu, 4 May 2006, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > When called with "--stdout", it still writes to standard output.
> >
> > Notable differences to git-format-patch:
> >
> > 	- since fmt-patch uses the standardized logging machinery, it is
> > 	  no longer "From nobody", but "From <commit_sha1>",
> 
> Yes, and the date on that UNIX-From line has been updated ;-).

Right.

> > 	- the empty lines before and after the "---" just before the
> > 	  diffstat are no longer there,
> 
> Personally, I find this the most annoying myself.  I am not
> complaining to you because as you know you inherited this
> behaviour from my code.

How about this?

-- snip --
diff --git a/log-tree.c b/log-tree.c
index d92abaf..6379d43 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -86,7 +86,7 @@ int log_tree_diff_flush(struct rev_info 
 	}
 
 	if (opt->loginfo && !opt->no_commit_id)
-		show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "---\n" : "\n");
+		show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "\n---\n\n" : "\n");
 	diff_flush(&opt->diffopt);
 	return 1;
 }
-- snap --

> > 	- git-format-patch outputs the commit_sha1 just before the first
> > 	  diff, which fmt-patch does not,
> 
> Which should be fine.

Yeah, I just wanted to mention it in case people rely on it.

> > 	- the file names are no longer output to stdout, but to stderr
> > 	  (since stdout is freopen()ed all the time), and
> 
> Which might be a bigger deal; I suspect people capture that while
> dumping patches into individual files, and do their
> postprocessing using the list of filenames.

I hoped it is not necessary to "FILE *realstdout = fdopen(dup(1));" but I 
can do it if this is wanted.

> > 	- "git fmt-patch HEAD^" does not work as expected: it outputs
> > 	  *all* commits reachable from HEAD^!
> 
> If we really wanted to handle this, you could do something like
> what builtin-diff does before letting the revision machinery
> start walking the revision tree.  Look at pending objects, and
> if you find only one UNINTERESTING commit, add_object the
> current HEAD there as well.  Personally I do not think it is
> worth it; rather we would probably want to standardize on rev-list
> syntax.

Well, I have to get used to add ".." after HEAD^, but that is probably not 
very difficult. I would like fmt-patch to error out without a range, 
though.

> Two major differences you forgot to mention.
> 
> One is that it does not do the "git cherry" filtering.  It is
> not a big deal for me personally, but some people may be
> depending on it.  I dunno.

Oops. I really did not think of that.

> Another is -o outdir, which should be trivial to add once you
> have implemented output switching with freopen().

Yes, this becomes easy now. I'll do that next.

Ciao,
Dscho

^ permalink raw reply related

* Re: [ANNOUNCE] Git wiki
From: linux @ 2006-05-05  0:56 UTC (permalink / raw)
  To: git; +Cc: linux

Actually, AFAICT from looking at the mailing list history, it's not dirty
politics: the tie-breaker was the support and enthusiasm of the mercurial
developers.  It passed with only minor comment on the git mailing list,
but it was a Big Thing to the hg folks.

There are ups and downs.  OpenSolaris is definitely the big fish in
the mercurial pond (that wasn't *meant* to sound like a recipe for
heavy metal toxicity), and will get lots of attention, but git has more
real-world experience.  The big fish in the git pond is Linus and Linux.

In any case, mercurial and git are really very similar, far closer
to each other than any third system, so it's not like the decision is
a descent into heresy.  Hopefully some useful cross-pollination
can occur, and converting history from one to the other would be
simple if anyone ever wanted to.


As for explicit renames, people are confused on the subject.
IMHO, the two most revolutionary things about git are:

- Finally, a complete break from file-oriented history.  History is made
  of trees, and trees are made of files.  There is no direct connection
  between files in different commits.
- An explicit representation of an in-progress merge.
  This is what makes multiple merge strategies easily implementable.

Third, I suppose, is the raw diff format and the diffcore pipeline.

But finally getting away from the SCCS & RCS idea that the file is the
unit of history is one of git's Great Features, and it shouldn't be
thrown away.


What people who are asking for explicit rename tracking actually want
is automatic rename merging.  If branch A renames a file, and branch B
corrects a typo on a comment somewhere, they'd like the merge to
both patch and rename the file.  If you can do that, you have met the
need, even if your solution isn't the one the feature requester
imagined.

(This is the general consulting problem: a client calls when they've
been trying a solution and can't get past some problem.  Usually, this
is because they've wandered into a blind alley, and what they're asking
for is either far more difficult than necessary, or will just lead them
into greater problems.  The first thing you have to determine is what
they actually want to do, as distinct from how they've decided to do it.)


But, as Linus has pointed out, this is a very partial solution which
introduces a lot of difficulties elsewhere.  File renaming is a subset of
the general class of code reorganizations.  Source files will be split,
merged, and have functions moved back and forth.  You want the patch to
find the code it applies to even if that code was moved.

And that can be done by taking a more global view of the patch.
Identical file names is only a heuristic.  If the hunk on branch A
can't find a place to apply on the same file in branch B, then
you have to look a little harder, either at changes from branch B
that introduce matching code elsewhere, or perhaps looking
through history for a change that removed the match from the
obvious place to see if it added a match elsewhere.

The one thing that makes this difficult is git-read-tree's automatic
collapse of "trivial" merges.  If branch B moves foo() unchanged from
x.c to y.c, while branch A doesn't touch y.c, but edits foo() in x.c,
git-read-tree will collapse the changes to y.c before even invoking
the advanced resolve script.

(The solution might be to keep *four* versions of the file in the index:
the three pre-merge, *and* the post-merge.  Then git-write-tree makes
sure everything has a stage 0 entry and strips out the stage 1, 2 and
3 entries.  This way, one merge algorithm can use another as a
subroutine but decide not to accept something it did.)


But anyway, it's the merging that's the desired feature.  Explicitly
recording renames is only the means to that end, and is superfluous
if there's another way of getting there.  (And the place to look for
interesting new ideas in that area Darcs.)

^ permalink raw reply

* [PATCH] fmt-patch: output file names to stdout
From: Johannes Schindelin @ 2006-05-05  1:33 UTC (permalink / raw)
  To: git, junkio


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

---

 builtin-log.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index 576703c..1649f49 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -75,6 +75,8 @@ static int istitlechar(char c)
 		(c >= '0' && c <= '9') || c == '.' || c == '_';
 }
 
+static FILE *realstdout = NULL;
+
 static void reopen_stdout(struct commit *commit, int nr)
 {
 	char filename[1024];
@@ -117,7 +119,7 @@ static void reopen_stdout(struct commit 
 			len--;
 	}
 	strcpy(filename + len, ".txt");
-	fprintf(stderr, "%s\n", filename);
+	fprintf(realstdout, "%s\n", filename);
 	freopen(filename, "w", stdout);
 }
 
@@ -149,6 +151,9 @@ int cmd_format_patch(int argc, const cha
 		argv++;
 	}
 
+	if (!use_stdout)
+		realstdout = fdopen(dup(1), "w");
+
 	prepare_revision_walk(&rev);
 	while ((commit = get_revision(&rev)) != NULL) {
 		/* ignore merges */
-- 
1.3.1.g6d0e-dirty

^ permalink raw reply related

* [PATCH] fmt-patch: implement -o <dir>
From: Johannes Schindelin @ 2006-05-05  1:33 UTC (permalink / raw)
  To: git, junkio


I had to move the command line parsing around a little; setup_revisions()
could mistaken <dir> for a valid ref.

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

---

 builtin-log.c |   44 ++++++++++++++++++++++++++++++++++----------
 1 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index 1649f49..53a47c9 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -76,15 +76,22 @@ static int istitlechar(char c)
 }
 
 static FILE *realstdout = NULL;
+static char *output_directory = NULL;
 
 static void reopen_stdout(struct commit *commit, int nr)
 {
 	char filename[1024];
 	char *sol;
-	int len;
+	int len = 0;
 
+	if (output_directory) {
+		strncpy(filename, output_directory, 1010);
+		len = strlen(filename);
+		if (filename[len - 1] != '/')
+			filename[len++] = '/';
+	}
 
-	sprintf(filename, "%04d", nr);
+	sprintf(filename + len, "%04d", nr);
 	len = strlen(filename);
 
 	sol = strstr(commit->buffer, "\n\n");
@@ -128,7 +135,7 @@ int cmd_format_patch(int argc, const cha
 	struct commit *commit;
 	struct commit **list = NULL;
 	struct rev_info rev;
-	int nr = 0, total;
+	int nr = 0, total, i, j;
 	int use_stdout = 0;
 
 	init_revisions(&rev);
@@ -140,16 +147,31 @@ int cmd_format_patch(int argc, const cha
 	rev.combine_merges = 0;
 	rev.ignore_merges = 1;
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
-	argc = setup_revisions(argc, argv, &rev, "HEAD");
 
-	while (argc > 1) {
-		if (!strcmp(argv[1], "--stdout"))
+	/*
+	 * Parse the arguments before setup_revisions(), or something
+	 * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is
+	 * possibly a valid SHA1.
+	 */
+	for (i = 1, j = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--stdout"))
 			use_stdout = 1;
-		else
-			die ("unrecognized argument: %s", argv[1]);
-		argc--;
-		argv++;
+		else if (!strcmp(argv[i], "-o")) {
+			if (argc < 3)
+				die ("Which directory?");
+			if (mkdir(argv[i + 1], 0777) < 0 && errno != EEXIST)
+				die("Could not create directory %s",
+						argv[i + 1]);
+			output_directory = strdup(argv[i + 1]);
+			i++;
+		} else
+			argv[j++] = argv[i];
 	}
+	argc = j;
+
+	argc = setup_revisions(argc, argv, &rev, "HEAD");
+	if (argc > 1)
+		die ("unrecognized argument: %s", argv[1]);
 
 	if (!use_stdout)
 		realstdout = fdopen(dup(1), "w");
@@ -177,6 +199,8 @@ int cmd_format_patch(int argc, const cha
 		if (!use_stdout)
 			fclose(stdout);
 	}
+	if (output_directory)
+		free(output_directory);
 	free(list);
 	return 0;
 }
-- 
1.3.1.g6d0e-dirty

^ 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