An integer -1..9, indicating a default compression level.
-1 is the zlib default. 0 means no compression,
and 1..9 are various speed/size tradeoffs, 9 being slowest.
+ If set, this provides a default to other compression variables,
+ such as 'core.loosecompression' and 'pack.compression'.
core.loosecompression::
An integer -1..9, indicating the compression level for objects that
are not in a pack file. -1 is the zlib default. 0 means no
compression, and 1..9 are various speed/size tradeoffs, 9 being
slowest. If not set, defaults to core.compression. If that is
- not set, defaults to 0 (best speed).
+ not set, defaults to 1 (best speed).
core.packedGitWindowSize::
Number of bytes of a pack file to map into memory in a
The command that git will use to paginate output. Can be overridden
with the `GIT_PAGER` environment variable.
+ core.whitespace::
+ A comma separated list of common whitespace problems to
+ notice. `git diff` will use `color.diff.whitespace` to
+ highlight them, and `git apply --whitespace=error` will
+ consider them as errors:
+ +
+ * `trailing-space` 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 that can be replaced with tab characters.
+
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
option values containing whitespace characters are currently not
supported.
+branch.<name>.rebase::
+ When true, rebase the branch <name> on top of the fetched branch,
+ instead of merging the default branch from the default remote.
+ *NOTE*: this is a possibly dangerous operation; do *not* use
+ it unless you understand the implications (see gitlink:git-rebase[1]
+ for details).
+
clean.requireForce::
- A boolean to make git-clean do nothing unless given -f or -n. Defaults
- to false.
+ A boolean to make git-clean do nothing unless given -f
+ or -n. Defaults to true.
color.branch::
A boolean to enable/disable color in the output of
- gitlink:git-branch[1]. May be set to `true` (or `always`),
- `false` (or `never`) or `auto`, in which case colors are used
+ gitlink:git-branch[1]. May be set to `always`,
+ `false` (or `never`) or `auto` (or `true`), in which case colors are used
only when the output is to a terminal. Defaults to false.
color.branch.<slot>::
doesn't matter.
color.diff::
- When true (or `always`), always use colors in patch.
- When false (or `never`), never. When set to `auto`, use
- colors only when the output is to the terminal.
+ When set to `always`, always use colors in patch.
+ When false (or `never`), never. When set to `true` or `auto`, use
+ colors only when the output is to the terminal. Defaults to false.
color.diff.<slot>::
Use customized color for diff colorization. `<slot>` specifies
which part of the patch to use the specified color, and is one
of `plain` (context text), `meta` (metainformation), `frag`
(hunk header), `old` (removed lines), `new` (added lines),
- `commit` (commit headers), or `whitespace` (highlighting dubious
- whitespace). The values of these variables may be specified as
+ `commit` (commit headers), or `whitespace` (highlighting
+ whitespace errors). The values of these variables may be specified as
in color.branch.<slot>.
+color.interactive::
+ When set to `always`, always use colors in `git add --interactive`.
+ When false (or `never`), never. When set to `true` or `auto`, use
+ colors only when the output is to the terminal. Defaults to false.
+
+color.interactive.<slot>::
+ Use customized color for `git add --interactive`
+ output. `<slot>` may be `prompt`, `header`, or `help`, for
+ three distinct types of normal output from interactive
+ programs. The values of these variables may be specified as
+ in color.branch.<slot>.
+
color.pager::
A boolean to enable/disable colored output when the pager is in
use (default is true).
color.status::
A boolean to enable/disable color in the output of
- gitlink:git-status[1]. May be set to `true` (or `always`),
- `false` (or `never`) or `auto`, in which case colors are used
+ gitlink:git-status[1]. May be set to `always`,
+ `false` (or `never`) or `auto` (or `true`), in which case colors are used
only when the output is to a terminal. Defaults to false.
color.status.<slot>::
pack from a push can make the push operation complete faster,
especially on slow filesystems.
+format.numbered::
+ A boolean which can enable sequence numbers in patch subjects.
+ Seting this option to "auto" will enable it only if there is
+ more than one patch. See --numbered option in
+ gitlink:git-format-patch[1].
+
format.headers::
Additional email headers to include in a patch to be submitted
by mail. See gitlink:git-format-patch[1].
rerere.enabled::
Activate recording of resolved conflicts, so that identical
conflict hunks can be resolved automatically, should they
- be encountered again. See gitlink:git-rerere[1].
+ be encountered again. gitlink:git-rerere[1] command is by
+ default enabled, but can be disabled by setting this option to
+ false.
gitcvs.enabled::
Whether the CVS server interface is enabled for this repository.
is one of "ext" and "pserver") to make them apply only for the given
access method.
+http.proxy::
+ Override the HTTP proxy, normally configured using the 'http_proxy'
+ environment variable (see gitlink:curl[1]). This can be overridden
+ on a per-remote basis; see remote.<name>.proxy
+
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
over HTTPS. Can be overridden by the 'GIT_SSL_NO_VERIFY' environment
in a pack file. -1 is the zlib default. 0 means no
compression, and 1..9 are various speed/size tradeoffs, 9 being
slowest. If not set, defaults to core.compression. If that is
- not set, defaults to -1.
+ not set, defaults to -1, the zlib default, which is "a default
+ compromise between speed and compression (currently equivalent
+ to level 6)."
pack.deltaCacheSize::
The maximum memory in bytes used for caching deltas in
machines. The required amount of memory for the delta search window
is however multiplied by the number of threads.
+pack.indexVersion::
+ Specify the default pack index version. Valid values are 1 for
+ legacy pack index used by Git versions prior to 1.5.2, and 2 for
+ the new pack index with capabilities for packs larger than 4 GB
+ as well as proper protection against the repacking of corrupted
+ packs. Version 2 is selected and this config option ignored
+ whenever the corresponding pack is larger than 2 GB. Otherwise
+ the default is 1.
+
pull.octopus::
The default merge strategy to use when pulling multiple branches
at once.
The URL of a remote repository. See gitlink:git-fetch[1] or
gitlink:git-push[1].
+remote.<name>.proxy::
+ For remotes that require curl (http, https and ftp), the URL to
+ the proxy to use for that remote. Set to the empty string to
+ disable proxying for that remote.
+
remote.<name>.fetch::
The default set of "refspec" for gitlink:git-fetch[1]. See
gitlink:git-fetch[1].
The default set of branches for gitlink:git-show-branch[1].
See gitlink:git-show-branch[1].
+status.relativePaths::
+ By default, gitlink:git-status[1] shows paths relative to the
+ current directory. Setting this variable to `false` shows paths
+ relative to the repository root (this was the default for git
+ prior to v1.5.4).
+
tar.umask::
This variable can be used to restrict the permission bits of
tar archive entries. The default is 0002, which turns off the
`filter`
^^^^^^^^
-A `filter` attribute can be set to a string value. This names
+A `filter` attribute can be set to a string value that names a
filter driver specified in the configuration.
-A filter driver consists of `clean` command and `smudge`
+A filter driver consists of a `clean` command and a `smudge`
command, either of which can be left unspecified. Upon
-checkout, when `smudge` command is specified, the command is fed
-the blob object from its standard input, and its standard output
-is used to update the worktree file. Similarly, `clean` command
-is used to convert the contents of worktree file upon checkin.
+checkout, when the `smudge` command is specified, the command is
+fed the blob object from its standard input, and its standard
+output is used to update the worktree file. Similarly, the
+`clean` command is used to convert the contents of worktree file
+upon checkin.
-Missing filter driver definition in the config is not an error
+A missing filter driver definition in the config is not an error
but makes the filter a no-op passthru.
The content filtering is done to massage the content into a
shape that is more convenient for the platform, filesystem, and
-the user to use. The keyword here is "more convenient" and not
+the user to use. The key phrase here is "more convenient" and not
"turning something unusable into usable". In other words, the
intent is that if someone unsets the filter driver definition,
or does not have the appropriate filter program, the project
internal merge and the final merge.
+ Checking whitespace errors
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ `whitespace`
+ ^^^^^^^^^^^^
+
+ The `core.whitespace` configuration variable allows you to define what
+ `diff` and `apply` should consider whitespace errors for all paths in
+ the project (See gitlink:git-config[1]). This attribute gives you finer
+ control per path.
+
+ Set::
+
+ Notice all types of potential whitespace errors known to git.
+
+ Unset::
+
+ Do not notice anything as error.
+
+ Unspecified::
+
+ Use the value of `core.whitespace` configuration variable to
+ decide what to notice as error.
+
+ String::
+
+ Specify a comma separate list of common whitespace problems to
+ notice in the same format as `core.whitespace` configuration
+ variable.
+
+
EXAMPLE
-------
# Define OLD_ICONV if your library has an old iconv(), where the second
# (input buffer pointer) parameter is declared with type (const char **).
#
+# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
+#
# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
# that tells runtime paths to dynamic libraries;
# "-Wl,-rpath=/path/lib" is used instead.
# times (my ext3 doesn't).
#
# Define USE_STDEV below if you want git to care about the underlying device
-# change being considered an inode change from the update-cache perspective.
+# change being considered an inode change from the update-index perspective.
#
# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
#
+# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
+#
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
# MakeMaker (e.g. using ActiveState under Cygwin).
#
prefix = $(HOME)
bindir = $(prefix)/bin
+mandir = $(prefix)/share/man
gitexecdir = $(bindir)
sharedir = $(prefix)/share
template_dir = $(sharedir)/git-core/templates
SCRIPT_SH = \
git-bisect.sh git-checkout.sh \
- git-clean.sh git-clone.sh git-commit.sh \
- git-ls-remote.sh \
+ git-clone.sh \
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
git-repack.sh git-request-pull.sh \
git-sh-setup.sh \
git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
- git-merge-resolve.sh git-merge-ours.sh \
+ git-merge-resolve.sh \
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
git-filter-branch.sh \
git-stash.sh
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
- git-status git-instaweb
+ git-instaweb
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-fast-import$X \
git-daemon$X \
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
- git-peek-remote$X git-receive-pack$X \
+ git-receive-pack$X \
git-send-pack$X git-shell$X \
git-show-index$X \
git-unpack-file$X \
BUILT_INS = \
git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
git-get-tar-commit-id$X git-init$X git-repo-config$X \
- git-fsck-objects$X git-cherry-pick$X \
+ git-fsck-objects$X git-cherry-pick$X git-peek-remote$X git-status$X \
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
# what 'all' will build and 'install' will install, in gitexecdir
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X gitweb/gitweb.cgi
-ifndef NO_TCLTK
-OTHER_PROGRAMS += gitk-wish
-endif
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
LIB_OBJS = \
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
date.o diff-delta.o entry.o exec_cmd.o ident.o \
- interpolate.o hash.o \
+ pretty.o interpolate.o hash.o \
lockfile.o \
patch-ids.o \
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
- transport.o bundle.o walker.o parse-options.o
+ transport.o bundle.o walker.o parse-options.o ws.o
BUILTIN_OBJS = \
builtin-add.o \
builtin-check-attr.o \
builtin-checkout-index.o \
builtin-check-ref-format.o \
+ builtin-clean.o \
+ builtin-commit.o \
builtin-commit-tree.o \
builtin-count-objects.o \
builtin-describe.o \
builtin-diff-files.o \
builtin-diff-index.o \
builtin-diff-tree.o \
+ builtin-fast-export.o \
builtin-fetch.o \
builtin-fetch-pack.o \
builtin-fetch--tool.o \
builtin-log.o \
builtin-ls-files.o \
builtin-ls-tree.o \
+ builtin-ls-remote.o \
builtin-mailinfo.o \
builtin-mailsplit.o \
builtin-merge-base.o \
builtin-merge-file.o \
+ builtin-merge-ours.o \
builtin-mv.o \
builtin-name-rev.o \
builtin-pack-objects.o \
builtin-push.o \
builtin-read-tree.o \
builtin-reflog.o \
+ builtin-send-pack.o \
builtin-config.o \
builtin-rerere.o \
builtin-reset.o \
builtin-rev-parse.o \
builtin-revert.o \
builtin-rm.o \
- builtin-runstatus.o \
builtin-shortlog.o \
builtin-show-branch.o \
builtin-stripspace.o \
ifeq ($(uname_S),Darwin)
NEEDS_SSL_WITH_CRYPTO = YesPlease
NEEDS_LIBICONV = YesPlease
- OLD_ICONV = UnfortunatelyYes
+ ifneq ($(shell expr "$(uname_R)" : '9\.'),2)
+ OLD_ICONV = UnfortunatelyYes
+ endif
NO_STRLCPY = YesPlease
NO_MEMMEM = YesPlease
endif
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
NO_HSTRERROR = YesPlease
+ NO_MKDTEMP = YesPlease
ifeq ($(uname_R),5.8)
NEEDS_LIBICONV = YesPlease
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
- NO_MKDTEMP = YesPlease
NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
endif
ifeq ($(uname_R),5.9)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
- NO_MKDTEMP = YesPlease
NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
endif
NEEDS_LIBICONV = YesPlease
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
+ OLD_ICONV = UnfortunatelyYes
# There are conflicting reports about this.
# On some boxes NO_MMAP is needed, and not so elsewhere.
# Try commenting this out if you suspect MMAP is more efficient
BASIC_CFLAGS += -DOLD_ICONV
endif
+ifdef NO_DEFLATE_BOUND
+ BASIC_CFLAGS += -DNO_DEFLATE_BOUND
+endif
+
ifdef PPC_SHA1
SHA1_HEADER = "ppc/sha1.h"
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
bindir_SQ = $(subst ','\'',$(bindir))
+mandir_SQ = $(subst ','\'',$(mandir))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
template_dir_SQ = $(subst ','\'',$(template_dir))
prefix_SQ = $(subst ','\'',$(prefix))
LIBS = $(GITLIBS) $(EXTLIBS)
BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
- -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $(COMPAT_CFLAGS)
+ $(COMPAT_CFLAGS)
LIB_OBJS += $(COMPAT_OBJS)
ALL_CFLAGS += $(BASIC_CFLAGS)
all::
ifndef NO_TCLTK
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all
+ $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
endif
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
strip: $(PROGRAMS) git$X
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
-gitk-wish: gitk GIT-GUI-VARS
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1,3s|^exec .* "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' <gitk >$@+ && \
- chmod +x $@+ && \
- mv -f $@+ $@
-
git.o: git.c common-cmds.h GIT-CFLAGS
$(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
$(ALL_CFLAGS) -c $(filter %.c,$^)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
-help.o: common-cmds.h
+help.o: help.c common-cmds.h GIT-CFLAGS
+ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_MAN_PATH="$(mandir_SQ)"' $<
git-merge-subtree$X: git-merge-recursive$X
$(QUIET_BUILT_IN)$(RM) $@ && ln git-merge-recursive$X $@
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && ln git$X $@
-common-cmds.h: ./generate-cmdlist.sh
+common-cmds.h: ./generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
chmod +x $@+ && \
mv $@+ $@
-git-status: git-commit
- $(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
gitweb/gitweb.cgi: gitweb/gitweb.perl
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
builtin-init-db.o: builtin-init-db.c GIT-CFLAGS
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
+config.o: config.c GIT-CFLAGS
+ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $<
+
http.o: http.c GIT-CFLAGS
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
+builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
test-delta$X: diff-delta.o patch-delta.o
+test-parse-options$X: parse-options.o
+
.PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
test-%$X: test-%.o $(GITLIBS)
### Installation rules
install: all
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
$(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)'
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
$(MAKE) -C perl prefix='$(prefix_SQ)' install
ifndef NO_TCLTK
- $(INSTALL) gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk
+ $(MAKE) -C gitk-git install
$(MAKE) -C git-gui install
endif
if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
$(MAKE) -C templates/ clean
$(MAKE) -C t/ clean
ifndef NO_TCLTK
- $(RM) gitk-wish
+ $(MAKE) -C gitk-git clean
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
### Check documentation
#
check-docs::
- @for v in $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk; \
+ @(for v in $(ALL_PROGRAMS) $(BUILT_INS) git gitk; \
do \
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
- git-merge-resolve | git-merge-stupid | \
+ git-merge-resolve | git-merge-stupid | git-merge-subtree | \
git-add--interactive | git-fsck-objects | git-init-db | \
+ git-rebase--interactive | \
git-repo-config | git-fetch--tool ) continue ;; \
esac ; \
test -f "Documentation/$$v.txt" || \
echo "no doc: $$v"; \
- sed -e '1,/^__DATA__/d' Documentation/cmd-list.perl | \
+ sed -e '/^#/d' command-list.txt | \
grep -q "^$$v[ ]" || \
case "$$v" in \
git) ;; \
*) echo "no link: $$v";; \
esac ; \
- done | sort
+ done; \
+ ( \
+ sed -e '/^#/d' \
+ -e 's/[ ].*//' \
+ -e 's/^/listed /' command-list.txt; \
+ ls -1 Documentation/git*txt | \
+ sed -e 's|Documentation/|documented |' \
+ -e 's/\.txt//'; \
+ ) | while read how cmd; \
+ do \
+ case "$$how,$$cmd" in \
+ *,git-citool | \
+ *,git-gui | \
+ *,git-help | \
+ documented,gitattributes | \
+ documented,gitignore | \
+ documented,gitmodules | \
+ documented,git-tools | \
+ sentinel,not,matching,is,ok ) continue ;; \
+ esac; \
+ case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
+ *" $$cmd "*) ;; \
+ *) echo "removed but $$how: $$cmd" ;; \
+ esac; \
+ done ) | sort
### Make sure built-ins do not have dups and listed in git.c
#
static int line_termination = '\n';
static unsigned long p_context = ULONG_MAX;
static const char apply_usage[] =
- "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
-
- static enum whitespace_eol {
- nowarn_whitespace,
- warn_on_whitespace,
- error_on_whitespace,
- strip_whitespace,
- } new_whitespace = warn_on_whitespace;
+ "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
+
+ static enum ws_error_action {
+ nowarn_ws_error,
+ warn_on_ws_error,
+ die_on_ws_error,
+ correct_ws_error,
+ } ws_error_action = warn_on_ws_error;
static int whitespace_error;
static int squelch_whitespace_errors = 5;
static int applied_after_fixing_ws;
static void parse_whitespace_option(const char *option)
{
if (!option) {
- new_whitespace = warn_on_whitespace;
+ ws_error_action = warn_on_ws_error;
return;
}
if (!strcmp(option, "warn")) {
- new_whitespace = warn_on_whitespace;
+ ws_error_action = warn_on_ws_error;
return;
}
if (!strcmp(option, "nowarn")) {
- new_whitespace = nowarn_whitespace;
+ ws_error_action = nowarn_ws_error;
return;
}
if (!strcmp(option, "error")) {
- new_whitespace = error_on_whitespace;
+ ws_error_action = die_on_ws_error;
return;
}
if (!strcmp(option, "error-all")) {
- new_whitespace = error_on_whitespace;
+ ws_error_action = die_on_ws_error;
squelch_whitespace_errors = 0;
return;
}
- if (!strcmp(option, "strip")) {
- new_whitespace = strip_whitespace;
+ if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
+ ws_error_action = correct_ws_error;
return;
}
die("unrecognized whitespace option '%s'", option);
static void set_default_whitespace_mode(const char *whitespace_option)
{
- if (!whitespace_option && !apply_default_whitespace) {
- new_whitespace = (apply
- ? warn_on_whitespace
- : nowarn_whitespace);
- }
+ if (!whitespace_option && !apply_default_whitespace)
+ ws_error_action = (apply ? warn_on_ws_error : nowarn_ws_error);
}
/*
#define BINARY_DELTA_DEFLATED 1
#define BINARY_LITERAL_DEFLATED 2
+ /*
+ * This represents a "patch" to a file, both metainfo changes
+ * such as creation/deletion, filemode and content changes represented
+ * as a series of fragments.
+ */
struct patch {
char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode;
int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
int rejected;
+ unsigned ws_rule;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
struct patch *next;
};
- static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post)
+ static void say_patch_name(FILE *output, const char *pre,
+ struct patch *patch, const char *post)
{
fputs(pre, output);
if (patch->old_name && patch->new_name &&
if (*line == '"') {
struct strbuf name;
- /* Proposed "new-style" GNU patch/diff format; see
+ /*
+ * Proposed "new-style" GNU patch/diff format; see
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
*/
strbuf_init(&name, 0);
static int gitdiff_index(const char *line, struct patch *patch)
{
- /* index line is N hexadecimal, "..", N hexadecimal,
+ /*
+ * index line is N hexadecimal, "..", N hexadecimal,
* and optional space with octal mode.
*/
const char *ptr, *eol;
return NULL;
}
- /* This is to extract the same name that appears on "diff --git"
+ /*
+ * This is to extract the same name that appears on "diff --git"
* line. We do not find and return anything if it is a rename
* patch, and it is OK because we will find the name elsewhere.
* We need to reliably find name only when it is mode-change only,
goto free_and_fail1;
strbuf_remove(&first, 0, cp + 1 - first.buf);
- /* second points at one past closing dq of name.
+ /*
+ * second points at one past closing dq of name.
* find the second name.
*/
while ((second < line + llen) && isspace(*second))
return NULL;
name++;
- /* since the first name is unquoted, a dq if exists must be
+ /*
+ * since the first name is unquoted, a dq if exists must be
* the beginning of the second name.
*/
for (second = name; second < line + llen; second++) {
}
}
}
- return NULL;
}
/* Verify that we recognize the lines following a git header */
}
static int parse_range(const char *line, int len, int offset, const char *expect,
- unsigned long *p1, unsigned long *p2)
+ unsigned long *p1, unsigned long *p2)
{
int digits, ex;
return offset;
}
- /** --- followed by +++ ? */
+ /* --- followed by +++ ? */
if (memcmp("--- ", line, 4) || memcmp("+++ ", line + len, 4))
continue;
/*
* We only accept unified patches, so we want it to
* at least have "@@ -a,b +c,d @@\n", which is 14 chars
- * minimum
+ * minimum ("@@ -0,0 +1 @@\n" is the shortest).
*/
nextlen = linelen(line + len, size - len);
if (size < nextlen + 14 || memcmp("@@ -", line + len + nextlen, 4))
return -1;
}
- static void check_whitespace(const char *line, int len)
+ static void check_whitespace(const char *line, int len, unsigned ws_rule)
{
const char *err = "Adds trailing whitespace";
int seen_space = 0;
* this function. That is, an addition of an empty line would
* check the '+' here. Sneaky...
*/
- if (isspace(line[len-2]))
+ if ((ws_rule & WS_TRAILING_SPACE) && isspace(line[len-2]))
goto error;
/*
* Make sure that there is no space followed by a tab in
* indentation.
*/
- err = "Space in indent is followed by a tab";
- for (i = 1; i < len; i++) {
- if (line[i] == '\t') {
- if (seen_space)
- goto error;
- }
- else if (line[i] == ' ')
- seen_space = 1;
- else
- break;
+ if (ws_rule & WS_SPACE_BEFORE_TAB) {
+ err = "Space in indent is followed by a tab";
+ for (i = 1; i < len; i++) {
+ if (line[i] == '\t') {
+ if (seen_space)
+ goto error;
+ }
+ else if (line[i] == ' ')
+ seen_space = 1;
+ else
+ break;
+ }
+ }
+
+ /*
+ * Make sure that the indentation does not contain more than
+ * 8 spaces.
+ */
+ if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+ (8 < len) && !strncmp("+ ", line, 9)) {
+ err = "Indent more than 8 places with spaces";
+ goto error;
}
return;
err, patch_input_file, linenr, len-2, line+1);
}
-
/*
* Parse a unified diff. Note that this really needs to parse each
* fragment separately, since the only way to know the difference
* between a "---" that is part of a patch, and a "---" that starts
* the next patch is to look at the line counts..
*/
- static int parse_fragment(char *line, unsigned long size, struct patch *patch, struct fragment *fragment)
+ static int parse_fragment(char *line, unsigned long size,
+ struct patch *patch, struct fragment *fragment)
{
int added, deleted;
int len = linelen(line, size), offset;
break;
case '-':
if (apply_in_reverse &&
- new_whitespace != nowarn_whitespace)
- check_whitespace(line, len);
+ ws_error_action != nowarn_ws_error)
+ check_whitespace(line, len, patch->ws_rule);
deleted++;
oldlines--;
trailing = 0;
break;
case '+':
if (!apply_in_reverse &&
- new_whitespace != nowarn_whitespace)
- check_whitespace(line, len);
+ ws_error_action != nowarn_ws_error)
+ check_whitespace(line, len, patch->ws_rule);
added++;
newlines--;
trailing = 0;
break;
- /* We allow "\ No newline at end of file". Depending
+ /*
+ * We allow "\ No newline at end of file". Depending
* on locale settings when the patch was produced we
* don't know what this line looks like. The only
* thing we do know is that it begins with "\ ".
fragment->leading = leading;
fragment->trailing = trailing;
- /* If a fragment ends with an incomplete line, we failed to include
+ /*
+ * If a fragment ends with an incomplete line, we failed to include
* it in the above loop because we hit oldlines == newlines == 0
* before seeing it.
*/
int *status_p,
int *used_p)
{
- /* Expect a line that begins with binary patch method ("literal"
+ /*
+ * Expect a line that begins with binary patch method ("literal"
* or "delta"), followed by the length of data before deflating.
* a sequence of 'length-byte' followed by base-85 encoded data
* should follow, terminated by a newline.
size--;
break;
}
- /* Minimum line is "A00000\n" which is 7-byte long,
+ /*
+ * Minimum line is "A00000\n" which is 7-byte long,
* and the line length must be multiple of 5 plus 2.
*/
if ((llen < 7) || (llen-2) % 5)
static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
{
- /* We have read "GIT binary patch\n"; what follows is a line
+ /*
+ * We have read "GIT binary patch\n"; what follows is a line
* that says the patch method (currently, either "literal" or
* "delta") and the length of data before deflating; a
* sequence of 'length-byte' followed by base-85 encoded data
if (reverse)
used += used_1;
else if (status) {
- /* not having reverse hunk is not an error, but having
+ /*
+ * Not having reverse hunk is not an error, but having
* a corrupt reverse hunk is.
*/
free((void*) forward->patch);
if (offset < 0)
return offset;
- patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
+ patch->ws_rule = whitespace_rule(patch->new_name
+ ? patch->new_name
+ : patch->old_name);
+
+ patchsize = parse_single_patch(buffer + offset + hdrsize,
+ size - offset - hdrsize, patch);
if (!patchsize) {
static const char *binhdr[] = {
}
}
- static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
- static const char minuses[]= "----------------------------------------------------------------------";
+ static const char pluses[] =
+ "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
+ static const char minuses[]=
+ "----------------------------------------------------------------------";
static void show_stats(struct patch *patch)
{
}
}
- static int find_offset(const char *buf, unsigned long size, const char *fragment, unsigned long fragsize, int line, int *lines)
+ static int find_offset(const char *buf, unsigned long size,
+ const char *fragment, unsigned long fragsize,
+ int line, int *lines)
{
int i;
unsigned long start, backwards, forwards;
*rsize = offset + 1;
}
- static int apply_line(char *output, const char *patch, int plen)
+ static int apply_line(char *output, const char *patch, int plen,
+ unsigned ws_rule)
{
- /* plen is number of bytes to be copied from patch,
+ /*
+ * plen is number of bytes to be copied from patch,
* starting at patch+1 (patch[0] is '+'). Typically
* patch[plen] is '\n', unless this is the incomplete
* last line.
int need_fix_leading_space = 0;
char *buf;
- if ((new_whitespace != strip_whitespace) || !whitespace_error ||
+ if ((ws_error_action != correct_ws_error) || !whitespace_error ||
*patch != '+') {
memcpy(output, patch + 1, plen);
return plen;
}
- if (1 < plen && isspace(patch[plen-1])) {
+ /*
+ * Strip trailing whitespace
+ */
+ if ((ws_rule & WS_TRAILING_SPACE) &&
+ (1 < plen && isspace(patch[plen-1]))) {
if (patch[plen] == '\n')
add_nl_to_tail = 1;
plen--;
fixed = 1;
}
+ /*
+ * Check leading whitespaces (indent)
+ */
for (i = 1; i < plen; i++) {
char ch = patch[i];
if (ch == '\t') {
last_tab_in_indent = i;
- if (0 <= last_space_in_indent)
+ if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
+ 0 <= last_space_in_indent)
+ need_fix_leading_space = 1;
+ } else if (ch == ' ') {
+ last_space_in_indent = i;
+ if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+ last_tab_in_indent < 0 &&
+ 8 <= i)
need_fix_leading_space = 1;
}
- else if (ch == ' ')
- last_space_in_indent = i;
else
break;
}
buf = output;
if (need_fix_leading_space) {
int consecutive_spaces = 0;
- /* between patch[1..last_tab_in_indent] strip the
- * funny spaces, updating them to tab as needed.
+ int last = last_tab_in_indent + 1;
+
+ if (ws_rule & WS_INDENT_WITH_NON_TAB) {
+ /* have "last" point at one past the indent */
+ if (last_tab_in_indent < last_space_in_indent)
+ last = last_space_in_indent + 1;
+ else
+ last = last_tab_in_indent + 1;
+ }
+
+ /*
+ * between patch[1..last], strip the funny spaces,
+ * updating them to tab as needed.
*/
- for (i = 1; i < last_tab_in_indent; i++, plen--) {
+ for (i = 1; i < last; i++, plen--) {
char ch = patch[i];
if (ch != ' ') {
consecutive_spaces = 0;
}
}
}
+ while (0 < consecutive_spaces--)
+ *output++ = ' ';
fixed = 1;
- i = last_tab_in_indent;
+ i = last;
}
else
i = 1;
return output + plen - buf;
}
- static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
+ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag,
+ int inaccurate_eof, unsigned ws_rule)
{
int match_beginning, match_end;
const char *patch = frag->patch;
case '+':
if (first != '+' || !no_add) {
int added = apply_line(new + newsize, patch,
- plen);
+ plen, ws_rule);
newsize += added;
if (first == '+' &&
added == 1 && new[newsize-1] == '\n')
size -= len;
}
- if (inaccurate_eof && oldsize > 0 && old[oldsize - 1] == '\n' &&
- newsize > 0 && new[newsize - 1] == '\n') {
+ if (inaccurate_eof &&
+ oldsize > 0 && old[oldsize - 1] == '\n' &&
+ newsize > 0 && new[newsize - 1] == '\n') {
oldsize--;
newsize--;
}
if (match_beginning && offset)
offset = -1;
if (offset >= 0) {
- if (new_whitespace == strip_whitespace &&
+ if (ws_error_action == correct_ws_error &&
(buf->len - oldsize - offset == 0)) /* end of file? */
newsize -= new_blank_lines_at_end;
match_beginning = match_end = 0;
continue;
}
- /* Reduce the number of context lines
- * Reduce both leading and trailing if they are equal
- * otherwise just reduce the larger context.
+ /*
+ * Reduce the number of context lines; reduce both
+ * leading and trailing if they are equal otherwise
+ * just reduce the larger context.
*/
if (leading >= trailing) {
remove_first_line(&oldlines, &oldsize);
const char *name = patch->old_name ? patch->old_name : patch->new_name;
unsigned char sha1[20];
- /* For safety, we require patch index line to contain
+ /*
+ * For safety, we require patch index line to contain
* full 40-byte textual SHA1 for old and new, at least for now.
*/
if (strlen(patch->old_sha1_prefix) != 40 ||
"without full index line", name);
if (patch->old_name) {
- /* See if the old one matches what the patch
+ /*
+ * See if the old one matches what the patch
* applies to.
*/
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
/* XXX read_sha1_file NUL-terminates */
strbuf_attach(buf, result, size, size + 1);
} else {
- /* We have verified buf matches the preimage;
+ /*
+ * We have verified buf matches the preimage;
* apply the patch data to it, which is stored
* in the patch->fragments->{patch,size}.
*/
{
struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name;
+ unsigned ws_rule = patch->ws_rule;
+ unsigned inaccurate_eof = patch->inaccurate_eof;
if (patch->is_binary)
return apply_binary(buf, patch);
while (frag) {
- if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
+ if (apply_one_fragment(buf, frag, inaccurate_eof, ws_rule)) {
error("patch failed: %s:%ld", name, frag->oldpos);
if (!apply_with_reject)
return -1;
return -1;
return 0;
}
- return ce_match_stat(ce, st, 1);
+ return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
}
static int check_patch(struct patch *patch, struct patch *prev_patch)
if (new_name && prev_patch && 0 < prev_patch->is_delete &&
!strcmp(prev_patch->old_name, new_name))
- /* A type-change diff is always split into a patch to
+ /*
+ * A type-change diff is always split into a patch to
* delete old, immediately followed by a patch to
* create new (see diff.c::run_diff()); in such a case
* it is Ok that the entry to be deleted by the
offset += nr;
}
- if (whitespace_error && (new_whitespace == error_on_whitespace))
+ if (whitespace_error && (ws_error_action == die_on_ws_error))
apply = 0;
update_index = check_index && apply;
squelched,
squelched == 1 ? "" : "s");
}
- if (new_whitespace == error_on_whitespace)
+ if (ws_error_action == die_on_ws_error)
die("%d line%s add%s whitespace errors.",
whitespace_error,
whitespace_error == 1 ? "" : "s",
#include SHA1_HEADER
#include <zlib.h>
-#if ZLIB_VERNUM < 0x1200
+#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
#define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
#endif
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
-#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
-#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
+#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
+#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#endif
enum object_type {
OBJ_MAX,
};
+static inline enum object_type object_type(unsigned int mode)
+{
+ return S_ISDIR(mode) ? OBJ_TREE :
+ S_ISGITLINK(mode) ? OBJ_COMMIT :
+ OBJ_BLOB;
+}
+
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
extern const char **get_pathspec(const char *prefix, const char **pathspec);
+extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern const char *prefix_path(const char *prefix, int len, const char *path);
extern int add_file_to_index(struct index_state *, const char *path, int verbose);
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
-extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
-extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID 01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY 02
+extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
struct lock_file {
struct lock_file *next;
+ int fd;
pid_t owner;
char on_list;
char filename[PATH_MAX];
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
+extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
+extern const char *ref_rev_parse_rules[];
+extern const char *ref_fetch_rules[];
+
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
unsigned long approxidate(const char *);
enum date_mode parse_date_format(const char *format);
+#define IDENT_WARN_ON_NO_NAME 1
+#define IDENT_ERROR_ON_NO_NAME 2
+#define IDENT_NO_DATE 4
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);
struct checkout {
const char *base_dir;
struct ref *next;
unsigned char old_sha1[20];
unsigned char new_sha1[20];
- unsigned char force;
- unsigned char merge;
+ unsigned int force:1,
+ merge:1,
+ nonfastforward:1,
+ deletion:1;
+ enum {
+ REF_STATUS_NONE = 0,
+ REF_STATUS_OK,
+ REF_STATUS_REJECT_NONFASTFORWARD,
+ REF_STATUS_REJECT_NODELETE,
+ REF_STATUS_UPTODATE,
+ REF_STATUS_REMOTE_REJECT,
+ REF_STATUS_EXPECTING_REPORT,
+ } status;
+ char *remote_status;
struct ref *peer_ref; /* when renaming */
char name[FLEX_ARRAY]; /* more */
};
#define REF_HEADS (1u << 1)
#define REF_TAGS (1u << 2)
+extern struct ref *find_ref_by_name(struct ref *list, const char *name);
+
#define CONNECT_VERBOSE (1u << 0)
-extern struct child_process *git_connect(int fd[2], char *url, const char *prog, int flags);
+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);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
+extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value);
#define MAX_GITNAME (1000)
extern int pager_use_color;
extern char *editor_program;
+extern char *excludes_file;
/* base85 */
int decode_85(char *dst, const char *line, int linelen);
/* trace.c */
extern void trace_printf(const char *format, ...);
-extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
+extern void trace_argv_printf(const char **argv, const char *format, ...);
/* convert.c */
/* returns 1 if *dst was used */
extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
+/* add */
+void add_files_to_cache(int verbose, const char *prefix, const char **pathspec);
+
/* diff.c */
extern int diff_auto_refresh_index;
/* match-trees.c */
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
+ /*
+ * whitespace rules.
+ * used by both diff and apply
+ */
+ #define WS_TRAILING_SPACE 01
+ #define WS_SPACE_BEFORE_TAB 02
+ #define WS_INDENT_WITH_NON_TAB 04
+ #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
+ extern unsigned whitespace_rule_cfg;
+ extern unsigned whitespace_rule(const char *);
+ extern unsigned parse_whitespace_rule(const char *);
+
+/* ls-files */
+int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);
+int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
+void overlay_tree_on_cache(const char *tree_name, const char *prefix);
+
#endif /* CACHE_H */
*
*/
#include "cache.h"
+#include "exec_cmd.h"
#define MAXNAME (256)
return 0;
}
+ if (!strcmp(var, "core.excludesfile")) {
+ if (!value)
+ die("core.excludesfile without value");
+ excludes_file = xstrdup(value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.whitespace")) {
+ whitespace_rule_cfg = parse_whitespace_rule(value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
return ret;
}
+const char *git_etc_gitconfig(void)
+{
+ static const char *system_wide;
+ if (!system_wide) {
+ system_wide = ETC_GITCONFIG;
+ if (!is_absolute_path(system_wide)) {
+ /* interpret path relative to exec-dir */
+ const char *exec_path = git_exec_path();
+ system_wide = prefix_path(exec_path, strlen(exec_path),
+ system_wide);
+ }
+ }
+ return system_wide;
+}
+
int git_config(config_fn_t fn)
{
int ret = 0;
* config file otherwise. */
filename = getenv(CONFIG_ENVIRONMENT);
if (!filename) {
- if (!access(ETC_GITCONFIG, R_OK))
- ret += git_config_from_file(fn, ETC_GITCONFIG);
+ if (!access(git_etc_gitconfig(), R_OK))
+ ret += git_config_from_file(fn, git_etc_gitconfig());
home = getenv("HOME");
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!filename)
int length = strlen(key+store.baselen+1);
int quote = 0;
- /* Check to see if the value needs to be quoted. */
+ /*
+ * Check to see if the value needs to be surrounded with a dq pair.
+ * Note that problematic characters are always backslash-quoted; this
+ * check is about not losing leading or trailing SP and strings that
+ * follow beginning-of-comment characters (i.e. ';' and '#') by the
+ * configuration parser.
+ */
if (value[0] == ' ')
quote = 1;
for (i = 0; value[i]; i++)
if (value[i] == ';' || value[i] == '#')
quote = 1;
- if (value[i-1] == ' ')
+ if (i && value[i-1] == ' ')
quote = 1;
if (write_in_full(fd, "\t", 1) != 1 ||
return 0;
}
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
- diff_use_color_default = git_config_colorbool(var, value);
+ diff_use_color_default = git_config_colorbool(var, value, -1);
return 0;
}
if (!strcmp(var, "diff.renames")) {
struct emit_callback {
struct xdiff_emit_state xm;
int nparents, color_diff;
+ unsigned ws_rule;
const char **label_path;
struct diff_words_data *diff_words;
int *found_changesp;
}
static void emit_line_with_ws(int nparents,
- const char *set, const char *reset, const char *ws,
- const char *line, int len)
+ const char *set, const char *reset, const char *ws,
+ const char *line, int len, unsigned ws_rule)
{
int col0 = nparents;
int last_tab_in_indent = -1;
int i;
int tail = len;
int need_highlight_leading_space = 0;
- /* The line is a newly added line. Does it have funny leading
- * whitespaces? In indent, SP should never precede a TAB.
+ /*
+ * The line is a newly added line. Does it have funny leading
+ * whitespaces? In indent, SP should never precede a TAB. In
+ * addition, under "indent with non tab" rule, there should not
+ * be more than 8 consecutive spaces.
*/
for (i = col0; i < len; i++) {
if (line[i] == '\t') {
last_tab_in_indent = i;
- if (0 <= last_space_in_indent)
+ if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
+ 0 <= last_space_in_indent)
need_highlight_leading_space = 1;
}
else if (line[i] == ' ')
else
break;
}
+ if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+ 0 <= last_space_in_indent &&
+ last_tab_in_indent < 0 &&
+ 8 <= (i - col0)) {
+ last_tab_in_indent = i;
+ need_highlight_leading_space = 1;
+ }
fputs(set, stdout);
fwrite(line, col0, 1, stdout);
fputs(reset, stdout);
tail = len - 1;
if (line[tail] == '\n' && i < tail)
tail--;
- while (i < tail) {
- if (!isspace(line[tail]))
- break;
- tail--;
+ if (ws_rule & WS_TRAILING_SPACE) {
+ while (i < tail) {
+ if (!isspace(line[tail]))
+ break;
+ tail--;
+ }
}
if ((i < tail && line[tail + 1] != '\n')) {
/* This has whitespace between tail+1..len */
emit_line(set, reset, line, len);
else
emit_line_with_ws(ecbdata->nparents, set, reset, ws,
- line, len);
+ line, len, ecbdata->ws_rule);
}
static void fn_out_consume(void *priv, char *line, unsigned long len)
}
/* Find the longest filename and max number of changes */
- reset = diff_get_color(options->color_diff, DIFF_RESET);
- set = diff_get_color(options->color_diff, DIFF_PLAIN);
- add_c = diff_get_color(options->color_diff, DIFF_FILE_NEW);
- del_c = diff_get_color(options->color_diff, DIFF_FILE_OLD);
+ reset = diff_get_color_opt(options, DIFF_RESET);
+ set = diff_get_color_opt(options, DIFF_PLAIN);
+ add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
+ del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
for (i = 0; i < data->nr; i++) {
struct diffstat_file *file = data->files[i];
struct xdiff_emit_state xm;
const char *filename;
int lineno, color_diff;
+ unsigned ws_rule;
};
static void checkdiff_consume(void *priv, char *line, unsigned long len)
if (white_space_at_end)
printf("white space at end");
printf(":%s ", reset);
- emit_line_with_ws(1, set, reset, ws, line, len);
+ emit_line_with_ws(1, set, reset, ws, line, len,
+ data->ws_rule);
}
data->lineno++;
mmfile_t mf1, mf2;
const char *lbl[2];
char *a_one, *b_two;
- const char *set = diff_get_color(o->color_diff, DIFF_METAINFO);
- const char *reset = diff_get_color(o->color_diff, DIFF_RESET);
+ const char *set = diff_get_color_opt(o, DIFF_METAINFO);
+ const char *reset = diff_get_color_opt(o, DIFF_RESET);
a_one = quote_two("a/", name_a + (*name_a == '/'));
b_two = quote_two("b/", name_b + (*name_b == '/'));
goto free_ab_and_return;
if (complete_rewrite) {
emit_rewrite_diff(name_a, name_b, one, two,
- o->color_diff);
+ DIFF_OPT_TST(o, COLOR_DIFF));
o->found_changes = 1;
goto free_ab_and_return;
}
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
- if (!o->text &&
+ if (!DIFF_OPT_TST(o, TEXT) &&
(diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) {
/* Quite common confusing case */
if (mf1.size == mf2.size &&
!memcmp(mf1.ptr, mf2.ptr, mf1.size))
goto free_ab_and_return;
- if (o->binary)
+ if (DIFF_OPT_TST(o, BINARY))
emit_binary_diff(&mf1, &mf2);
else
printf("Binary files %s and %s differ\n",
memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.label_path = lbl;
- ecbdata.color_diff = o->color_diff;
+ ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
ecbdata.found_changesp = &o->found_changes;
+ ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
ecb.outf = xdiff_outf;
ecb.priv = &ecbdata;
ecbdata.xm.consume = fn_out_consume;
- if (o->color_diff_words)
+ if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
- if (o->color_diff_words)
+ if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
}
data.xm.consume = checkdiff_consume;
data.filename = name_b ? name_b : name_a;
data.lineno = 0;
- data.color_diff = o->color_diff;
+ data.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
+ data.ws_rule = whitespace_rule(data.filename);
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
struct diff_options *o,
int complete_rewrite)
{
- if (!o->allow_external)
+ if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
pgm = NULL;
else {
const char *cmd = external_diff_attr(name);
}
if (hashcmp(one->sha1, two->sha1)) {
- int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
+ int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
- if (o->binary) {
+ if (DIFF_OPT_TST(o, BINARY)) {
mmfile_t mf;
if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
options->change = diff_change;
options->add_remove = diff_addremove;
- options->color_diff = diff_use_color_default;
+ if (diff_use_color_default)
+ DIFF_OPT_SET(options, COLOR_DIFF);
+ else
+ DIFF_OPT_CLR(options, COLOR_DIFF);
options->detect_rename = diff_detect_rename_default;
}
if (count > 1)
die("--name-only, --name-status, --check and -s are mutually exclusive");
- if (options->find_copies_harder)
+ if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
options->detect_rename = DIFF_DETECT_COPY;
if (options->output_format & (DIFF_FORMAT_NAME |
DIFF_FORMAT_SHORTSTAT |
DIFF_FORMAT_SUMMARY |
DIFF_FORMAT_CHECKDIFF))
- options->recursive = 1;
+ DIFF_OPT_SET(options, RECURSIVE);
/*
* Also pickaxe would not work very well if you do not say recursive
*/
if (options->pickaxe)
- options->recursive = 1;
+ DIFF_OPT_SET(options, RECURSIVE);
if (options->detect_rename && options->rename_limit < 0)
options->rename_limit = diff_rename_limit_default;
* to have found. It does not make sense not to return with
* exit code in such a case either.
*/
- if (options->quiet) {
+ if (DIFF_OPT_TST(options, QUIET)) {
options->output_format = DIFF_FORMAT_NO_OUTPUT;
- options->exit_with_status = 1;
+ DIFF_OPT_SET(options, EXIT_WITH_STATUS);
}
/*
* upon the first hit. We need to run diff as usual.
*/
if (options->pickaxe || options->filter)
- options->quiet = 0;
+ DIFF_OPT_CLR(options, QUIET);
return 0;
}
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
+
+ /* Output format options */
if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
options->output_format |= DIFF_FORMAT_PATCH;
else if (opt_arg(arg, 'U', "unified", &options->context))
options->output_format |= DIFF_FORMAT_PATCH;
else if (!strcmp(arg, "--raw"))
options->output_format |= DIFF_FORMAT_RAW;
- else if (!strcmp(arg, "--patch-with-raw")) {
+ else if (!strcmp(arg, "--patch-with-raw"))
options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
- }
- else if (!strcmp(arg, "--numstat")) {
+ else if (!strcmp(arg, "--numstat"))
options->output_format |= DIFF_FORMAT_NUMSTAT;
- }
- else if (!strcmp(arg, "--shortstat")) {
+ else if (!strcmp(arg, "--shortstat"))
options->output_format |= DIFF_FORMAT_SHORTSTAT;
- }
+ else if (!strcmp(arg, "--check"))
+ options->output_format |= DIFF_FORMAT_CHECKDIFF;
+ else if (!strcmp(arg, "--summary"))
+ options->output_format |= DIFF_FORMAT_SUMMARY;
+ else if (!strcmp(arg, "--patch-with-stat"))
+ options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
+ else if (!strcmp(arg, "--name-only"))
+ options->output_format |= DIFF_FORMAT_NAME;
+ else if (!strcmp(arg, "--name-status"))
+ options->output_format |= DIFF_FORMAT_NAME_STATUS;
+ else if (!strcmp(arg, "-s"))
+ options->output_format |= DIFF_FORMAT_NO_OUTPUT;
else if (!prefixcmp(arg, "--stat")) {
char *end;
int width = options->stat_width;
options->stat_name_width = name_width;
options->stat_width = width;
}
- else if (!strcmp(arg, "--check"))
- options->output_format |= DIFF_FORMAT_CHECKDIFF;
- else if (!strcmp(arg, "--summary"))
- options->output_format |= DIFF_FORMAT_SUMMARY;
- else if (!strcmp(arg, "--patch-with-stat")) {
- options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
- }
- else if (!strcmp(arg, "-z"))
- options->line_termination = 0;
- else if (!prefixcmp(arg, "-l"))
- options->rename_limit = strtoul(arg+2, NULL, 10);
- else if (!strcmp(arg, "--full-index"))
- options->full_index = 1;
- else if (!strcmp(arg, "--binary")) {
- options->output_format |= DIFF_FORMAT_PATCH;
- options->binary = 1;
- }
- else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) {
- options->text = 1;
- }
- else if (!strcmp(arg, "--name-only"))
- options->output_format |= DIFF_FORMAT_NAME;
- else if (!strcmp(arg, "--name-status"))
- options->output_format |= DIFF_FORMAT_NAME_STATUS;
- else if (!strcmp(arg, "-R"))
- options->reverse_diff = 1;
- else if (!prefixcmp(arg, "-S"))
- options->pickaxe = arg + 2;
- else if (!strcmp(arg, "-s")) {
- options->output_format |= DIFF_FORMAT_NO_OUTPUT;
- }
- else if (!prefixcmp(arg, "-O"))
- options->orderfile = arg + 2;
- else if (!prefixcmp(arg, "--diff-filter="))
- options->filter = arg + 14;
- else if (!strcmp(arg, "--pickaxe-all"))
- options->pickaxe_opts = DIFF_PICKAXE_ALL;
- else if (!strcmp(arg, "--pickaxe-regex"))
- options->pickaxe_opts = DIFF_PICKAXE_REGEX;
+
+ /* renames options */
else if (!prefixcmp(arg, "-B")) {
- if ((options->break_opt =
- diff_scoreopt_parse(arg)) == -1)
+ if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
return -1;
}
else if (!prefixcmp(arg, "-M")) {
- if ((options->rename_score =
- diff_scoreopt_parse(arg)) == -1)
+ if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
return -1;
options->detect_rename = DIFF_DETECT_RENAME;
}
else if (!prefixcmp(arg, "-C")) {
if (options->detect_rename == DIFF_DETECT_COPY)
- options->find_copies_harder = 1;
- if ((options->rename_score =
- diff_scoreopt_parse(arg)) == -1)
+ DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+ if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
return -1;
options->detect_rename = DIFF_DETECT_COPY;
}
- else if (!strcmp(arg, "--find-copies-harder"))
- options->find_copies_harder = 1;
- else if (!strcmp(arg, "--follow"))
- options->follow_renames = 1;
- else if (!strcmp(arg, "--abbrev"))
- options->abbrev = DEFAULT_ABBREV;
- else if (!prefixcmp(arg, "--abbrev=")) {
- options->abbrev = strtoul(arg + 9, NULL, 10);
- if (options->abbrev < MINIMUM_ABBREV)
- options->abbrev = MINIMUM_ABBREV;
- else if (40 < options->abbrev)
- options->abbrev = 40;
- }
- else if (!strcmp(arg, "--color"))
- options->color_diff = 1;
- else if (!strcmp(arg, "--no-color"))
- options->color_diff = 0;
+ else if (!strcmp(arg, "--no-renames"))
+ options->detect_rename = 0;
+
+ /* xdiff options */
else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE;
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
else if (!strcmp(arg, "--ignore-space-at-eol"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
+
+ /* flags options */
+ else if (!strcmp(arg, "--binary")) {
+ options->output_format |= DIFF_FORMAT_PATCH;
+ DIFF_OPT_SET(options, BINARY);
+ }
+ else if (!strcmp(arg, "--full-index"))
+ DIFF_OPT_SET(options, FULL_INDEX);
+ else if (!strcmp(arg, "-a") || !strcmp(arg, "--text"))
+ DIFF_OPT_SET(options, TEXT);
+ else if (!strcmp(arg, "-R"))
+ DIFF_OPT_SET(options, REVERSE_DIFF);
+ else if (!strcmp(arg, "--find-copies-harder"))
+ DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+ else if (!strcmp(arg, "--follow"))
+ DIFF_OPT_SET(options, FOLLOW_RENAMES);
+ else if (!strcmp(arg, "--color"))
+ DIFF_OPT_SET(options, COLOR_DIFF);
+ else if (!strcmp(arg, "--no-color"))
+ DIFF_OPT_CLR(options, COLOR_DIFF);
else if (!strcmp(arg, "--color-words"))
- options->color_diff = options->color_diff_words = 1;
- else if (!strcmp(arg, "--no-renames"))
- options->detect_rename = 0;
+ options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
else if (!strcmp(arg, "--exit-code"))
- options->exit_with_status = 1;
+ DIFF_OPT_SET(options, EXIT_WITH_STATUS);
else if (!strcmp(arg, "--quiet"))
- options->quiet = 1;
+ DIFF_OPT_SET(options, QUIET);
else if (!strcmp(arg, "--ext-diff"))
- options->allow_external = 1;
+ DIFF_OPT_SET(options, ALLOW_EXTERNAL);
else if (!strcmp(arg, "--no-ext-diff"))
- options->allow_external = 0;
+ DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
+
+ /* misc options */
+ else if (!strcmp(arg, "-z"))
+ options->line_termination = 0;
+ else if (!prefixcmp(arg, "-l"))
+ options->rename_limit = strtoul(arg+2, NULL, 10);
+ else if (!prefixcmp(arg, "-S"))
+ options->pickaxe = arg + 2;
+ else if (!strcmp(arg, "--pickaxe-all"))
+ options->pickaxe_opts = DIFF_PICKAXE_ALL;
+ else if (!strcmp(arg, "--pickaxe-regex"))
+ options->pickaxe_opts = DIFF_PICKAXE_REGEX;
+ else if (!prefixcmp(arg, "-O"))
+ options->orderfile = arg + 2;
+ else if (!prefixcmp(arg, "--diff-filter="))
+ options->filter = arg + 14;
+ else if (!strcmp(arg, "--abbrev"))
+ options->abbrev = DEFAULT_ABBREV;
+ else if (!prefixcmp(arg, "--abbrev=")) {
+ options->abbrev = strtoul(arg + 9, NULL, 10);
+ if (options->abbrev < MINIMUM_ABBREV)
+ options->abbrev = MINIMUM_ABBREV;
+ else if (40 < options->abbrev)
+ options->abbrev = 40;
+ }
else
return 0;
return 1;
break;
default:
if (p->score) {
- puts(" rewrite ");
+ fputs(" rewrite ", stdout);
write_name_quoted(p->two->path, stdout, ' ');
printf("(%d%%)\n", similarity_index(p));
}
* to determine how many paths were dirty only
* due to stat info mismatch.
*/
- if (!diffopt->no_index)
+ if (!DIFF_OPT_TST(diffopt, NO_INDEX))
diffopt->skip_stat_unmatch++;
diff_free_filepair(p);
}
void diffcore_std(struct diff_options *options)
{
- if (options->quiet)
+ if (DIFF_OPT_TST(options, QUIET))
return;
- if (options->skip_stat_unmatch && !options->find_copies_harder)
+ if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER))
diffcore_skip_stat_unmatch(options);
if (options->break_opt != -1)
diffcore_break(options->break_opt);
diff_resolve_rename_copy();
diffcore_apply_filter(options->filter);
- options->has_changes = !!diff_queued_diff.nr;
+ if (diff_queued_diff.nr)
+ DIFF_OPT_SET(options, HAS_CHANGES);
+ else
+ DIFF_OPT_CLR(options, HAS_CHANGES);
}
* Before the final output happens, they are pruned after
* merged into rename/copy pairs as appropriate.
*/
- if (options->reverse_diff)
+ if (DIFF_OPT_TST(options, REVERSE_DIFF))
addremove = (addremove == '+' ? '-' :
addremove == '-' ? '+' : addremove);
fill_filespec(two, sha1, mode);
diff_queue(&diff_queued_diff, one, two);
- options->has_changes = 1;
+ DIFF_OPT_SET(options, HAS_CHANGES);
}
void diff_change(struct diff_options *options,
char concatpath[PATH_MAX];
struct diff_filespec *one, *two;
- if (options->reverse_diff) {
+ if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
unsigned tmp;
const unsigned char *tmp_c;
tmp = old_mode; old_mode = new_mode; new_mode = tmp;
fill_filespec(two, new_sha1, new_mode);
diff_queue(&diff_queued_diff, one, two);
- options->has_changes = 1;
+ DIFF_OPT_SET(options, HAS_CHANGES);
}
void diff_unmerge(struct diff_options *options,
int pager_in_use;
int pager_use_color = 1;
char *editor_program;
+char *excludes_file;
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
+ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
char *git_work_tree_cfg;