# If not set it defaults to the bare 'wish'. If it is set to the empty
# string then NO_TCLTK will be forced (this is used by configure script).
#
-# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
-# parallel delta searching when packing objects.
-#
# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
# is a simplified version of the merge sort used in glibc. This is
# recommended if Git triggers O(n^2) behavior in your platform's qsort().
# DEFAULT_EDITOR='~/bin/vi',
# DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
# DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
+#
+# Define COMPUTE_HEADER_DEPENDENCIES if your compiler supports the -MMD option
+# and you want to avoid rebuilding objects when an unrelated header file
+# changes.
+#
+# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
+# dependency rules.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
# JavaScript minifier invocation that can function as filter
JSMIN =
-# default configuration for gitweb
-GITWEB_CONFIG = gitweb_config.perl
-GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
-GITWEB_HOME_LINK_STR = projects
-GITWEB_SITENAME =
-GITWEB_PROJECTROOT = /pub/git
-GITWEB_PROJECT_MAXDEPTH = 2007
-GITWEB_EXPORT_OK =
-GITWEB_STRICT_EXPORT =
-GITWEB_BASE_URL =
-GITWEB_LIST =
-GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = gitweb.css
-GITWEB_LOGO = git-logo.png
-GITWEB_FAVICON = git-favicon.png
-ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-else
-GITWEB_JS = gitweb.js
-endif
-GITWEB_SITE_HEADER =
-GITWEB_SITE_FOOTER =
-
export prefix bindir sharedir sysconfdir
CC = gcc
# Those must not be GNU-specific; they are shared with perl/ which may
# be built by a different compiler. (Note that this is an artifact now
# but it still might be nice to keep that distinction.)
-BASIC_CFLAGS =
+BASIC_CFLAGS = -I.
BASIC_LDFLAGS =
# Guard against environment variables
COMPAT_OBJS =
LIB_H =
LIB_OBJS =
+PROGRAM_OBJS =
PROGRAMS =
SCRIPT_PERL =
SCRIPT_PYTHON =
SCRIPT_SH =
-TEST_PROGRAMS =
+SCRIPT_LIB =
+TEST_PROGRAMS_NEED_X =
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
- SCRIPT_SH += git-notes.sh
-SCRIPT_SH += git-mergetool--lib.sh
-SCRIPT_SH += git-parse-remote.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase--interactive.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-repack.sh
SCRIPT_SH += git-request-pull.sh
-SCRIPT_SH += git-sh-setup.sh
SCRIPT_SH += git-stash.sh
SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-web--browse.sh
+SCRIPT_LIB += git-mergetool--lib
+SCRIPT_LIB += git-parse-remote
+SCRIPT_LIB += git-sh-setup
+
SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-difftool.perl
SCRIPT_PERL += git-archimport.perl
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
-PROGRAMS += git-fast-import$X
-PROGRAMS += git-imap-send$X
-PROGRAMS += git-shell$X
-PROGRAMS += git-show-index$X
-PROGRAMS += git-upload-pack$X
-PROGRAMS += git-http-backend$X
+
+PROGRAM_OBJS += fast-import.o
+PROGRAM_OBJS += imap-send.o
+PROGRAM_OBJS += shell.o
+PROGRAM_OBJS += show-index.o
+PROGRAM_OBJS += upload-pack.o
+PROGRAM_OBJS += http-backend.o
+
+PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
+
+TEST_PROGRAMS_NEED_X += test-chmtime
+TEST_PROGRAMS_NEED_X += test-ctype
+TEST_PROGRAMS_NEED_X += test-date
+TEST_PROGRAMS_NEED_X += test-delta
+TEST_PROGRAMS_NEED_X += test-dump-cache-tree
+TEST_PROGRAMS_NEED_X += test-genrandom
+TEST_PROGRAMS_NEED_X += test-match-trees
+TEST_PROGRAMS_NEED_X += test-parse-options
+TEST_PROGRAMS_NEED_X += test-path-utils
+TEST_PROGRAMS_NEED_X += test-run-command
+TEST_PROGRAMS_NEED_X += test-sha1
+TEST_PROGRAMS_NEED_X += test-sigchain
+TEST_PROGRAMS_NEED_X += test-index-version
+
+TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_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.
-BUILT_INS += $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
+# builtin/$C.o but is linked in as part of some other command.
+BUILT_INS += $(patsubst builtin/%.o,git-%$X,$(BUILTIN_OBJS))
BUILT_INS += git-cherry$X
BUILT_INS += git-cherry-pick$X
LIB_H += builtin.h
LIB_H += cache.h
LIB_H += cache-tree.h
+LIB_H += color.h
LIB_H += commit.h
LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h
LIB_H += diffcore.h
LIB_H += diff.h
LIB_H += dir.h
+LIB_H += exec_cmd.h
LIB_H += fsck.h
LIB_H += git-compat-util.h
LIB_H += graph.h
LIB_H += unpack-trees.h
LIB_H += userdiff.h
LIB_H += utf8.h
-LIB_H += wt-status.h
+LIB_H += xdiff-interface.h
+LIB_H += xdiff/xdiff.h
LIB_OBJS += abspath.o
LIB_OBJS += advice.o
LIB_OBJS += wt-status.o
LIB_OBJS += xdiff-interface.o
-BUILTIN_OBJS += builtin-add.o
-BUILTIN_OBJS += builtin-annotate.o
-BUILTIN_OBJS += builtin-apply.o
-BUILTIN_OBJS += builtin-archive.o
-BUILTIN_OBJS += builtin-bisect--helper.o
-BUILTIN_OBJS += builtin-blame.o
-BUILTIN_OBJS += builtin-branch.o
-BUILTIN_OBJS += builtin-bundle.o
-BUILTIN_OBJS += builtin-cat-file.o
-BUILTIN_OBJS += builtin-check-attr.o
-BUILTIN_OBJS += builtin-check-ref-format.o
-BUILTIN_OBJS += builtin-checkout-index.o
-BUILTIN_OBJS += builtin-checkout.o
-BUILTIN_OBJS += builtin-clean.o
-BUILTIN_OBJS += builtin-clone.o
-BUILTIN_OBJS += builtin-commit-tree.o
-BUILTIN_OBJS += builtin-commit.o
-BUILTIN_OBJS += builtin-config.o
-BUILTIN_OBJS += builtin-count-objects.o
-BUILTIN_OBJS += builtin-describe.o
-BUILTIN_OBJS += builtin-diff-files.o
-BUILTIN_OBJS += builtin-diff-index.o
-BUILTIN_OBJS += builtin-diff-tree.o
-BUILTIN_OBJS += builtin-diff.o
-BUILTIN_OBJS += builtin-fast-export.o
-BUILTIN_OBJS += builtin-fetch-pack.o
-BUILTIN_OBJS += builtin-fetch.o
-BUILTIN_OBJS += builtin-fmt-merge-msg.o
-BUILTIN_OBJS += builtin-for-each-ref.o
-BUILTIN_OBJS += builtin-fsck.o
-BUILTIN_OBJS += builtin-gc.o
-BUILTIN_OBJS += builtin-grep.o
-BUILTIN_OBJS += builtin-hash-object.o
-BUILTIN_OBJS += builtin-help.o
-BUILTIN_OBJS += builtin-index-pack.o
-BUILTIN_OBJS += builtin-init-db.o
-BUILTIN_OBJS += builtin-log.o
-BUILTIN_OBJS += builtin-ls-files.o
-BUILTIN_OBJS += builtin-ls-remote.o
-BUILTIN_OBJS += builtin-ls-tree.o
-BUILTIN_OBJS += builtin-mailinfo.o
-BUILTIN_OBJS += builtin-mailsplit.o
-BUILTIN_OBJS += builtin-merge.o
-BUILTIN_OBJS += builtin-merge-base.o
-BUILTIN_OBJS += builtin-merge-file.o
-BUILTIN_OBJS += builtin-merge-index.o
-BUILTIN_OBJS += builtin-merge-ours.o
-BUILTIN_OBJS += builtin-merge-recursive.o
-BUILTIN_OBJS += builtin-merge-tree.o
-BUILTIN_OBJS += builtin-mktag.o
-BUILTIN_OBJS += builtin-mktree.o
-BUILTIN_OBJS += builtin-mv.o
-BUILTIN_OBJS += builtin-name-rev.o
-BUILTIN_OBJS += builtin-notes.o
-BUILTIN_OBJS += builtin-pack-objects.o
-BUILTIN_OBJS += builtin-pack-redundant.o
-BUILTIN_OBJS += builtin-pack-refs.o
-BUILTIN_OBJS += builtin-patch-id.o
-BUILTIN_OBJS += builtin-prune-packed.o
-BUILTIN_OBJS += builtin-prune.o
-BUILTIN_OBJS += builtin-push.o
-BUILTIN_OBJS += builtin-read-tree.o
-BUILTIN_OBJS += builtin-receive-pack.o
-BUILTIN_OBJS += builtin-reflog.o
-BUILTIN_OBJS += builtin-remote.o
-BUILTIN_OBJS += builtin-replace.o
-BUILTIN_OBJS += builtin-rerere.o
-BUILTIN_OBJS += builtin-reset.o
-BUILTIN_OBJS += builtin-rev-list.o
-BUILTIN_OBJS += builtin-rev-parse.o
-BUILTIN_OBJS += builtin-revert.o
-BUILTIN_OBJS += builtin-rm.o
-BUILTIN_OBJS += builtin-send-pack.o
-BUILTIN_OBJS += builtin-shortlog.o
-BUILTIN_OBJS += builtin-show-branch.o
-BUILTIN_OBJS += builtin-show-ref.o
-BUILTIN_OBJS += builtin-stripspace.o
-BUILTIN_OBJS += builtin-symbolic-ref.o
-BUILTIN_OBJS += builtin-tag.o
-BUILTIN_OBJS += builtin-tar-tree.o
-BUILTIN_OBJS += builtin-unpack-file.o
-BUILTIN_OBJS += builtin-unpack-objects.o
-BUILTIN_OBJS += builtin-update-index.o
-BUILTIN_OBJS += builtin-update-ref.o
-BUILTIN_OBJS += builtin-update-server-info.o
-BUILTIN_OBJS += builtin-upload-archive.o
-BUILTIN_OBJS += builtin-var.o
-BUILTIN_OBJS += builtin-verify-pack.o
-BUILTIN_OBJS += builtin-verify-tag.o
-BUILTIN_OBJS += builtin-write-tree.o
+BUILTIN_OBJS += builtin/add.o
+BUILTIN_OBJS += builtin/annotate.o
+BUILTIN_OBJS += builtin/apply.o
+BUILTIN_OBJS += builtin/archive.o
+BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/blame.o
+BUILTIN_OBJS += builtin/branch.o
+BUILTIN_OBJS += builtin/bundle.o
+BUILTIN_OBJS += builtin/cat-file.o
+BUILTIN_OBJS += builtin/check-attr.o
+BUILTIN_OBJS += builtin/check-ref-format.o
+BUILTIN_OBJS += builtin/checkout-index.o
+BUILTIN_OBJS += builtin/checkout.o
+BUILTIN_OBJS += builtin/clean.o
+BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/commit-tree.o
+BUILTIN_OBJS += builtin/commit.o
+BUILTIN_OBJS += builtin/config.o
+BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/describe.o
+BUILTIN_OBJS += builtin/diff-files.o
+BUILTIN_OBJS += builtin/diff-index.o
+BUILTIN_OBJS += builtin/diff-tree.o
+BUILTIN_OBJS += builtin/diff.o
+BUILTIN_OBJS += builtin/fast-export.o
+BUILTIN_OBJS += builtin/fetch-pack.o
+BUILTIN_OBJS += builtin/fetch.o
+BUILTIN_OBJS += builtin/fmt-merge-msg.o
+BUILTIN_OBJS += builtin/for-each-ref.o
+BUILTIN_OBJS += builtin/fsck.o
+BUILTIN_OBJS += builtin/gc.o
+BUILTIN_OBJS += builtin/grep.o
+BUILTIN_OBJS += builtin/hash-object.o
+BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/index-pack.o
+BUILTIN_OBJS += builtin/init-db.o
+BUILTIN_OBJS += builtin/log.o
+BUILTIN_OBJS += builtin/ls-files.o
+BUILTIN_OBJS += builtin/ls-remote.o
+BUILTIN_OBJS += builtin/ls-tree.o
+BUILTIN_OBJS += builtin/mailinfo.o
+BUILTIN_OBJS += builtin/mailsplit.o
+BUILTIN_OBJS += builtin/merge.o
+BUILTIN_OBJS += builtin/merge-base.o
+BUILTIN_OBJS += builtin/merge-file.o
+BUILTIN_OBJS += builtin/merge-index.o
+BUILTIN_OBJS += builtin/merge-ours.o
+BUILTIN_OBJS += builtin/merge-recursive.o
+BUILTIN_OBJS += builtin/merge-tree.o
+BUILTIN_OBJS += builtin/mktag.o
+BUILTIN_OBJS += builtin/mktree.o
+BUILTIN_OBJS += builtin/mv.o
+BUILTIN_OBJS += builtin/name-rev.o
++BUILTIN_OBJS += builtin/notes.o
+BUILTIN_OBJS += builtin/pack-objects.o
+BUILTIN_OBJS += builtin/pack-redundant.o
+BUILTIN_OBJS += builtin/pack-refs.o
+BUILTIN_OBJS += builtin/patch-id.o
+BUILTIN_OBJS += builtin/prune-packed.o
+BUILTIN_OBJS += builtin/prune.o
+BUILTIN_OBJS += builtin/push.o
+BUILTIN_OBJS += builtin/read-tree.o
+BUILTIN_OBJS += builtin/receive-pack.o
+BUILTIN_OBJS += builtin/reflog.o
+BUILTIN_OBJS += builtin/remote.o
+BUILTIN_OBJS += builtin/replace.o
+BUILTIN_OBJS += builtin/rerere.o
+BUILTIN_OBJS += builtin/reset.o
+BUILTIN_OBJS += builtin/rev-list.o
+BUILTIN_OBJS += builtin/rev-parse.o
+BUILTIN_OBJS += builtin/revert.o
+BUILTIN_OBJS += builtin/rm.o
+BUILTIN_OBJS += builtin/send-pack.o
+BUILTIN_OBJS += builtin/shortlog.o
+BUILTIN_OBJS += builtin/show-branch.o
+BUILTIN_OBJS += builtin/show-ref.o
+BUILTIN_OBJS += builtin/stripspace.o
+BUILTIN_OBJS += builtin/symbolic-ref.o
+BUILTIN_OBJS += builtin/tag.o
+BUILTIN_OBJS += builtin/tar-tree.o
+BUILTIN_OBJS += builtin/unpack-file.o
+BUILTIN_OBJS += builtin/unpack-objects.o
+BUILTIN_OBJS += builtin/update-index.o
+BUILTIN_OBJS += builtin/update-ref.o
+BUILTIN_OBJS += builtin/update-server-info.o
+BUILTIN_OBJS += builtin/upload-archive.o
+BUILTIN_OBJS += builtin/var.o
+BUILTIN_OBJS += builtin/verify-pack.o
+BUILTIN_OBJS += builtin/verify-tag.o
+BUILTIN_OBJS += builtin/write-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
EXTLIBS =
ifeq ($(uname_S),Linux)
NO_STRLCPY = YesPlease
NO_MKSTEMPS = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
endif
ifeq ($(uname_S),GNU/kFreeBSD)
NO_STRLCPY = YesPlease
NO_MKSTEMPS = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
endif
ifeq ($(uname_S),UnixWare)
CC = cc
NO_STRLCPY = YesPlease
endif
NO_MEMMEM = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
endif
ifeq ($(uname_S),SunOS)
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
NO_REGEX = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
ifeq ($(uname_R),5.7)
NEEDS_RESOLV = YesPlease
NO_IPV6 = YesPlease
BASIC_LDFLAGS += -L/usr/local/lib
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
USE_ST_TIMESPEC = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
PTHREAD_LIBS = -pthread
NO_UINTMAX_T = YesPlease
NEEDS_LIBICONV = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
- THREADED_DELTA_SEARCH = YesPlease
endif
ifeq ($(uname_S),NetBSD)
ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
endif
BASIC_CFLAGS += -I/usr/pkg/include
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
- THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
NO_MKSTEMPS = YesPlease
endif
INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease
BASIC_CFLAGS += -D_LARGE_FILES
- ifneq ($(shell expr "$(uname_V)" : '[1234]'),1)
- THREADED_DELTA_SEARCH = YesPlease
- else
+ ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
NO_PTHREADS = YesPlease
endif
endif
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH = /usr/gnu/bin/bash
NEEDS_LIBGEN = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
endif
ifeq ($(uname_S),IRIX64)
NO_SETENV=YesPlease
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH=/usr/gnu/bin/bash
NEEDS_LIBGEN = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
endif
ifeq ($(uname_S),HP-UX)
NO_IPV6=YesPlease
NO_CURL = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
+ PTHREAD_LIBS =
lib =
ifndef DEBUG
BASIC_CFLAGS += -GL -Os -MT
NO_REGEX = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
- THREADED_DELTA_SEARCH = YesPlease
- COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
+ COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
compat/win32/pthread.o
EXTLIBS += -lws2_32
+ PTHREAD_LIBS =
X = .exe
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
htmldir=doc/git/html/
-include config.mak.autogen
-include config.mak
+ifdef CHECK_HEADER_DEPENDENCIES
+USE_COMPUTED_HEADER_DEPENDENCIES =
+endif
+
+ifdef COMPUTE_HEADER_DEPENDENCIES
+USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+endif
+
ifdef SANE_TOOL_PATH
SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix $(SANE_TOOL_PATH_SQ)|'
REMOTE_CURL_PRIMARY = git-remote-http$X
REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
- PROGRAMS += $(REMOTE_CURL_NAMES) git-http-fetch$X
+ PROGRAM_OBJS += http-fetch.o
+ PROGRAMS += $(REMOTE_CURL_NAMES)
curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
ifeq "$(curl_check)" "070908"
ifndef NO_EXPAT
- PROGRAMS += git-http-push$X
+ PROGRAM_OBJS += http-push.o
endif
endif
ifndef NO_EXPAT
EXTLIBS += -lz
ifndef NO_POSIX_ONLY_PROGRAMS
- PROGRAMS += git-daemon$X
+ PROGRAM_OBJS += daemon.o
endif
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
endif
ifdef NO_MKSTEMPS
COMPAT_CFLAGS += -DNO_MKSTEMPS
- COMPAT_OBJS += compat/mkstemps.o
endif
ifdef NO_UNSETENV
COMPAT_CFLAGS += -DNO_UNSETENV
ifdef BLK_SHA1
SHA1_HEADER = "block-sha1/sha1.h"
LIB_OBJS += block-sha1/sha1.o
+ LIB_H += block-sha1/sha1.h
else
ifdef PPC_SHA1
SHA1_HEADER = "ppc/sha1.h"
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
+ LIB_H += ppc/sha1.h
else
SHA1_HEADER = <openssl/sha.h>
EXTLIBS += $(LIB_4_CRYPTO)
endif
ifdef NO_PTHREADS
- THREADED_DELTA_SEARCH =
BASIC_CFLAGS += -DNO_PTHREADS
else
EXTLIBS += $(PTHREAD_LIBS)
-endif
-
-ifdef THREADED_DELTA_SEARCH
- BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
LIB_OBJS += thread-utils.o
endif
+
ifdef DIR_HAS_BSD_GROUP_SEMANTICS
COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
endif
SHELL = $(SHELL_PATH)
-all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+all:: shell_compatibility_test $(ALL_PROGRAMS) $(SCRIPT_LIB) $(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 -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
endif
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
-builtin-help.o: common-cmds.h
-builtin-help.s builtin-help.o: ALL_CFLAGS += \
+builtin/help.o: common-cmds.h
+builtin/help.s builtin/help.o: ALL_CFLAGS += \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"'
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
+define cmd_munge_script
+$(RM) $@ $@+ && \
+sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
+ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
+ -e $(BROKEN_PATH_FIX) \
+ $@.sh >$@+
+endef
+
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e $(BROKEN_PATH_FIX) \
- $@.sh >$@+ && \
+ $(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
+$(SCRIPT_LIB) : % : %.sh
+ $(QUIET_GEN)$(cmd_munge_script) && \
+ mv $@+ $@
+
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
chmod +x $@+ && \
mv $@+ $@
+
+.PHONY: gitweb
+gitweb:
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
+
ifdef JSMIN
OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.min.js
gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
OTHER_PROGRAMS += gitweb/gitweb.cgi
gitweb/gitweb.cgi: gitweb/gitweb.perl
endif
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
- -e 's|++GIT_BINDIR++|$(bindir)|g' \
- -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
- -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
- -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
- -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
- -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
- -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
- -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
- -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
- -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
- -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
- -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
- -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
- -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
- -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
- -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
- -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
- -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
- $< >$@+ && \
- chmod +x $@+ && \
- mv $@+ $@
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+
+ifdef JSMIN
+gitweb/gitweb.min.js: gitweb/gitweb.js
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+endif # JSMIN
+
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
$(QUIET_GEN)$(RM) $@ $@+ && \
mv $@+ $@
endif # NO_PERL
-
-ifdef JSMIN
-gitweb/gitweb.min.js: gitweb/gitweb.js
- $(QUIET_GEN)$(JSMIN) <$< >$@
-endif # JSMIN
-
ifndef NO_PYTHON
$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
: GIT-VERSION-FILE
-%.o: %.c GIT-CFLAGS
- $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+ git.o http.o http-walker.o remote-curl.o
+XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
+ xdiff/xmerge.o xdiff/xpatience.o
+OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS)
+
+dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
+dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
+
+ifdef COMPUTE_HEADER_DEPENDENCIES
+$(dep_dirs):
+ mkdir -p $@
+
+missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
+dep_file = $(dir $@).depend/$(notdir $@).d
+dep_args = -MF $(dep_file) -MMD -MP
+ifdef CHECK_HEADER_DEPENDENCIES
+$(error cannot compute header dependencies outside a normal build. \
+Please unset CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+ifndef COMPUTE_HEADER_DEPENDENCIES
+ifndef CHECK_HEADER_DEPENDENCIES
+dep_dirs =
+missing_dep_dirs =
+dep_args =
+endif
+endif
+
+ifdef CHECK_HEADER_DEPENDENCIES
+ifndef PRINT_HEADER_DEPENDENCIES
+missing_deps = $(filter-out $(notdir $^), \
+ $(notdir $(shell $(MAKE) -s $@ \
+ CHECK_HEADER_DEPENDENCIES=YesPlease \
+ USE_COMPUTED_HEADER_DEPENDENCIES=YesPlease \
+ PRINT_HEADER_DEPENDENCIES=YesPlease)))
+endif
+endif
+
+ASM_SRC := $(wildcard $(OBJECTS:o=S))
+ASM_OBJ := $(ASM_SRC:S=o)
+C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+
+.SUFFIXES:
+
+ifdef PRINT_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c FORCE
+ echo $^
+$(ASM_OBJ): %.o: %.S FORCE
+ echo $^
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(error cannot print header dependencies during a normal build. \
+Please set CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+ifndef PRINT_HEADER_DEPENDENCIES
+ifdef CHECK_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c $(dep_files) FORCE
+ @set -e; echo CHECK $@; \
+ missing_deps="$(missing_deps)"; \
+ if test "$$missing_deps"; \
+ then \
+ echo missing dependencies: $$missing_deps; \
+ false; \
+ fi
+$(ASM_OBJ): %.o: %.S $(dep_files) FORCE
+ @set -e; echo CHECK $@; \
+ missing_deps="$(missing_deps)"; \
+ if test "$$missing_deps"; \
+ then \
+ echo missing dependencies: $$missing_deps; \
+ false; \
+ fi
+endif
+endif
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
+$(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
+endif
+
%.s: %.c GIT-CFLAGS FORCE
$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
-%.o: %.S GIT-CFLAGS
- $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+
+ifdef USE_COMPUTED_HEADER_DEPENDENCIES
+# Take advantage of gcc's on-the-fly dependency generation
+# See <http://gcc.gnu.org/gcc-3.0/features.html>.
+dep_files_present := $(wildcard $(dep_files))
+ifneq ($(dep_files_present),)
+include $(dep_files_present)
+endif
+else
+# Dependencies on header files, for platforms that do not support
+# the gcc -MMD option.
+#
+# Dependencies on automatically generated headers such as common-cmds.h
+# should _not_ be included here, since they are necessary even when
+# building an object for the first time.
+#
+# XXX. Please check occasionally that these include all dependencies
+# gcc detects!
+
+$(GIT_OBJS): $(LIB_H)
+builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h
+builtin/bundle.o bundle.o transport.o: bundle.h
+builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
+builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
+builtin/grep.o: thread-utils.h
+builtin/send-pack.o transport.o: send-pack.h
+builtin/log.o builtin/shortlog.o: shortlog.h
+builtin/prune.o builtin/reflog.o reachable.o: reachable.h
+builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
+builtin/tar-tree.o archive-tar.o: tar.h
+builtin/pack-objects.o: thread-utils.h
+http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
+http.o http-walker.o http-push.o remote-curl.o: http.h
+
+xdiff-interface.o $(XDIFF_OBJS): \
+ xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
+ xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+endif
exec_cmd.s exec_cmd.o: ALL_CFLAGS += \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
'-DBINDIR="$(bindir_relative_SQ)"' \
'-DPREFIX="$(prefix_SQ)"'
-builtin-init-db.s builtin-init-db.o: ALL_CFLAGS += \
+builtin/init-db.s builtin/init-db.o: ALL_CFLAGS += \
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
config.s config.o: ALL_CFLAGS += -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
http.s http.o: ALL_CFLAGS += -DGIT_USER_AGENT='"git/$(GIT_VERSION)"'
ifdef NO_EXPAT
-http-walker.o: http.h
http-walker.s http-walker.o: ALL_CFLAGS += -DNO_EXPAT
endif
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
-http.o http-walker.o http-push.o: http.h
-
-http.o http-walker.o: $(LIB_H)
-
git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
-builtin-revert.o wt-status.o: wt-status.h
-
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
-XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
- xdiff/xmerge.o xdiff/xpatience.o
-$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
- xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
-
$(XDIFF_LIB): $(XDIFF_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
fi
endif
-### Testing rules
-
-TEST_PROGRAMS_NEED_X += test-chmtime
-TEST_PROGRAMS_NEED_X += test-ctype
-TEST_PROGRAMS_NEED_X += test-date
-TEST_PROGRAMS_NEED_X += test-delta
-TEST_PROGRAMS_NEED_X += test-dump-cache-tree
-TEST_PROGRAMS_NEED_X += test-genrandom
-TEST_PROGRAMS_NEED_X += test-match-trees
-TEST_PROGRAMS_NEED_X += test-parse-options
-TEST_PROGRAMS_NEED_X += test-path-utils
-TEST_PROGRAMS_NEED_X += test-run-command
-TEST_PROGRAMS_NEED_X += test-sha1
-TEST_PROGRAMS_NEED_X += test-sigchain
-TEST_PROGRAMS_NEED_X += test-index-version
-
-TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
-
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
all:: $(TEST_PROGRAMS) $(test_bindir_programs)
export NO_SVN_TESTS
+### Testing rules
+
test: all
$(MAKE) -C t/ all
test-parse-options$X: parse-options.o
-test-parse-options.o: parse-options.h
-
-.PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+.PRECIOUS: $(TEST_OBJS)
test-%$X: test-%.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
ifndef NO_PERL
clean:
$(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
- $(LIB_FILE) $(XDIFF_LIB)
- $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
+ builtin/*.o $(LIB_FILE) $(XDIFF_LIB)
+ $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
$(RM) $(TEST_PROGRAMS)
$(RM) -r bin-wrappers
+ $(RM) -r $(dep_dirs)
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
$(RM) -r autom4te.cache
$(RM) config.log config.mak.autogen config.mak.append config.status config.cache
### Check documentation
#
check-docs::
- @(for v in $(ALL_PROGRAMS) $(BUILT_INS) git gitk; \
+ @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
do \
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
git-merge-resolve | git-merge-subtree | \
git-fsck-objects | git-init-db | \
+ git-remote-* | git-stage | \
git-?*--?* ) continue ;; \
esac ; \
test -f "Documentation/$$v.txt" || \
documented,gitrepository-layout | \
documented,gittutorial | \
documented,gittutorial-2 | \
+ documented,git-bisect-lk2009 | \
+ documented,git-remote-helpers | \
+ documented,gitworkflows | \
sentinel,not,matching,is,ok ) continue ;; \
esac; \
- case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
+ case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
*" $$cmd "*) ;; \
*) echo "removed but $$how: $$cmd" ;; \
esac; \
--- /dev/null
--- /dev/null
++/*
++ * Builtin "git notes"
++ *
++ * Copyright (c) 2010 Johan Herland <johan@herland.net>
++ *
++ * Based on git-notes.sh by Johannes Schindelin,
++ * and builtin-tag.c by Kristian Høgsberg and Carlos Rica.
++ */
++
++#include "cache.h"
++#include "builtin.h"
++#include "notes.h"
++#include "blob.h"
++#include "commit.h"
++#include "refs.h"
++#include "exec_cmd.h"
++#include "run-command.h"
++#include "parse-options.h"
++
++static const char * const git_notes_usage[] = {
++ "git notes [list [<object>]]",
++ "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
++ "git notes copy [-f] <from-object> <to-object>",
++ "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
++ "git notes edit [<object>]",
++ "git notes show [<object>]",
++ "git notes remove [<object>]",
++ "git notes prune",
++ NULL
++};
++
++static const char note_template[] =
++ "\n"
++ "#\n"
++ "# Write/edit the notes for the following object:\n"
++ "#\n";
++
++struct msg_arg {
++ int given;
++ int use_editor;
++ struct strbuf buf;
++};
++
++static int list_each_note(const unsigned char *object_sha1,
++ const unsigned char *note_sha1, char *note_path,
++ void *cb_data)
++{
++ printf("%s %s\n", sha1_to_hex(note_sha1), sha1_to_hex(object_sha1));
++ return 0;
++}
++
++static void write_note_data(int fd, const unsigned char *sha1)
++{
++ unsigned long size;
++ enum object_type type;
++ char *buf = read_sha1_file(sha1, &type, &size);
++ if (buf) {
++ if (size)
++ write_or_die(fd, buf, size);
++ free(buf);
++ }
++}
++
++static void write_commented_object(int fd, const unsigned char *object)
++{
++ const char *show_args[5] =
++ {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
++ struct child_process show;
++ struct strbuf buf = STRBUF_INIT;
++ FILE *show_out;
++
++ /* Invoke "git show --stat --no-notes $object" */
++ memset(&show, 0, sizeof(show));
++ show.argv = show_args;
++ show.no_stdin = 1;
++ show.out = -1;
++ show.err = 0;
++ show.git_cmd = 1;
++ if (start_command(&show))
++ die("unable to start 'show' for object '%s'",
++ sha1_to_hex(object));
++
++ /* Open the output as FILE* so strbuf_getline() can be used. */
++ show_out = xfdopen(show.out, "r");
++ if (show_out == NULL)
++ die_errno("can't fdopen 'show' output fd");
++
++ /* Prepend "# " to each output line and write result to 'fd' */
++ while (strbuf_getline(&buf, show_out, '\n') != EOF) {
++ write_or_die(fd, "# ", 2);
++ write_or_die(fd, buf.buf, buf.len);
++ write_or_die(fd, "\n", 1);
++ }
++ strbuf_release(&buf);
++ if (fclose(show_out))
++ die_errno("failed to close pipe to 'show' for object '%s'",
++ sha1_to_hex(object));
++ if (finish_command(&show))
++ die("failed to finish 'show' for object '%s'",
++ sha1_to_hex(object));
++}
++
++static void create_note(const unsigned char *object, struct msg_arg *msg,
++ int append_only, const unsigned char *prev,
++ unsigned char *result)
++{
++ char *path = NULL;
++
++ if (msg->use_editor || !msg->given) {
++ int fd;
++
++ /* write the template message before editing: */
++ path = git_pathdup("NOTES_EDITMSG");
++ fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
++ if (fd < 0)
++ die_errno("could not create file '%s'", path);
++
++ if (msg->given)
++ write_or_die(fd, msg->buf.buf, msg->buf.len);
++ else if (prev && !append_only)
++ write_note_data(fd, prev);
++ write_or_die(fd, note_template, strlen(note_template));
++
++ write_commented_object(fd, object);
++
++ close(fd);
++ strbuf_reset(&(msg->buf));
++
++ if (launch_editor(path, &(msg->buf), NULL)) {
++ die("Please supply the note contents using either -m" \
++ " or -F option");
++ }
++ stripspace(&(msg->buf), 1);
++ }
++
++ if (prev && append_only) {
++ /* Append buf to previous note contents */
++ unsigned long size;
++ enum object_type type;
++ char *prev_buf = read_sha1_file(prev, &type, &size);
++
++ strbuf_grow(&(msg->buf), size + 1);
++ if (msg->buf.len && prev_buf && size)
++ strbuf_insert(&(msg->buf), 0, "\n", 1);
++ if (prev_buf && size)
++ strbuf_insert(&(msg->buf), 0, prev_buf, size);
++ free(prev_buf);
++ }
++
++ if (!msg->buf.len) {
++ fprintf(stderr, "Removing note for object %s\n",
++ sha1_to_hex(object));
++ hashclr(result);
++ } else {
++ if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
++ error("unable to write note object");
++ if (path)
++ error("The note contents has been left in %s",
++ path);
++ exit(128);
++ }
++ }
++
++ if (path) {
++ unlink_or_warn(path);
++ free(path);
++ }
++}
++
++static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
++{
++ struct msg_arg *msg = opt->value;
++
++ strbuf_grow(&(msg->buf), strlen(arg) + 2);
++ if (msg->buf.len)
++ strbuf_addch(&(msg->buf), '\n');
++ strbuf_addstr(&(msg->buf), arg);
++ stripspace(&(msg->buf), 0);
++
++ msg->given = 1;
++ return 0;
++}
++
++static int parse_file_arg(const struct option *opt, const char *arg, int unset)
++{
++ struct msg_arg *msg = opt->value;
++
++ if (msg->buf.len)
++ strbuf_addch(&(msg->buf), '\n');
++ if (!strcmp(arg, "-")) {
++ if (strbuf_read(&(msg->buf), 0, 1024) < 0)
++ die_errno("cannot read '%s'", arg);
++ } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
++ die_errno("could not open or read '%s'", arg);
++ stripspace(&(msg->buf), 0);
++
++ msg->given = 1;
++ return 0;
++}
++
++static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
++{
++ struct msg_arg *msg = opt->value;
++ char *buf;
++ unsigned char object[20];
++ enum object_type type;
++ unsigned long len;
++
++ if (msg->buf.len)
++ strbuf_addch(&(msg->buf), '\n');
++
++ if (get_sha1(arg, object))
++ die("Failed to resolve '%s' as a valid ref.", arg);
++ if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
++ free(buf);
++ die("Failed to read object '%s'.", arg);;
++ }
++ strbuf_add(&(msg->buf), buf, len);
++ free(buf);
++
++ msg->given = 1;
++ return 0;
++}
++
++static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
++{
++ struct msg_arg *msg = opt->value;
++ msg->use_editor = 1;
++ return parse_reuse_arg(opt, arg, unset);
++}
++
++int commit_notes(struct notes_tree *t, const char *msg)
++{
++ struct commit_list *parent;
++ unsigned char tree_sha1[20], prev_commit[20], new_commit[20];
++ struct strbuf buf = STRBUF_INIT;
++
++ if (!t)
++ t = &default_notes_tree;
++ if (!t->initialized || !t->ref || !*t->ref)
++ die("Cannot commit uninitialized/unreferenced notes tree");
++
++ /* Prepare commit message and reflog message */
++ strbuf_addstr(&buf, "notes: "); /* commit message starts at index 7 */
++ strbuf_addstr(&buf, msg);
++ if (buf.buf[buf.len - 1] != '\n')
++ strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
++
++ /* Convert notes tree to tree object */
++ if (write_notes_tree(t, tree_sha1))
++ die("Failed to write current notes tree to database");
++
++ /* Create new commit for the tree object */
++ if (!read_ref(t->ref, prev_commit)) { /* retrieve parent commit */
++ parent = xmalloc(sizeof(*parent));
++ parent->item = lookup_commit(prev_commit);
++ parent->next = NULL;
++ } else {
++ hashclr(prev_commit);
++ parent = NULL;
++ }
++ if (commit_tree(buf.buf + 7, tree_sha1, parent, new_commit, NULL))
++ die("Failed to commit notes tree to database");
++
++ /* Update notes ref with new commit */
++ update_ref(buf.buf, t->ref, new_commit, prev_commit, 0, DIE_ON_ERR);
++
++ strbuf_release(&buf);
++ return 0;
++}
++
++int cmd_notes(int argc, const char **argv, const char *prefix)
++{
++ struct notes_tree *t;
++ unsigned char object[20], from_obj[20], new_note[20];
++ const unsigned char *note;
++ const char *object_ref;
++ char logmsg[100];
++
++ int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
++ remove = 0, prune = 0, force = 0;
++ int given_object = 0, i = 1, retval = 0;
++ struct msg_arg msg = { 0, 0, STRBUF_INIT };
++ struct option options[] = {
++ OPT_GROUP("Notes contents options"),
++ { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
++ "note contents as a string", PARSE_OPT_NONEG,
++ parse_msg_arg},
++ { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
++ "note contents in a file", PARSE_OPT_NONEG,
++ parse_file_arg},
++ { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
++ "reuse and edit specified note object", PARSE_OPT_NONEG,
++ parse_reedit_arg},
++ { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
++ "reuse specified note object", PARSE_OPT_NONEG,
++ parse_reuse_arg},
++ OPT_GROUP("Other options"),
++ OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
++ OPT_END()
++ };
++
++ git_config(git_default_config, NULL);
++
++ argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0);
++
++ if (argc && !strcmp(argv[0], "list"))
++ list = 1;
++ else if (argc && !strcmp(argv[0], "add"))
++ add = 1;
++ else if (argc && !strcmp(argv[0], "copy"))
++ copy = 1;
++ else if (argc && !strcmp(argv[0], "append"))
++ append = 1;
++ else if (argc && !strcmp(argv[0], "edit"))
++ edit = 1;
++ else if (argc && !strcmp(argv[0], "show"))
++ show = 1;
++ else if (argc && !strcmp(argv[0], "remove"))
++ remove = 1;
++ else if (argc && !strcmp(argv[0], "prune"))
++ prune = 1;
++ else if (!argc) {
++ list = 1; /* Default to 'list' if no other subcommand given */
++ i = 0;
++ }
++
++ if (list + add + copy + append + edit + show + remove + prune != 1)
++ usage_with_options(git_notes_usage, options);
++
++ if (msg.given && !(add || append || edit)) {
++ error("cannot use -m/-F/-c/-C options with %s subcommand.",
++ argv[0]);
++ usage_with_options(git_notes_usage, options);
++ }
++
++ if (msg.given && edit) {
++ fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
++ "for the 'edit' subcommand.\n"
++ "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
++ }
++
++ if (force && !(add || copy)) {
++ error("cannot use -f option with %s subcommand.", argv[0]);
++ usage_with_options(git_notes_usage, options);
++ }
++
++ if (copy) {
++ const char *from_ref;
++ if (argc < 3) {
++ error("too few parameters");
++ usage_with_options(git_notes_usage, options);
++ }
++ from_ref = argv[i++];
++ if (get_sha1(from_ref, from_obj))
++ die("Failed to resolve '%s' as a valid ref.", from_ref);
++ }
++
++ given_object = argc > i;
++ object_ref = given_object ? argv[i++] : "HEAD";
++
++ if (argc > i || (prune && given_object)) {
++ error("too many parameters");
++ usage_with_options(git_notes_usage, options);
++ }
++
++ if (get_sha1(object_ref, object))
++ die("Failed to resolve '%s' as a valid ref.", object_ref);
++
++ init_notes(NULL, NULL, NULL, 0);
++ t = &default_notes_tree;
++
++ if (prefixcmp(t->ref, "refs/notes/"))
++ die("Refusing to %s notes in %s (outside of refs/notes/)",
++ argv[0], t->ref);
++
++ note = get_note(t, object);
++
++ /* list command */
++
++ if (list) {
++ if (given_object) {
++ if (note) {
++ puts(sha1_to_hex(note));
++ goto end;
++ }
++ } else {
++ retval = for_each_note(t, 0, list_each_note, NULL);
++ goto end;
++ }
++ }
++
++ /* show command */
++
++ if ((list || show) && !note) {
++ error("No note found for object %s.", sha1_to_hex(object));
++ retval = 1;
++ goto end;
++ } else if (show) {
++ const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
++ retval = execv_git_cmd(show_args);
++ goto end;
++ }
++
++ /* add/append/edit/remove/prune command */
++
++ if ((add || copy) && note) {
++ if (!force) {
++ error("Cannot %s notes. Found existing notes for object"
++ " %s. Use '-f' to overwrite existing notes",
++ argv[0], sha1_to_hex(object));
++ retval = 1;
++ goto end;
++ }
++ fprintf(stderr, "Overwriting existing notes for object %s\n",
++ sha1_to_hex(object));
++ }
++
++ if (remove) {
++ msg.given = 1;
++ msg.use_editor = 0;
++ strbuf_reset(&(msg.buf));
++ }
++
++ if (prune) {
++ hashclr(new_note);
++ prune_notes(t);
++ goto commit;
++ } else if (copy) {
++ const unsigned char *from_note = get_note(t, from_obj);
++ if (!from_note) {
++ error("Missing notes on source object %s. Cannot copy.",
++ sha1_to_hex(from_obj));
++ retval = 1;
++ goto end;
++ }
++ hashcpy(new_note, from_note);
++ } else
++ create_note(object, &msg, append, note, new_note);
++
++ if (is_null_sha1(new_note))
++ remove_note(t, object);
++ else
++ add_note(t, object, new_note, combine_notes_overwrite);
++
++commit:
++ snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
++ is_null_sha1(new_note) ? "removed" : "added", argv[0]);
++ commit_notes(t, logmsg);
++
++end:
++ free_notes(t);
++ strbuf_release(&(msg.buf));
++ return retval;
++}
. ./test-lib.sh
cat > fake_editor.sh << \EOF
+#!/bin/sh
echo "$MSG" > "$1"
echo "$MSG" >& 2
EOF
chmod a+x fake_editor.sh
- VISUAL=./fake_editor.sh
- export VISUAL
+ GIT_EDITOR=./fake_editor.sh
+ export GIT_EDITOR
test_expect_success 'cannot annotate non-existing HEAD' '
- (MSG=3 && export MSG && test_must_fail git notes edit)
+ (MSG=3 && export MSG && test_must_fail git notes add)
'
test_expect_success setup '
test_expect_success 'need valid notes ref' '
(MSG=1 GIT_NOTES_REF=/ && export MSG GIT_NOTES_REF &&
- test_must_fail git notes edit) &&
+ test_must_fail git notes add) &&
(MSG=2 GIT_NOTES_REF=/ && export MSG GIT_NOTES_REF &&
test_must_fail git notes show)
'
- test_expect_success 'refusing to edit in refs/heads/' '
+ test_expect_success 'refusing to add notes in refs/heads/' '
(MSG=1 GIT_NOTES_REF=refs/heads/bogus &&
export MSG GIT_NOTES_REF &&
- test_must_fail git notes edit)
+ test_must_fail git notes add)
'
- test_expect_success 'refusing to edit in refs/remotes/' '
+ test_expect_success 'refusing to edit notes in refs/remotes/' '
(MSG=1 GIT_NOTES_REF=refs/remotes/bogus &&
export MSG GIT_NOTES_REF &&
test_must_fail git notes edit)
test_expect_success 'create notes' '
git config core.notesRef refs/notes/commits &&
- MSG=b1 git notes edit &&
- test ! -f .git/new-notes &&
+ MSG=b4 git notes add &&
+ test ! -f .git/NOTES_EDITMSG &&
+ test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
+ test b4 = $(git notes show) &&
+ git show HEAD^ &&
+ test_must_fail git notes show HEAD^
+ '
+
+ test_expect_success 'edit existing notes' '
+ MSG=b3 git notes edit &&
+ test ! -f .git/NOTES_EDITMSG &&
+ test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
+ test b3 = $(git notes show) &&
+ git show HEAD^ &&
+ test_must_fail git notes show HEAD^
+ '
+
+ test_expect_success 'cannot add note where one exists' '
+ ! MSG=b2 git notes add &&
+ test ! -f .git/NOTES_EDITMSG &&
+ test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
+ test b3 = $(git notes show) &&
+ git show HEAD^ &&
+ test_must_fail git notes show HEAD^
+ '
+
+ test_expect_success 'can overwrite existing note with "git notes add -f"' '
+ MSG=b1 git notes add -f &&
+ test ! -f .git/NOTES_EDITMSG &&
test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
test b1 = $(git notes show) &&
git show HEAD^ &&
git log -1 > output &&
test_cmp expect output
'
+
test_expect_success 'create multi-line notes (setup)' '
: > a3 &&
git add a3 &&
git commit -m 3rd &&
MSG="b3
c3c3c3c3
- d3d3d3" git notes edit
+ d3d3d3" git notes add
'
cat > expect-multiline << EOF
git log -2 > output &&
test_cmp expect-multiline output
'
- test_expect_success 'create -m and -F notes (setup)' '
+ test_expect_success 'create -F notes (setup)' '
: > a4 &&
git add a4 &&
test_tick &&
git commit -m 4th &&
echo "xyzzy" > note5 &&
- git notes edit -m spam -F note5 -m "foo
- bar
- baz"
+ git notes add -F note5
'
- whitespace=" "
- cat > expect-m-and-F << EOF
+ cat > expect-F << EOF
commit 15023535574ded8b1a89052b32673f84cf9582b8
Author: A U Thor <author@example.com>
Date: Thu Apr 7 15:16:13 2005 -0700
4th
Notes:
- spam
- $whitespace
xyzzy
- $whitespace
- foo
- bar
- baz
EOF
- printf "\n" >> expect-m-and-F
- cat expect-multiline >> expect-m-and-F
+ printf "\n" >> expect-F
+ cat expect-multiline >> expect-F
- test_expect_success 'show -m and -F notes' '
+ test_expect_success 'show -F notes' '
git log -3 > output &&
- test_cmp expect-m-and-F output
+ test_cmp expect-F output
'
cat >expect << EOF
cat >>expect <<EOF
Notes:
- spam
- $whitespace
xyzzy
- $whitespace
- foo
- bar
- baz
EOF
test_expect_success 'git log --show-notes' '
git log -1 --pretty=raw --show-notes >output &&
test_expect_success 'git log --no-notes' '
git log -1 --no-notes >output &&
- ! grep spam output
+ ! grep xyzzy output
'
test_expect_success 'git format-patch does not show notes' '
git format-patch -1 --stdout >output &&
- ! grep spam output
+ ! grep xyzzy output
'
test_expect_success 'git format-patch --show-notes does show notes' '
git format-patch --show-notes -1 --stdout >output &&
- grep spam output
+ grep xyzzy output
'
for pretty in \
esac
test_expect_success "git show $pretty does$not show notes" '
git show $p >output &&
- eval "$negate grep spam output"
+ eval "$negate grep xyzzy output"
'
done
+ test_expect_success 'create -m notes (setup)' '
+ : > a5 &&
+ git add a5 &&
+ test_tick &&
+ git commit -m 5th &&
+ git notes add -m spam -m "foo
+ bar
+ baz"
+ '
+
+ whitespace=" "
+ cat > expect-m << EOF
+ commit bd1753200303d0a0344be813e504253b3d98e74d
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
+
+ 5th
+
+ Notes:
+ spam
+ $whitespace
+ foo
+ bar
+ baz
+ EOF
+
+ printf "\n" >> expect-m
+ cat expect-F >> expect-m
+
+ test_expect_success 'show -m notes' '
+ git log -4 > output &&
+ test_cmp expect-m output
+ '
+
+ test_expect_success 'remove note with add -f -F /dev/null (setup)' '
+ git notes add -f -F /dev/null
+ '
+
+ cat > expect-rm-F << EOF
+ commit bd1753200303d0a0344be813e504253b3d98e74d
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
+
+ 5th
+ EOF
+
+ printf "\n" >> expect-rm-F
+ cat expect-F >> expect-rm-F
+
+ test_expect_success 'verify note removal with -F /dev/null' '
+ git log -4 > output &&
+ test_cmp expect-rm-F output &&
+ ! git notes show
+ '
+
+ test_expect_success 'do not create empty note with -m "" (setup)' '
+ git notes add -m ""
+ '
+
+ test_expect_success 'verify non-creation of note with -m ""' '
+ git log -4 > output &&
+ test_cmp expect-rm-F output &&
+ ! git notes show
+ '
+
+ cat > expect-combine_m_and_F << EOF
+ foo
+
+ xyzzy
+
+ bar
+
+ zyxxy
+
+ baz
+ EOF
+
+ test_expect_success 'create note with combination of -m and -F' '
+ echo "xyzzy" > note_a &&
+ echo "zyxxy" > note_b &&
+ git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" &&
+ git notes show > output &&
+ test_cmp expect-combine_m_and_F output
+ '
+
+ test_expect_success 'remove note with "git notes remove" (setup)' '
+ git notes remove HEAD^ &&
+ git notes remove
+ '
+
+ cat > expect-rm-remove << EOF
+ commit bd1753200303d0a0344be813e504253b3d98e74d
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
+
+ 5th
+
+ commit 15023535574ded8b1a89052b32673f84cf9582b8
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:16:13 2005 -0700
+
+ 4th
+ EOF
+
+ printf "\n" >> expect-rm-remove
+ cat expect-multiline >> expect-rm-remove
+
+ test_expect_success 'verify note removal with "git notes remove"' '
+ git log -4 > output &&
+ test_cmp expect-rm-remove output &&
+ ! git notes show HEAD^
+ '
+
+ cat > expect << EOF
+ c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
+ c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
+ EOF
+
+ test_expect_success 'list notes with "git notes list"' '
+ git notes list > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success 'list notes with "git notes"' '
+ git notes > output &&
+ test_cmp expect output
+ '
+
+ cat > expect << EOF
+ c18dc024e14f08d18d14eea0d747ff692d66d6a3
+ EOF
+
+ test_expect_success 'list specific note with "git notes list <object>"' '
+ git notes list HEAD^^ > output &&
+ test_cmp expect output
+ '
+
+ cat > expect << EOF
+ EOF
+
+ test_expect_success 'listing non-existing notes fails' '
+ test_must_fail git notes list HEAD > output &&
+ test_cmp expect output
+ '
+
+ cat > expect << EOF
+ Initial set of notes
+
+ More notes appended with git notes append
+ EOF
+
+ test_expect_success 'append to existing note with "git notes append"' '
+ git notes add -m "Initial set of notes" &&
+ git notes append -m "More notes appended with git notes append" &&
+ git notes show > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success 'appending empty string does not change existing note' '
+ git notes append -m "" &&
+ git notes show > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success 'git notes append == add when there is no existing note' '
+ git notes remove HEAD &&
+ test_must_fail git notes list HEAD &&
+ git notes append -m "Initial set of notes
+
+ More notes appended with git notes append" &&
+ git notes show > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success 'appending empty string to non-existing note does not create note' '
+ git notes remove HEAD &&
+ test_must_fail git notes list HEAD &&
+ git notes append -m "" &&
+ test_must_fail git notes list HEAD
+ '
+
+ test_expect_success 'create other note on a different notes ref (setup)' '
+ : > a6 &&
+ git add a6 &&
+ test_tick &&
+ git commit -m 6th &&
+ GIT_NOTES_REF="refs/notes/other" git notes add -m "other note"
+ '
+
+ cat > expect-other << EOF
+ commit 387a89921c73d7ed72cd94d179c1c7048ca47756
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
+
+ 6th
+
+ Notes:
+ other note
+ EOF
+
+ cat > expect-not-other << EOF
+ commit 387a89921c73d7ed72cd94d179c1c7048ca47756
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
+
+ 6th
+ EOF
+
+ test_expect_success 'Do not show note on other ref by default' '
+ git log -1 > output &&
+ test_cmp expect-not-other output
+ '
+
+ test_expect_success 'Do show note when ref is given in GIT_NOTES_REF' '
+ GIT_NOTES_REF="refs/notes/other" git log -1 > output &&
+ test_cmp expect-other output
+ '
+
+ test_expect_success 'Do show note when ref is given in core.notesRef config' '
+ git config core.notesRef "refs/notes/other" &&
+ git log -1 > output &&
+ test_cmp expect-other output
+ '
+
+ test_expect_success 'Do not show note when core.notesRef is overridden' '
+ GIT_NOTES_REF="refs/notes/wrong" git log -1 > output &&
+ test_cmp expect-not-other output
+ '
+
+ test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
+ echo "Note on a tree" > expect
+ git notes add -m "Note on a tree" HEAD: &&
+ git notes show HEAD: > actual &&
+ test_cmp expect actual &&
+ echo "Note on a blob" > expect
+ filename=$(git ls-tree --name-only HEAD | head -n1) &&
+ git notes add -m "Note on a blob" HEAD:$filename &&
+ git notes show HEAD:$filename > actual &&
+ test_cmp expect actual &&
+ echo "Note on a tag" > expect
+ git tag -a -m "This is an annotated tag" foobar HEAD^ &&
+ git notes add -m "Note on a tag" foobar &&
+ git notes show foobar > actual &&
+ test_cmp expect actual
+ '
+
+ cat > expect << EOF
+ commit 2ede89468182a62d0bde2583c736089bcf7d7e92
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:19:13 2005 -0700
+
+ 7th
+
+ Notes:
+ other note
+ EOF
+
+ test_expect_success 'create note from other note with "git notes add -C"' '
+ : > a7 &&
+ git add a7 &&
+ test_tick &&
+ git commit -m 7th &&
+ git notes add -C $(git notes list HEAD^) &&
+ git log -1 > actual &&
+ test_cmp expect actual &&
+ test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+ '
+
+ test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
+ : > a8 &&
+ git add a8 &&
+ test_tick &&
+ git commit -m 8th &&
+ test_must_fail git notes add -C deadbeef &&
+ test_must_fail git notes list HEAD
+ '
+
+ cat > expect << EOF
+ commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:21:13 2005 -0700
+
+ 9th
+
+ Notes:
+ yet another note
+ EOF
+
+ test_expect_success 'create note from other note with "git notes add -c"' '
+ : > a9 &&
+ git add a9 &&
+ test_tick &&
+ git commit -m 9th &&
+ MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
+ git log -1 > actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success 'create note from non-existing note with "git notes add -c" fails' '
+ : > a10 &&
+ git add a10 &&
+ test_tick &&
+ git commit -m 10th &&
+ test_must_fail MSG="yet another note" git notes add -c deadbeef &&
+ test_must_fail git notes list HEAD
+ '
+
+ cat > expect << EOF
+ commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:21:13 2005 -0700
+
+ 9th
+
+ Notes:
+ yet another note
+ $whitespace
+ yet another note
+ EOF
+
+ test_expect_success 'append to note from other note with "git notes append -C"' '
+ git notes append -C $(git notes list HEAD^) HEAD^ &&
+ git log -1 HEAD^ > actual &&
+ test_cmp expect actual
+ '
+
+ cat > expect << EOF
+ commit ffed603236bfa3891c49644257a83598afe8ae5a
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:22:13 2005 -0700
+
+ 10th
+
+ Notes:
+ other note
+ EOF
+
+ test_expect_success 'create note from other note with "git notes append -c"' '
+ MSG="other note" git notes append -c $(git notes list HEAD^) &&
+ git log -1 > actual &&
+ test_cmp expect actual
+ '
+
+ cat > expect << EOF
+ commit ffed603236bfa3891c49644257a83598afe8ae5a
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:22:13 2005 -0700
+
+ 10th
+
+ Notes:
+ other note
+ $whitespace
+ yet another note
+ EOF
+
+ test_expect_success 'append to note from other note with "git notes append -c"' '
+ MSG="yet another note" git notes append -c $(git notes list HEAD) &&
+ git log -1 > actual &&
+ test_cmp expect actual
+ '
+
+ cat > expect << EOF
+ commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:23:13 2005 -0700
+
+ 11th
+
+ Notes:
+ other note
+ $whitespace
+ yet another note
+ EOF
+
+ test_expect_success 'copy note with "git notes copy"' '
+ : > a11 &&
+ git add a11 &&
+ test_tick &&
+ git commit -m 11th &&
+ git notes copy HEAD^ HEAD &&
+ git log -1 > actual &&
+ test_cmp expect actual &&
+ test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+ '
+
+ test_expect_success 'prevent overwrite with "git notes copy"' '
+ test_must_fail git notes copy HEAD~2 HEAD &&
+ git log -1 > actual &&
+ test_cmp expect actual &&
+ test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+ '
+
+ cat > expect << EOF
+ commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:23:13 2005 -0700
+
+ 11th
+
+ Notes:
+ yet another note
+ $whitespace
+ yet another note
+ EOF
+
+ test_expect_success 'allow overwrite with "git notes copy -f"' '
+ git notes copy -f HEAD~2 HEAD &&
+ git log -1 > actual &&
+ test_cmp expect actual &&
+ test "$(git notes list HEAD)" = "$(git notes list HEAD~2)"
+ '
+
+ test_expect_success 'cannot copy note from object without notes' '
+ : > a12 &&
+ git add a12 &&
+ test_tick &&
+ git commit -m 12th &&
+ : > a13 &&
+ git add a13 &&
+ test_tick &&
+ git commit -m 13th &&
+ test_must_fail git notes copy HEAD^ HEAD
+ '
+
test_done