Merge branch 'jh/notes' (early part)
authorJunio C Hamano <gitster@pobox.com>
Sat, 21 Nov 2009 07:53:55 +0000 (23:53 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 21 Nov 2009 07:53:55 +0000 (23:53 -0800)
* 'jh/notes' (early part):
Add selftests verifying concatenation of multiple notes for the same commit
Refactor notes code to concatenate multiple notes annotating the same object
Add selftests verifying that we can parse notes trees with various fanouts
Teach the notes lookup code to parse notes trees with various fanout schemes
Teach notes code to free its internal data structures on request
Add '%N'-format for pretty-printing commit notes
Add flags to get_commit_notes() to control the format of the note string
t3302-notes-index-expensive: Speed up create_repo()
fast-import: Add support for importing commit notes
Teach "-m <msg>" and "-F <file>" to "git notes edit"
Add an expensive test for git-notes
Speed up git notes lookup
Add a script to edit/inspect notes
Introduce commit notes

Conflicts:
.gitignore
Documentation/pretty-formats.txt
pretty.c

1  2 
.gitignore
Documentation/config.txt
Documentation/pretty-formats.txt
Makefile
cache.h
command-list.txt
commit.c
fast-import.c
pretty.c
diff --combined .gitignore
index f63992a6cca190f1b226f746dfc815e7399f47b5,cbafa64b44905ec61a643b1b1b3dfe3c04ff3e38..ac02a580daf07150b03194a5a0de522ac1e3415d
 -GIT-BUILD-OPTIONS
 -GIT-CFLAGS
 -GIT-GUI-VARS
 -GIT-VERSION-FILE
 -git
 -git-add
 -git-add--interactive
 -git-am
 -git-annotate
 -git-apply
 -git-archimport
 -git-archive
 -git-bisect
 -git-bisect--helper
 -git-blame
 -git-branch
 -git-bundle
 -git-cat-file
 -git-check-attr
 -git-check-ref-format
 -git-checkout
 -git-checkout-index
 -git-cherry
 -git-cherry-pick
 -git-clean
 -git-clone
 -git-commit
 -git-commit-tree
 -git-config
 -git-count-objects
 -git-cvsexportcommit
 -git-cvsimport
 -git-cvsserver
 -git-daemon
 -git-diff
 -git-diff-files
 -git-diff-index
 -git-diff-tree
 -git-difftool
 -git-difftool--helper
 -git-describe
 -git-fast-export
 -git-fast-import
 -git-fetch
 -git-fetch--tool
 -git-fetch-pack
 -git-filter-branch
 -git-fmt-merge-msg
 -git-for-each-ref
 -git-format-patch
 -git-fsck
 -git-fsck-objects
 -git-gc
 -git-get-tar-commit-id
 -git-grep
 -git-hash-object
 -git-help
 -git-http-fetch
 -git-http-push
 -git-imap-send
 -git-index-pack
 -git-init
 -git-init-db
 -git-instaweb
 -git-log
 -git-lost-found
 -git-ls-files
 -git-ls-remote
 -git-ls-tree
 -git-mailinfo
 -git-mailsplit
 -git-merge
 -git-merge-base
 -git-merge-index
 -git-merge-file
 -git-merge-tree
 -git-merge-octopus
 -git-merge-one-file
 -git-merge-ours
 -git-merge-recursive
 -git-merge-resolve
 -git-merge-subtree
 -git-mergetool
 -git-mergetool--lib
 -git-mktag
 -git-mktree
 -git-name-rev
 -git-mv
 -git-notes
 -git-pack-redundant
 -git-pack-objects
 -git-pack-refs
 -git-parse-remote
 -git-patch-id
 -git-peek-remote
 -git-prune
 -git-prune-packed
 -git-pull
 -git-push
 -git-quiltimport
 -git-read-tree
 -git-rebase
 -git-rebase--interactive
 -git-receive-pack
 -git-reflog
 -git-relink
 -git-remote
 -git-remote-curl
 -git-repack
 -git-replace
 -git-repo-config
 -git-request-pull
 -git-rerere
 -git-reset
 -git-rev-list
 -git-rev-parse
 -git-revert
 -git-rm
 -git-send-email
 -git-send-pack
 -git-sh-setup
 -git-shell
 -git-shortlog
 -git-show
 -git-show-branch
 -git-show-index
 -git-show-ref
 -git-stage
 -git-stash
 -git-status
 -git-stripspace
 -git-submodule
 -git-svn
 -git-symbolic-ref
 -git-tag
 -git-tar-tree
 -git-unpack-file
 -git-unpack-objects
 -git-update-index
 -git-update-ref
 -git-update-server-info
 -git-upload-archive
 -git-upload-pack
 -git-var
 -git-verify-pack
 -git-verify-tag
 -git-web--browse
 -git-whatchanged
 -git-write-tree
 -git-core-*/?*
 -gitk-wish
 -gitweb/gitweb.cgi
 -test-chmtime
 -test-ctype
 -test-date
 -test-delta
 -test-dump-cache-tree
 -test-genrandom
 -test-match-trees
 -test-parse-options
 -test-path-utils
 -test-sha1
 -test-sigchain
 -common-cmds.h
 +/GIT-BUILD-OPTIONS
 +/GIT-CFLAGS
 +/GIT-GUI-VARS
 +/GIT-VERSION-FILE
 +/git
 +/git-add
 +/git-add--interactive
 +/git-am
 +/git-annotate
 +/git-apply
 +/git-archimport
 +/git-archive
 +/git-bisect
 +/git-bisect--helper
 +/git-blame
 +/git-branch
 +/git-bundle
 +/git-cat-file
 +/git-check-attr
 +/git-check-ref-format
 +/git-checkout
 +/git-checkout-index
 +/git-cherry
 +/git-cherry-pick
 +/git-clean
 +/git-clone
 +/git-commit
 +/git-commit-tree
 +/git-config
 +/git-count-objects
 +/git-cvsexportcommit
 +/git-cvsimport
 +/git-cvsserver
 +/git-daemon
 +/git-diff
 +/git-diff-files
 +/git-diff-index
 +/git-diff-tree
 +/git-difftool
 +/git-difftool--helper
 +/git-describe
 +/git-fast-export
 +/git-fast-import
 +/git-fetch
 +/git-fetch--tool
 +/git-fetch-pack
 +/git-filter-branch
 +/git-fmt-merge-msg
 +/git-for-each-ref
 +/git-format-patch
 +/git-fsck
 +/git-fsck-objects
 +/git-gc
 +/git-get-tar-commit-id
 +/git-grep
 +/git-hash-object
 +/git-help
 +/git-http-backend
 +/git-http-fetch
 +/git-http-push
 +/git-imap-send
 +/git-index-pack
 +/git-init
 +/git-init-db
 +/git-instaweb
 +/git-log
 +/git-lost-found
 +/git-ls-files
 +/git-ls-remote
 +/git-ls-tree
 +/git-mailinfo
 +/git-mailsplit
 +/git-merge
 +/git-merge-base
 +/git-merge-index
 +/git-merge-file
 +/git-merge-tree
 +/git-merge-octopus
 +/git-merge-one-file
 +/git-merge-ours
 +/git-merge-recursive
 +/git-merge-resolve
 +/git-merge-subtree
 +/git-mergetool
 +/git-mergetool--lib
 +/git-mktag
 +/git-mktree
 +/git-name-rev
 +/git-mv
++/git-notes
 +/git-pack-redundant
 +/git-pack-objects
 +/git-pack-refs
 +/git-parse-remote
 +/git-patch-id
 +/git-peek-remote
 +/git-prune
 +/git-prune-packed
 +/git-pull
 +/git-push
 +/git-quiltimport
 +/git-read-tree
 +/git-rebase
 +/git-rebase--interactive
 +/git-receive-pack
 +/git-reflog
 +/git-relink
 +/git-remote
 +/git-remote-curl
 +/git-repack
 +/git-replace
 +/git-repo-config
 +/git-request-pull
 +/git-rerere
 +/git-reset
 +/git-rev-list
 +/git-rev-parse
 +/git-revert
 +/git-rm
 +/git-send-email
 +/git-send-pack
 +/git-sh-setup
 +/git-shell
 +/git-shortlog
 +/git-show
 +/git-show-branch
 +/git-show-index
 +/git-show-ref
 +/git-stage
 +/git-stash
 +/git-status
 +/git-stripspace
 +/git-submodule
 +/git-svn
 +/git-symbolic-ref
 +/git-tag
 +/git-tar-tree
 +/git-unpack-file
 +/git-unpack-objects
 +/git-update-index
 +/git-update-ref
 +/git-update-server-info
 +/git-upload-archive
 +/git-upload-pack
 +/git-var
 +/git-verify-pack
 +/git-verify-tag
 +/git-web--browse
 +/git-whatchanged
 +/git-write-tree
 +/git-core-*/?*
 +/gitk-git/gitk-wish
 +/gitweb/gitweb.cgi
 +/test-chmtime
 +/test-ctype
 +/test-date
 +/test-delta
 +/test-dump-cache-tree
 +/test-genrandom
 +/test-match-trees
 +/test-parse-options
 +/test-path-utils
 +/test-sha1
 +/test-sigchain
 +/common-cmds.h
  *.tar.gz
  *.dsc
  *.deb
 -git.spec
 +/git.spec
  *.exe
  *.[aos]
  *.py[co]
 -config.mak
 -autom4te.cache
 -config.cache
 -config.log
 -config.status
 -config.mak.autogen
 -config.mak.append
 -configure
 -tags
 -TAGS
 -cscope*
 +*+
 +/config.mak
 +/autom4te.cache
 +/config.cache
 +/config.log
 +/config.status
 +/config.mak.autogen
 +/config.mak.append
 +/configure
 +/tags
 +/TAGS
 +/cscope*
  *.obj
  *.lib
  *.sln
  *.user
  *.idb
  *.pdb
 -Debug/
 -Release/
 +/Debug/
 +/Release/
diff --combined Documentation/config.txt
index 1ff21938e7cc2924f8637649c7378bacb82da26d,57d64e4d990bc60d9fd94e9ef55826bb2b2e9643..78ee90631986f8299a804c8f311282fadbc0dfd7
@@@ -387,7 -387,9 +387,7 @@@ core.editor:
        Commands such as `commit` and `tag` that lets you edit
        messages by launching an editor uses the value of this
        variable when it is set, and the environment variable
 -      `GIT_EDITOR` is not set.  The order of preference is
 -      `GIT_EDITOR` environment, `core.editor`, `VISUAL` and
 -      `EDITOR` environment variables and then finally `vi`.
 +      `GIT_EDITOR` is not set.  See linkgit:git-var[1].
  
  core.pager::
        The command that git will use to paginate output.  Can
@@@ -414,17 -416,13 +414,17 @@@ core.whitespace:
        consider them as errors.  You can prefix `-` to disable
        any of them (e.g. `-trailing-space`):
  +
 -* `trailing-space` treats trailing whitespaces at the end of the line
 +* `blank-at-eol` treats trailing whitespaces at the end of the line
    as an error (enabled by default).
  * `space-before-tab` treats a space character that appears immediately
    before a tab character in the initial indent part of the line as an
    error (enabled by default).
  * `indent-with-non-tab` treats a line that is indented with 8 or more
    space characters as an error (not enabled by default).
 +* `blank-at-eof` treats blank lines added at the end of file as an error
 +  (enabled by default).
 +* `trailing-space` is a short-hand to cover both `blank-at-eol` and
 +  `blank-at-eof`.
  * `cr-at-eol` treats a carriage-return at the end of line as
    part of the line terminator, i.e. with it, `trailing-space`
    does not trigger if the character before such a carriage-return
@@@ -456,6 -454,19 +456,19 @@@ On some file system/operating system co
  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'
@@@ -1091,14 -1102,6 +1104,14 @@@ http.maxRequests:
        How many HTTP requests to launch in parallel. Can be overridden
        by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
  
 +http.postBuffer::
 +      Maximum size in bytes of the buffer used by smart HTTP
 +      transports when POSTing data to the remote system.
 +      For requests larger than this buffer size, HTTP/1.1 and
 +      Transfer-Encoding: chunked is used to avoid creating a
 +      massive pack file locally.  Default is 1 MiB, which is
 +      sufficient for most requests.
 +
  http.lowSpeedLimit, http.lowSpeedTime::
        If the HTTP transfer speed is less than 'http.lowSpeedLimit'
        for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
@@@ -1330,11 -1333,6 +1343,11 @@@ rebase.stat:
        Whether to show a diffstat of what changed upstream since the last
        rebase. False by default.
  
 +receive.autogc::
 +      By default, git-receive-pack will run "git-gc --auto" after
 +      receiving data from git-push and updating refs.  You can stop
 +      it by setting this variable to false.
 +
  receive.fsckObjects::
        If it is set to true, git-receive-pack will check all received
        objects. It will abort in the case of a malformed object or a
@@@ -1366,14 -1364,10 +1379,14 @@@ receive.denyCurrentBranch:
  
  receive.denyNonFastForwards::
        If set to true, git-receive-pack will deny a ref update which is
 -      not a fast forward. Use this to prevent such an update via a push,
 +      not a fast-forward. Use this to prevent such an update via a push,
        even if that push is forced. This configuration variable is
        set when initializing a shared repository.
  
 +receive.updateserverinfo::
 +      If set to true, git-receive-pack will run git-update-server-info
 +      after receiving data from git-push and updating refs.
 +
  remote.<name>.url::
        The URL of a remote repository.  See linkgit:git-fetch[1] or
        linkgit:git-push[1].
index 38b9904791466152a98ab3df7c5b84ac66dbac73,5fb10b3a1525dabd0f0e75835847a6187fa99a30..09462021ead2591ae1f21f4441ff0bc357af2a1c
@@@ -123,9 -123,7 +123,10 @@@ The placeholders are
  - '%s': subject
  - '%f': sanitized subject line, suitable for a filename
  - '%b': body
+ - '%N': commit notes
 +- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
 +- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
 +- '%gs': reflog subject
  - '%Cred': switch color to red
  - '%Cgreen': switch color to green
  - '%Cblue': switch color to blue
  - '%n': newline
  - '%x00': print a byte from a hex code
  
 +NOTE: Some placeholders may depend on other options given to the
 +revision traversal engine. For example, the `%g*` reflog options will
 +insert an empty string unless we are traversing reflog entries (e.g., by
 +`git log -g`). The `%d` placeholder will use the "short" decoration
 +format if `--decorate` was not already provided on the command line.
 +
  * 'tformat:'
  +
  The 'tformat:' format works exactly like 'format:', except that it
diff --combined Makefile
index da418c39c9a6f1c77cb47e1d051fd99d6adc9bcc,8d7cec79d9097c2d822a329a862700940c04441f..abb7a741eeeaf4b4823260a3253533e90d0d8719
+++ b/Makefile
@@@ -159,10 -159,6 +159,10 @@@ all:
  # Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives
  # (versions 1.72 and later and 1.68.1 and earlier).
  #
 +# Define GNU_ROFF if your target system uses GNU groff.  This forces
 +# apostrophes to be ASCII so that cut&pasting examples to the shell
 +# will work.
 +#
  # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
  # MakeMaker (e.g. using ActiveState under Cygwin).
  #
  # memory allocators with the nedmalloc allocator written by Niall Douglas.
  #
  # Define NO_REGEX if you have no or inferior regex support in your C library.
 +#
 +# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
 +# you want to use something different.  The value will be interpreted by the
 +# shell at runtime when it is used.
 +#
 +# Define DEFAULT_EDITOR to a sensible editor command (defaults to "vi") if you
 +# want to use something different.  The value will be interpreted by the shell
 +# if necessary when it is used.  Examples:
 +#
 +#   DEFAULT_EDITOR='~/bin/vi',
 +#   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
 +#   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
  
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@@ -228,12 -212,6 +228,12 @@@ uname_R := $(shell sh -c 'uname -r 2>/d
  uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
  uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
  
 +ifdef MSVC
 +      # avoid the MingW and Cygwin configuration sections
 +      uname_S := Windows
 +      uname_O := Windows
 +endif
 +
  # CFLAGS and LDFLAGS are for the users to override from the command line.
  
  CFLAGS = -g -O2 -Wall
@@@ -343,6 -321,7 +343,7 @@@ SCRIPT_SH += git-merge-one-file.s
  SCRIPT_SH += git-merge-resolve.sh
  SCRIPT_SH += git-mergetool.sh
  SCRIPT_SH += git-mergetool--lib.sh
+ SCRIPT_SH += git-notes.sh
  SCRIPT_SH += git-parse-remote.sh
  SCRIPT_SH += git-pull.sh
  SCRIPT_SH += git-quiltimport.sh
@@@ -376,7 -355,6 +377,7 @@@ EXTRA_PROGRAMS 
  PROGRAMS += $(EXTRA_PROGRAMS)
  PROGRAMS += git-fast-import$X
  PROGRAMS += git-hash-object$X
 +PROGRAMS += git-imap-send$X
  PROGRAMS += git-index-pack$X
  PROGRAMS += git-merge-index$X
  PROGRAMS += git-merge-tree$X
@@@ -388,7 -366,6 +389,7 @@@ PROGRAMS += git-show-index$
  PROGRAMS += git-unpack-file$X
  PROGRAMS += git-upload-pack$X
  PROGRAMS += git-var$X
 +PROGRAMS += git-http-backend$X
  
  # List built-in command $C whose implementation cmd_$C() is not in
  # builtin-$C.o but is linked in as part of some other command.
@@@ -436,7 -413,6 +437,7 @@@ LIB_H += builtin.
  LIB_H += cache.h
  LIB_H += cache-tree.h
  LIB_H += commit.h
 +LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
  LIB_H += csum-file.h
@@@ -457,6 -433,7 +458,7 @@@ LIB_H += ll-merge.
  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
@@@ -477,7 -454,6 +479,7 @@@ LIB_H += sideband.
  LIB_H += sigchain.h
  LIB_H += strbuf.h
  LIB_H += string-list.h
 +LIB_H += submodule.h
  LIB_H += tag.h
  LIB_H += transport.h
  LIB_H += tree.h
@@@ -542,6 -518,7 +544,7 @@@ LIB_OBJS += match-trees.
  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
@@@ -576,7 -553,6 +579,7 @@@ LIB_OBJS += sideband.
  LIB_OBJS += sigchain.o
  LIB_OBJS += strbuf.o
  LIB_OBJS += string-list.o
 +LIB_OBJS += submodule.o
  LIB_OBJS += symlinks.o
  LIB_OBJS += tag.o
  LIB_OBJS += trace.o
@@@ -621,6 -597,7 +624,6 @@@ BUILTIN_OBJS += builtin-diff-index.
  BUILTIN_OBJS += builtin-diff-tree.o
  BUILTIN_OBJS += builtin-diff.o
  BUILTIN_OBJS += builtin-fast-export.o
 -BUILTIN_OBJS += builtin-fetch--tool.o
  BUILTIN_OBJS += builtin-fetch-pack.o
  BUILTIN_OBJS += builtin-fetch.o
  BUILTIN_OBJS += builtin-fmt-merge-msg.o
@@@ -808,8 -785,6 +811,8 @@@ ifeq ($(uname_O),Cygwin
        NO_MMAP = YesPlease
        NO_IPV6 = YesPlease
        X = .exe
 +      COMPAT_OBJS += compat/cygwin.o
 +      UNRELIABLE_FSTAT = UnfortunatelyYes
  endif
  ifeq ($(uname_S),FreeBSD)
        NEEDS_LIBICONV = YesPlease
@@@ -919,11 -894,15 +922,11 @@@ ifeq ($(uname_S),HP-UX
        NO_SYS_SELECT_H = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
  endif
 -ifneq (,$(findstring CYGWIN,$(uname_S)))
 -      COMPAT_OBJS += compat/cygwin.o
 -      UNRELIABLE_FSTAT = UnfortunatelyYes
 -endif
 -ifdef MSVC
 +ifeq ($(uname_S),Windows)
        GIT_VERSION := $(GIT_VERSION).MSVC
        pathsep = ;
        NO_PREAD = YesPlease
 -      NO_OPENSSL = YesPlease
 +      NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
        NO_SYMLINK_HEAD = YesPlease
        NO_IPV6 = YesPlease
        NO_REGEX = YesPlease
        NO_CURL = YesPlease
        NO_PTHREADS = YesPlease
 +      BLK_SHA1 = YesPlease
  
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
@@@ -972,11 -950,11 +975,11 @@@ els
        BASIC_CFLAGS += -Zi -MTd
  endif
        X = .exe
 -else
 +endif
  ifneq (,$(findstring MINGW,$(uname_S)))
        pathsep = ;
        NO_PREAD = YesPlease
 -      NO_OPENSSL = YesPlease
 +      NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
        NO_SYMLINK_HEAD = YesPlease
        NO_IPV6 = YesPlease
        UNRELIABLE_FSTAT = UnfortunatelyYes
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
 +      BLK_SHA1 = YesPlease
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
@@@ -1022,6 -999,7 +1025,6 @@@ els
        NO_PTHREADS = YesPlease
  endif
  endif
 -endif
  
  -include config.mak.autogen
  -include config.mak
@@@ -1100,6 -1078,7 +1103,6 @@@ EXTLIBS += -l
  
  ifndef NO_POSIX_ONLY_PROGRAMS
        PROGRAMS += git-daemon$X
 -      PROGRAMS += git-imap-send$X
  endif
  ifndef NO_OPENSSL
        OPENSSL_LIBSSL = -lssl
@@@ -1387,22 -1366,6 +1390,22 @@@ BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_H
        $(COMPAT_CFLAGS)
  LIB_OBJS += $(COMPAT_OBJS)
  
 +# Quote for C
 +
 +ifdef DEFAULT_EDITOR
 +DEFAULT_EDITOR_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_EDITOR)))"
 +DEFAULT_EDITOR_CQ_SQ = $(subst ','\'',$(DEFAULT_EDITOR_CQ))
 +
 +BASIC_CFLAGS += -DDEFAULT_EDITOR='$(DEFAULT_EDITOR_CQ_SQ)'
 +endif
 +
 +ifdef DEFAULT_PAGER
 +DEFAULT_PAGER_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_PAGER)))"
 +DEFAULT_PAGER_CQ_SQ = $(subst ','\'',$(DEFAULT_PAGER_CQ))
 +
 +BASIC_CFLAGS += -DDEFAULT_PAGER='$(DEFAULT_PAGER_CQ_SQ)'
 +endif
 +
  ALL_CFLAGS += $(BASIC_CFLAGS)
  ALL_LDFLAGS += $(BASIC_LDFLAGS)
  
@@@ -1415,7 -1378,7 +1418,7 @@@ SHELL = $(SHELL_PATH
  
  all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
  ifneq (,$X)
 -      $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
 +      $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
  endif
  
  all::
@@@ -1839,10 -1802,7 +1842,10 @@@ dist: git.spec git-archive$(X) configur
        gzip -f -9 $(GIT_TARNAME).tar
  
  rpm: dist
 -      $(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
 +      $(RPMBUILD) \
 +              --define "_source_filedigest_algorithm md5" \
 +              --define "_binary_filedigest_algorithm md5" \
 +              -ta $(GIT_TARNAME).tar.gz
  
  htmldocs = git-htmldocs-$(GIT_VERSION)
  manpages = git-manpages-$(GIT_VERSION)
@@@ -1870,7 -1830,7 +1873,7 @@@ distclean: clea
        $(RM) configure
  
  clean:
 -      $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
 +      $(RM) *.o block-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
                $(LIB_FILE) $(XDIFF_LIB)
        $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS)
diff --combined cache.h
index 2cfce27abd703309690ef9bbc69105a32a70910a,4f0ddeca11b4bdfe9ee8ee5171e19094acf42a05..f7533ff86244f4132e46a4bd3b624d821b5717c9
+++ b/cache.h
@@@ -372,6 -372,8 +372,8 @@@ static inline enum object_type object_t
  #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);
@@@ -396,7 -398,6 +398,7 @@@ extern const char *setup_git_directory_
  extern const char *setup_git_directory(void);
  extern const char *prefix_path(const char *prefix, int len, const char *path);
  extern const char *prefix_filename(const char *prefix, int len, const char *path);
 +extern int check_filename(const char *prefix, const char *name);
  extern void verify_filename(const char *prefix, const char *name);
  extern void verify_non_filename(const char *prefix, const char *name);
  
@@@ -568,6 -569,8 +570,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
@@@ -657,7 -660,6 +661,7 @@@ const char *make_relative_path(const ch
  int normalize_path_copy(char *dst, const char *src);
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
 +int daemon_avoid_alias(const char *path);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
@@@ -752,8 -754,6 +756,8 @@@ extern const char *git_author_info(int)
  extern const char *git_committer_info(int);
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
 +extern const char *git_editor(void);
 +extern const char *git_pager(void);
  
  struct checkout {
        const char *base_dir;
@@@ -860,6 -860,7 +864,6 @@@ extern struct ref *find_ref_by_name(con
  extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
  extern int finish_connect(struct child_process *conn);
  extern int path_match(const char *path, int nr, char **match);
 -extern int get_ack(int fd, unsigned char *result_sha1);
  struct extra_have_objects {
        int nr, alloc;
        unsigned char (*array)[20];
@@@ -989,12 -990,10 +993,12 @@@ void shift_tree(const unsigned char *, 
   * whitespace rules.
   * used by both diff and apply
   */
 -#define WS_TRAILING_SPACE     01
 +#define WS_BLANK_AT_EOL         01
  #define WS_SPACE_BEFORE_TAB   02
  #define WS_INDENT_WITH_NON_TAB        04
  #define WS_CR_AT_EOL           010
 +#define WS_BLANK_AT_EOF        020
 +#define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
  #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
  extern unsigned whitespace_rule_cfg;
  extern unsigned whitespace_rule(const char *);
diff --combined command-list.txt
index 59b0adc39b7c2d30103fe5d30b416b6d4ca64c31,4296941b68f981577306afbe4b0e5eca685c6e25..cc5d48b3851cda643b3790ff326c04fdf1333d1c
@@@ -74,6 -74,7 +74,7 @@@ git-mkta
  git-mktree                              plumbingmanipulators
  git-mv                                  mainporcelain common
  git-name-rev                            plumbinginterrogators
+ git-notes                               mainporcelain
  git-pack-objects                        plumbingmanipulators
  git-pack-redundant                      plumbinginterrogators
  git-pack-refs                           ancillarymanipulators
@@@ -92,7 -93,6 +93,7 @@@ git-reflo
  git-relink                              ancillarymanipulators
  git-remote                              ancillarymanipulators
  git-repack                              ancillarymanipulators
 +git-replace                             ancillarymanipulators
  git-repo-config                         ancillarymanipulators deprecated
  git-request-pull                        foreignscminterface
  git-rerere                              ancillaryinterrogators
diff --combined commit.c
index 51839fbedb1cb19f3d0cb11c60c7b9f695975654,5ade8edf81cb887f425b1e15b4f02a2e25af9a02..632061c2c3669991b6526a5b6b452e3b54ee718c
+++ b/commit.c
@@@ -5,6 -5,7 +5,7 @@@
  #include "utf8.h"
  #include "diff.h"
  #include "revision.h"
+ #include "notes.h"
  
  int save_commit_buffer = 1;
  
@@@ -132,8 -133,8 +133,8 @@@ struct commit_graft *read_graft_line(ch
        int i;
        struct commit_graft *graft = NULL;
  
 -      if (buf[len-1] == '\n')
 -              buf[--len] = 0;
 +      while (len && isspace(buf[len-1]))
 +              buf[--len] = '\0';
        if (buf[0] == '#' || buf[0] == '\0')
                return NULL;
        if ((len + 1) % 41) {
@@@ -199,7 -200,7 +200,7 @@@ struct commit_graft *lookup_commit_graf
        return commit_graft[pos];
  }
  
 -int write_shallow_commits(int fd, int use_pack_protocol)
 +int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
  {
        int i, count = 0;
        for (i = 0; i < commit_graft_nr; i++)
                                sha1_to_hex(commit_graft[i]->sha1);
                        count++;
                        if (use_pack_protocol)
 -                              packet_write(fd, "shallow %s", hex);
 +                              packet_buf_write(out, "shallow %s", hex);
                        else {
 -                              if (write_in_full(fd, hex,  40) != 40)
 -                                      break;
 -                              if (write_str_in_full(fd, "\n") != 1)
 -                                      break;
 +                              strbuf_addstr(out, hex);
 +                              strbuf_addch(out, '\n');
                        }
                }
        return count;
diff --combined fast-import.c
index f4f1de6dd7f313ffe123bcf86bd92b70f54d3f5d,b41d29fd31e47f3a73e61af4fc14ac16dd7ae218..dd3c99d60d0ccf2506b08632c35c5ffc2bbc3255
@@@ -22,8 -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;
    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 +91,7 @@@
       # 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;
@@@ -2006,6 -2010,80 +2010,80 @@@ static void file_change_cr(struct branc
                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);
@@@ -2175,6 -2253,8 +2253,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 {
@@@ -2405,9 -2485,6 +2485,9 @@@ int main(int argc, const char **argv
  
        git_extract_argv0_path(argv[0]);
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage(fast_import_usage);
 +
        setup_git_directory();
        git_config(git_pack_config, NULL);
        if (!pack_compression_seen && core_compression_seen)
diff --combined pretty.c
index 2e031e62fd98c02bfa6cc558fc49aef86c03ed09,7f350bbdff050041f541d227de6bfe20ec7fe510..5661cba5952e2e68dd067a8afebe144bc1ca63af
+++ b/pretty.c
@@@ -6,8 -6,8 +6,9 @@@
  #include "string-list.h"
  #include "mailmap.h"
  #include "log-tree.h"
+ #include "notes.h"
  #include "color.h"
 +#include "reflog-walk.h"
  
  static char *user_format;
  
@@@ -443,10 -443,9 +444,10 @@@ struct chunk 
  
  struct format_commit_context {
        const struct commit *commit;
 -      enum date_mode dmode;
 +      const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
 +      size_t width, indent1, indent2;
  
        /* These offsets are relative to the start of the commit message. */
        struct chunk author;
        struct chunk abbrev_commit_hash;
        struct chunk abbrev_tree_hash;
        struct chunk abbrev_parent_hashes;
 +      size_t wrap_start;
  };
  
  static int add_again(struct strbuf *sb, struct chunk *chunk)
@@@ -598,35 -596,6 +599,35 @@@ static void format_decoration(struct st
                strbuf_addch(sb, ')');
  }
  
 +static void strbuf_wrap(struct strbuf *sb, size_t pos,
 +                      size_t width, size_t indent1, size_t indent2)
 +{
 +      struct strbuf tmp = STRBUF_INIT;
 +
 +      if (pos)
 +              strbuf_add(&tmp, sb->buf, pos);
 +      strbuf_add_wrapped_text(&tmp, sb->buf + pos,
 +                              (int) indent1, (int) indent2, (int) width);
 +      strbuf_swap(&tmp, sb);
 +      strbuf_release(&tmp);
 +}
 +
 +static void rewrap_message_tail(struct strbuf *sb,
 +                              struct format_commit_context *c,
 +                              size_t new_width, size_t new_indent1,
 +                              size_t new_indent2)
 +{
 +      if (c->width == new_width && c->indent1 == new_indent1 &&
 +          c->indent2 == new_indent2)
 +              return;
 +      if (c->wrap_start < sb->len)
 +              strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
 +      c->wrap_start = sb->len;
 +      c->width = new_width;
 +      c->indent1 = new_indent1;
 +      c->indent2 = new_indent2;
 +}
 +
  static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                                 void *context)
  {
                        return 3;
                } else
                        return 0;
 +      case 'w':
 +              if (placeholder[1] == '(') {
 +                      unsigned long width = 0, indent1 = 0, indent2 = 0;
 +                      char *next;
 +                      const char *start = placeholder + 2;
 +                      const char *end = strchr(start, ')');
 +                      if (!end)
 +                              return 0;
 +                      if (end > start) {
 +                              width = strtoul(start, &next, 10);
 +                              if (*next == ',') {
 +                                      indent1 = strtoul(next + 1, &next, 10);
 +                                      if (*next == ',') {
 +                                              indent2 = strtoul(next + 1,
 +                                                               &next, 10);
 +                                      }
 +                              }
 +                              if (*next != ')')
 +                                      return 0;
 +                      }
 +                      rewrap_message_tail(sb, c, width, indent1, indent2);
 +                      return end - placeholder + 1;
 +              } else
 +                      return 0;
        }
  
        /* these depend on the commit */
        case 'd':
                format_decoration(sb, commit);
                return 1;
 +      case 'g':               /* reflog info */
 +              switch(placeholder[1]) {
 +              case 'd':       /* reflog selector */
 +              case 'D':
 +                      if (c->pretty_ctx->reflog_info)
 +                              get_reflog_selector(sb,
 +                                                  c->pretty_ctx->reflog_info,
 +                                                  c->pretty_ctx->date_mode,
 +                                                  (placeholder[1] == 'd'));
 +                      return 2;
 +              case 's':       /* reflog message */
 +                      if (c->pretty_ctx->reflog_info)
 +                              get_reflog_message(sb, c->pretty_ctx->reflog_info);
 +                      return 2;
 +              }
 +              return 0;       /* unknown %g placeholder */
+       case 'N':
+               get_commit_notes(commit, sb, git_log_output_encoding ?
+                            git_log_output_encoding : git_commit_encoding, 0);
+               return 1;
        }
  
        /* For the rest we have to parse the commit header. */
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
 -                                 c->dmode);
 +                                 c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
 -                                 c->dmode);
 +                                 c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
  }
  
  void format_commit_message(const struct commit *commit,
 -                         const void *format, struct strbuf *sb,
 -                         enum date_mode dmode)
 +                         const char *format, struct strbuf *sb,
 +                         const struct pretty_print_context *pretty_ctx)
  {
        struct format_commit_context context;
  
        memset(&context, 0, sizeof(context));
        context.commit = commit;
 -      context.dmode = dmode;
 +      context.pretty_ctx = pretty_ctx;
 +      context.wrap_start = sb->len;
        strbuf_expand(sb, format, format_commit_item, &context);
 +      rewrap_message_tail(sb, &context, 0, 0, 0);
  }
  
  static void pp_header(enum cmit_fmt fmt,
@@@ -974,18 -905,18 +979,18 @@@ char *reencode_commit_message(const str
  }
  
  void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 -                       struct strbuf *sb, int abbrev,
 -                       const char *subject, const char *after_subject,
 -                       enum date_mode dmode, int need_8bit_cte)
 +                       struct strbuf *sb,
 +                       const struct pretty_print_context *context)
  {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
 +      int need_8bit_cte = context->need_8bit_cte;
  
        if (fmt == CMIT_FMT_USERFORMAT) {
 -              format_commit_message(commit, user_format, sb, dmode);
 +              format_commit_message(commit, user_format, sb, context);
                return;
        }
  
                }
        }
  
 -      pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
 -      if (fmt != CMIT_FMT_ONELINE && !subject) {
 +      pp_header(fmt, context->abbrev, context->date_mode, encoding,
 +                commit, &msg, sb);
 +      if (fmt != CMIT_FMT_ONELINE && !context->subject) {
                strbuf_addch(sb, '\n');
        }
  
  
        /* These formats treat the title line specially. */
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
 -              pp_title_line(fmt, &msg, sb, subject,
 -                            after_subject, encoding, need_8bit_cte);
 +              pp_title_line(fmt, &msg, sb, context->subject,
 +                            context->after_subject, encoding, need_8bit_cte);
  
        beginning_of_body = sb->len;
        if (fmt != CMIT_FMT_ONELINE)
         */
        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,
+                                NOTES_SHOW_HEADER | NOTES_INDENT);
        free(reencoded);
  }