diff options
72 files changed, 1259 insertions, 449 deletions
diff --git a/Documentation/RelNotes-1.6.5.1.txt b/Documentation/RelNotes-1.6.5.1.txt new file mode 100644 index 0000000000..309ba181b2 --- /dev/null +++ b/Documentation/RelNotes-1.6.5.1.txt @@ -0,0 +1,20 @@ +GIT v1.6.5.1 Release Notes +========================== + +Fixes since v1.6.5 +------------------ + + * An corrupt pack could make codepath to read objects into an + infinite loop. + + * Download throughput display was always shown in KiB/s but on fast links + it is more appropriate to show it in MiB/s. + + * "git grep -f filename" used uninitialized variable and segfaulted. + + * "git clone -b branch" gave a wrong commit object name to post-checkout + hook. + + * "git pull" over http did not work on msys. + +Other minor documentation updates are included. diff --git a/Documentation/RelNotes-1.6.5.txt b/Documentation/RelNotes-1.6.5.txt index d260b03723..ee141c19ad 100644 --- a/Documentation/RelNotes-1.6.5.txt +++ b/Documentation/RelNotes-1.6.5.txt @@ -53,6 +53,10 @@ Updates since v1.6.4 * Unnecessary inefficiency in deepening of a shallow repository has been removed. + * "git clone" does not grab objects that it does not need (i.e. + referenced only from refs outside refs/heads and refs/tags + hierarchy) anymore. + * The "git" main binary used to link with libcurl, which then dragged in a large number of external libraries. When using basic plumbing commands in scripts, this unnecessarily slowed things down. We now @@ -154,18 +158,12 @@ Updates since v1.6.4 * With GIT_TEST_OPTS="--root=/p/a/t/h", tests can be run outside the source directory; using tmpfs may give faster turnaround. + * With NO_PERL_MAKEMAKER set, DESTDIR= is now honoured, so you can + build for one location, and install into another location to tar it + up. Fixes since v1.6.4 ------------------ -# All of the fixes in v1.6.4.X maintenance series are included in this -# release, unless otherwise noted. - -# Here are fixes that this release has, but have not been backported to -# v1.6.4.X series. - --- -exec >/var/tmp/1 -O=v1.6.5-rc1-44-ga16753d -echo O=$(git describe master) -git shortlog --no-merges $O..master --not maint +All of the fixes in v1.6.4.X maintenance series are included in this +release, unless otherwise noted. diff --git a/Documentation/RelNotes-1.6.6.txt b/Documentation/RelNotes-1.6.6.txt new file mode 100644 index 0000000000..5f1fecb5ec --- /dev/null +++ b/Documentation/RelNotes-1.6.6.txt @@ -0,0 +1,60 @@ +GIT v1.6.6 Release Notes +======================== + +In git 1.7.0, which is planned to be the release after 1.6.6, "git +push" into a branch that is currently checked out will be refused by +default. + +You can choose what should happen upon such a push by setting the +configuration variable receive.denyCurrentBranch in the receiving +repository. + +Also, "git push $there :$killed" to delete the branch $killed in a remote +repository $there, when $killed branch is the current branch pointed at by +its HEAD, will be refused by default. + +You can choose what should happen upon such a push by setting the +configuration variable receive.denyDeleteCurrent in the receiving +repository. + +To ease the transition plan, the receiving repository of such a +push running this release will issue a big warning when the +configuration variable is missing. Please refer to: + + http://git.or.cz/gitwiki/GitFaq#non-bare + http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007 + +for more details on the reason why this change is needed and the +transition plan. + +Updates since v1.6.5 +-------------------- + +(subsystems) + +(portability) + +(performance) + +(usability, bells and whistles) + + * "git log --decorate" shows the location of HEAD as well. + +(developers) + +Fixes since v1.6.5 +------------------ + +All of the fixes in v1.6.5.X maintenance series are included in this +release, unless otherwise noted. + + * "git apply" and "git diff" (including patch output from "git log -p") + now flags trailing blank lines as whitespace errors correctly (only + "apply --whitespace=fix" stripped them but "apply --whitespace=warn" + did not even warn). + + * Two whitespace error classes, 'blank-at-eof' and 'blank-at-eol', have + been introduced (settable by core.whitespace configuration variable and + whitespace attribute). The 'trailing-space' whitespace error class has + become a short-hand to cover both of these and there is no behaviour + change for existing set-ups. diff --git a/Documentation/config.txt b/Documentation/config.txt index be0b8cacaa..5a8f57cbf7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -416,13 +416,17 @@ core.whitespace:: consider them as errors. You can prefix `-` to disable any of them (e.g. `-trailing-space`): + -* `trailing-space` treats trailing whitespaces at the end of the line +* `blank-at-eol` treats trailing whitespaces at the end of the line as an error (enabled by default). * `space-before-tab` treats a space character that appears immediately before a tab character in the initial indent part of the line as an error (enabled by default). * `indent-with-non-tab` treats a line that is indented with 8 or more space characters as an error (not enabled by default). +* `blank-at-eof` treats blank lines added at the end of file as an error + (enabled by default). +* `trailing-space` is a short-hand to cover both `blank-at-eol` and + `blank-at-eof`. * `cr-at-eol` treats a carriage-return at the end of line as part of the line terminator, i.e. with it, `trailing-space` does not trigger if the character before such a carriage-return @@ -539,7 +543,7 @@ branch.<name>.merge:: branch.<name>.mergeoptions:: Sets default options for merging into branch <name>. The syntax and - supported options are equal to that of linkgit:git-merge[1], but + supported options are the same as those of linkgit:git-merge[1], but option values containing whitespace characters are currently not supported. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index aad71dc59a..0e836809c2 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -30,10 +30,8 @@ commit) will be listed. With `--no-merged` only branches not merged into the named commit will be listed. If the <commit> argument is missing it defaults to 'HEAD' (i.e. the tip of the current branch). -In the command's second form, a new branch named <branchname> will be created. -It will start out with a head equal to the one given as <start-point>. -If no <start-point> is given, the branch will be created with a head -equal to that of the currently checked out branch. +The command's second form creates a new branch head named <branchname> +which points to the current 'HEAD', or <start-point> if given. Note that this will create the new branch, but it will not switch the working tree to it; use "git checkout <newbranch>" to switch to the @@ -134,11 +132,13 @@ start-point is either a local or remote branch. --contains <commit>:: Only list branches which contain the specified commit. ---merged:: - Only list branches which are fully contained by HEAD. +--merged [<commit>]:: + Only list branches whose tips are reachable from the + specified commit (HEAD if not specified). ---no-merged:: - Do not list branches which are fully contained by HEAD. +--no-merged [<commit>]:: + Only list branches whose tips are not reachable from the + specified commit (HEAD if not specified). <branchname>:: The name of the branch to create or delete. @@ -147,9 +147,9 @@ start-point is either a local or remote branch. may restrict the characters allowed in a branch name. <start-point>:: - The new branch will be created with a HEAD equal to this. It may - be given as a branch name, a commit-id, or a tag. If this option - is omitted, the current branch is assumed. + The new branch head will point to this commit. It may be + given as a branch name, a commit-id, or a tag. If this + option is omitted, the current HEAD will be used instead. <oldbranch>:: The name of an existing branch to rename. @@ -214,7 +214,9 @@ SEE ALSO -------- linkgit:git-check-ref-format[1], linkgit:git-fetch[1], -linkgit:git-remote[1]. +linkgit:git-remote[1], +link:user-manual.html#what-is-a-branch[``Understanding history: What is +a branch?''] in the Git User's Manual. Author ------ diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 0b7982ea76..e9b3b40af4 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git check-ref-format' <refname> -'git check-ref-format' [--branch] <branchname-shorthand> +'git check-ref-format' --branch <branchname-shorthand> DESCRIPTION ----------- @@ -63,8 +63,11 @@ reference name expressions (see linkgit:git-rev-parse[1]): . at-open-brace `@{` is used as a notation to access a reflog entry. -With the `--branch` option, it expands a branch name shorthand and -prints the name of the branch the shorthand refers to. +With the `--branch` option, it expands the ``previous branch syntax'' +`@{-n}`. For example, `@{-1}` is a way to refer the last branch you +were on. This option should be used by porcelains to accept this +syntax anywhere a branch name is expected, so they can act as if you +typed the branch name. EXAMPLE ------- diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index aacf4fd327..5ebcba1c7c 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -19,8 +19,9 @@ DESCRIPTION Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository -(visible using `git branch -r`), and creates and checks out an initial -branch equal to the cloned repository's currently active branch. +(visible using `git branch -r`), and creates and checks out an +initial branch that is forked from the cloned repository's +currently active branch. After the clone, a plain `git fetch` without arguments will update all the remote-tracking branches, and a `git pull` without diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt index 1c24796d66..a586950b48 100644 --- a/Documentation/git-fmt-merge-msg.txt +++ b/Documentation/git-fmt-merge-msg.txt @@ -18,8 +18,8 @@ Takes the list of merged objects on stdin and produces a suitable commit message to be used for the merge commit, usually to be passed as the '<merge-message>' argument of 'git-merge'. -This script is intended mostly for internal use by scripts -automatically invoking 'git-merge'. +This command is intended mostly for internal use by scripts +automatically invoking 'git merge'. OPTIONS ------- diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index af68d694a0..d05f324462 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -28,9 +28,10 @@ OPTIONS include::merge-options.txt[] -m <msg>:: - The commit message to be used for the merge commit (in case - it is created). The 'git-fmt-merge-msg' script can be used - to give a good default for automated 'git-merge' invocations. + Set the commit message to be used for the merge commit (in + case one is created). The 'git fmt-merge-msg' command can be + used to give a good default for automated 'git merge' + invocations. <remote>...:: Other branch heads to merge into our branch. You need at @@ -49,8 +50,8 @@ include::merge-config.txt[] branch.<name>.mergeoptions:: Sets default options for merging into branch <name>. The syntax and - supported options are equal to that of 'git-merge', but option values - containing whitespace characters are currently not supported. + supported options are the same as those of 'git merge', but option + values containing whitespace characters are currently not supported. HOW MERGE WORKS --------------- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index ba6a8a2fb2..37c88953d1 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -138,6 +138,11 @@ useful if you write an alias or script around 'git-push'. --verbose:: Run verbosely. +-q:: +--quiet:: + Suppress all output, including the listing of updated refs, + unless an error occurs. + include::urls-remotes.txt[] OUTPUT diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt index 915cb77b29..8adc1ef55c 100644 --- a/Documentation/git-replace.txt +++ b/Documentation/git-replace.txt @@ -23,6 +23,26 @@ replacement object. Unless `-f` is given, the replace reference must not yet exist in `.git/refs/replace/` directory. +Replace references will be used by default by all git commands except +those doing reachability traversal (prune, pack transfer and fsck). + +It is possible to disable use of replacement refs for any command +using the --no-replace-objects option just after "git". + +For example if commit "foo" has been replaced by commit "bar": + +------------------------------------------------ +$ git --no-replace-object cat-file commit foo +------------------------------------------------ + +show information about commit "foo", while: + +------------------------------------------------ +$ git cat-file commit foo +------------------------------------------------ + +show information about commit "bar". + OPTIONS ------- -f:: @@ -54,6 +74,7 @@ SEE ALSO -------- linkgit:git-tag[1] linkgit:git-branch[1] +linkgit:git[1] Author ------ diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 3f14b727b8..fafe728f89 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -78,7 +78,8 @@ stash@{1}: On master: 9cc0589... Add git-stash ---------------------------------------------------------------- + The command takes options applicable to the 'git-log' -command to control what is shown and how. See linkgit:git-log[1]. +command to control what is shown and how. If no options are set, the +default is `-n 10`. See linkgit:git-log[1]. show [<stash>]:: diff --git a/Documentation/git.txt b/Documentation/git.txt index 20b573e37c..df46a34371 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path] - [-p|--paginate|--no-pager] + [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS] @@ -43,6 +43,12 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: +* link:v1.6.5/git.html[documentation for release 1.6.5] + +* release notes for + link:RelNotes-1.6.5.1.txt[1.6.5.1], + link:RelNotes-1.6.5.txt[1.6.5]. + * link:v1.6.4.4/git.html[documentation for release 1.6.4.4] * release notes for @@ -232,6 +238,10 @@ help ...`. environment is not set, it is set to the current working directory. +--no-replace-objects:: + Do not use replacement refs to replace git objects. See + linkgit:git-replace[1] for more information. + FURTHER DOCUMENTATION --------------------- diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 572374f7a6..43d84d15e9 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -456,6 +456,6 @@ This commit is referred to as a "merge commit", or sometimes just a of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'". [[def_working_tree]]working tree:: - The tree of actual checked out files. The working tree is - normally equal to the <<def_HEAD,HEAD>> plus any local changes - that you have made but not yet committed. + The tree of actual checked out files. The working tree normally + contains the contents of the <<def_HEAD,HEAD>> commit's tree, + plus any local changes that you have made but not yet committed. diff --git a/Documentation/pt_BR/gittutorial.txt b/Documentation/pt_BR/gittutorial.txt index 81e7ad7df4..beba065252 100644 --- a/Documentation/pt_BR/gittutorial.txt +++ b/Documentation/pt_BR/gittutorial.txt @@ -1,15 +1,15 @@ gittutorial(7) ============== -NAME +NOME ---- gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova) -SYNOPSIS +SINOPSE -------- git * -DESCRIPTION +DESCRIÇÃO ----------- Este tutorial explica como importar um novo projeto para o git, @@ -64,11 +64,11 @@ Git irá responder Initialized empty Git repository in .git/ ------------------------------------------------ -Você agora iniciou seu diretório de trabalho--você deve ter notado um -novo diretório criado, com o nome de ".git". +Agora que você iniciou seu diretório de trabalho, você deve ter notado que um +novo diretório foi criado com o nome de ".git". A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os -arquivos sob o diretório corrente (note o '.'), com 'git-add': +arquivos sob o diretório atual (note o '.'), com 'git-add': ------------------------------------------------ $ git add . @@ -126,8 +126,8 @@ mudanças com: $ git commit ------------------------------------------------ -Isto irá novamente te pedir por uma mensagem descrevendo a mudança, e, -então, gravar a nova versão do projeto. +Ao executar esse comando, ele irá te pedir uma mensagem descrevendo a mudança, +e, então, irá gravar a nova versão do projeto. Alternativamente, ao invés de executar 'git-add' antes, você pode usar @@ -143,7 +143,7 @@ idéia começar a mensagem com uma simples e curta (menos de 50 caracteres) linha sumarizando a mudança, seguida de uma linha em branco e, então, uma descrição mais detalhada. Ferramentas que transformam commits em email, por exemplo, usam a primeira linha no campo de -cabeçalho Subject: e o resto no corpo. +cabeçalho "Subject:" e o resto no corpo. Git rastreia conteúdo, não arquivos ---------------------------- @@ -155,7 +155,7 @@ usado tanto para arquivos novos e arquivos recentemente modificados, e em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena o conteúdo no Ãndice, pronto para inclusão do próximo commit. -Visualizando história do projeto +Visualizando a história do projeto ----------------------- Em qualquer ponto você pode visualizar a história das suas mudanças @@ -165,7 +165,7 @@ usando $ git log ------------------------------------------------ -Se você também quer ver a diferença completa a cada passo, use +Se você também quiser ver a diferença completa a cada passo, use ------------------------------------------------ $ git log -p diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt index 48bb97f0b1..53aa0c82c2 100644 --- a/Documentation/technical/racy-git.txt +++ b/Documentation/technical/racy-git.txt @@ -42,10 +42,12 @@ compared, but this is not enabled by default because this member is not stable on network filesystems. With `USE_NSEC` compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec` members are also compared, but this is not enabled by default -because the value of this member becomes meaningless once the -inode is evicted from the inode cache on filesystems that do not -store it on disk. - +because in-core timestamps can have finer granularity than +on-disk timestamps, resulting in meaningless changes when an +inode is evicted from the inode cache. See commit 8ce13b0 +of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git +([PATCH] Sync in core time granuality with filesystems, +2005-01-04). Racy git -------- diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index d7d9a9a063..710d361233 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.4.GIT +DEF_VER=v1.6.5.GIT LF=' ' @@ -153,7 +153,11 @@ all:: # # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 # -# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. +# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72 +# (not v1.73 or v1.71). +# +# Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives +# (versions 1.72 and later and 1.68.1 and earlier). # # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's # MakeMaker (e.g. using ActiveState under Cygwin). @@ -734,6 +738,7 @@ ifeq ($(uname_S),SunOS) NO_MKSTEMPS = YesPlease NO_REGEX = YesPlease NO_EXTERNAL_GREP = YesPlease + THREADED_DELTA_SEARCH = YesPlease ifeq ($(uname_R),5.7) NEEDS_RESOLV = YesPlease NO_IPV6 = YesPlease @@ -840,11 +845,18 @@ ifeq ($(uname_S),IRIX) NO_MEMMEM = YesPlease NO_MKSTEMPS = YesPlease NO_MKDTEMP = YesPlease + # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads + # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set), + # git dies with a segmentation fault when trying to access the first + # entry of a reflog. The conservative choice is made to always set + # NO_MMAP. If you suspect that your compiler is not affected by this + # issue, comment out the NO_MMAP statement. NO_MMAP = YesPlease NO_EXTERNAL_GREP = UnfortunatelyYes 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 @@ -853,11 +865,18 @@ ifeq ($(uname_S),IRIX64) NO_MEMMEM = YesPlease NO_MKSTEMPS = YesPlease NO_MKDTEMP = YesPlease + # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads + # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set), + # git dies with a segmentation fault when trying to access the first + # entry of a reflog. The conservative choice is made to always set + # NO_MMAP. If you suspect that your compiler is not affected by this + # issue, comment out the NO_MMAP statement. NO_MMAP = YesPlease NO_EXTERNAL_GREP = UnfortunatelyYes 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 @@ -914,7 +933,7 @@ ifdef MSVC CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl CFLAGS = - BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32-D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE + BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib @@ -1808,7 +1827,7 @@ distclean: clean $(RM) configure clean: - $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \ + $(RM) *.o block-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \ $(LIB_FILE) $(XDIFF_LIB) $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X $(RM) $(TEST_PROGRAMS) @@ -37,7 +37,7 @@ CVS users may also want to read Documentation/gitcvs-migration.txt ("man gitcvs-migration" or "git help cvs-migration" if git is installed). -Many Git online resources are accessible from http://git.or.cz/ +Many Git online resources are accessible from http://git-scm.com/ including full documentation and Git related tools. The user discussion and development of Git take place on the Git @@ -1 +1 @@ -Documentation/RelNotes-1.6.5.txt
\ No newline at end of file +Documentation/RelNotes-1.6.6.txt
\ No newline at end of file @@ -115,6 +115,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, strbuf_reset(&path); strbuf_grow(&path, PATH_MAX); + strbuf_add(&path, args->base, args->baselen); strbuf_add(&path, base, baselen); strbuf_addstr(&path, filename); path_without_prefix = path.buf + args->baselen; @@ -187,8 +188,8 @@ int write_archive_entries(struct archiver_args *args, git_attr_set_direction(GIT_ATTR_INDEX, &the_index); } - err = read_tree_recursive(args->tree, args->base, args->baselen, 0, - args->pathspec, write_archive_entry, &context); + err = read_tree_recursive(args->tree, "", 0, 0, args->pathspec, + write_archive_entry, &context); if (err == READ_TREE_RECURSIVE) err = 0; return err; @@ -211,7 +212,7 @@ static const struct archiver *lookup_archiver(const char *name) static void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args) { - ar_args->pathspec = get_pathspec(ar_args->base, pathspec); + ar_args->pathspec = get_pathspec("", pathspec); } static void parse_treeish_arg(const char **argv, diff --git a/builtin-apply.c b/builtin-apply.c index c8372a0a80..f667368d16 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -153,6 +153,7 @@ struct fragment { const char *patch; int size; int rejected; + int linenr; struct fragment *next; }; @@ -1227,23 +1228,29 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc return -1; } -static void check_whitespace(const char *line, int len, unsigned ws_rule) +static void record_ws_error(unsigned result, const char *line, int len, int linenr) { char *err; - unsigned result = ws_check(line + 1, len - 1, ws_rule); + if (!result) return; whitespace_error++; if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) - ; - else { - err = whitespace_error_string(result); - fprintf(stderr, "%s:%d: %s.\n%.*s\n", - patch_input_file, linenr, err, len - 2, line + 1); - free(err); - } + return; + + err = whitespace_error_string(result); + fprintf(stderr, "%s:%d: %s.\n%.*s\n", + patch_input_file, linenr, err, len, line); + free(err); +} + +static void check_whitespace(const char *line, int len, unsigned ws_rule) +{ + unsigned result = ws_check(line + 1, len - 1, ws_rule); + + record_ws_error(result, line + 1, len - 2, linenr); } /* @@ -1359,6 +1366,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc int len; fragment = xcalloc(1, sizeof(*fragment)); + fragment->linenr = linenr; len = parse_fragment(line, size, patch, fragment); if (len <= 0) die("corrupt patch at line %d", linenr); @@ -2142,6 +2150,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, int len = linelen(patch, size); int plen, added; int added_blank_line = 0; + int is_blank_context = 0; if (!len) break; @@ -2174,8 +2183,12 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, *new++ = '\n'; add_line_info(&preimage, "\n", 1, LINE_COMMON); add_line_info(&postimage, "\n", 1, LINE_COMMON); + is_blank_context = 1; break; case ' ': + if (plen && (ws_rule & WS_BLANK_AT_EOF) && + ws_blank_line(patch + 1, plen, ws_rule)) + is_blank_context = 1; case '-': memcpy(old, patch + 1, plen); add_line_info(&preimage, old, plen, @@ -2202,7 +2215,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, (first == '+' ? 0 : LINE_COMMON)); new += added; if (first == '+' && - added == 1 && new[-1] == '\n') + (ws_rule & WS_BLANK_AT_EOF) && + ws_blank_line(patch + 1, plen, ws_rule)) added_blank_line = 1; break; case '@': case '\\': @@ -2215,6 +2229,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, } if (added_blank_line) new_blank_lines_at_end++; + else if (is_blank_context) + ; else new_blank_lines_at_end = 0; patch += len; @@ -2296,17 +2312,24 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, } if (applied_pos >= 0) { - if (ws_error_action == correct_ws_error && - new_blank_lines_at_end && - postimage.nr + applied_pos == img->nr) { + if (new_blank_lines_at_end && + preimage.nr + applied_pos == img->nr && + (ws_rule & WS_BLANK_AT_EOF) && + ws_error_action != nowarn_ws_error) { + record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr); + if (ws_error_action == correct_ws_error) { + while (new_blank_lines_at_end--) + remove_last_line(&postimage); + } /* - * If the patch application adds blank lines - * at the end, and if the patch applies at the - * end of the image, remove those added blank - * lines. + * We would want to prevent write_out_results() + * from taking place in apply_patch() that follows + * the callchain led us here, which is: + * apply_patch->check_patch_list->check_patch-> + * apply_data->apply_fragments->apply_one_fragment */ - while (new_blank_lines_at_end--) - remove_last_line(&postimage); + if (ws_error_action == die_on_ws_error) + apply = 0; } /* diff --git a/builtin-clone.c b/builtin-clone.c index 4992c2597c..5762a6f9d8 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -641,7 +641,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die("unable to write new index file"); err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), - sha1_to_hex(remote_head->old_sha1), "1", NULL); + sha1_to_hex(our_head_points_at->old_sha1), "1", + NULL); if (!err && option_recursive) err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); diff --git a/builtin-describe.c b/builtin-describe.c index df67a733ae..2dcfd3dfeb 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -180,7 +180,6 @@ static void describe(const char *arg, int last_one) unsigned char sha1[20]; struct commit *cmit, *gave_up_on = NULL; struct commit_list *list; - static int initialized = 0; struct commit_name *n; struct possible_tag all_matches[MAX_TAGS]; unsigned int match_cnt = 0, annotated_cnt = 0, cur_match; @@ -192,14 +191,6 @@ static void describe(const char *arg, int last_one) if (!cmit) die("%s is not a valid '%s' object", arg, commit_type); - if (!initialized) { - initialized = 1; - for_each_ref(get_name, NULL); - } - - if (!found_names) - die("cannot describe '%s'", sha1_to_hex(sha1)); - n = cmit->util; if (n) { /* @@ -359,6 +350,10 @@ int cmd_describe(int argc, const char **argv, const char *prefix) return cmd_name_rev(i + argc, args, prefix); } + for_each_ref(get_name, NULL); + if (!found_names) + die("No names found, cannot describe anything."); + if (argc == 0) { describe("HEAD", 1); } else { diff --git a/builtin-fetch.c b/builtin-fetch.c index cb48c57ca3..a35a6f8cb8 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -504,57 +504,98 @@ static int will_fetch(struct ref **head, const unsigned char *sha1) return 0; } +struct tag_data { + struct ref **head; + struct ref ***tail; +}; + +static int add_to_tail(struct string_list_item *item, void *cb_data) +{ + struct tag_data *data = (struct tag_data *)cb_data; + struct ref *rm = NULL; + + /* We have already decided to ignore this item */ + if (!item->util) + return 0; + + rm = alloc_ref(item->string); + rm->peer_ref = alloc_ref(item->string); + hashcpy(rm->old_sha1, item->util); + + **data->tail = rm; + *data->tail = &rm->next; + + return 0; +} + static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { struct string_list existing_refs = { NULL, 0, 0, 0 }; - struct string_list new_refs = { NULL, 0, 0, 1 }; - char *ref_name; - int ref_name_len; - const unsigned char *ref_sha1; - const struct ref *tag_ref; - struct ref *rm = NULL; + struct string_list remote_refs = { NULL, 0, 0, 0 }; + struct tag_data data = {head, tail}; const struct ref *ref; + struct string_list_item *item = NULL; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { if (prefixcmp(ref->name, "refs/tags")) continue; - ref_name = xstrdup(ref->name); - ref_name_len = strlen(ref_name); - ref_sha1 = ref->old_sha1; - - if (!strcmp(ref_name + ref_name_len - 3, "^{}")) { - ref_name[ref_name_len - 3] = 0; - tag_ref = transport_get_remote_refs(transport); - while (tag_ref) { - if (!strcmp(tag_ref->name, ref_name)) { - ref_sha1 = tag_ref->old_sha1; - break; - } - tag_ref = tag_ref->next; - } + /* + * The peeled ref always follows the matching base + * ref, so if we see a peeled ref that we don't want + * to fetch then we can mark the ref entry in the list + * as one to ignore by setting util to NULL. + */ + if (!strcmp(ref->name + strlen(ref->name) - 3, "^{}")) { + if (item && !has_sha1_file(ref->old_sha1) && + !will_fetch(head, ref->old_sha1) && + !has_sha1_file(item->util) && + !will_fetch(head, item->util)) + item->util = NULL; + item = NULL; + continue; } - if (!string_list_has_string(&existing_refs, ref_name) && - !string_list_has_string(&new_refs, ref_name) && - (has_sha1_file(ref->old_sha1) || - will_fetch(head, ref->old_sha1))) { - string_list_insert(ref_name, &new_refs); + /* + * If item is non-NULL here, then we previously saw a + * ref not followed by a peeled reference, so we need + * to check if it is a lightweight tag that we want to + * fetch. + */ + if (item && !has_sha1_file(item->util) && + !will_fetch(head, item->util)) + item->util = NULL; - rm = alloc_ref(ref_name); - rm->peer_ref = alloc_ref(ref_name); - hashcpy(rm->old_sha1, ref_sha1); + item = NULL; - **tail = rm; - *tail = &rm->next; - } - free(ref_name); + /* skip duplicates and refs that we already have */ + if (string_list_has_string(&remote_refs, ref->name) || + string_list_has_string(&existing_refs, ref->name)) + continue; + + item = string_list_insert(ref->name, &remote_refs); + item->util = (void *)ref->old_sha1; } string_list_clear(&existing_refs, 0); - string_list_clear(&new_refs, 0); + + /* + * We may have a final lightweight tag that needs to be + * checked to see if it needs fetching. + */ + if (item && !has_sha1_file(item->util) && + !will_fetch(head, item->util)) + item->util = NULL; + + /* + * For all the tags in the remote_refs string list, call + * add_to_tail to add them to the list of refs to be fetched + */ + for_each_string_list(add_to_tail, &remote_refs, &data); + + string_list_clear(&remote_refs, 0); } static void check_not_current_branch(struct ref *ref_map) diff --git a/builtin-grep.c b/builtin-grep.c index 761799d7d0..1df25b07b5 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -631,7 +631,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset) struct grep_opt *grep_opt = opt->value; FILE *patterns; int lno = 0; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; patterns = fopen(arg, "r"); if (!patterns) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index f473220502..c5c0407b0b 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -170,10 +170,6 @@ static void show_files(struct dir_struct *dir, const char *prefix) if (show_cached | show_stage) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != - !!(dir->flags & DIR_SHOW_IGNORED)) - continue; if (show_unmerged && !ce_stage(ce)) continue; if (ce->ce_flags & CE_UPDATE) @@ -186,10 +182,6 @@ static void show_files(struct dir_struct *dir, const char *prefix) struct cache_entry *ce = active_cache[i]; struct stat st; int err; - int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != - !!(dir->flags & DIR_SHOW_IGNORED)) - continue; if (ce->ce_flags & CE_UPDATE) continue; err = lstat(ce->name, &st); @@ -524,11 +516,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) ps_matched = xcalloc(1, num); } - if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) { - fprintf(stderr, "%s: --ignored needs some exclude pattern\n", - argv[0]); - exit(1); - } + if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) + die("ls-files --ignored needs some exclude pattern"); /* With no flags, we default to showing the cached files */ if (!(show_stage | show_deleted | show_others | show_unmerged | diff --git a/builtin-push.c b/builtin-push.c index 3cb1ee46d1..b5cd2cdad0 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -10,7 +10,7 @@ #include "parse-options.h" static const char * const push_usage[] = { - "git push [--all | --mirror] [-n | --dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]", + "git push [<options>] [<repository> <refspec>...]", NULL, }; @@ -181,7 +181,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, "mirror all refs", (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), - OPT_BOOLEAN( 0 , "tags", &tags, "push tags"), + OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror"), OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE), diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 3510a86e38..be95930b78 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -565,7 +565,15 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) if (!strcmp(var, "showbranch.default")) { if (!value) return config_error_nonbool(var); - if (default_alloc <= default_num + 1) { + /* + * default_arg is now passed to parse_options(), so we need to + * mimick the real argv a bit better. + */ + if (!default_num) { + default_alloc = 20; + default_arg = xcalloc(default_alloc, sizeof(*default_arg)); + default_arg[default_num++] = "show-branch"; + } else if (default_alloc <= default_num + 1) { default_alloc = default_alloc * 3 / 2 + 20; default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc); } @@ -692,8 +700,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { - ac = default_num + 1; - av = default_arg - 1; /* ick; we would not address av[0] */ + ac = default_num; + av = default_arg; } ac = parse_options(ac, av, prefix, builtin_show_branch_options, @@ -986,10 +986,12 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i * whitespace rules. * used by both diff and apply */ -#define WS_TRAILING_SPACE 01 +#define WS_BLANK_AT_EOL 01 #define WS_SPACE_BEFORE_TAB 02 #define WS_INDENT_WITH_NON_TAB 04 #define WS_CR_AT_EOL 010 +#define WS_BLANK_AT_EOF 020 +#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF) #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB) extern unsigned whitespace_rule_cfg; extern unsigned whitespace_rule(const char *); diff --git a/command-list.txt b/command-list.txt index fb03a2ebb5..59b0adc39b 100644 --- a/command-list.txt +++ b/command-list.txt @@ -92,6 +92,7 @@ git-reflog ancillarymanipulators git-relink ancillarymanipulators git-remote ancillarymanipulators git-repack ancillarymanipulators +git-replace ancillarymanipulators git-repo-config ancillarymanipulators deprecated git-request-pull foreignscminterface git-rerere ancillaryinterrogators @@ -70,7 +70,7 @@ extern char *reencode_commit_message(const struct commit *commit, const char **encoding_p); extern void get_commit_format(const char *arg, struct rev_info *); extern void format_commit_message(const struct commit *commit, - const void *format, struct strbuf *sb, + const char *format, struct strbuf *sb, enum date_mode dmode); extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*, struct strbuf *, diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl index 0ffd59f9fb..f9528c0ea1 100644 --- a/compat/vcbuild/scripts/clink.pl +++ b/compat/vcbuild/scripts/clink.pl @@ -45,4 +45,4 @@ if ($is_linking) { push(@args, @cflags); } #printf("**** @args\n"); -exit system(@args); +exit (system(@args) != 0); diff --git a/compat/vcbuild/scripts/lib.pl b/compat/vcbuild/scripts/lib.pl index 68f66446ea..d8054e469f 100644 --- a/compat/vcbuild/scripts/lib.pl +++ b/compat/vcbuild/scripts/lib.pl @@ -23,4 +23,4 @@ while (@ARGV) { } unshift(@args, "lib.exe"); # printf("**** @args\n"); -exit system(@args); +exit (system(@args) != 0); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2c2a0d4614..d3fec32997 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -496,7 +496,7 @@ __git_all_commands () return fi local i IFS=" "$'\n' - for i in $(git help -a|egrep '^ ') + for i in $(git help -a|egrep '^ [a-zA-Z0-9]') do case $i in *--*) : helper pattern;; @@ -602,8 +602,12 @@ __git_aliases () { local i IFS=$'\n' for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do - i="${i#alias.}" - echo "${i/ */}" + case "$i" in + alias.*) + i="${i#alias.}" + echo "${i/ */}" + ;; + esac done } @@ -668,7 +672,7 @@ _git_am () --3way --committer-date-is-author-date --ignore-date --ignore-whitespace --ignore-space-change --interactive --keep --no-utf8 --signoff --utf8 - --whitespace= + --whitespace= --scissors " return esac @@ -894,6 +898,7 @@ _git_commit () __gitcomp " --all --author= --signoff --verify --no-verify --edit --amend --include --only --interactive + --dry-run " return esac @@ -926,6 +931,8 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --inter-hunk-context= --patience --raw + --dirstat --dirstat= --dirstat-by-file + --dirstat-by-file= --cumulative " _git_diff () @@ -1062,7 +1069,8 @@ _git_grep () return ;; esac - COMPREPLY=() + + __gitcomp "$(__git_refs)" } _git_help () @@ -1179,6 +1187,10 @@ _git_log () __gitcomp "$__git_log_date_formats" "" "${cur##--date=}" return ;; + --decorate=*) + __gitcomp "long short" "" "${cur##--decorate=}" + return + ;; --*) __gitcomp " $__git_log_common_options @@ -1191,7 +1203,7 @@ _git_log () --pretty= --format= --oneline --cherry-pick --graph - --decorate + --decorate --decorate= --walk-reflogs --parents --children $merge @@ -1787,6 +1799,11 @@ _git_remote () esac } +_git_replace () +{ + __gitcomp "$(__git_refs)" +} + _git_reset () { __git_has_doubledash && return @@ -2155,6 +2172,7 @@ _git () push) _git_push ;; rebase) _git_rebase ;; remote) _git_remote ;; + replace) _git_replace ;; reset) _git_reset ;; revert) _git_revert ;; rm) _git_rm ;; diff --git a/contrib/emacs/git-blame.el b/contrib/emacs/git-blame.el index 4fa70c5ad4..7f4c792978 100644 --- a/contrib/emacs/git-blame.el +++ b/contrib/emacs/git-blame.el @@ -80,6 +80,57 @@ (eval-when-compile (require 'cl)) ; to use `push', `pop' +(defface git-blame-prefix-face + '((((background dark)) (:foreground "gray" + :background "black")) + (((background light)) (:foreground "gray" + :background "white")) + (t (:weight bold))) + "The face used for the hash prefix." + :group 'git-blame) + +(defgroup git-blame nil + "A minor mode showing Git blame information." + :group 'git + :link '(function-link git-blame-mode)) + + +(defcustom git-blame-use-colors t + "Use colors to indicate commits in `git-blame-mode'." + :type 'boolean + :group 'git-blame) + +(defcustom git-blame-prefix-format + "%h %20A:" + "The format of the prefix added to each line in `git-blame' +mode. The format is passed to `format-spec' with the following format keys: + + %h - the abbreviated hash + %H - the full hash + %a - the author name + %A - the author email + %c - the committer name + %C - the committer email + %s - the commit summary +" + :group 'git-blame) + +(defcustom git-blame-mouseover-format + "%h %a %A: %s" + "The format of the description shown when pointing at a line in +`git-blame' mode. The format string is passed to `format-spec' +with the following format keys: + + %h - the abbreviated hash + %H - the full hash + %a - the author name + %A - the author email + %c - the committer name + %C - the committer email + %s - the commit summary +" + :group 'git-blame) + (defun git-blame-color-scale (&rest elements) "Given a list, returns a list of triples formed with each @@ -302,72 +353,69 @@ See also function `git-blame-mode'." (src-line (string-to-number (match-string 2))) (res-line (string-to-number (match-string 3))) (num-lines (string-to-number (match-string 4)))) - (setq git-blame-current - (if (string= hash "0000000000000000000000000000000000000000") - nil - (git-blame-new-commit - hash src-line res-line num-lines)))) - (delete-region (point) (match-end 0)) - t) - ((looking-at "filename \\(.+\\)\n") - (let ((filename (match-string 1))) - (git-blame-add-info "filename" filename)) - (delete-region (point) (match-end 0)) + (delete-region (point) (match-end 0)) + (setq git-blame-current (list (git-blame-new-commit hash) + src-line res-line num-lines))) t) ((looking-at "\\([a-z-]+\\) \\(.+\\)\n") (let ((key (match-string 1)) (value (match-string 2))) - (git-blame-add-info key value)) - (delete-region (point) (match-end 0)) - t) - ((looking-at "boundary\n") - (setq git-blame-current nil) - (delete-region (point) (match-end 0)) + (delete-region (point) (match-end 0)) + (git-blame-add-info (car git-blame-current) key value) + (when (string= key "filename") + (git-blame-create-overlay (car git-blame-current) + (caddr git-blame-current) + (cadddr git-blame-current)) + (setq git-blame-current nil))) t) (t nil))) -(defun git-blame-new-commit (hash src-line res-line num-lines) +(defun git-blame-new-commit (hash) + (with-current-buffer git-blame-file + (or (gethash hash git-blame-cache) + ;; Assign a random color to each new commit info + ;; Take care not to select the same color multiple times + (let* ((color (if git-blame-colors + (git-blame-random-pop git-blame-colors) + git-blame-ancient-color)) + (info `(,hash (color . ,color)))) + (puthash hash info git-blame-cache) + info)))) + +(defun git-blame-create-overlay (info start-line num-lines) (save-excursion (set-buffer git-blame-file) - (let ((info (gethash hash git-blame-cache)) - (inhibit-point-motion-hooks t) + (let ((inhibit-point-motion-hooks t) (inhibit-modification-hooks t)) - (when (not info) - ;; Assign a random color to each new commit info - ;; Take care not to select the same color multiple times - (let ((color (if git-blame-colors - (git-blame-random-pop git-blame-colors) - git-blame-ancient-color))) - (setq info (list hash src-line res-line num-lines - (git-describe-commit hash) - (cons 'color color)))) - (puthash hash info git-blame-cache)) - (goto-line res-line) - (while (> num-lines 0) - (if (get-text-property (point) 'git-blame) - (forward-line) - (let* ((start (point)) - (end (progn (forward-line 1) (point))) - (ovl (make-overlay start end))) - (push ovl git-blame-overlays) - (overlay-put ovl 'git-blame info) - (overlay-put ovl 'help-echo hash) + (goto-line start-line) + (let* ((start (point)) + (end (progn (forward-line num-lines) (point))) + (ovl (make-overlay start end)) + (hash (car info)) + (spec `((?h . ,(substring hash 0 6)) + (?H . ,hash) + (?a . ,(git-blame-get-info info 'author)) + (?A . ,(git-blame-get-info info 'author-mail)) + (?c . ,(git-blame-get-info info 'committer)) + (?C . ,(git-blame-get-info info 'committer-mail)) + (?s . ,(git-blame-get-info info 'summary))))) + (push ovl git-blame-overlays) + (overlay-put ovl 'git-blame info) + (overlay-put ovl 'help-echo + (format-spec git-blame-mouseover-format spec)) + (if git-blame-use-colors (overlay-put ovl 'face (list :background - (cdr (assq 'color (nthcdr 5 info))))) - ;; the point-entered property doesn't seem to work in overlays - ;;(overlay-put ovl 'point-entered - ;; `(lambda (x y) (git-blame-identify ,hash))) - (let ((modified (buffer-modified-p))) - (put-text-property (if (= start 1) start (1- start)) (1- end) - 'point-entered - `(lambda (x y) (git-blame-identify ,hash))) - (set-buffer-modified-p modified)))) - (setq num-lines (1- num-lines)))))) - -(defun git-blame-add-info (key value) - (if git-blame-current - (nconc git-blame-current (list (cons (intern key) value))))) + (cdr (assq 'color (cdr info)))))) + (overlay-put ovl 'line-prefix + (propertize (format-spec git-blame-prefix-format spec) + 'face 'git-blame-prefix-face)))))) + +(defun git-blame-add-info (info key value) + (nconc info (list (cons (intern key) value)))) + +(defun git-blame-get-info (info key) + (cdr (assq key (cdr info)))) (defun git-blame-current-commit () (let ((info (get-char-property (point) 'git-blame))) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index a909716682..7001862bfd 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -140,7 +140,7 @@ foreach my $tar_file (@ARGV) } elsif (!$header_done && /^Author:\s+([^<>]*)\s+<(.*)>\s*$/i) { $this_author_name = $1; $this_author_email = $2; - } elsif (!$header_done && /^$/ { # empty line ends header. + } elsif (!$header_done && /^$/) { # empty line ends header. $header_done = 1; } else { $commit_msg .= $_; @@ -174,6 +174,175 @@ static struct diff_tempfile { char tmp_path[PATH_MAX]; } diff_temp[2]; +typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); + +struct emit_callback { + int color_diff; + unsigned ws_rule; + int blank_at_eof_in_preimage; + int blank_at_eof_in_postimage; + int lno_in_preimage; + int lno_in_postimage; + sane_truncate_fn truncate; + const char **label_path; + struct diff_words_data *diff_words; + int *found_changesp; + FILE *file; +}; + +static int count_lines(const char *data, int size) +{ + int count, ch, completely_empty = 1, nl_just_seen = 0; + count = 0; + while (0 < size--) { + ch = *data++; + if (ch == '\n') { + count++; + nl_just_seen = 1; + completely_empty = 0; + } + else { + nl_just_seen = 0; + completely_empty = 0; + } + } + if (completely_empty) + return 0; + if (!nl_just_seen) + count++; /* no trailing newline */ + return count; +} + +static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) +{ + if (!DIFF_FILE_VALID(one)) { + mf->ptr = (char *)""; /* does not matter */ + mf->size = 0; + return 0; + } + else if (diff_populate_filespec(one, 0)) + return -1; + + mf->ptr = one->data; + mf->size = one->size; + return 0; +} + +static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) +{ + char *ptr = mf->ptr; + long size = mf->size; + int cnt = 0; + + if (!size) + return cnt; + ptr += size - 1; /* pointing at the very end */ + if (*ptr != '\n') + ; /* incomplete line */ + else + ptr--; /* skip the last LF */ + while (mf->ptr < ptr) { + char *prev_eol; + for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) + if (*prev_eol == '\n') + break; + if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) + break; + cnt++; + ptr = prev_eol - 1; + } + return cnt; +} + +static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, + struct emit_callback *ecbdata) +{ + int l1, l2, at; + unsigned ws_rule = ecbdata->ws_rule; + l1 = count_trailing_blank(mf1, ws_rule); + l2 = count_trailing_blank(mf2, ws_rule); + if (l2 <= l1) { + ecbdata->blank_at_eof_in_preimage = 0; + ecbdata->blank_at_eof_in_postimage = 0; + return; + } + at = count_lines(mf1->ptr, mf1->size); + ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; + + at = count_lines(mf2->ptr, mf2->size); + ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; +} + +static void emit_line_0(FILE *file, const char *set, const char *reset, + int first, const char *line, int len) +{ + int has_trailing_newline, has_trailing_carriage_return; + int nofirst; + + if (len == 0) { + has_trailing_newline = (first == '\n'); + has_trailing_carriage_return = (!has_trailing_newline && + (first == '\r')); + nofirst = has_trailing_newline || has_trailing_carriage_return; + } else { + has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; + nofirst = 0; + } + + fputs(set, file); + + if (!nofirst) + fputc(first, file); + fwrite(line, len, 1, file); + fputs(reset, file); + if (has_trailing_carriage_return) + fputc('\r', file); + if (has_trailing_newline) + fputc('\n', file); +} + +static void emit_line(FILE *file, const char *set, const char *reset, + const char *line, int len) +{ + emit_line_0(file, set, reset, line[0], line+1, len-1); +} + +static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) +{ + if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && + ecbdata->blank_at_eof_in_preimage && + ecbdata->blank_at_eof_in_postimage && + ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && + ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) + return 0; + return ws_blank_line(line, len, ecbdata->ws_rule); +} + +static void emit_add_line(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len) +{ + const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); + const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); + + if (!*ws) + emit_line_0(ecbdata->file, set, reset, '+', line, len); + else if (new_blank_line_at_eof(ecbdata, line, len)) + /* Blank line at EOF - paint '+' as well */ + emit_line_0(ecbdata->file, ws, reset, '+', line, len); + else { + /* Emit just the prefix, then the rest. */ + emit_line_0(ecbdata->file, set, reset, '+', "", 0); + ws_check_emit(line, len, ecbdata->ws_rule, + ecbdata->file, set, reset, ws); + } +} + static struct diff_tempfile *claim_diff_tempfile(void) { int i; for (i = 0; i < ARRAY_SIZE(diff_temp); i++) @@ -201,29 +370,6 @@ static void remove_tempfile_on_signal(int signo) raise(signo); } -static int count_lines(const char *data, int size) -{ - int count, ch, completely_empty = 1, nl_just_seen = 0; - count = 0; - while (0 < size--) { - ch = *data++; - if (ch == '\n') { - count++; - nl_just_seen = 1; - completely_empty = 0; - } - else { - nl_just_seen = 0; - completely_empty = 0; - } - } - if (completely_empty) - return 0; - if (!nl_just_seen) - count++; /* no trailing newline */ - return count; -} - static void print_line_count(FILE *file, int count) { switch (count) { @@ -239,26 +385,36 @@ static void print_line_count(FILE *file, int count) } } -static void copy_file_with_prefix(FILE *file, - int prefix, const char *data, int size, - const char *set, const char *reset) +static void emit_rewrite_lines(struct emit_callback *ecb, + int prefix, const char *data, int size) { - int ch, nl_just_seen = 1; - while (0 < size--) { - ch = *data++; - if (nl_just_seen) { - fputs(set, file); - putc(prefix, file); + const char *endp = NULL; + static const char *nneof = " No newline at end of file\n"; + const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD); + const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET); + + while (0 < size) { + int len; + + endp = memchr(data, '\n', size); + len = endp ? (endp - data + 1) : size; + if (prefix != '+') { + ecb->lno_in_preimage++; + emit_line_0(ecb->file, old, reset, '-', + data, len); + } else { + ecb->lno_in_postimage++; + emit_add_line(reset, ecb, data, len); } - if (ch == '\n') { - nl_just_seen = 1; - fputs(reset, file); - } else - nl_just_seen = 0; - putc(ch, file); + size -= len; + data += len; + } + if (!endp) { + const char *plain = diff_get_color(ecb->color_diff, + DIFF_PLAIN); + emit_line_0(ecb->file, plain, reset, '\\', + nneof, strlen(nneof)); } - if (!nl_just_seen) - fprintf(file, "%s\n\\ No newline at end of file\n", reset); } static void emit_rewrite_diff(const char *name_a, @@ -274,13 +430,12 @@ static void emit_rewrite_diff(const char *name_a, const char *name_a_tab, *name_b_tab; const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO); const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO); - const char *old = diff_get_color(color_diff, DIFF_FILE_OLD); - const char *new = diff_get_color(color_diff, DIFF_FILE_NEW); const char *reset = diff_get_color(color_diff, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; const char *a_prefix, *b_prefix; const char *data_one, *data_two; size_t size_one, size_two; + struct emit_callback ecbdata; if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) { a_prefix = o->b_prefix; @@ -321,6 +476,22 @@ static void emit_rewrite_diff(const char *name_a, size_two = two->size; } + memset(&ecbdata, 0, sizeof(ecbdata)); + ecbdata.color_diff = color_diff; + ecbdata.found_changesp = &o->found_changes; + ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); + ecbdata.file = o->file; + if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { + mmfile_t mf1, mf2; + mf1.ptr = (char *)data_one; + mf2.ptr = (char *)data_two; + mf1.size = size_one; + mf2.size = size_two; + check_blank_at_eof(&mf1, &mf2, &ecbdata); + } + ecbdata.lno_in_preimage = 1; + ecbdata.lno_in_postimage = 1; + lc_a = count_lines(data_one, size_one); lc_b = count_lines(data_two, size_two); fprintf(o->file, @@ -332,24 +503,9 @@ static void emit_rewrite_diff(const char *name_a, print_line_count(o->file, lc_b); fprintf(o->file, " @@%s\n", reset); if (lc_a) - copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset); + emit_rewrite_lines(&ecbdata, '-', data_one, size_one); if (lc_b) - copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset); -} - -static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) -{ - if (!DIFF_FILE_VALID(one)) { - mf->ptr = (char *)""; /* does not matter */ - mf->size = 0; - return 0; - } - else if (diff_populate_filespec(one, 0)) - return -1; - - mf->ptr = one->data; - mf->size = one->size; - return 0; + emit_rewrite_lines(&ecbdata, '+', data_two, size_two); } struct diff_words_buffer { @@ -529,18 +685,6 @@ static void diff_words_show(struct diff_words_data *diff_words) diff_words->minus.text.size = diff_words->plus.text.size = 0; } -typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); - -struct emit_callback { - int nparents, color_diff; - unsigned ws_rule; - sane_truncate_fn truncate; - const char **label_path; - struct diff_words_data *diff_words; - int *found_changesp; - FILE *file; -}; - static void free_diff_words_data(struct emit_callback *ecbdata) { if (ecbdata->diff_words) { @@ -566,42 +710,6 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) return ""; } -static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) -{ - int has_trailing_newline, has_trailing_carriage_return; - - has_trailing_newline = (len > 0 && line[len-1] == '\n'); - if (has_trailing_newline) - len--; - has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); - if (has_trailing_carriage_return) - len--; - - fputs(set, file); - fwrite(line, len, 1, file); - fputs(reset, file); - if (has_trailing_carriage_return) - fputc('\r', file); - if (has_trailing_newline) - fputc('\n', file); -} - -static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) -{ - const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); - const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); - - if (!*ws) - emit_line(ecbdata->file, set, reset, line, len); - else { - /* Emit just the prefix, then the rest. */ - emit_line(ecbdata->file, set, reset, line, ecbdata->nparents); - ws_check_emit(line + ecbdata->nparents, - len - ecbdata->nparents, ecbdata->ws_rule, - ecbdata->file, set, reset, ws); - } -} - static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len) { const char *cp; @@ -620,10 +728,23 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u return allot - l; } +static void find_lno(const char *line, struct emit_callback *ecbdata) +{ + const char *p; + ecbdata->lno_in_preimage = 0; + ecbdata->lno_in_postimage = 0; + p = strchr(line, '-'); + if (!p) + return; /* cannot happen */ + ecbdata->lno_in_preimage = strtol(p + 1, NULL, 10); + p = strchr(p, '+'); + if (!p) + return; /* cannot happen */ + ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10); +} + static void fn_out_consume(void *priv, char *line, unsigned long len) { - int i; - int color; struct emit_callback *ecbdata = priv; const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); @@ -650,14 +771,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) len = 1; } - /* This is not really necessary for now because - * this codepath only deals with two-way diffs. - */ - for (i = 0; i < len && line[i] == '@'; i++) - ; - if (2 <= i && i < len && line[i] == ' ') { - ecbdata->nparents = i - 1; + if (line[0] == '@') { len = sane_truncate_line(ecbdata, line, len); + find_lno(line, ecbdata); emit_line(ecbdata->file, diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), reset, line, len); @@ -666,15 +782,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) return; } - if (len < ecbdata->nparents) { + if (len < 1) { emit_line(ecbdata->file, reset, reset, line, len); return; } - color = DIFF_PLAIN; - if (ecbdata->diff_words && ecbdata->nparents != 1) - /* fall back to normal diff */ - free_diff_words_data(ecbdata); if (ecbdata->diff_words) { if (line[0] == '-') { diff_words_append(line, len, @@ -693,20 +805,19 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) emit_line(ecbdata->file, plain, reset, line, len); return; } - for (i = 0; i < ecbdata->nparents && len; i++) { - if (line[i] == '-') - color = DIFF_FILE_OLD; - else if (line[i] == '+') - color = DIFF_FILE_NEW; - } - if (color != DIFF_FILE_NEW) { - emit_line(ecbdata->file, - diff_get_color(ecbdata->color_diff, color), - reset, line, len); - return; + if (line[0] != '+') { + const char *color = + diff_get_color(ecbdata->color_diff, + line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN); + ecbdata->lno_in_preimage++; + if (line[0] == ' ') + ecbdata->lno_in_postimage++; + emit_line(ecbdata->file, color, reset, line, len); + } else { + ecbdata->lno_in_postimage++; + emit_add_line(reset, ecbdata, line + 1, len - 1); } - emit_add_line(reset, ecbdata, line, len); } static char *pprint_rename(const char *a, const char *b) @@ -999,7 +1110,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) total_files, adds, dels); } -static void show_shortstats(struct diffstat_t* data, struct diff_options *options) +static void show_shortstats(struct diffstat_t *data, struct diff_options *options) { int i, adds = 0, dels = 0, total_files = data->nr; @@ -1211,7 +1322,6 @@ struct checkdiff_t { struct diff_options *o; unsigned ws_rule; unsigned status; - int trailing_blanks_start; }; static int is_conflict_marker(const char *line, unsigned long len) @@ -1255,10 +1365,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (line[0] == '+') { unsigned bad; data->lineno++; - if (!ws_blank_line(line + 1, len - 1, data->ws_rule)) - data->trailing_blanks_start = 0; - else if (!data->trailing_blanks_start) - data->trailing_blanks_start = data->lineno; if (is_conflict_marker(line + 1, len - 1)) { data->status |= 1; fprintf(data->o->file, @@ -1278,14 +1384,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) data->o->file, set, reset, ws); } else if (line[0] == ' ') { data->lineno++; - data->trailing_blanks_start = 0; } else if (line[0] == '@') { char *plus = strchr(line, '+'); if (plus) data->lineno = strtol(plus, NULL, 10) - 1; else die("invalid diff"); - data->trailing_blanks_start = 0; } } @@ -1562,6 +1666,8 @@ static void builtin_diff(const char *name_a, 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); + if (ecbdata.ws_rule & WS_BLANK_AT_EOF) + check_blank_at_eof(&mf1, &mf2, &ecbdata); ecbdata.file = o->file; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; @@ -1704,11 +1810,22 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, &xpp, &xecfg, &ecb); - if ((data.ws_rule & WS_TRAILING_SPACE) && - data.trailing_blanks_start) { - fprintf(o->file, "%s:%d: ends with blank lines.\n", - data.filename, data.trailing_blanks_start); - data.status = 1; /* report errors */ + if (data.ws_rule & WS_BLANK_AT_EOF) { + struct emit_callback ecbdata; + int blank_at_eof; + + ecbdata.ws_rule = data.ws_rule; + check_blank_at_eof(&mf1, &mf2, &ecbdata); + blank_at_eof = ecbdata.blank_at_eof_in_preimage; + + if (blank_at_eof) { + static char *err; + if (!err) + err = whitespace_error_string(WS_BLANK_AT_EOF); + fprintf(o->file, "%s:%d: %s.\n", + data.filename, blank_at_eof, err); + data.status = 1; /* report errors */ + } } } free_and_return: diff --git a/fast-import.c b/fast-import.c index 7ef9865aa6..6faaaacb68 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1744,10 +1744,12 @@ static int validate_raw_date(const char *src, char *result, int maxlen) { const char *orig_src = src; char *endp; + unsigned long num; errno = 0; - strtoul(src, &endp, 10); + num = strtoul(src, &endp, 10); + /* NEEDSWORK: perhaps check for reasonable values? */ if (errno || endp == src || *endp != ' ') return -1; @@ -1755,8 +1757,9 @@ static int validate_raw_date(const char *src, char *result, int maxlen) if (*src != '-' && *src != '+') return -1; - strtoul(src + 1, &endp, 10); - if (errno || endp == src || *endp || (endp - orig_src) >= maxlen) + num = strtoul(src + 1, &endp, 10); + if (errno || endp == src + 1 || *endp || (endp - orig_src) >= maxlen || + 1400 < num) return -1; strcpy(result, orig_src); diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 392efb913f..69aeaf03ec 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -259,7 +259,7 @@ sub list_modified { @tracked = map { chomp $_; unquote_path($_); - } run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV); + } run_cmd_pipe(qw(git ls-files --), @ARGV); return if (!@tracked); } @@ -205,7 +205,7 @@ check_patch_format () { # and see if it looks like that they all begin with the # header field names... sed -n -e '/^$/q' -e '/^[ ]/d' -e p "$1" | - egrep -v '^[A-Za-z]+(-[A-Za-z]+)*:' >/dev/null || + LC_ALL=C egrep -v '^[!-9;-~]+:' >/dev/null || patch_format=mbox fi } < "$1" || clean_abort diff --git a/git-compat-util.h b/git-compat-util.h index 8d6e29cdea..ef60803384 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -176,8 +176,10 @@ extern char *gitbasename(char *); #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) +#define NORETURN_PTR __attribute__((__noreturn__)) #else #define NORETURN +#define NORETURN_PTR #ifndef __attribute__ #define __attribute__(x) #endif @@ -186,13 +188,13 @@ extern char *gitbasename(char *); #include "compat/bswap.h" /* General helper functions */ -extern void usage(const char *err) NORETURN; -extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); -extern void die_errno(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); +extern NORETURN void usage(const char *err); +extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2))); +extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); +extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)); extern int prefixcmp(const char *str, const char *prefix); extern time_t tm_to_time_t(const struct tm *tm); diff --git a/git-instaweb.sh b/git-instaweb.sh index d96eddbe56..622a5f0eb2 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -317,7 +317,21 @@ EOF resolve_full_httpd list_mods=$(echo "$full_httpd" | sed "s/-f$/-l/") $list_mods | grep 'mod_cgi\.c' >/dev/null 2>&1 || \ - echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf" + if test -f "$module_path/mod_cgi.so" + then + echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf" + else + $list_mods | grep 'mod_cgid\.c' >/dev/null 2>&1 || \ + if test -f "$module_path/mod_cgid.so" + then + echo "LoadModule cgid_module $module_path/mod_cgid.so" \ + >> "$conf" + else + echo "You have no CGI support!" + exit 2 + fi + echo "ScriptSock logs/gitweb.sock" >> "$conf" + fi cat >> "$conf" <<EOF AddHandler cgi-script .cgi <Location /gitweb.cgi> diff --git a/git-pull.sh b/git-pull.sh index edf3ce33bf..fc78592ae0 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -90,8 +90,17 @@ error_on_no_merge_candidates () { curr_branch=${curr_branch#refs/heads/} upstream=$(git config "branch.$curr_branch.merge") + remote=$(git config "branch.$curr_branch.remote") - if [ -z "$curr_branch" ]; then + if [ $# -gt 1 ]; then + echo "There are no candidates for merging in the refs that you just fetched." + echo "Generally this means that you provided a wildcard refspec which had no" + echo "matches on the remote end." + elif [ $# -gt 0 ] && [ "$1" != "$remote" ]; then + echo "You asked to pull from the remote '$1', but did not specify" + echo "a branch to merge. Because this is not the default configured remote" + echo "for your current branch, you must specify a branch on the command line." + elif [ -z "$curr_branch" ]; then echo "You are not currently on a branch, so I cannot use any" echo "'branch.<branchname>.merge' in your configuration file." echo "Please specify which branch you want to merge on the command" @@ -116,9 +125,8 @@ error_on_no_merge_candidates () { echo echo "See git-config(1) for details." else - echo "Your configuration specifies to merge the ref" - echo "'${upstream#refs/heads/}' from the remote, but no such ref" - echo "was fetched." + echo "Your configuration specifies to merge the ref '${upstream#refs/heads/}' from the" + echo "remote, but no such ref was fetched." fi exit 1 } @@ -182,14 +190,7 @@ merge_head=$(sed -e '/ not-for-merge /d' \ case "$merge_head" in '') - case $? in - 0) error_on_no_merge_candidates "$@";; - 1) echo >&2 "You are not currently on a branch; you must explicitly" - echo >&2 "specify which branch you wish to merge:" - echo >&2 " git pull <remote> <branch>" - exit 1;; - *) exit $?;; - esac + error_on_no_merge_candidates "$@" ;; ?*' '?*) if test -z "$orig_head" diff --git a/git-send-email.perl b/git-send-email.perl index dd821f70cd..a0279de687 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -401,7 +401,7 @@ my %aliases; my %parse_alias = ( # multiline formats can be supported in the future mutt => sub { my $fh = shift; while (<$fh>) { - if (/^\s*alias\s+(\S+)\s+(.*)$/) { + if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) { my ($alias, $addr) = ($1, $2); $addr =~ s/#.*$//; # mutt allows # comments # commas delimit multiple addresses @@ -835,7 +835,7 @@ sub send_message $gitversion = Git::version(); } - my $cc = join(", ", unique_email_list(@cc)); + my $cc = join(",\n\t", unique_email_list(@cc)); my $ccline = ""; if ($cc ne '') { $ccline = "\nCc: $cc"; @@ -976,7 +976,9 @@ X-Mailer: git-send-email $gitversion if ($smtp_server !~ m#^/#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; - print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n"; + foreach my $entry (@recipients) { + print "RCPT TO:<$entry>\n"; + } } else { print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n"; } diff --git a/git-svn.perl b/git-svn.perl index e0ec258e33..eb4b75aff3 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -603,8 +603,15 @@ sub cmd_dcommit { "\nBefore dcommitting"; } if ($url_ ne $expect_url) { - fatal "URL mismatch after rebase: ", - "$url_ != $expect_url"; + if ($url_ eq $gs->metadata_url) { + print + "Accepting rewritten URL:", + " $url_\n"; + } else { + fatal + "URL mismatch after rebase:", + " $url_ != $expect_url"; + } } if ($uuid_ ne $uuid) { fatal "uuid mismatch after rebase: ", @@ -2626,7 +2633,8 @@ sub find_parent_branch { my $url = $self->ra->{url}; my $new_url = $url . $branch_from; print STDERR "Found possible branch point: ", - "$new_url => ", $self->full_url, ", $r\n"; + "$new_url => ", $self->full_url, ", $r\n" + unless $::_q > 1; $branch_from =~ s#^/##; my $gs = $self->other_gs($new_url, $url, $branch_from, $r, $self->{ref_id}); @@ -2647,11 +2655,13 @@ sub find_parent_branch { ($r0, $parent) = $gs->find_rev_before($r, 1); } if (defined $r0 && defined $parent) { - print STDERR "Found branch parent: ($self->{ref_id}) $parent\n"; + print STDERR "Found branch parent: ($self->{ref_id}) $parent\n" + unless $::_q > 1; my $ed; if ($self->ra->can_do_switch) { $self->assert_index_clean($parent); - print STDERR "Following parent with do_switch\n"; + print STDERR "Following parent with do_switch\n" + unless $::_q > 1; # do_switch works with svn/trunk >= r22312, but that # is not included with SVN 1.4.3 (the latest version # at the moment), so we can't rely on it @@ -2666,18 +2676,20 @@ sub find_parent_branch { print STDERR "Trees match:\n", " $new_url\@$r0\n", " ${\$self->full_url}\@$rev\n", - "Following parent with no changes\n"; + "Following parent with no changes\n" + unless $::_q > 1; $self->tmp_index_do(sub { command_noisy('read-tree', $parent); }); $self->{last_commit} = $parent; } else { - print STDERR "Following parent with do_update\n"; + print STDERR "Following parent with do_update\n" + unless $::_q > 1; $ed = SVN::Git::Fetcher->new($self); $self->ra->gs_do_update($rev, $rev, $self, $ed) or die "SVN connection failed somewhere...\n"; } - print STDERR "Successfully followed parent\n"; + print STDERR "Successfully followed parent\n" unless $::_q > 1; return $self->make_log_entry($rev, [$parent], $ed); } return undef; @@ -2822,7 +2834,7 @@ sub other_gs { $ref_id .= "\@$r"; # just grow a tail if we're not unique enough :x $ref_id .= '-' while find_ref($ref_id); - print STDERR "Initializing parent: $ref_id\n"; + print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1; my ($u, $p, $repo_id) = ($new_url, '', $ref_id); if ($u =~ s#^\Q$url\E(/|$)##) { $p = $u; @@ -6,7 +6,7 @@ const char git_usage_string[] = "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n" - " [-p|--paginate|--no-pager]\n" + " [-p|--paginate|--no-pager] [--no-replace-objects]\n" " [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n" " [--help] COMMAND [ARGS]"; @@ -87,6 +87,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) use_pager = 0; if (envchanged) *envchanged = 1; + } else if (!strcmp(cmd, "--no-replace-objects")) { + read_replace_refs = 0; } else if (!strcmp(cmd, "--git-dir")) { if (*argc < 2) { fprintf(stderr, "No directory given for --git-dir.\n" ); diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 8f68fe3091..d60bfc1f64 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -341,6 +341,12 @@ td.mode { font-family: monospace; } +/* format of (optional) objects size in 'tree' view */ +td.size { + font-family: monospace; + text-align: right; +} + /* styling of diffs (patchsets): commitdiff and blobdiff views */ div.diff.header, div.diff.extended_header { diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 24b219310a..d6eb7291d6 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -297,6 +297,19 @@ our %feature = ( 'override' => 0, 'default' => [1]}, + # Enable showing size of blobs in a 'tree' view, in a separate + # column, similar to what 'ls -l' does. This cost a bit of IO. + + # To disable system wide have in $GITWEB_CONFIG + # $feature{'show-sizes'}{'default'} = [0]; + # To have project specific config enable override in $GITWEB_CONFIG + # $feature{'show-sizes'}{'override'} = 1; + # and in project config gitweb.showsizes = 0|1; + 'show-sizes' => { + 'sub' => sub { feature_bool('showsizes', @_) }, + 'override' => 0, + 'default' => [1]}, + # Make gitweb use an alternative format of the URLs which can be # more readable and natural-looking: project name is embedded # directly in the path and the query string contains other @@ -2764,16 +2777,31 @@ sub parse_ls_tree_line { my %opts = @_; my %res; - #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' - $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s; + if ($opts{'-l'}) { + #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa 16717 panic.c' + $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40}) +(-|[0-9]+)\t(.+)$/s; - $res{'mode'} = $1; - $res{'type'} = $2; - $res{'hash'} = $3; - if ($opts{'-z'}) { - $res{'name'} = $4; + $res{'mode'} = $1; + $res{'type'} = $2; + $res{'hash'} = $3; + $res{'size'} = $4; + if ($opts{'-z'}) { + $res{'name'} = $5; + } else { + $res{'name'} = unquote($5); + } } else { - $res{'name'} = unquote($4); + #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' + $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s; + + $res{'mode'} = $1; + $res{'type'} = $2; + $res{'hash'} = $3; + if ($opts{'-z'}) { + $res{'name'} = $4; + } else { + $res{'name'} = unquote($4); + } } return wantarray ? %res : \%res; @@ -3564,6 +3592,9 @@ sub git_print_tree_entry { # and link is the action links of the entry. print "<td class=\"mode\">" . mode_str($t->{'mode'}) . "</td>\n"; + if (exists $t->{'size'}) { + print "<td class=\"size\">$t->{'size'}</td>\n"; + } if ($t->{'type'} eq "blob") { print "<td class=\"list\">" . $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, @@ -3609,12 +3640,14 @@ sub git_print_tree_entry { } elsif ($t->{'type'} eq "tree") { print "<td class=\"list\">"; print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, + file_name=>"$basedir$t->{'name'}", + %base_key)}, esc_path($t->{'name'})); print "</td>\n"; print "<td class=\"link\">"; print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, + file_name=>"$basedir$t->{'name'}", + %base_key)}, "tree"); if (defined $hash_base) { print " | " . @@ -5088,10 +5121,14 @@ sub git_tree { } die_error(404, "No such tree") unless defined($hash); + my $show_sizes = gitweb_check_feature('show-sizes'); + my $have_blame = gitweb_check_feature('blame'); + my @entries = (); { local $/ = "\0"; - open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash + open my $fd, "-|", git_cmd(), "ls-tree", '-z', + ($show_sizes ? '-l' : ()), @extra_options, $hash or die_error(500, "Open git-ls-tree failed"); @entries = map { chomp; $_ } <$fd>; close $fd @@ -5102,7 +5139,6 @@ sub git_tree { my $ref = format_ref_marker($refs, $hash_base); git_header_html(); my $basedir = ''; - my $have_blame = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { my @views_nav = (); if (defined $file_name) { @@ -5118,7 +5154,8 @@ sub git_tree { # FIXME: Should be available when we have no hash base as well. push @views_nav, $snapshot_links; } - git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav)); + git_print_page_nav('tree','', $hash_base, undef, undef, + join(' | ', @views_nav)); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { undef $hash_base; @@ -5151,8 +5188,10 @@ sub git_tree { undef $up unless $up; # based on git_print_tree_entry print '<td class="mode">' . mode_str('040000') . "</td>\n"; + print '<td class="size"> </td>'."\n" if $show_sizes; print '<td class="list">'; - print $cgi->a({-href => href(action=>"tree", hash_base=>$hash_base, + print $cgi->a({-href => href(action=>"tree", + hash_base=>$hash_base, file_name=>$up)}, ".."); print "</td>\n"; @@ -5161,7 +5200,7 @@ sub git_tree { print "</tr>\n"; } foreach my $line (@entries) { - my %t = parse_ls_tree_line($line, -z => 1); + my %t = parse_ls_tree_line($line, -z => 1, -l => $show_sizes); if ($alternate) { print "<tr class=\"dark\">\n"; @@ -5328,7 +5367,7 @@ sub git_commit { } @$parents ) . ')'; } - if (gitweb_check_feature('patches')) { + if (gitweb_check_feature('patches') && @$parents <= 1) { $formats_nav .= " | " . $cgi->a({-href => href(action=>"patch", -replay=>1)}, "patch"); @@ -5616,7 +5655,7 @@ sub git_commitdiff { $formats_nav = $cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)}, "raw"); - if ($patch_max) { + if ($patch_max && @{$co{'parents'}} <= 1) { $formats_nav .= " | " . $cgi->a({-href => href(action=>"patch", -replay=>1)}, "patch"); @@ -5824,7 +5863,7 @@ sub git_commitdiff_plain { # format-patch-style patches sub git_patch { - git_commitdiff(-format => 'patch', -single=> 1); + git_commitdiff(-format => 'patch', -single => 1); } sub git_patches { diff --git a/index-pack.c b/index-pack.c index 340074fc79..b4f8278659 100644 --- a/index-pack.c +++ b/index-pack.c @@ -206,8 +206,8 @@ static void parse_pack_header(void) use(sizeof(struct pack_header)); } -static void bad_object(unsigned long offset, const char *format, - ...) NORETURN __attribute__((format (printf, 2, 3))); +static NORETURN void bad_object(unsigned long offset, const char *format, + ...) __attribute__((format (printf, 2, 3))); static void bad_object(unsigned long offset, const char *format, ...) { diff --git a/log-tree.c b/log-tree.c index 1c9eefee33..f7d54f2f1b 100644 --- a/log-tree.c +++ b/log-tree.c @@ -43,6 +43,7 @@ void load_ref_decorations(int flags) if (!loaded) { loaded = 1; for_each_ref(add_ref_decoration, &flags); + head_ref(add_ref_decoration, &flags); } } @@ -390,7 +391,9 @@ void show_log(struct rev_info *opt) */ show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, - opt->date_mode); + opt->date_mode_explicit ? + opt->date_mode : + DATE_NORMAL); if (opt->commit_format == CMIT_FMT_ONELINE) return; } @@ -740,7 +740,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, } void format_commit_message(const struct commit *commit, - const void *format, struct strbuf *sb, + const char *format, struct strbuf *sb, enum date_mode dmode) { struct format_commit_context context; diff --git a/progress.c b/progress.c index 132ed95a3d..3971f49f4d 100644 --- a/progress.c +++ b/progress.c @@ -131,7 +131,13 @@ static void throughput_string(struct throughput *tp, off_t total, } else { l -= snprintf(tp->display, l, ", %u bytes", (int)total); } - if (rate) + + if (rate > 1 << 10) { + int x = rate + 5; /* for rounding */ + snprintf(tp->display + sizeof(tp->display) - l, l, + " | %u.%2.2u MiB/s", + x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10); + } else if (rate) snprintf(tp->display + sizeof(tp->display) - l, l, " | %u KiB/s", rate); } diff --git a/remote-curl.c b/remote-curl.c index ad6a1637b5..2faf1c6344 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -3,6 +3,7 @@ #include "strbuf.h" #include "walker.h" #include "http.h" +#include "exec_cmd.h" static struct ref *get_refs(struct walker *walker, const char *url) { @@ -82,6 +83,7 @@ int main(int argc, const char **argv) const char *url; struct walker *walker = NULL; + git_extract_argv0_path(argv[0]); setup_git_directory(); if (argc < 2) { fprintf(stderr, "Remote needed\n"); diff --git a/revision.c b/revision.c index 35eca4a361..9fc4e8d381 100644 --- a/revision.c +++ b/revision.c @@ -1159,8 +1159,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->simplify_history = 0; } else if (!strcmp(arg, "--relative-date")) { revs->date_mode = DATE_RELATIVE; + revs->date_mode_explicit = 1; } else if (!strncmp(arg, "--date=", 7)) { revs->date_mode = parse_date_format(arg + 7); + revs->date_mode_explicit = 1; } else if (!strcmp(arg, "--log-size")) { revs->show_log_size = 1; } diff --git a/revision.h b/revision.h index 9d0dddbcbc..b6421a6432 100644 --- a/revision.h +++ b/revision.h @@ -81,7 +81,8 @@ struct rev_info { show_merge:1, abbrev_commit:1, use_terminator:1, - missing_newline:1; + missing_newline:1, + date_mode_explicit:1; enum date_mode date_mode; unsigned int abbrev; diff --git a/sha1_file.c b/sha1_file.c index 4ea0b18d0a..4cc8939e4b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1357,6 +1357,8 @@ unsigned long get_size_from_delta(struct packed_git *p, in = use_pack(p, w_curs, curpos, &stream.avail_in); stream.next_in = in; st = git_inflate(&stream, Z_FINISH); + if (st == Z_BUF_ERROR && (stream.avail_in || !stream.avail_out)) + break; curpos += stream.next_in - in; } while ((st == Z_OK || st == Z_BUF_ERROR) && stream.total_out < sizeof(delta_head)); @@ -1594,6 +1596,8 @@ static void *unpack_compressed_entry(struct packed_git *p, in = use_pack(p, w_curs, curpos, &stream.avail_in); stream.next_in = in; st = git_inflate(&stream, Z_FINISH); + if (st == Z_BUF_ERROR && (stream.avail_in || !stream.avail_out)) + break; curpos += stream.next_in - in; } while (st == Z_OK || st == Z_BUF_ERROR); git_inflate_end(&stream); diff --git a/t/t3003-ls-files-exclude.sh b/t/t3003-ls-files-exclude.sh new file mode 100755 index 0000000000..fc1e379321 --- /dev/null +++ b/t/t3003-ls-files-exclude.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='ls-files --exclude does not affect index files' +. ./test-lib.sh + +test_expect_success 'create repo with file' ' + echo content >file && + git add file && + git commit -m file && + echo modification >file +' + +check_output() { +test_expect_success "ls-files output contains file ($1)" " + echo '$2' >expect && + git ls-files --exclude-standard --$1 >output && + test_cmp expect output +" +} + +check_all_output() { + check_output 'cached' 'file' + check_output 'modified' 'file' +} + +check_all_output +test_expect_success 'add file to gitignore' ' + echo file >.gitignore +' +check_all_output + +test_done diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh index 7fe4a6ecb0..0a5d5e669f 100755 --- a/t/t3202-show-branch-octopus.sh +++ b/t/t3202-show-branch-octopus.sh @@ -56,4 +56,12 @@ test_expect_success 'show-branch with more than 8 branches' ' ' +test_expect_success 'show-branch with showbranch.default' ' + for i in $numbers; do + git config --add showbranch.default branch$i + done && + git show-branch >out && + test_cmp expect out +' + test_done diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 62fd65e18d..687bd7ab53 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -138,6 +138,20 @@ test_expect_success 'real edit works' ' test_cmp expected output ' +test_expect_success 'skip files similarly as commit -a' ' + git reset && + echo file >.gitignore && + echo changed >file && + echo y | git add -p file && + git diff >output && + git reset && + git commit -am commit && + git diff >expected && + test_cmp expected output && + git reset --hard HEAD^ +' +rm -f .gitignore + if test "$(git config --bool core.filemode)" = false then say 'skipping filemode tests (filesystem does not properly support modes)' diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all index 903d9d9659..d155e0bab2 100644 --- a/t/t4013/diff.log_--decorate=full_--all +++ b/t/t4013/diff.log_--decorate=full_--all @@ -1,5 +1,5 @@ $ git log --decorate=full --all -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all index 954210ea90..fd7c3e6439 100644 --- a/t/t4013/diff.log_--decorate_--all +++ b/t/t4013/diff.log_--decorate_--all @@ -1,5 +1,5 @@ $ git log --decorate --all -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 6d13da30da..8dd147d78f 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -362,10 +362,17 @@ test_expect_success 'line numbers in --check output are correct' ' ' -test_expect_success 'checkdiff detects trailing blank lines' ' +test_expect_success 'checkdiff detects new trailing blank lines (1)' ' echo "foo();" >x && echo "" >>x && - git diff --check | grep "ends with blank" + git diff --check | grep "new blank line" +' + +test_expect_success 'checkdiff detects new trailing blank lines (2)' ' + { echo a; echo b; echo; echo; } >x && + git add x && + { echo a; echo; echo; echo; echo; } >x && + git diff --check | grep "new blank line" ' test_expect_success 'checkdiff allows new blank lines' ' diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 84a1fe3115..3a3663fbcb 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -165,7 +165,7 @@ test_expect_success 'trailing empty lines (1)' ' rm -f .gitattributes && test_must_fail git diff --check >output && - grep "ends with blank lines." output && + grep "new blank line at" output && grep "trailing whitespace" output ' @@ -190,4 +190,13 @@ test_expect_success 'do not color trailing cr in context' ' ' +test_expect_success 'color new trailing blank lines' ' + { echo a; echo b; echo; echo; } >x && + git add x && + { echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x && + git diff --color x >output && + cnt=$(grep "${blue_grep}" output | wc -l) && + test $cnt = 2 +' + test_done diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index fac2093d7f..ca26397590 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -170,4 +170,95 @@ test_expect_success 'trailing whitespace & no newline at the end of file' ' grep "^$" target ' +test_expect_success 'blank at EOF with --whitespace=fix (1)' ' + : these can fail depending on what we did before + git config --unset core.whitespace + rm -f .gitattributes + + { echo a; echo b; echo c; } >one && + git add one && + { echo a; echo b; echo c; } >expect && + { cat expect; echo; } >one && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=fix patch && + test_cmp expect one +' + +test_expect_success 'blank at EOF with --whitespace=fix (2)' ' + { echo a; echo b; echo c; } >one && + git add one && + { echo a; echo c; } >expect && + { cat expect; echo; echo; } >one && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=fix patch && + test_cmp expect one +' + +test_expect_success 'blank at EOF with --whitespace=fix (3)' ' + { echo a; echo b; echo; } >one && + git add one && + { echo a; echo c; echo; } >expect && + { cat expect; echo; echo; } >one && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=fix patch && + test_cmp expect one +' + +test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' ' + { echo a; echo b; echo; echo; echo; echo; echo; echo d; } >one && + git add one && + { echo a; echo c; echo; echo; echo; echo; echo; echo; echo d; } >expect && + cp expect one && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=fix patch && + test_cmp expect one +' + +test_expect_success 'blank at EOF with --whitespace=warn' ' + { echo a; echo b; echo c; } >one && + git add one && + echo >>one && + cat one >expect && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=warn patch 2>error && + test_cmp expect one && + grep "new blank line at EOF" error +' + +test_expect_success 'blank at EOF with --whitespace=error' ' + { echo a; echo b; echo c; } >one && + git add one && + cat one >expect && + echo >>one && + git diff -- one >patch && + + git checkout one && + test_must_fail git apply --whitespace=error patch 2>error && + test_cmp expect one && + grep "new blank line at EOF" error +' + +test_expect_success 'blank but not empty at EOF' ' + { echo a; echo b; echo c; } >one && + git add one && + echo " " >>one && + cat one >expect && + git diff -- one >patch && + + git checkout one && + git apply --whitespace=warn patch 2>error && + test_cmp expect one && + grep "new blank line at EOF" error +' + test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 5f84b18fa5..0037f63d91 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -230,4 +230,16 @@ test_expect_success \ 'git archive --list outside of a git repo' \ 'GIT_DIR=some/non-existing/directory git archive --list' +test_expect_success 'git-archive --prefix=olde-' ' + git archive --prefix=olde- >h.tar HEAD && + ( + mkdir h && + cd h && + "$TAR" xf - <../h.tar + ) && + test -d h/olde-a && + test -d h/olde-a/bin && + test -f h/olde-a/bin/sh +' + test_done diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5132d41309..5f6cd4f333 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -275,4 +275,13 @@ test_expect_success \ git cat-file blob $blob_2 > /dev/null && git cat-file blob $blob_3 > /dev/null' +test_expect_success \ + 'corrupting header to have too small output buffer fails unpack' \ + 'create_new_pack && + git prune-packed && + printf "\262\001" | do_corrupt_object $blob_1 0 && + test_must_fail git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null' + test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 8b8bd81c09..d4818b430a 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -70,6 +70,13 @@ test_expect_success 'replace the author' ' git show $HASH2 | grep "O Thor" ' +test_expect_success 'test --no-replace-objects option' ' + git cat-file commit $HASH2 | grep "author O Thor" && + git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" && + git show $HASH2 | grep "O Thor" && + git --no-replace-objects show $HASH2 | grep "A U Thor" +' + cat >tag.sig <<EOF object $HASH2 type commit diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index ae56a36eac..ae5290ab43 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -213,6 +213,72 @@ test_expect_success 'grep -e A --and --not -e B' ' test_cmp expected actual ' +test_expect_success 'grep -f, non-existent file' ' + test_must_fail git grep -f patterns +' + +cat >expected <<EOF +file:foo mmap bar +file:foo_mmap bar +file:foo_mmap bar mmap +file:foo mmap bar_mmap +file:foo_mmap bar mmap baz +EOF + +cat >pattern <<EOF +mmap +EOF + +test_expect_success 'grep -f, one pattern' ' + git grep -f pattern >actual && + test_cmp expected actual +' + +cat >expected <<EOF +file:foo mmap bar +file:foo_mmap bar +file:foo_mmap bar mmap +file:foo mmap bar_mmap +file:foo_mmap bar mmap baz +t/a/v:vvv +t/v:vvv +v:vvv +EOF + +cat >patterns <<EOF +mmap +vvv +EOF + +test_expect_success 'grep -f, multiple patterns' ' + git grep -f patterns >actual && + test_cmp expected actual +' + +cat >expected <<EOF +file:foo mmap bar +file:foo_mmap bar +file:foo_mmap bar mmap +file:foo mmap bar_mmap +file:foo_mmap bar mmap baz +t/a/v:vvv +t/v:vvv +v:vvv +EOF + +cat >patterns <<EOF + +mmap + +vvv + +EOF + +test_expect_success 'grep -f, ignore empty lines' ' + git grep -f patterns >actual && + test_cmp expected actual +' + cat >expected <<EOF y:y yy -- diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index fb606a9f05..84a7f03d46 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -103,10 +103,18 @@ cat >expected-show-all-headers <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<bcc@example.com> +RCPT TO:<to@example.com> +RCPT TO:<cc@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> +RCPT TO:<bcc@example.com> From: Example <from@example.com> To: to@example.com -Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com +Cc: cc@example.com, + A <author@example.com>, + One <one@example.com>, + two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -164,7 +172,7 @@ test_expect_success 'cccmd works' ' --smtp-server="$(pwd)/fake.sendmail" \ cccmd.patch \ && - grep ^Cc:.*cccmd@example.com msgtxt1 + grep "^ cccmd@example.com" msgtxt1 ' z8=zzzzzzzz @@ -278,10 +286,17 @@ cat >expected-suppress-sob <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com> +RCPT TO:<to@example.com> +RCPT TO:<cc@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> From: Example <from@example.com> To: to@example.com -Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com +Cc: cc@example.com, + A <author@example.com>, + One <one@example.com>, + two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -318,10 +333,15 @@ cat >expected-suppress-sob <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -344,10 +364,17 @@ cat >expected-suppress-cccmd <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> +RCPT TO:<committer@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com> +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com, + C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -392,10 +419,17 @@ cat >expected-suppress-body <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<cc-cmd@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> +RCPT TO:<cc-cmd@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com, cc-cmd@example.com +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com, + cc-cmd@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -416,10 +450,15 @@ cat >expected-suppress-body-cccmd <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -440,10 +479,15 @@ cat >expected-suppress-sob <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -466,10 +510,17 @@ cat >expected-suppress-bodycc <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<one@example.com> +RCPT TO:<two@example.com> +RCPT TO:<committer@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com> +Cc: A <author@example.com>, + One <one@example.com>, + two@example.com, + C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -489,10 +540,13 @@ cat >expected-suppress-cc <<\EOF Dry-OK. Log says: Server: relay.example.com MAIL FROM:<from@example.com> -RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com> +RCPT TO:<to@example.com> +RCPT TO:<author@example.com> +RCPT TO:<committer@example.com> From: Example <from@example.com> To: to@example.com -Cc: A <author@example.com>, C O Mitter <committer@example.com> +Cc: A <author@example.com>, + C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING Message-Id: MESSAGE-ID-STRING @@ -605,7 +659,7 @@ test_expect_success 'utf8 Cc is rfc2047 encoded' ' --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ outdir/*.patch && - grep "^Cc:" msgtxt1 | + grep "^ " msgtxt1 | grep "=?UTF-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>" ' @@ -36,12 +36,12 @@ static void warn_builtin(const char *warn, va_list params) /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ -static void (*usage_routine)(const char *err) NORETURN = usage_builtin; -static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; +static NORETURN_PTR void (*usage_routine)(const char *err) = usage_builtin; +static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; -void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) +void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)) { die_routine = routine; } @@ -16,6 +16,8 @@ static struct whitespace_rule { { "space-before-tab", WS_SPACE_BEFORE_TAB, 0 }, { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 }, { "cr-at-eol", WS_CR_AT_EOL, 1 }, + { "blank-at-eol", WS_BLANK_AT_EOL, 0 }, + { "blank-at-eof", WS_BLANK_AT_EOF, 0 }, }; unsigned parse_whitespace_rule(const char *string) @@ -102,8 +104,17 @@ unsigned whitespace_rule(const char *pathname) char *whitespace_error_string(unsigned ws) { struct strbuf err = STRBUF_INIT; - if (ws & WS_TRAILING_SPACE) + if ((ws & WS_TRAILING_SPACE) == WS_TRAILING_SPACE) strbuf_addstr(&err, "trailing whitespace"); + else { + if (ws & WS_BLANK_AT_EOL) + strbuf_addstr(&err, "trailing whitespace"); + if (ws & WS_BLANK_AT_EOF) { + if (err.len) + strbuf_addstr(&err, ", "); + strbuf_addstr(&err, "new blank line at EOF"); + } + } if (ws & WS_SPACE_BEFORE_TAB) { if (err.len) strbuf_addstr(&err, ", "); @@ -141,11 +152,11 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule, } /* Check for trailing whitespace. */ - if (ws_rule & WS_TRAILING_SPACE) { + if (ws_rule & WS_BLANK_AT_EOL) { for (i = len - 1; i >= 0; i--) { if (isspace(line[i])) { trailing_whitespace = i; - result |= WS_TRAILING_SPACE; + result |= WS_BLANK_AT_EOL; } else break; @@ -261,7 +272,7 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro /* * Strip trailing whitespace */ - if (ws_rule & WS_TRAILING_SPACE) { + if (ws_rule & WS_BLANK_AT_EOL) { if (0 < len && src[len - 1] == '\n') { add_nl_to_tail = 1; len--; |