Git development
 help / color / mirror / Atom feed
* [PATCH] git-svn: Avoid spurious errors when rewriteRoot is used.
From: Alexander Gavrilov @ 2009-10-09  7:01 UTC (permalink / raw)
  To: Eric Wong; +Cc: git

After doing a rebase, git-svn checks that the SVN URL
is what it expects. However, it does not account for
rewriteRoot, which is a legitimate way for the URL
to change. This produces a lot of spurious errors.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
 git-svn.perl |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index e0ec258..e9030ff 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -603,8 +603,12 @@ sub cmd_dcommit {
 					  "\nBefore dcommitting";
 				}
 				if ($url_ ne $expect_url) {
-					fatal "URL mismatch after rebase: ",
-					      "$url_ != $expect_url";
+					if ($url_ eq $gs->metadata_url) {
+						print "Accepting rewritten URL: $url_\n";
+					} else {
+						fatal "URL mismatch after rebase: ",
+						      "$url_ != $expect_url";
+					}
 				}
 				if ($uuid_ ne $uuid) {
 					fatal "uuid mismatch after rebase: ",
-- 
1.6.3.2.13.g94af7

^ permalink raw reply related

* Re: combine git repo historically
From: Christian Couder @ 2009-10-09  7:40 UTC (permalink / raw)
  To: bill lam; +Cc: Johannes Sixt, git
In-Reply-To: <4ACED204.3000907@viscovery.net>

On Fri, Oct 9, 2009 at 8:02 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:
> bill lam schrieb:
>> I have two git repos, no branches.
>>
>> repo 1.
>>   emptyrootcommit -- A ... M
>>
>> repo 2.
>>   emptyrootcommit -- N ... Z
>>
>> N was evolved from M but the time gap is large, how can I combine them
>> into one repo
>>
>> emptyrootcommit -- A ... M -- N ... Z
>>
>> so that snapshots N .. Z will not be changed.
>
> $ echo $(git rev-parse N) $(git rev-parse M) >> .git/info/grafts
> $ git filter-branch --tag-name-filter cat -- --all --not M
>
> i.e. you graft the older history right before the younger history, then
> you use git filter-branch to rewrite the parentship of the younger commits.

If you cannot create a new history, using "git replace" could be
better than using grafts.
("git replace" is in the "master" branch in the git repository. It
will be in git 1.6.5 that should be released soon.)

Regards,
Christian

^ permalink raw reply

* Re: Confusing git pull error message
From: Junio C Hamano @ 2009-10-09  7:38 UTC (permalink / raw)
  To: Nanako Shiraishi; +Cc: Jeff King, Johannes Sixt, John Tapsell, Git List
In-Reply-To: <20091009070122.6117@nanako3.lavabit.com>

Nanako Shiraishi <nanako3@lavabit.com> writes:

> Quoting Jeff King <peff@peff.net>
>
>> Subject: [PATCH] pull: improve advice for unconfigured error case
>> ...
> Junio, may I ask what happened to this patch?

Thanks for prodding.  Unfortunately I lost track.  Will look at it again
but probably not tonight.

^ permalink raw reply

* Re: [RFC PATCH 1/4] Document the HTTP transport protocol
From: Sverre Rabbelier @ 2009-10-09  8:01 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git
In-Reply-To: <1255065768-10428-2-git-send-email-spearce@spearce.org>

Heya,

I had some spare time, I hope these comments from someone that is not
too familiar with the protocol are helpful :).

On Fri, Oct 9, 2009 at 07:22, Shawn O. Pearce <spearce@spearce.org> wrote:
> +Compatible clients must expand
> +'$GIT_URL/info/refs' as 'foo/info/refs' and not 'foo//info/refs'.

Does this not need s/must/MUST/

> +       S: ....# service=git-upload-pack
> +       S: ....95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0 multi_ack
> +       S: ....d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
> +       S: ....2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
> +       S: ....a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}

Shouldn't this contain HEAD as the first ref?

> +       ref_list       = empty_list | populated_list
> +
> +       empty_list     = PKT-LINE(id SP "capabilities^{}" NUL cap_list LF)
> +
> +       non_empty_list = PKT-LINE(id SP name NUL cap_list LF)
> +                        *ref_record

Does this need a s/non_empty_list/populated_list/ ?

> +       cap_list      = *(SP capability) SP

You never define capability.

> + (c) Send one $GIT_URL/git-upload-pack request:

I don't think you documented what $GIT_URL/git-upload-pack means.

> +     If the client has sent 256 HAVE commits and has not yet
> +     received one of those back from S_COMMON, or the client has
> +     emptied C_PENDING it should include a "done" command to let
> +     the server know it won't proceed:
> +
> +       C: 0009done

This should probably move down to after you define what S_COMMON is in
the first place.


> +     Here a "closed set of objects" is defined to have at least
> +     one path from every WANT to at least one COMMON object.

A 'path from' is perhaps a bit unclear.

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply

* Re: [RFC PATCH 1/4] Document the HTTP transport protocol
From: Sverre Rabbelier @ 2009-10-09  8:09 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git
In-Reply-To: <fabb9a1e0910090101g2de58824p6cfdea86c98e0191@mail.gmail.com>

Heya,

On Fri, Oct 9, 2009 at 10:01, Sverre Rabbelier <srabbelier@gmail.com> wrote:
>> + (c) Send one $GIT_URL/git-upload-pack request:
>
> I don't think you documented what $GIT_URL/git-upload-pack means.

Ah, I didn't realize until I read 4/4 that this is just a regular
request to the 'http://<host>:<port>/git-upload-pack' url, I was
confused by the need to query
"http://<host>:<port>/info/refs?service=git-upload-pack".

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply

* Re: [PATCH] git-svn: Avoid spurious errors when rewriteRoot is used.
From: Eric Wong @ 2009-10-09  8:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Alexander Gavrilov
In-Reply-To: <200910091101.04116.angavrilov@gmail.com>

Alexander Gavrilov <angavrilov@gmail.com> wrote:
> After doing a rebase, git-svn checks that the SVN URL
> is what it expects. However, it does not account for
> rewriteRoot, which is a legitimate way for the URL
> to change. This produces a lot of spurious errors.
> 
> Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>

Thanks Alexander,

Acked-by: Eric Wong <normalperson@yhbt.net>

Fixed some line wrapping and pushed out to
  git://git.bogomips.org/git-svn

-- 
Eric Wong

^ permalink raw reply

* Re: [RFC PATCH 1/4] Document the HTTP transport protocol
From: Alex Blewitt @ 2009-10-09  8:54 UTC (permalink / raw)
  To: git
In-Reply-To: <1255065768-10428-2-git-send-email-spearce@spearce.org>

Shawn O. Pearce <spearce <at> spearce.org> writes:

> +URL Format
> +----------
> +
> +URLs for Git repositories accessed by HTTP use the standard HTTP
> +URL syntax documented by RFC 1738, so they are of the form:
> +
> +  http://<host>:<port>/<path>
> +
> +Within this documentation the placeholder $GIT_URL will stand for
> +the http:// repository URL entered by the end-user.

It's worth making clear here that $GIT_URL will be the path to the repository,
rather than necessarily just the host upon which the server sits. Perhaps
including an example, like http://example:8080/repos/example.git
would make it clearer that there can be a path (and so leading to
a request like http://example:8080/repos/example.git/info/refs?service=...

It's also worth clarifying, therefore, that multiple repositories can be served
by the same process (as with the git server today) by using different path(s).
And for those that are interested in submodules, it's worth confirming that
http://example/repos/master.git/child.git/info/refs?service= will ensure 
that the repository is the 'child' git rather than anything else.

> HEX = [0-9a-f]

Is there any reason not to support A-F as well in the hex spec, even if they
SHOULD use a-f? This may limit the appeal for some case-insensitive systems.

It would also be good to document, like with the git daemon, whether all
repositories under a path are exported or only those that have the magic
setting in the config like git-daemon-export-ok.

Lastly, it would be good to clarify when the result of this GET/POST exchange
is a text-based (and encoded in UTF-8) vs when binary data is returned; we 
don't want to get into the state where we're returning binary data and 
pretending that it's UTF-8.

Alex

^ permalink raw reply

* Re: git log -S not finding all commits?
From: Matthieu Moy @ 2009-10-09  8:55 UTC (permalink / raw)
  To: Randal L. Schwartz; +Cc: Daniel, Andreas Ericsson, git
In-Reply-To: <86tyy9qz08.fsf@blue.stonehenge.com>

merlyn@stonehenge.com (Randal L. Schwartz) writes:

>>>>>> "Matthieu" == Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>
> Matthieu> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>>> git log -p --format="%s\n%x00"  | perl -0 -ne 'print if(/whatever-you-search/);'
>
> That "if" is noisier than it needs to be:
>
>   perl -0 -ne 'print if /this/'

Thanks,

Also, this seems to actually print the \0 character. Perhaps a perl
guru can give a simple solution to replace the \0 by a \n?

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply

* Re: [PATCH] Speedup bash completion loading
From: Kirill Smelkov @ 2009-10-09  9:09 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Ted Pavlic, git
In-Reply-To: <20091008150206.GD9261@spearce.org>

On Thu, Oct 08, 2009 at 08:02:06AM -0700, Shawn O. Pearce wrote:
> Kirill Smelkov <kirr@mns.spb.ru> wrote:
> > diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile
> > new file mode 100644
> > index 0000000..a0fbb66
> > --- /dev/null
> > +++ b/contrib/completion/Makefile
> > @@ -0,0 +1,11 @@
> > +all	: git-completion.bash
> > +
> > +
> > +git-completion.bash: git-completion.bash.in git-completion.bash.generate
> > +	# Generate completions for binaries we have just built
> > +	PATH="$(shell pwd)/..:$$PATH" ./git-completion.bash.generate
> 
> Is only one .. enough?  Isn't that putting us into the contrib
> directory, and therefore not finding the 'git' we just compiled?

Fixed, thanks.

> I'm also concerned that git-completion.bash.generate requires
> bash to compile the completion for bash.  IMHO, if we are building
> this code at compile time we shouldn't assume bash is available.
> What if this is a sandboxed build environment using another shell
> and /bin/bash isn't installed?
> 
> I think the git-completion.bash.generate code needs to be a bit
> more sh agnostic than the completion routines themselves are.

I've reworked it not to depend on bash in 2nd patch.

> > +# pregenerated stuff (to save load time)
> > +__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST
> > +__git_all_commandlist=__GIT_ALL_COMMANDLIST
> > +__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST
> 
> This also makes testing the completion a bit more difficult, now
> we have to build it before we can load it, making the testing cycle
> actually be:
> 
>   make && . git-completion.bash
> 
> We probably should place a quick comment here to remind folks that
> they need to build the script in order to test it properly.

I've added some sort of protection, so that git-completion.bash.in can't
be sourced at all. Is it ok?

(interdiff for patch 1)

diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile
index a0fbb66..90aa225 100644
--- a/contrib/completion/Makefile
+++ b/contrib/completion/Makefile
@@ -3,7 +3,7 @@ all	: git-completion.bash
 
 git-completion.bash: git-completion.bash.in git-completion.bash.generate
 	# Generate completions for binaries we have just built
-	PATH="$(shell pwd)/..:$$PATH" ./git-completion.bash.generate
+	PATH="$(shell pwd)/../..:$$PATH" ./git-completion.bash.generate
 
 
 clean:
diff --git a/contrib/completion/git-completion.bash.in b/contrib/completion/git-completion.bash.in
index cf1b5fd..e1ab612 100644
--- a/contrib/completion/git-completion.bash.in
+++ b/contrib/completion/git-completion.bash.in
@@ -54,6 +54,21 @@
 #       git@vger.kernel.org
 #
 
+
+# pregenerated stuff (to save load time)
+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST
+__git_all_commandlist=__GIT_ALL_COMMANDLIST
+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST
+
+# remind folks that git-completion.bash.in can't be sourced
+case "$__git_merge_strategylist" in
+__GIT*)
+	echo "E: git-completion.bash.in can't be sourced"
+	return 1 ;;
+esac
+
+
+
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -79,12 +94,6 @@ __gitdir ()
 }
 
 
-# pregenerated stuff (to save load time)
-__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST
-__git_all_commandlist=__GIT_ALL_COMMANDLIST
-__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST
-
-
 
 # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
 # returns text to add to bash PS1 prompt (includes branch name)



Here are new patches themselves:


---- 8< ----

From: Kirill Smelkov <kirr@mns.spb.ru>
Date: Mon, 5 Oct 2009 13:36:15 +0400
Subject: [PATCH v3 1/2] Speedup bash completion loading

On my slow laptop (P3 700MHz), system-wide bash completions take too
much time to load (> 1s), and significant fraction of this time is spent
loading git-completion.bash:

    $ time bash -c '. git-completion.bash'  # before this patch

    real    0m0.317s
    user    0m0.250s
    sys     0m0.060s

I've tracked down that the most time is spent warming up merge_strategy,
all_command & porcelain_command caches.

Initially I thought that since git is not used in each and every
interactive xterm, it would be perfectly ok to load completion support
with cold caches, and then load needed thing lazily.

But for me this strategy turned out to be difficult to implement in
simple and maintainable way -- bash does not provide a way to return values
from inside functions, so one will have to use e.g.

    ${__git_all_commandlist:=$(__git_all_commands)}

everywhere in place where $(__git_all_commands) we used before, so as
also Ted Pavlic suggested let's pregenerate everything at build time so
that we have nothing to compute at runtime when git-completion.bash
script is loaded.

The result is that loading completion is significantly faster now:

    $ time bash -c '. git-completion.bash'  # after this patch

    real    0m0.068s
    user    0m0.060s
    sys     0m0.010s

Cc: Ted Pavlic <ted@tedpavlic.com>
Signed-off-by: Kirill Smelkov <kirr@mns.spb.ru>
---
 contrib/completion/.gitignore                      |    1 +
 contrib/completion/Makefile                        |   11 ++
 contrib/completion/git-completion.bash.generate    |  128 ++++++++++++++++
 ...{git-completion.bash => git-completion.bash.in} |  161 +++-----------------
 4 files changed, 162 insertions(+), 139 deletions(-)
 create mode 100644 contrib/completion/.gitignore
 create mode 100644 contrib/completion/Makefile
 create mode 100755 contrib/completion/git-completion.bash.generate
 rename contrib/completion/{git-completion.bash => git-completion.bash.in} (90%)
 mode change 100755 => 100644

diff --git a/contrib/completion/.gitignore b/contrib/completion/.gitignore
new file mode 100644
index 0000000..578e6a8
--- /dev/null
+++ b/contrib/completion/.gitignore
@@ -0,0 +1 @@
+git-completion.bash
diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile
new file mode 100644
index 0000000..90aa225
--- /dev/null
+++ b/contrib/completion/Makefile
@@ -0,0 +1,11 @@
+all	: git-completion.bash
+
+
+git-completion.bash: git-completion.bash.in git-completion.bash.generate
+	# Generate completions for binaries we have just built
+	PATH="$(shell pwd)/../..:$$PATH" ./git-completion.bash.generate
+
+
+clean:
+	rm -f git-completion.bash
+
diff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate
new file mode 100755
index 0000000..fa998dc
--- /dev/null
+++ b/contrib/completion/git-completion.bash.generate
@@ -0,0 +1,128 @@
+#!/bin/bash
+#
+# Generate bash completion for git.
+#
+# Precompute everything that can be known in advance at build time, so that
+# actual bash completion script is loaded faster.
+
+__git_merge_strategies ()
+{
+	git merge -s help 2>&1 |
+	sed -n -e '/[Aa]vailable strategies are: /,/^$/{
+		s/\.$//
+		s/.*://
+		s/^[ 	]*//
+		s/[ 	]*$//
+		p
+	}'
+}
+
+__git_all_commands ()
+{
+	local i IFS=" "$'\n'
+	for i in $(git help -a|egrep '^ ')
+	do
+		case $i in
+		*--*)             : helper pattern;;
+		*) echo $i;;
+		esac
+	done
+}
+
+
+__git_porcelain_commands ()
+{
+	local i IFS=" "$'\n'
+	for i in "help" $(__git_all_commands)
+	do
+		case $i in
+		*--*)             : helper pattern;;
+		applymbox)        : ask gittus;;
+		applypatch)       : ask gittus;;
+		archimport)       : import;;
+		cat-file)         : plumbing;;
+		check-attr)       : plumbing;;
+		check-ref-format) : plumbing;;
+		checkout-index)   : plumbing;;
+		commit-tree)      : plumbing;;
+		count-objects)    : infrequent;;
+		cvsexportcommit)  : export;;
+		cvsimport)        : import;;
+		cvsserver)        : daemon;;
+		daemon)           : daemon;;
+		diff-files)       : plumbing;;
+		diff-index)       : plumbing;;
+		diff-tree)        : plumbing;;
+		fast-import)      : import;;
+		fast-export)      : export;;
+		fsck-objects)     : plumbing;;
+		fetch-pack)       : plumbing;;
+		fmt-merge-msg)    : plumbing;;
+		for-each-ref)     : plumbing;;
+		hash-object)      : plumbing;;
+		http-*)           : transport;;
+		index-pack)       : plumbing;;
+		init-db)          : deprecated;;
+		local-fetch)      : plumbing;;
+		lost-found)       : infrequent;;
+		ls-files)         : plumbing;;
+		ls-remote)        : plumbing;;
+		ls-tree)          : plumbing;;
+		mailinfo)         : plumbing;;
+		mailsplit)        : plumbing;;
+		merge-*)          : plumbing;;
+		mktree)           : plumbing;;
+		mktag)            : plumbing;;
+		pack-objects)     : plumbing;;
+		pack-redundant)   : plumbing;;
+		pack-refs)        : plumbing;;
+		parse-remote)     : plumbing;;
+		patch-id)         : plumbing;;
+		peek-remote)      : plumbing;;
+		prune)            : plumbing;;
+		prune-packed)     : plumbing;;
+		quiltimport)      : import;;
+		read-tree)        : plumbing;;
+		receive-pack)     : plumbing;;
+		reflog)           : plumbing;;
+		repo-config)      : deprecated;;
+		rerere)           : plumbing;;
+		rev-list)         : plumbing;;
+		rev-parse)        : plumbing;;
+		runstatus)        : plumbing;;
+		sh-setup)         : internal;;
+		shell)            : daemon;;
+		show-ref)         : plumbing;;
+		send-pack)        : plumbing;;
+		show-index)       : plumbing;;
+		ssh-*)            : transport;;
+		stripspace)       : plumbing;;
+		symbolic-ref)     : plumbing;;
+		tar-tree)         : deprecated;;
+		unpack-file)      : plumbing;;
+		unpack-objects)   : plumbing;;
+		update-index)     : plumbing;;
+		update-ref)       : plumbing;;
+		update-server-info) : daemon;;
+		upload-archive)   : plumbing;;
+		upload-pack)      : plumbing;;
+		write-tree)       : plumbing;;
+		var)              : infrequent;;
+		verify-pack)      : infrequent;;
+		verify-tag)       : plumbing;;
+		*) echo $i;;
+		esac
+	done
+}
+
+
+__git_merge_strategylist=$(__git_merge_strategies | tr '\n' ' ')
+__git_all_commandlist="$(__git_all_commands | tr '\n' ' ')"
+__git_porcelain_commandlist="$(__git_porcelain_commands | tr '\n' ' ')"
+
+
+sed -e "s/__GIT_MERGE_STRATEGYLIST/\"$__git_merge_strategylist\"/"	\
+    -e "s/__GIT_ALL_COMMANDLIST/\"$__git_all_commandlist\"/"	\
+    -e "s/__GIT_PORCELAIN_COMMANDLIST/\"$__git_porcelain_commandlist\"/"	\
+    git-completion.bash.in > git-completion.bash
+
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash.in
old mode 100755
new mode 100644
similarity index 90%
rename from contrib/completion/git-completion.bash
rename to contrib/completion/git-completion.bash.in
index 88b1b3c..67d03c3
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash.in
@@ -21,13 +21,7 @@
 #    2) Added the following line to your .bashrc:
 #        source ~/.git-completion.sh
 #
-#    3) You may want to make sure the git executable is available
-#       in your PATH before this script is sourced, as some caching
-#       is performed while the script loads.  If git isn't found
-#       at source time then all lookups will be done on demand,
-#       which may be slightly slower.
-#
-#    4) Consider changing your PS1 to also show the current branch:
+#    3) Consider changing your PS1 to also show the current branch:
 #        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 #
 #       The argument to __git_ps1 will be displayed only if you
@@ -60,6 +54,21 @@
 #       git@vger.kernel.org
 #
 
+
+# pregenerated stuff (to save load time)
+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST
+__git_all_commandlist=__GIT_ALL_COMMANDLIST
+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST
+
+# remind folks that git-completion.bash.in can't be sourced
+case "$__git_merge_strategylist" in
+__GIT*)
+	echo "E: git-completion.bash.in can't be sourced"
+	return 1 ;;
+esac
+
+
+
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -324,23 +333,6 @@ __git_remotes ()
 	done
 }
 
-__git_merge_strategies ()
-{
-	if [ -n "${__git_merge_strategylist-}" ]; then
-		echo "$__git_merge_strategylist"
-		return
-	fi
-	git merge -s help 2>&1 |
-	sed -n -e '/[Aa]vailable strategies are: /,/^$/{
-		s/\.$//
-		s/.*://
-		s/^[ 	]*//
-		s/[ 	]*$//
-		p
-	}'
-}
-__git_merge_strategylist=
-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)
 
 __git_complete_file ()
 {
@@ -476,128 +468,19 @@ __git_complete_strategy ()
 {
 	case "${COMP_WORDS[COMP_CWORD-1]}" in
 	-s|--strategy)
-		__gitcomp "$(__git_merge_strategies)"
+		__gitcomp "$__git_merge_strategylist"
 		return 0
 	esac
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--strategy=*)
-		__gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
+		__gitcomp "$__git_merge_strategylist" "" "${cur##--strategy=}"
 		return 0
 		;;
 	esac
 	return 1
 }
 
-__git_all_commands ()
-{
-	if [ -n "${__git_all_commandlist-}" ]; then
-		echo "$__git_all_commandlist"
-		return
-	fi
-	local i IFS=" "$'\n'
-	for i in $(git help -a|egrep '^ ')
-	do
-		case $i in
-		*--*)             : helper pattern;;
-		*) echo $i;;
-		esac
-	done
-}
-__git_all_commandlist=
-__git_all_commandlist="$(__git_all_commands 2>/dev/null)"
-
-__git_porcelain_commands ()
-{
-	if [ -n "${__git_porcelain_commandlist-}" ]; then
-		echo "$__git_porcelain_commandlist"
-		return
-	fi
-	local i IFS=" "$'\n'
-	for i in "help" $(__git_all_commands)
-	do
-		case $i in
-		*--*)             : helper pattern;;
-		applymbox)        : ask gittus;;
-		applypatch)       : ask gittus;;
-		archimport)       : import;;
-		cat-file)         : plumbing;;
-		check-attr)       : plumbing;;
-		check-ref-format) : plumbing;;
-		checkout-index)   : plumbing;;
-		commit-tree)      : plumbing;;
-		count-objects)    : infrequent;;
-		cvsexportcommit)  : export;;
-		cvsimport)        : import;;
-		cvsserver)        : daemon;;
-		daemon)           : daemon;;
-		diff-files)       : plumbing;;
-		diff-index)       : plumbing;;
-		diff-tree)        : plumbing;;
-		fast-import)      : import;;
-		fast-export)      : export;;
-		fsck-objects)     : plumbing;;
-		fetch-pack)       : plumbing;;
-		fmt-merge-msg)    : plumbing;;
-		for-each-ref)     : plumbing;;
-		hash-object)      : plumbing;;
-		http-*)           : transport;;
-		index-pack)       : plumbing;;
-		init-db)          : deprecated;;
-		local-fetch)      : plumbing;;
-		lost-found)       : infrequent;;
-		ls-files)         : plumbing;;
-		ls-remote)        : plumbing;;
-		ls-tree)          : plumbing;;
-		mailinfo)         : plumbing;;
-		mailsplit)        : plumbing;;
-		merge-*)          : plumbing;;
-		mktree)           : plumbing;;
-		mktag)            : plumbing;;
-		pack-objects)     : plumbing;;
-		pack-redundant)   : plumbing;;
-		pack-refs)        : plumbing;;
-		parse-remote)     : plumbing;;
-		patch-id)         : plumbing;;
-		peek-remote)      : plumbing;;
-		prune)            : plumbing;;
-		prune-packed)     : plumbing;;
-		quiltimport)      : import;;
-		read-tree)        : plumbing;;
-		receive-pack)     : plumbing;;
-		reflog)           : plumbing;;
-		repo-config)      : deprecated;;
-		rerere)           : plumbing;;
-		rev-list)         : plumbing;;
-		rev-parse)        : plumbing;;
-		runstatus)        : plumbing;;
-		sh-setup)         : internal;;
-		shell)            : daemon;;
-		show-ref)         : plumbing;;
-		send-pack)        : plumbing;;
-		show-index)       : plumbing;;
-		ssh-*)            : transport;;
-		stripspace)       : plumbing;;
-		symbolic-ref)     : plumbing;;
-		tar-tree)         : deprecated;;
-		unpack-file)      : plumbing;;
-		unpack-objects)   : plumbing;;
-		update-index)     : plumbing;;
-		update-ref)       : plumbing;;
-		update-server-info) : daemon;;
-		upload-archive)   : plumbing;;
-		upload-pack)      : plumbing;;
-		write-tree)       : plumbing;;
-		var)              : infrequent;;
-		verify-pack)      : infrequent;;
-		verify-tag)       : plumbing;;
-		*) echo $i;;
-		esac
-	done
-}
-__git_porcelain_commandlist=
-__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
-
 __git_aliases ()
 {
 	local i IFS=$'\n'
@@ -1077,7 +960,7 @@ _git_help ()
 		return
 		;;
 	esac
-	__gitcomp "$(__git_all_commands)
+	__gitcomp "$__git_all_commandlist
 		attributes cli core-tutorial cvs-migration
 		diffcore gitk glossary hooks ignore modules
 		repository-layout tutorial tutorial-2
@@ -1423,7 +1306,7 @@ _git_config ()
 		return
 		;;
 	pull.twohead|pull.octopus)
-		__gitcomp "$(__git_merge_strategies)"
+		__gitcomp "$__git_merge_strategylist"
 		return
 		;;
 	color.branch|color.diff|color.interactive|\
@@ -1524,7 +1407,7 @@ _git_config ()
 	pager.*)
 		local pfx="${cur%.*}."
 		cur="${cur#*.}"
-		__gitcomp "$(__git_all_commands)" "$pfx" "$cur"
+		__gitcomp "$__git_all_commandlist" "$pfx" "$cur"
 		return
 		;;
 	remote.*.*)
@@ -2116,7 +1999,7 @@ _git ()
 			--help
 			"
 			;;
-		*)     __gitcomp "$(__git_porcelain_commands) $(__git_aliases)" ;;
+		*)     __gitcomp "$__git_porcelain_commandlist $(__git_aliases)" ;;
 		esac
 		return
 	fi
-- 
1.6.5.rc2.18.g84f98.dirty



From: Kirill Smelkov <kirr@mns.spb.ru>
Date: Fri, 9 Oct 2009 12:45:30 +0400
Subject: [PATCH 2/2] bash: make git-completion.bash.generate bash agnostic

We've just moved some code from git-completion.bash into
git-completion.bash.generate, but as Shawn O. Pearce notes, this code is
now used at compile time, so we shouldn't assume bash is avalable.

In more details: we used IFS=" "$'\n' which works in bash, but not e.g.
in dash, but it turns out that we can avoid setting IFS at all, look:

    $ ./git help -a | egrep '^ '
               [-p|--paginate|--no-pager]
               [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
               [--help] COMMAND [ARGS]
      add                    get-tar-commit-id      rebase
      add--interactive       grep                   rebase--interactive
      am                     gui                    receive-pack
      ...

First, there are some unneedded lines, with e.g. [--bare], and this does
produce noise, since e.g. in bash

    $ for i in "[--bare]"; do echo $i ; done
    a b

so we kill it though grepping more explicitely:

    $ ./git help -a | egrep '^  [^ ]'
      add                    get-tar-commit-id      rebase
      add--interactive       grep                   rebase--interactive
      am                     gui                    receive-pack
      ...

And then, plain "for in in $(git help -a|egrep '^ [^ ]')" works in both
bash and dash, which was the goal.

Signed-off-by: Kirill Smelkov <kirr@mns.spb.ru>
---
 contrib/completion/git-completion.bash.generate |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate
index fa998dc..04460eb 100755
--- a/contrib/completion/git-completion.bash.generate
+++ b/contrib/completion/git-completion.bash.generate
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 #
 # Generate bash completion for git.
 #
@@ -19,8 +19,8 @@ __git_merge_strategies ()
 
 __git_all_commands ()
 {
-	local i IFS=" "$'\n'
-	for i in $(git help -a|egrep '^ ')
+	local i
+	for i in $(git help -a|egrep '^  [^ ]')
 	do
 		case $i in
 		*--*)             : helper pattern;;
@@ -32,7 +32,7 @@ __git_all_commands ()
 
 __git_porcelain_commands ()
 {
-	local i IFS=" "$'\n'
+	local i
 	for i in "help" $(__git_all_commands)
 	do
 		case $i in
-- 
1.6.5.rc2.18.g84f98.dirty

^ permalink raw reply related

* [PATCH 0/9] Documentation tweaks
From: Jonathan Nieder @ 2009-10-09 10:14 UTC (permalink / raw)
  To: git

Hi gitsters,

Here are some small documentation patches that have been sitting in
my tree for a while.  Most important is the first one, which makes it
easier to find the appropriate options for building documentation
from source on a new machine.

Perhaps they could be of some use.  I look forward to your thoughts.

Jonathan Nieder (9):
  Describe DOCBOOK_XSL_172, ASCIIDOC_NO_ROFF options in Makefile
  Documentation: git fmt-merge-message is not a script
  Documentation: fix singular/plural mismatch
  Documentation: say "the same" instead of "equal"
  Documentation: clone: clarify discussion of initial branch
  Documentation: branch: update --merged description
  Documentation: clarify branch creation
  Documentation: clarify "working tree" definition
  racy-git.txt: explain nsec problem in more detail

 Documentation/config.txt             |    2 +-
 Documentation/git-branch.txt         |   27 ++++++++++++++++-----------
 Documentation/git-clone.txt          |    3 ++-
 Documentation/git-fmt-merge-msg.txt  |    2 +-
 Documentation/git-merge.txt          |   11 ++++++-----
 Documentation/glossary-content.txt   |    6 +++---
 Documentation/technical/racy-git.txt |   10 ++++++----
 Makefile                             |    6 +++++-
 8 files changed, 40 insertions(+), 27 deletions(-)

^ permalink raw reply

* [PATCH 2/9] Documentation: git fmt-merge-message is not a script
From: Jonathan Nieder @ 2009-10-09 10:16 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

The fmt-merge-message builtin is usually invoked as
"git fmt-merge-message" rather than through the hard link in
GIT_EXEC_PATH.  Although this is unlikely to confuse most script
writers, it should not hurt to make the documentation a little
clearer anyway.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/git-fmt-merge-msg.txt |    2 +-
 Documentation/git-merge.txt         |    7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index 1c24796..0067805 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -18,7 +18,7 @@ Takes the list of merged objects on stdin and produces a suitable
 commit message to be used for the merge commit, usually to be
 passed as the '<merge-message>' argument of 'git-merge'.
 
-This script is intended mostly for internal use by scripts
+This command is intended mostly for internal use by scripts
 automatically invoking 'git-merge'.
 
 OPTIONS
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index af68d69..354e9d9 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -28,9 +28,10 @@ OPTIONS
 include::merge-options.txt[]
 
 -m <msg>::
-	The commit message to be used for the merge commit (in case
-	it is created). The 'git-fmt-merge-msg' script can be used
-	to give a good default for automated 'git-merge' invocations.
+	Set the commit message to be used for the merge commit (in
+	case one is created). The 'fmt-merge-msg' Git command can be
+	used to give a good default for automated 'git-merge'
+	invocations.
 
 <remote>...::
 	Other branch heads to merge into our branch.  You need at
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 3/9] Documentation: fix singular/plural mismatch
From: Jonathan Nieder @ 2009-10-09 10:16 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

Sounds better this way, at least to my ears.  ("syntax and
supported options of git merge" is a plural noun.)

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/config.txt    |    2 +-
 Documentation/git-merge.txt |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index be0b8ca..4d01dde 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -539,7 +539,7 @@ branch.<name>.merge::
 
 branch.<name>.mergeoptions::
 	Sets default options for merging into branch <name>. The syntax and
-	supported options are equal to that of linkgit:git-merge[1], but
+	supported options are equal to those of linkgit:git-merge[1], but
 	option values containing whitespace characters are currently not
 	supported.
 
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 354e9d9..6da07bb 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -50,7 +50,7 @@ include::merge-config.txt[]
 
 branch.<name>.mergeoptions::
 	Sets default options for merging into branch <name>. The syntax and
-	supported options are equal to that of 'git-merge', but option values
+	supported options are equal to those of 'git-merge', but option values
 	containing whitespace characters are currently not supported.
 
 HOW MERGE WORKS
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 4/9] Documentation: say "the same" instead of "equal"
From: Jonathan Nieder @ 2009-10-09 10:17 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

When non-mathematical objects are declared equal in documentation,
this is a sign that perhaps the discussion is becoming too
technical or exact.  Use "same" instead if no other nuance is
required.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/config.txt    |    2 +-
 Documentation/git-merge.txt |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4d01dde..cd17814 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -539,7 +539,7 @@ branch.<name>.merge::
 
 branch.<name>.mergeoptions::
 	Sets default options for merging into branch <name>. The syntax and
-	supported options are equal to those of linkgit:git-merge[1], but
+	supported options are the same as those of linkgit:git-merge[1], but
 	option values containing whitespace characters are currently not
 	supported.
 
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 6da07bb..6ffd4b0 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -50,8 +50,8 @@ include::merge-config.txt[]
 
 branch.<name>.mergeoptions::
 	Sets default options for merging into branch <name>. The syntax and
-	supported options are equal to those of 'git-merge', but option values
-	containing whitespace characters are currently not supported.
+	supported options are the same as those of 'git-merge', but option
+	values containing whitespace characters are currently not supported.
 
 HOW MERGE WORKS
 ---------------
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 6/9] Documentation: branch: update --merged description
From: Jonathan Nieder @ 2009-10-09 10:18 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

Update the documentation for --merged and --no-merged to explain
the meaning of the optional parameter introduced in commit 049716b
(branch --merged/--no-merged: allow specifying arbitrary commit,
2008-07-08).

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/git-branch.txt |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index aad71dc..e8b32a2 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -134,11 +134,13 @@ start-point is either a local or remote branch.
 --contains <commit>::
 	Only list branches which contain the specified commit.
 
---merged::
-	Only list branches which are fully contained by HEAD.
+--merged [<commit>]::
+	Only list branches whose tips are reachable from the
+	specified commit (HEAD if not specified).
 
---no-merged::
-	Do not list branches which are fully contained by HEAD.
+--no-merged [<commit>]::
+	Do not list branches whose tips are reachable from the
+	specified commit (HEAD if not specified).
 
 <branchname>::
 	The name of the branch to create or delete.
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 7/9] Documentation: clarify branch creation
From: Jonathan Nieder @ 2009-10-09 10:19 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

The documentation seems to assume that the starting point for a new
branch is the tip of an existing (ordinary) branch, but that is not
the most common case.  More often, "git branch" is used to begin
a branch from a remote-tracking branch, a tag, or an interesting
commit (e.g. origin/pu^2).  Clarify the language so it can apply
to these cases.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/git-branch.txt |   17 ++++++++++-------
 1 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index e8b32a2..990f782 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -30,10 +30,11 @@ commit) will be listed.  With `--no-merged` only branches not merged into
 the named commit will be listed.  If the <commit> argument is missing it
 defaults to 'HEAD' (i.e. the tip of the current branch).
 
-In the command's second form, a new branch named <branchname> will be created.
-It will start out with a head equal to the one given as <start-point>.
-If no <start-point> is given, the branch will be created with a head
-equal to that of the currently checked out branch.
+In the command's second form, creates a new branch named <branchname>.
+The branch will start out with head pointing to the commit
+<start-point>.  If no <start-point> is given, the branch will start
+out with head pointing to the tip of the currently checked out branch,
+or the currently checked out commit if no branch is checked out.
 
 Note that this will create the new branch, but it will not switch the
 working tree to it; use "git checkout <newbranch>" to switch to the
@@ -149,9 +150,11 @@ start-point is either a local or remote branch.
 	may restrict the characters allowed in a branch name.
 
 <start-point>::
-	The new branch will be created with a HEAD equal to this.  It may
-	be given as a branch name, a commit-id, or a tag.  If this option
-	is omitted, the current branch is assumed.
+	The new branch head will point to this commit.  It may be
+	given as a branch name, a commit-id, or a tag.  If this
+	option is omitted, the currently checked out branch head
+	is used, or the current commit if no branch is checked
+	out.
 
 <oldbranch>::
 	The name of an existing branch to rename.
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 8/9] Documentation: clarify "working tree" definition
From: Jonathan Nieder @ 2009-10-09 10:20 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

It is not necessarily obvious to a git novice what it means for a
filesystem tree to be equal to the HEAD.  Spell it out.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/glossary-content.txt |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index 572374f..43d84d1 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -456,6 +456,6 @@ This commit is referred to as a "merge commit", or sometimes just a
 	of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'".
 
 [[def_working_tree]]working tree::
-	The tree of actual checked out files.  The working tree is
-	normally equal to the <<def_HEAD,HEAD>> plus any local changes
-	that you have made but not yet committed.
+	The tree of actual checked out files.  The working tree normally
+	contains the contents of the <<def_HEAD,HEAD>> commit's tree,
+	plus any local changes that you have made but not yet committed.
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 1/9] Describe DOCBOOK_XSL_172, ASCIIDOC_NO_ROFF options in Makefile
From: Jonathan Nieder @ 2009-10-09 10:15 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

There is excellent documentation for these options in
Documentation/Makefile, but some users may never find it.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Makefile |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/Makefile b/Makefile
index dd3d520..929d592 100644
--- a/Makefile
+++ b/Makefile
@@ -153,7 +153,11 @@ all::
 #
 # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
 #
-# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
+# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
+# (not v1.73 or v1.71).
+#
+# Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives
+# (versions 1.72 and later and 1.68.1 and earlier).
 #
 # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
 # MakeMaker (e.g. using ActiveState under Cygwin).
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 5/9] Documentation: clone: clarify discussion of initial branch
From: Jonathan Nieder @ 2009-10-09 10:18 UTC (permalink / raw)
  To: git
In-Reply-To: <20091009101400.GA16549@progeny.tock>

When saying the initial branch is equal to the currently active
remote branch, it is probably intended that the branch heads
point to the same commit.  Maybe it would be more useful to a new
user to emphasize that the tree contents and history are the
same.

More important, probably, is that this new branch is set up so
that "git pull" merges changes from the corresponding remote
branch.  The next paragraph addresses that directly, but
clarifying the initial content of the branch should make it
clearer why a pull is required at all (that local and remote
branches each have their own history after the clone).

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 Documentation/git-clone.txt |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index aacf4fd..7cd06e2 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -20,7 +20,8 @@ DESCRIPTION
 Clones a repository into a newly created directory, creates
 remote-tracking branches for each branch in the cloned repository
 (visible using `git branch -r`), and creates and checks out an initial
-branch equal to the cloned repository's currently active branch.
+branch with the contents of the cloned repository's currently active
+branch.
 
 After the clone, a plain `git fetch` without arguments will update
 all the remote-tracking branches, and a `git pull` without
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [PATCH 9/9] racy-git.txt: explain nsec problem in more detail
From: Jonathan Nieder @ 2009-10-09 10:25 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20091009101400.GA16549@progeny.tock>

Idealists may want USE_NSEC to be the default on Linux some day.
Point to a patch to better explain the requirements on
filesystem code for that to happen.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Am I understanding the problem here correctly?  It seems to me
that ext2/3/4, tmpfs, ntfs, and so on shouldn’t have problems
with USE_NSEC, and all that is left is the monster that is
networked filesystems.

 Documentation/technical/racy-git.txt |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index 48bb97f..53aa0c8 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -42,10 +42,12 @@ compared, but this is not enabled by default because this member
 is not stable on network filesystems.  With `USE_NSEC`
 compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
 members are also compared, but this is not enabled by default
-because the value of this member becomes meaningless once the
-inode is evicted from the inode cache on filesystems that do not
-store it on disk.
-
+because in-core timestamps can have finer granularity than
+on-disk timestamps, resulting in meaningless changes when an
+inode is evicted from the inode cache.  See commit 8ce13b0
+of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+([PATCH] Sync in core time granuality with filesystems,
+2005-01-04).
 
 Racy git
 --------
-- 
1.6.5.rc1.199.g596ec

^ permalink raw reply related

* [RFC/PATCHv7 00/22] git notes
From: Johan Herland @ 2009-10-09 10:21 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam

Hi,

(Feel free to put this on hold until v1.6.5 is released. In any case,
I'm going to Berlin for the weekend, and don't expect to read much
email...)

Here is the 7th iteration of the git-notes series. Changes in this
iteration are as follows:

- Rebased onto current 'next'

- Patch 1: Include minor leak fix

- Patch 10: Rename free_commit_notes() to free_notes() (Notes are
  no longer bound to commits only, see patch 15 for details)

- Patch 12: Remove tests that are invalidated by concatenation code
  in patch 13.

Overall, I consider the 12 first patches fairly stable at this point.
There's also a slew of new patches, that has more of an RFC status:

- Patches 13-14: Concatenation of multiple notes annotating the same
  commit/object. This was originally suggested by mugwump many months
  ago, and the suggestion was re-iterated by Dscho. This change has a
  minor perfomance impact (see [1]), but I still think it's worth it.

- Patch 15: Allow notes to be attached to any object (not just commits).
  Rename get_commit_notes() to format_note() to reflect this change.

- Patch 16-19: Expand notes API in preparation for querying and
  manipulating notes from elsewhere in Git (see patch 22 for examples).

- Patch 20: Add a new notes_tree struct, and use it as the first
  parameter to all functions in the notes API. This allows API users to
  maintain their own (multiple, concurrent) notes trees (see patch 22
  for an example). We still have a default notes tree in notes.c as a
  fallback (when NULL is passed as to an API function).

- Patch 21: The default behaviour when there are multiple notes for a
  given object is to concatenate them. However, some callers (see patch
  22) want to tweak this behaviour. This patch defines a new function
  type: combine_notes_fn, for combining two notes that reference the
  same object. The notes API is then expanded to allow the caller to
  specify a suitable combine_notes_fn. For convenience, three simple
  combine_notes functions are available in the notes API:
  - combine_notes_concatenate(): Concatenates the contents of the two
    notes. (This is the default behaviour)
  - combine_notes_overwrite(): Overwrite the existing note with the
    new note.
  - combine_notes_ignore(): Keep the existing note, and ignore the new
    note.

- Patch 22: This teaches fast-import to use the new notes API when
  adding note objects to a commit. Since adding a note to a notes tree
  might cause restructuring of that notes tree, the note objects must
  be handled differently from regular blobs.
  There are some testcases for the new behaviour in this patch, but not
  enough. These will be added later.
  This patch is still very much in RFC mode...


Although this iteration brings the jh/notes topic towards feature-
completion, there are still some things left to do before I consider
the git notes feature fully complete:

- Builtin-ify git-notes shell script to take advantage of notes API

- Garbage-collect notes whose referenced objects are unreachable

- Handle note objects that are not blobs, but trees (e.g.
  refs/notes/<topic>:<commit>/<subtopic>)

- Add a simple notation for referring to an object's note (e.g.
  "<object>^{note}")

- Probably more that I haven't thought of yet...

However, It might be a good idea to consider merging the early/stable
parts of jh/notes, instead of waiting for everything to complete.


Have fun! :)

...Johan


[1] Performance impact of the concatenation rewrite.

In order to concatenate notes correctly, the tree traversal code must be
changed to more proactively unpack subtree entries (so that we can safely
determine whether there are multiple notes for a given key).

As before, the test case is as follows:
Linux kernel repo with 157101 commits, 1 note per commit, organized into
various fanout schemes. Hardware is Intel Core 2 Quad with 4GB RAM.


Algorithm / Notes tree   git log -n10 (x100)   git log --all

next / no-notes                 4.78s             63.90s

before / no-notes               4.77s             63.61s
before / no-fanout             56.59s             65.19s

16tree / no-notes               4.73s             63.80s
16tree / no-fanout             30.21s             65.11s
16tree / 2_38                   5.53s             65.24s
16tree / 2_2_36                 5.15s             65.12s

concat / no-notes               4.80s             64.21s
concat / no-fanout             30.66s             65.35s
concat / 2_38                   5.64s             65.87s
concat / 2_2_36                 5.23s             66.44s

Conclusion: There is a small, but measurable impact (about .1s or so in
the 100 x 'git log -n10' case), but I think this is small enough to be
acceptable.


Johan Herland (17):
  Teach "-m <msg>" and "-F <file>" to "git notes edit"
  fast-import: Add support for importing commit notes
  t3302-notes-index-expensive: Speed up create_repo()
  Add flags to get_commit_notes() to control the format of the note string
  Teach notes code to free its internal data structures on request
  Teach the notes lookup code to parse notes trees with various fanout schemes
  Add selftests verifying that we can parse notes trees with various fanouts
  Refactor notes code to concatenate multiple notes annotating the same object
  Add selftests verifying concatenation of multiple notes for the same commit
  Notes API: get_commit_notes() -> format_note() + remove the commit restriction
  Notes API: init_notes(): Initialize the notes tree from the given notes ref
  Notes API: add_note(): Add note objects to the internal notes tree structure
  Notes API: get_note(): Return the note annotating the given object
  Notes API: for_each_note(): Traverse the entire notes tree with a callback
  Notes API: Allow multiple concurrent notes trees with new struct notes_tree
  Refactor notes concatenation into a flexible interface for combining notes
  fast-import: Proper notes tree manipulation using the notes API

Johannes Schindelin (5):
  Introduce commit notes
  Add a script to edit/inspect notes
  Speed up git notes lookup
  Add an expensive test for git-notes
  Add '%N'-format for pretty-printing commit notes

 .gitignore                        |    1 +
 Documentation/config.txt          |   13 +
 Documentation/git-fast-import.txt |   45 +++-
 Documentation/git-notes.txt       |   60 ++++
 Documentation/pretty-formats.txt  |    1 +
 Makefile                          |    3 +
 cache.h                           |    4 +
 command-list.txt                  |    1 +
 commit.c                          |    1 +
 config.c                          |    5 +
 environment.c                     |    1 +
 fast-import.c                     |  176 +++++++++++-
 git-notes.sh                      |  121 ++++++++
 notes.c                           |  579 +++++++++++++++++++++++++++++++++++++
 notes.h                           |  113 +++++++
 pretty.c                          |   10 +
 t/t3301-notes.sh                  |  150 ++++++++++
 t/t3302-notes-index-expensive.sh  |  118 ++++++++
 t/t3303-notes-subtrees.sh         |  188 ++++++++++++
 t/t9300-fast-import.sh            |  296 +++++++++++++++++++
 20 files changed, 1875 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/git-notes.txt
 create mode 100755 git-notes.sh
 create mode 100644 notes.c
 create mode 100644 notes.h
 create mode 100755 t/t3301-notes.sh
 create mode 100755 t/t3302-notes-index-expensive.sh
 create mode 100755 t/t3303-notes-subtrees.sh

^ permalink raw reply

* [RFC/PATCHv7 00/22] git notes
From: Johan Herland @ 2009-10-09 10:21 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam
In-Reply-To: <1255083738-23263-1-git-send-email-johan@herland.net>

Hi,

Here is the 7th iteration of the git-notes series. Changes in this
iteration are as follows:

- Rebased onto current 'next'

- Patch 1: Include minor leak fix

- Patch 10: Rename free_commit_notes() to free_notes() (Notes are
  no longer bound to only commits, see patch 15 for details)

- Patch 12: Remove tests that are invalidated by concatenation code
  in patch 13.

There's also a slew of new patches:

- Patches 13-14: Concatenation of multiple notes annotating the same
  commit/object. This was originally suggested by mugwump many months
  ago, and the suggestion was re-iterated by Dscho. This change has a
  minor perfomance impact (see [1]), but I still think it's worth it.

- Patch 15: Allow notes to be attached to any object (not just commits).
  Rename get_commit_notes() to format_note() to reflect this change.

- Patch 16-19: Expand notes API in preparation for querying and manipulating notes from other parts of Git.


TODO:
- Builtin-ify git-notes shell script to take advantage of notes API
- Garbage collect notes whose referenced object is unreachable (gc_notes())
- Handle note objects that are not blobs, but trees

Have fun! :)

...Johan


[1] Performance impact of the concatenation rewrite.

In order to concatenate notes correctly, the tree traversal code must be
changed to more proactively unpack subtree entries (so that we can safely
determine whether there are multiple notes for a given key).

As before, the test case is as follows:
Linux kernel repo with 157101 commits, 1 note per commit, organized into
various fanout schemes. Hardware is Intel Core 2 Quad with 4GB RAM.


Algorithm / Notes tree   git log -n10 (x100)   git log --all

next / no-notes                 4.78s             63.90s

before / no-notes               4.77s             63.61s
before / no-fanout             56.59s             65.19s

16tree / no-notes               4.73s             63.80s
16tree / no-fanout             30.21s             65.11s
16tree / 2_38                   5.53s             65.24s
16tree / 2_2_36                 5.15s             65.12s

concat / no-notes               4.80s             64.21s
concat / no-fanout             30.66s             65.35s
concat / 2_38                   5.64s             65.87s
concat / 2_2_36                 5.23s             66.44s

Conclusion: There is a measurable impact (about .1s or so in the 100 x
'git log -n10' case), but I think this is low enough to be acceptable.


Johan Herland (17):
  Teach "-m <msg>" and "-F <file>" to "git notes edit"
  fast-import: Add support for importing commit notes
  t3302-notes-index-expensive: Speed up create_repo()
  Add flags to get_commit_notes() to control the format of the note string
  Teach notes code to free its internal data structures on request.
  Teach the notes lookup code to parse notes trees with various fanout schemes
  Add selftests verifying that we can parse notes trees with various fanouts
  Refactor notes code to concatenate multiple notes annotating the same object
  Add selftests verifying that multiple notes for the same commits are concatenated correctly
  Notes API: get_commit_notes() -> format_note() + remove the commit restriction
  Notes API: init_notes(): Initialize the notes tree from the given notes ref
  Notes API: add_note(): Add note objects to the internal notes tree structure
  Notes API: get_note(): Return the note annotating the given object
  Notes API: for_each_note(): Traverse the entire notes tree with a callback
  Notes API: Allow multiple concurrent notes trees with new struct notes_tree
  Refactor notes concatenation into a flexible interface for combining notes
  fast-import: Proper notes tree manipulation using the notes API

Johannes Schindelin (5):
  Introduce commit notes
  Add a script to edit/inspect notes
  Speed up git notes lookup
  Add an expensive test for git-notes
  Add '%N'-format for pretty-printing commit notes

 .gitignore                        |    1 +
 Documentation/config.txt          |   13 +
 Documentation/git-fast-import.txt |   45 +++-
 Documentation/git-notes.txt       |   60 ++++
 Documentation/pretty-formats.txt  |    1 +
 Makefile                          |    3 +
 cache.h                           |    4 +
 command-list.txt                  |    1 +
 commit.c                          |    1 +
 config.c                          |    5 +
 environment.c                     |    1 +
 fast-import.c                     |  176 +++++++++++-
 git-notes.sh                      |  121 ++++++++
 notes.c                           |  579 +++++++++++++++++++++++++++++++++++++
 notes.h                           |  121 ++++++++
 pretty.c                          |   10 +
 t/t3301-notes.sh                  |  150 ++++++++++
 t/t3302-notes-index-expensive.sh  |  118 ++++++++
 t/t3303-notes-subtrees.sh         |  188 ++++++++++++
 t/t9300-fast-import.sh            |  296 +++++++++++++++++++
 20 files changed, 1883 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/git-notes.txt
 create mode 100755 git-notes.sh
 create mode 100644 notes.c
 create mode 100644 notes.h
 create mode 100755 t/t3301-notes.sh
 create mode 100755 t/t3302-notes-index-expensive.sh
 create mode 100755 t/t3303-notes-subtrees.sh

^ permalink raw reply

* [RFC/PATCHv7 04/22] Add an expensive test for git-notes
From: Johan Herland @ 2009-10-09 10:22 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam, Johannes Schindelin
In-Reply-To: <1255083738-23263-1-git-send-email-johan@herland.net>

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

git-notes have the potential of being pretty expensive, so test with
a lot of commits.  A lot.  So to make things cheaper, you have to
opt-in explicitely, by setting the environment variable
GIT_NOTES_TIMING_TESTS.

This patch has been improved by the following contributions:
- Junio C Hamano: tests: fix "export var=val"

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 t/t3302-notes-index-expensive.sh |   98 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100755 t/t3302-notes-index-expensive.sh

diff --git a/t/t3302-notes-index-expensive.sh b/t/t3302-notes-index-expensive.sh
new file mode 100755
index 0000000..0ef3e95
--- /dev/null
+++ b/t/t3302-notes-index-expensive.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='Test commit notes index (expensive!)'
+
+. ./test-lib.sh
+
+test -z "$GIT_NOTES_TIMING_TESTS" && {
+	say Skipping timing tests
+	test_done
+	exit
+}
+
+create_repo () {
+	number_of_commits=$1
+	nr=0
+	parent=
+	test -d .git || {
+	git init &&
+	tree=$(git write-tree) &&
+	while [ $nr -lt $number_of_commits ]; do
+		test_tick &&
+		commit=$(echo $nr | git commit-tree $tree $parent) ||
+			return
+		parent="-p $commit"
+		nr=$(($nr+1))
+	done &&
+	git update-ref refs/heads/master $commit &&
+	{
+		GIT_INDEX_FILE=.git/temp; export GIT_INDEX_FILE;
+		git rev-list HEAD | cat -n | sed "s/^[ 	][ 	]*/ /g" |
+		while read nr sha1; do
+			blob=$(echo note $nr | git hash-object -w --stdin) &&
+			echo $sha1 | sed "s/^/0644 $blob 0	/"
+		done | git update-index --index-info &&
+		tree=$(git write-tree) &&
+		test_tick &&
+		commit=$(echo notes | git commit-tree $tree) &&
+		git update-ref refs/notes/commits $commit
+	} &&
+	git config core.notesRef refs/notes/commits
+	}
+}
+
+test_notes () {
+	count=$1 &&
+	git config core.notesRef refs/notes/commits &&
+	git log | grep "^    " > output &&
+	i=1 &&
+	while [ $i -le $count ]; do
+		echo "    $(($count-$i))" &&
+		echo "    note $i" &&
+		i=$(($i+1));
+	done > expect &&
+	git diff expect output
+}
+
+cat > time_notes << \EOF
+	mode=$1
+	i=1
+	while [ $i -lt $2 ]; do
+		case $1 in
+		no-notes)
+			GIT_NOTES_REF=non-existing; export GIT_NOTES_REF
+		;;
+		notes)
+			unset GIT_NOTES_REF
+		;;
+		esac
+		git log >/dev/null
+		i=$(($i+1))
+	done
+EOF
+
+time_notes () {
+	for mode in no-notes notes
+	do
+		echo $mode
+		/usr/bin/time sh ../time_notes $mode $1
+	done
+}
+
+for count in 10 100 1000 10000; do
+
+	mkdir $count
+	(cd $count;
+
+	test_expect_success "setup $count" "create_repo $count"
+
+	test_expect_success 'notes work' "test_notes $count"
+
+	test_expect_success 'notes timing' "time_notes 100"
+	)
+done
+
+test_done
-- 
1.6.4.304.g1365c.dirty

^ permalink raw reply related

* [RFC/PATCHv7 01/22] Introduce commit notes
From: Johan Herland @ 2009-10-09 10:21 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam, Johannes Schindelin
In-Reply-To: <1255083738-23263-1-git-send-email-johan@herland.net>

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

Commit notes are blobs which are shown together with the commit
message.  These blobs are taken from the notes ref, which you can
configure by the config variable core.notesRef, which in turn can
be overridden by the environment variable GIT_NOTES_REF.

The notes ref is a branch which contains "files" whose names are
the names of the corresponding commits (i.e. the SHA-1).

The rationale for putting this information into a ref is this: we
want to be able to fetch and possibly union-merge the notes,
maybe even look at the date when a note was introduced, and we
want to store them efficiently together with the other objects.

This patch has been improved by the following contributions:
- Thomas Rast: fix core.notesRef documentation
- Tor Arne Vestbø: fix printing of multi-line notes
- Alex Riesen: Using char array instead of char pointer costs less BSS
- Johan Herland: Plug leak when msg is good, but msglen or type causes return

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
Signed-off-by: Tor Arne Vestbø <tavestbo@trolltech.com>
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

get_commit_notes(): Plug memory leak when 'if' triggers, but not because of read_sha1_file() failure
---
 Documentation/config.txt |   13 ++++++++
 Makefile                 |    2 +
 cache.h                  |    4 ++
 commit.c                 |    1 +
 config.c                 |    5 +++
 environment.c            |    1 +
 notes.c                  |   70 ++++++++++++++++++++++++++++++++++++++++++++++
 notes.h                  |    7 ++++
 pretty.c                 |    5 +++
 9 files changed, 108 insertions(+), 0 deletions(-)
 create mode 100644 notes.c
 create mode 100644 notes.h

diff --git a/Documentation/config.txt b/Documentation/config.txt
index cc156b8..32b0cdf 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -458,6 +458,19 @@ On some file system/operating system combinations, this is unreliable.
 Set this config setting to 'rename' there; However, This will remove the
 check that makes sure that existing object files will not get overwritten.
 
+core.notesRef::
+	When showing commit messages, also show notes which are stored in
+	the given ref.  This ref is expected to contain files named
+	after the full SHA-1 of the commit they annotate.
++
+If such a file exists in the given ref, the referenced blob is read, and
+appended to the commit message, separated by a "Notes:" line.  If the
+given ref itself does not exist, it is not an error, but means that no
+notes should be printed.
++
+This setting defaults to "refs/notes/commits", and can be overridden by
+the `GIT_NOTES_REF` environment variable.
+
 add.ignore-errors::
 	Tells 'git-add' to continue adding files when some files cannot be
 	added due to indexing errors. Equivalent to the '--ignore-errors'
diff --git a/Makefile b/Makefile
index 8925b1d..9e414db 100644
--- a/Makefile
+++ b/Makefile
@@ -429,6 +429,7 @@ LIB_H += ll-merge.h
 LIB_H += log-tree.h
 LIB_H += mailmap.h
 LIB_H += merge-recursive.h
+LIB_H += notes.h
 LIB_H += object.h
 LIB_H += pack.h
 LIB_H += pack-refs.h
@@ -513,6 +514,7 @@ LIB_OBJS += match-trees.o
 LIB_OBJS += merge-file.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += name-hash.o
+LIB_OBJS += notes.o
 LIB_OBJS += object.o
 LIB_OBJS += pack-check.o
 LIB_OBJS += pack-refs.o
diff --git a/cache.h b/cache.h
index 96840c7..0343e8e 100644
--- a/cache.h
+++ b/cache.h
@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
 #define GITATTRIBUTES_FILE ".gitattributes"
 #define INFOATTRIBUTES_FILE "info/attributes"
 #define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
+#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
 
 extern int is_bare_repository_cfg;
 extern int is_bare_repository(void);
@@ -567,6 +569,8 @@ enum object_creation_mode {
 
 extern enum object_creation_mode object_creation_mode;
 
+extern char *notes_ref_name;
+
 extern int grafts_replace_parents;
 
 #define GIT_REPO_VERSION 0
diff --git a/commit.c b/commit.c
index fedbd5e..5ade8ed 100644
--- a/commit.c
+++ b/commit.c
@@ -5,6 +5,7 @@
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
+#include "notes.h"
 
 int save_commit_buffer = 1;
 
diff --git a/config.c b/config.c
index c644061..51f2208 100644
--- a/config.c
+++ b/config.c
@@ -467,6 +467,11 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.notesref")) {
+		notes_ref_name = xstrdup(value);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.pager"))
 		return git_config_string(&pager_program, var, value);
 
diff --git a/environment.c b/environment.c
index 5de6837..571ab56 100644
--- a/environment.c
+++ b/environment.c
@@ -49,6 +49,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
 #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
+char *notes_ref_name;
 int grafts_replace_parents = 1;
 
 /* Parallel index stat data preload? */
diff --git a/notes.c b/notes.c
new file mode 100644
index 0000000..66379ff
--- /dev/null
+++ b/notes.c
@@ -0,0 +1,70 @@
+#include "cache.h"
+#include "commit.h"
+#include "notes.h"
+#include "refs.h"
+#include "utf8.h"
+#include "strbuf.h"
+
+static int initialized;
+
+void get_commit_notes(const struct commit *commit, struct strbuf *sb,
+		const char *output_encoding)
+{
+	static const char utf8[] = "utf-8";
+	struct strbuf name = STRBUF_INIT;
+	unsigned char sha1[20];
+	char *msg, *msg_p;
+	unsigned long linelen, msglen;
+	enum object_type type;
+
+	if (!initialized) {
+		const char *env = getenv(GIT_NOTES_REF_ENVIRONMENT);
+		if (env)
+			notes_ref_name = getenv(GIT_NOTES_REF_ENVIRONMENT);
+		else if (!notes_ref_name)
+			notes_ref_name = GIT_NOTES_DEFAULT_REF;
+		if (notes_ref_name && read_ref(notes_ref_name, sha1))
+			notes_ref_name = NULL;
+		initialized = 1;
+	}
+
+	if (!notes_ref_name)
+		return;
+
+	strbuf_addf(&name, "%s:%s", notes_ref_name,
+			sha1_to_hex(commit->object.sha1));
+	if (get_sha1(name.buf, sha1))
+		return;
+
+	if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
+			type != OBJ_BLOB) {
+		free(msg);
+		return;
+	}
+
+	if (output_encoding && *output_encoding &&
+			strcmp(utf8, output_encoding)) {
+		char *reencoded = reencode_string(msg, output_encoding, utf8);
+		if (reencoded) {
+			free(msg);
+			msg = reencoded;
+			msglen = strlen(msg);
+		}
+	}
+
+	/* we will end the annotation by a newline anyway */
+	if (msglen && msg[msglen - 1] == '\n')
+		msglen--;
+
+	strbuf_addstr(sb, "\nNotes:\n");
+
+	for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {
+		linelen = strchrnul(msg_p, '\n') - msg_p;
+
+		strbuf_addstr(sb, "    ");
+		strbuf_add(sb, msg_p, linelen);
+		strbuf_addch(sb, '\n');
+	}
+
+	free(msg);
+}
diff --git a/notes.h b/notes.h
new file mode 100644
index 0000000..79d21b6
--- /dev/null
+++ b/notes.h
@@ -0,0 +1,7 @@
+#ifndef NOTES_H
+#define NOTES_H
+
+void get_commit_notes(const struct commit *commit, struct strbuf *sb,
+		const char *output_encoding);
+
+#endif
diff --git a/pretty.c b/pretty.c
index f5983f8..e25db81 100644
--- a/pretty.c
+++ b/pretty.c
@@ -6,6 +6,7 @@
 #include "string-list.h"
 #include "mailmap.h"
 #include "log-tree.h"
+#include "notes.h"
 #include "color.h"
 
 static char *user_format;
@@ -975,5 +976,9 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 	 */
 	if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
 		strbuf_addch(sb, '\n');
+
+	if (fmt != CMIT_FMT_ONELINE)
+		get_commit_notes(commit, sb, encoding);
+
 	free(reencoded);
 }
-- 
1.6.4.304.g1365c.dirty

^ permalink raw reply related

* [RFC/PATCHv7 06/22] fast-import: Add support for importing commit notes
From: Johan Herland @ 2009-10-09 10:22 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam
In-Reply-To: <1255083738-23263-1-git-send-email-johan@herland.net>

Introduce a 'notemodify' subcommand of the 'commit' command. This subcommand
is similar to 'filemodify', except that no mode is supplied (all notes have
mode 0644), and the path is set to the hex SHA1 of the given "comittish".

This enables fast import of note objects along with their associated commits,
since the notes can now be named using the mark references of their
corresponding commits.

The patch also includes a test case of the added functionality.

Signed-off-by: Johan Herland <johan@herland.net>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
---
 Documentation/git-fast-import.txt |   45 +++++++++--
 fast-import.c                     |   88 +++++++++++++++++++-
 t/t9300-fast-import.sh            |  166 +++++++++++++++++++++++++++++++++++++
 3 files changed, 289 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index f1c94b4..bb198c2 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -325,7 +325,7 @@ change to the project.
 	data
 	('from' SP <committish> LF)?
 	('merge' SP <committish> LF)?
-	(filemodify | filedelete | filecopy | filerename | filedeleteall)*
+	(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
 	LF?
 ....
 
@@ -348,14 +348,13 @@ commit message use a 0 length data.  Commit messages are free-form
 and are not interpreted by Git.  Currently they must be encoded in
 UTF-8, as fast-import does not permit other encodings to be specified.
 
-Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`
-and `filedeleteall` commands
+Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`,
+`filedeleteall` and `notemodify` commands
 may be included to update the contents of the branch prior to
 creating the commit.  These commands may be supplied in any order.
 However it is recommended that a `filedeleteall` command precede
-all `filemodify`, `filecopy` and `filerename` commands in the same
-commit, as `filedeleteall`
-wipes the branch clean (see below).
+all `filemodify`, `filecopy`, `filerename` and `notemodify` commands in
+the same commit, as `filedeleteall` wipes the branch clean (see below).
 
 The `LF` after the command is optional (it used to be required).
 
@@ -604,6 +603,40 @@ more memory per active branch (less than 1 MiB for even most large
 projects); so frontends that can easily obtain only the affected
 paths for a commit are encouraged to do so.
 
+`notemodify`
+^^^^^^^^^^^^
+Included in a `commit` command to add a new note (annotating a given
+commit) or change the content of an existing note.  This command has
+two different means of specifying the content of the note.
+
+External data format::
+	The data content for the note was already supplied by a prior
+	`blob` command.  The frontend just needs to connect it to the
+	commit that is to be annotated.
++
+....
+	'N' SP <dataref> SP <committish> LF
+....
++
+Here `<dataref>` can be either a mark reference (`:<idnum>`)
+set by a prior `blob` command, or a full 40-byte SHA-1 of an
+existing Git blob object.
+
+Inline data format::
+	The data content for the note has not been supplied yet.
+	The frontend wants to supply it as part of this modify
+	command.
++
+....
+	'N' SP 'inline' SP <committish> LF
+	data
+....
++
+See below for a detailed description of the `data` command.
+
+In both formats `<committish>` is any of the commit specification
+expressions also accepted by `from` (see above).
+
 `mark`
 ~~~~~~
 Arranges for fast-import to save a reference to the current object, allowing
diff --git a/fast-import.c b/fast-import.c
index 992220e..fcdcfaa 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -22,8 +22,8 @@ Format of STDIN stream:
     ('author' sp name sp '<' email '>' sp when lf)?
     'committer' sp name sp '<' email '>' sp when lf
     commit_msg
-    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
-    ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
+    ('from' sp committish lf)?
+    ('merge' sp committish lf)*
     file_change*
     lf?;
   commit_msg ::= data;
@@ -41,15 +41,18 @@ Format of STDIN stream:
   file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
   file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
     data;
+  note_obm ::= 'N' sp (hexsha1 | idnum) sp committish lf;
+  note_inm ::= 'N' sp 'inline' sp committish lf
+    data;
 
   new_tag ::= 'tag' sp tag_str lf
-    'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
+    'from' sp committish lf
     ('tagger' sp name sp '<' email '>' sp when lf)?
     tag_msg;
   tag_msg ::= data;
 
   reset_branch ::= 'reset' sp ref_str lf
-    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    ('from' sp committish lf)?
     lf?;
 
   checkpoint ::= 'checkpoint' lf
@@ -88,6 +91,7 @@ Format of STDIN stream:
      # stream formatting is: \, " and LF.  Otherwise these values
      # are UTF8.
      #
+  committish  ::= (ref_str | hexsha1 | sha1exp_str | idnum);
   ref_str     ::= ref;
   sha1exp_str ::= sha1exp;
   tag_str     ::= tag;
@@ -2056,6 +2060,80 @@ static void file_change_cr(struct branch *b, int rename)
 		leaf.tree);
 }
 
+static void note_change_n(struct branch *b)
+{
+	const char *p = command_buf.buf + 2;
+	static struct strbuf uq = STRBUF_INIT;
+	struct object_entry *oe = oe;
+	struct branch *s;
+	unsigned char sha1[20], commit_sha1[20];
+	uint16_t inline_data = 0;
+
+	/* <dataref> or 'inline' */
+	if (*p == ':') {
+		char *x;
+		oe = find_mark(strtoumax(p + 1, &x, 10));
+		hashcpy(sha1, oe->sha1);
+		p = x;
+	} else if (!prefixcmp(p, "inline")) {
+		inline_data = 1;
+		p += 6;
+	} else {
+		if (get_sha1_hex(p, sha1))
+			die("Invalid SHA1: %s", command_buf.buf);
+		oe = find_object(sha1);
+		p += 40;
+	}
+	if (*p++ != ' ')
+		die("Missing space after SHA1: %s", command_buf.buf);
+
+	/* <committish> */
+	s = lookup_branch(p);
+	if (s) {
+		hashcpy(commit_sha1, s->sha1);
+	} else if (*p == ':') {
+		uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
+		struct object_entry *commit_oe = find_mark(commit_mark);
+		if (commit_oe->type != OBJ_COMMIT)
+			die("Mark :%" PRIuMAX " not a commit", commit_mark);
+		hashcpy(commit_sha1, commit_oe->sha1);
+	} else if (!get_sha1(p, commit_sha1)) {
+		unsigned long size;
+		char *buf = read_object_with_reference(commit_sha1,
+			commit_type, &size, commit_sha1);
+		if (!buf || size < 46)
+			die("Not a valid commit: %s", p);
+		free(buf);
+	} else
+		die("Invalid ref name or SHA1 expression: %s", p);
+
+	if (inline_data) {
+		static struct strbuf buf = STRBUF_INIT;
+
+		if (p != uq.buf) {
+			strbuf_addstr(&uq, p);
+			p = uq.buf;
+		}
+		read_next_command();
+		parse_data(&buf);
+		store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
+	} else if (oe) {
+		if (oe->type != OBJ_BLOB)
+			die("Not a blob (actually a %s): %s",
+				typename(oe->type), command_buf.buf);
+	} else {
+		enum object_type type = sha1_object_info(sha1, NULL);
+		if (type < 0)
+			die("Blob not found: %s", command_buf.buf);
+		if (type != OBJ_BLOB)
+			die("Not a blob (actually a %s): %s",
+			    typename(type), command_buf.buf);
+	}
+
+	tree_content_set(&b->branch_tree, sha1_to_hex(commit_sha1), sha1,
+		S_IFREG | 0644, NULL);
+}
+
 static void file_change_deleteall(struct branch *b)
 {
 	release_tree_content_recursive(b->branch_tree.tree);
@@ -2225,6 +2303,8 @@ static void parse_new_commit(void)
 			file_change_cr(b, 1);
 		else if (!prefixcmp(command_buf.buf, "C "))
 			file_change_cr(b, 0);
+		else if (!prefixcmp(command_buf.buf, "N "))
+			note_change_n(b);
 		else if (!strcmp("deleteall", command_buf.buf))
 			file_change_deleteall(b);
 		else {
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index d33fc55..2f5c323 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -1089,6 +1089,172 @@ test_expect_success 'P: fail on blob mark in gitlink' '
     test_must_fail git fast-import <input'
 
 ###
+### series Q (notes)
+###
+
+note1_data="Note for the first commit"
+note2_data="Note for the second commit"
+note3_data="Note for the third commit"
+
+test_tick
+cat >input <<INPUT_END
+blob
+mark :2
+data <<EOF
+$file2_data
+EOF
+
+commit refs/heads/notes-test
+mark :3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+first (:3)
+COMMIT
+
+M 644 :2 file2
+
+blob
+mark :4
+data $file4_len
+$file4_data
+commit refs/heads/notes-test
+mark :5
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+second (:5)
+COMMIT
+
+M 644 :4 file4
+
+commit refs/heads/notes-test
+mark :6
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+third (:6)
+COMMIT
+
+M 644 inline file5
+data <<EOF
+$file5_data
+EOF
+
+M 755 inline file6
+data <<EOF
+$file6_data
+EOF
+
+blob
+mark :7
+data <<EOF
+$note1_data
+EOF
+
+blob
+mark :8
+data <<EOF
+$note2_data
+EOF
+
+commit refs/notes/foobar
+mark :9
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+notes (:9)
+COMMIT
+
+N :7 :3
+N :8 :5
+N inline :6
+data <<EOF
+$note3_data
+EOF
+
+INPUT_END
+test_expect_success \
+	'Q: commit notes' \
+	'git fast-import <input &&
+	 git whatchanged notes-test'
+test_expect_success \
+	'Q: verify pack' \
+	'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+commit1=$(git rev-parse notes-test~2)
+commit2=$(git rev-parse notes-test^)
+commit3=$(git rev-parse notes-test)
+
+cat >expect <<EOF
+author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+
+first (:3)
+EOF
+test_expect_success \
+	'Q: verify first commit' \
+	'git cat-file commit notes-test~2 | sed 1d >actual &&
+	test_cmp expect actual'
+
+cat >expect <<EOF
+parent $commit1
+author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+
+second (:5)
+EOF
+test_expect_success \
+	'Q: verify second commit' \
+	'git cat-file commit notes-test^ | sed 1d >actual &&
+	test_cmp expect actual'
+
+cat >expect <<EOF
+parent $commit2
+author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+
+third (:6)
+EOF
+test_expect_success \
+	'Q: verify third commit' \
+	'git cat-file commit notes-test | sed 1d >actual &&
+	test_cmp expect actual'
+
+cat >expect <<EOF
+author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+
+notes (:9)
+EOF
+test_expect_success \
+	'Q: verify notes commit' \
+	'git cat-file commit refs/notes/foobar | sed 1d >actual &&
+	test_cmp expect actual'
+
+cat >expect.unsorted <<EOF
+100644 blob $commit1
+100644 blob $commit2
+100644 blob $commit3
+EOF
+cat expect.unsorted | sort >expect
+test_expect_success \
+	'Q: verify notes tree' \
+	'git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]*	/ /" >actual &&
+	 test_cmp expect actual'
+
+echo "$note1_data" >expect
+test_expect_success \
+	'Q: verify note for first commit' \
+	'git cat-file blob refs/notes/foobar:$commit1 >actual && test_cmp expect actual'
+
+echo "$note2_data" >expect
+test_expect_success \
+	'Q: verify note for second commit' \
+	'git cat-file blob refs/notes/foobar:$commit2 >actual && test_cmp expect actual'
+
+echo "$note3_data" >expect
+test_expect_success \
+	'Q: verify note for third commit' \
+	'git cat-file blob refs/notes/foobar:$commit3 >actual && test_cmp expect actual'
+
+###
 ### series R (feature and option)
 ###
 
-- 
1.6.4.304.g1365c.dirty

^ permalink raw reply related

* [RFC/PATCHv7 03/22] Speed up git notes lookup
From: Johan Herland @ 2009-10-09 10:21 UTC (permalink / raw)
  To: git
  Cc: gitster, johan, Johannes.Schindelin, trast, tavestbo, git,
	chriscool, spearce, sam, Johannes Schindelin
In-Reply-To: <1255083738-23263-1-git-send-email-johan@herland.net>

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

To avoid looking up each and every commit in the notes ref's tree
object, which is very expensive, speed things up by slurping the tree
object's contents into a hash_map.

The idea for the hashmap singleton is from David Reiss, initial
benchmarking by Jeff King.

Note: the implementation allows for arbitrary entries in the notes
tree object, ignoring those that do not reference a valid object.  This
allows you to annotate arbitrary branches, or objects.

This patch has been improved by the following contributions:
- Junio C Hamano: fixed an obvious error in initialize_hash_map()

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 notes.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 102 insertions(+), 10 deletions(-)

diff --git a/notes.c b/notes.c
index 66379ff..2b66723 100644
--- a/notes.c
+++ b/notes.c
@@ -4,15 +4,112 @@
 #include "refs.h"
 #include "utf8.h"
 #include "strbuf.h"
+#include "tree-walk.h"
+
+struct entry {
+	unsigned char commit_sha1[20];
+	unsigned char notes_sha1[20];
+};
+
+struct hash_map {
+	struct entry *entries;
+	off_t count, size;
+};
 
 static int initialized;
+static struct hash_map hash_map;
+
+static int hash_index(struct hash_map *map, const unsigned char *sha1)
+{
+	int i = ((*(unsigned int *)sha1) % map->size);
+
+	for (;;) {
+		unsigned char *current = map->entries[i].commit_sha1;
+
+		if (!hashcmp(sha1, current))
+			return i;
+
+		if (is_null_sha1(current))
+			return -1 - i;
+
+		if (++i == map->size)
+			i = 0;
+	}
+}
+
+static void add_entry(const unsigned char *commit_sha1,
+		const unsigned char *notes_sha1)
+{
+	int index;
+
+	if (hash_map.count + 1 > hash_map.size >> 1) {
+		int i, old_size = hash_map.size;
+		struct entry *old = hash_map.entries;
+
+		hash_map.size = old_size ? old_size << 1 : 64;
+		hash_map.entries = (struct entry *)
+			xcalloc(sizeof(struct entry), hash_map.size);
+
+		for (i = 0; i < old_size; i++)
+			if (!is_null_sha1(old[i].commit_sha1)) {
+				index = -1 - hash_index(&hash_map,
+						old[i].commit_sha1);
+				memcpy(hash_map.entries + index, old + i,
+					sizeof(struct entry));
+			}
+		free(old);
+	}
+
+	index = hash_index(&hash_map, commit_sha1);
+	if (index < 0) {
+		index = -1 - index;
+		hash_map.count++;
+	}
+
+	hashcpy(hash_map.entries[index].commit_sha1, commit_sha1);
+	hashcpy(hash_map.entries[index].notes_sha1, notes_sha1);
+}
+
+static void initialize_hash_map(const char *notes_ref_name)
+{
+	unsigned char sha1[20], commit_sha1[20];
+	unsigned mode;
+	struct tree_desc desc;
+	struct name_entry entry;
+	void *buf;
+
+	if (!notes_ref_name || read_ref(notes_ref_name, commit_sha1) ||
+	    get_tree_entry(commit_sha1, "", sha1, &mode))
+		return;
+
+	buf = fill_tree_descriptor(&desc, sha1);
+	if (!buf)
+		die("Could not read %s for notes-index", sha1_to_hex(sha1));
+
+	while (tree_entry(&desc, &entry))
+		if (!get_sha1(entry.path, commit_sha1))
+			add_entry(commit_sha1, entry.sha1);
+	free(buf);
+}
+
+static unsigned char *lookup_notes(const unsigned char *commit_sha1)
+{
+	int index;
+
+	if (!hash_map.size)
+		return NULL;
+
+	index = hash_index(&hash_map, commit_sha1);
+	if (index < 0)
+		return NULL;
+	return hash_map.entries[index].notes_sha1;
+}
 
 void get_commit_notes(const struct commit *commit, struct strbuf *sb,
 		const char *output_encoding)
 {
 	static const char utf8[] = "utf-8";
-	struct strbuf name = STRBUF_INIT;
-	unsigned char sha1[20];
+	unsigned char *sha1;
 	char *msg, *msg_p;
 	unsigned long linelen, msglen;
 	enum object_type type;
@@ -23,17 +120,12 @@ void get_commit_notes(const struct commit *commit, struct strbuf *sb,
 			notes_ref_name = getenv(GIT_NOTES_REF_ENVIRONMENT);
 		else if (!notes_ref_name)
 			notes_ref_name = GIT_NOTES_DEFAULT_REF;
-		if (notes_ref_name && read_ref(notes_ref_name, sha1))
-			notes_ref_name = NULL;
+		initialize_hash_map(notes_ref_name);
 		initialized = 1;
 	}
 
-	if (!notes_ref_name)
-		return;
-
-	strbuf_addf(&name, "%s:%s", notes_ref_name,
-			sha1_to_hex(commit->object.sha1));
-	if (get_sha1(name.buf, sha1))
+	sha1 = lookup_notes(commit->object.sha1);
+	if (!sha1)
 		return;
 
 	if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
-- 
1.6.4.304.g1365c.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