Merge branch 'bc/maint-diff-hunk-header-fix' into bc/master-diff-hunk-header-fix

* bc/maint-diff-hunk-header-fix:
  diff.*.xfuncname which uses "extended" regex's for hunk header selection
  diff.c: associate a flag with each pattern and use it for compiling regex
  diff.c: return pattern entry pointer rather than just the hunk header pattern
  Cosmetical command name fix
  Start conforming code to "git subcmd" style part 3
  t9700/test.pl: remove File::Temp requirement
  t9700/test.pl: avoid bareword 'STDERR' in 3-argument open()
  GIT 1.6.0.2
  Fix some manual typos.
  Use compatibility regex library also on FreeBSD
  Use compatibility regex library also on AIX
  Update draft release notes for 1.6.0.2
  Use compatibility regex library for OSX/Darwin
  git-svn: Fixes my() parameter list syntax error in pre-5.8 Perl
  Git.pm: Use File::Temp->tempfile instead of ->new
  t7501: always use test_cmp instead of diff
  Start conforming code to "git subcmd" style part 2
  diff: Help "less" hide ^M from the output
  checkout: do not check out unmerged higher stages randomly

Conflicts:
	Documentation/git.txt
	Documentation/gitattributes.txt
	Makefile
	diff.c
	t/t7201-co.sh
This commit is contained in:
Junio C Hamano 2008-09-18 20:32:50 -07:00
Родитель af9ce1ffc6 45d9414fa5
Коммит dde4af4313
37 изменённых файлов: 266 добавлений и 123 удалений

Просмотреть файл

@ -17,6 +17,10 @@ Fixes since v1.6.0.1
* Many commands did not use the correct working tree location when used
with GIT_WORK_TREE environment settings.
* Some systems needs to use compatibility fnmach and regex libraries
independent from each other; the compat/ area has been reorganized to
allow this.
* "git apply --unidiff-zero" incorrectly applied a -U0 patch that inserts
a new line before the second line.
@ -24,9 +28,15 @@ Fixes since v1.6.0.1
* "git blame -c" did not exactly work like "git annotate" when range
boundaries are involved.
* "git checkout file" when file is still unmerged checked out contents from
a random high order stage, which was confusing.
* "git clone $there $here/" with extra trailing slashes after explicit
local directory name $here did not work as expected.
* "git diff" on tracked contents with CRLF line endings did not drive "less"
intelligently when showing added or removed lines.
* "git diff --dirstat -M" did not add changes in subdirectories up
correctly for renamed paths.
@ -42,18 +52,29 @@ Fixes since v1.6.0.1
* "git gui" translation updates and i18n fixes.
* "git index-pack" is more careful against disk corruption while completing
a thin pack.
* "git log -i --grep=pattern" did not ignore case; neither "git log -E
--grep=pattern" triggered extended regexp.
* "git log --pretty="%ad" --date=short" did not use short format when
showing the timestamp.
* "git log --author=author" match incorrectly matched with the
timestamp part of "author " line in commit objects.
* "git log -F --author=author" did not work at all.
* Build procedure for "git shell" that used stub versions of some
functions and globals was not understood by linkers on some platforms.
* "git stash" was fooled by a stat-dirty but otherwise unmodified paths
and refused to work until the user refreshed the index.
* "git svn" was broken on Perl before 5.8 with recent fixes to reduce
use of temporary files.
* "git verify-pack -v" did not work correctly when given more than one
packfile.
@ -61,7 +82,6 @@ Also contains many documentation updates.
--
exec >/var/tmp/1
O=v1.6.0.1-61-g1eff26c
O=v1.6.0.1-78-g3632cfc
echo O=$(git describe maint)
git shortlog --no-merges $O..maint

Просмотреть файл

@ -77,7 +77,7 @@ the URLs passed as arguments.
Note about konqueror
--------------------
When 'konqueror' is specified by the a command line option or a
When 'konqueror' is specified by a command line option or a
configuration variable, we launch 'kfmclient' to try to open the HTML
man page on an already opened konqueror in a new tab if possible.

Просмотреть файл

@ -43,10 +43,11 @@ 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.1/git.html[documentation for release 1.6.1]
* link:v1.6.0.2/git.html[documentation for release 1.6.0.2]
* release notes for
link:RelNotes-1.6.1.txt[1.6.1],
link:RelNotes-1.6.0.2.txt[1.6.0.2],
link:RelNotes-1.6.0.1.txt[1.6.0.1],
link:RelNotes-1.6.0.txt[1.6.0].
* link:v1.5.6.5/git.html[documentation for release 1.5.6.5]

Просмотреть файл

@ -288,13 +288,13 @@ for paths.
*.tex diff=tex
------------------------
Then, you would define "diff.tex.funcname" configuration to
Then, you would define "diff.tex.xfuncname" configuration to
specify a regular expression that matches a line that you would
want to appear as the hunk header, like this:
------------------------
[diff "tex"]
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
xfuncname = "^(\\\\(sub)*section\\{.*)$"
------------------------
Note. A single level of backslashes are eaten by the
@ -313,7 +313,7 @@ patterns are available:
- `html` suitable for HTML/XHTML documents.
- `java` suitable for source code in the Java lanugage.
- `java` suitable for source code in the Java language.
- `pascal` suitable for source code in the Pascal/Delphi language.

Просмотреть файл

@ -1,5 +1,5 @@
merge.stat::
Whether to print the diffstat between ORIG_HEAD and merge result
Whether to print the diffstat between ORIG_HEAD and the merge result
at the end of the merge. True by default.
merge.log::

Просмотреть файл

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.6.0.GIT
DEF_VER=v1.6.0.2.GIT
LF='
'

Просмотреть файл

@ -633,6 +633,8 @@ ifeq ($(uname_S),Darwin)
endif
NO_STRLCPY = YesPlease
NO_MEMMEM = YesPlease
COMPAT_CFLAGS += -Icompat/regex
COMPAT_OBJS += compat/regex/regex.o
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@ -683,6 +685,8 @@ ifeq ($(uname_S),FreeBSD)
BASIC_LDFLAGS += -L/usr/local/lib
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
THREADED_DELTA_SEARCH = YesPlease
COMPAT_CFLAGS += -Icompat/regex
COMPAT_OBJS += compat/regex/regex.o
endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
@ -710,6 +714,8 @@ ifeq ($(uname_S),AIX)
INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease
BASIC_CFLAGS += -D_LARGE_FILES
COMPAT_CFLAGS += -Icompat/regex
COMPAT_OBJS += compat/regex/regex.o
endif
ifeq ($(uname_S),GNU)
# GNU/Hurd
@ -761,10 +767,10 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_PERL_MAKEMAKER = YesPlease
NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o
EXTLIBS += -lws2_32
X = .exe
gitexecdir = ../libexec/git-core

Просмотреть файл

@ -5,26 +5,26 @@
*
* Careful: order of argument flags does matter. For example,
*
* git-checkout-index -a -f file.c
* git checkout-index -a -f file.c
*
* Will first check out all files listed in the cache (but not
* overwrite any old ones), and then force-checkout "file.c" a
* second time (ie that one _will_ overwrite any old contents
* with the same filename).
*
* Also, just doing "git-checkout-index" does nothing. You probably
* meant "git-checkout-index -a". And if you want to force it, you
* want "git-checkout-index -f -a".
* Also, just doing "git checkout-index" does nothing. You probably
* meant "git checkout-index -a". And if you want to force it, you
* want "git checkout-index -f -a".
*
* Intuitiveness is not the goal here. Repeatability is. The
* reason for the "no arguments means no work" thing is that
* from scripts you are supposed to be able to do things like
*
* find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
* find . -name '*.h' -print0 | xargs -0 git checkout-index -f --
*
* or:
*
* find . -name '*.h' -print0 | git-checkout-index -f -z --stdin
* find . -name '*.h' -print0 | git checkout-index -f -z --stdin
*
* which will force all existing *.h files to be replaced with
* their cached copies. If an empty command line implied "all",
@ -107,7 +107,7 @@ static int checkout_file(const char *name, int prefix_length)
}
if (!state.quiet) {
fprintf(stderr, "git-checkout-index: %s ", name);
fprintf(stderr, "git checkout-index: %s ", name);
if (!has_same_name)
fprintf(stderr, "is not in the cache");
else if (checkout_stage)

Просмотреть файл

@ -76,6 +76,15 @@ static int read_tree_some(struct tree *tree, const char **pathspec)
return 0;
}
static int skip_same_name(struct cache_entry *ce, int pos)
{
while (++pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name))
; /* skip */
return pos;
}
static int checkout_paths(struct tree *source_tree, const char **pathspec)
{
int pos;
@ -107,6 +116,20 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
if (report_path_error(ps_matched, pathspec, 0))
return 1;
/* Any unmerged paths? */
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
if (pathspec_match(pathspec, NULL, ce->name, 0)) {
if (!ce_stage(ce))
continue;
errs = 1;
error("path '%s' is unmerged", ce->name);
pos = skip_same_name(ce, pos) - 1;
}
}
if (errs)
return 1;
/* Now we are committed to check them out */
memset(&state, 0, sizeof(state));
state.force = 1;
@ -114,7 +137,11 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
if (pathspec_match(pathspec, NULL, ce->name, 0)) {
errs |= checkout_entry(ce, &state, NULL);
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state, NULL);
continue;
}
pos = skip_same_name(ce, pos) - 1;
}
}

Просмотреть файл

@ -24,7 +24,7 @@ static void check_valid(unsigned char *sha1, enum object_type expect)
typename(expect));
}
static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog";
static void new_parent(struct commit *parent, struct commit_list **parents_p)
{

Просмотреть файл

@ -750,7 +750,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
if (!ret && nr_heads) {
/* If the heads to pull were given, we should have
* consumed all of them by matching the remote.
* Otherwise, 'git-fetch remote no-such-ref' would
* Otherwise, 'git fetch remote no-such-ref' would
* silently succeed without issuing an error.
*/
for (i = 0; i < nr_heads; i++)

Просмотреть файл

@ -86,10 +86,10 @@ static void add_merge_config(struct ref **head,
/*
* Not fetched to a tracking branch? We need to fetch
* it anyway to allow this branch's "branch.$name.merge"
* to be honored by git-pull, but we do not have to
* to be honored by 'git pull', but we do not have to
* fail if branch.$name.merge is misconfigured to point
* at a nonexisting branch. If we were indeed called by
* git-pull, it will notice the misconfiguration because
* 'git pull', it will notice the misconfiguration because
* there is no entry in the resulting FETCH_HEAD marked
* for merging.
*/
@ -396,7 +396,7 @@ static int store_updated_refs(const char *url, const char *remote_name,
* The refs we are going to fetch are in to_fetch (nr_heads in
* total). If running
*
* $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
* $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
*
* does not error out, that means everything reachable from the
* refs we are going to fetch exists and is connected to some of

Просмотреть файл

@ -42,7 +42,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
arg++;
}
if (argc < arg + 2 - commits_on_stdin) {
usage("git-http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url");
usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url");
return 1;
}
if (commits_on_stdin) {
@ -75,7 +75,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
fprintf(stderr,
"Some loose object were found to be corrupt, but they might be just\n"
"a false '404 Not Found' error message sent with incorrect HTTP\n"
"status code. Suggest running git-fsck.\n");
"status code. Suggest running 'git fsck'.\n");
}
walker_free(walker);

Просмотреть файл

@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen,
/* Note: if ".git/hooks" file exists in the repository being
* re-initialized, /etc/core-git/templates/hooks/update would
* cause git-init to fail here. I think this is sane but
* cause "git init" to fail here. I think this is sane but
* it means that the set of templates we ship by default, along
* with the way the namespace under .git/ is organized, should
* be really carefully chosen.

Просмотреть файл

@ -23,7 +23,7 @@
#endif
static const char pack_usage[] = "\
git-pack-objects [{ -q | --progress | --all-progress }] \n\
git pack-objects [{ -q | --progress | --all-progress }] \n\
[--max-pack-size=N] [--local] [--incremental] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
@ -1872,7 +1872,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str
/*
* Compare the objects in the offset order, in order to emulate the
* "git-rev-list --objects" output that produced the pack originally.
* "git rev-list --objects" output that produced the pack originally.
*/
static int ofscmp(const void *a_, const void *b_)
{

Просмотреть файл

@ -64,7 +64,7 @@ static void prime_cache_tree(void)
}
static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static struct lock_file lock_file;

Просмотреть файл

@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p)
static void show_object(struct object_array_entry *p)
{
/* An object with name "foo\n0000000..." can be used to
* confuse downstream git-pack-objects very badly.
* confuse downstream "git pack-objects" very badly.
*/
const char *ep = strchr(p->name, '\n');

Просмотреть файл

@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only)
"from both the file and the HEAD\n"
"(use -f to force removal)", name);
else if (!index_only) {
/* It's not dangerous to git-rm --cached a
/* It's not dangerous to "git rm --cached" a
* file if the index matches the file or the
* HEAD, since it means the deleted content is
* still available somewhere.

Просмотреть файл

@ -43,7 +43,7 @@ static int pack_objects(int fd, struct ref *refs)
po.out = fd;
po.git_cmd = 1;
if (start_command(&po))
die("git-pack-objects failed (%s)", strerror(errno));
die("git pack-objects failed (%s)", strerror(errno));
/*
* We feed the pack-objects we just spawned with revision

Просмотреть файл

@ -9,26 +9,26 @@
static const char tar_tree_usage[] =
"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
"*** Note that this command is now deprecated; use git-archive instead.";
"*** Note that this command is now deprecated; use \"git archive\" instead.";
int cmd_tar_tree(int argc, const char **argv, const char *prefix)
{
/*
* git-tar-tree is now a wrapper around git-archive --format=tar
* "git tar-tree" is now a wrapper around "git archive --format=tar"
*
* $0 --remote=<repo> arg... ==>
* git-archive --format=tar --remote=<repo> arg...
* git archive --format=tar --remote=<repo> arg...
* $0 tree-ish ==>
* git-archive --format=tar tree-ish
* git archive --format=tar tree-ish
* $0 tree-ish basedir ==>
* git-archive --format-tar --prefix=basedir tree-ish
* git archive --format-tar --prefix=basedir tree-ish
*/
int i;
const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
char *basedir_arg;
int nargc = 0;
nargv[nargc++] = "git-archive";
nargv[nargc++] = "archive";
nargv[nargc++] = "--format=tar";
if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
nargv[nargc] = NULL;
fprintf(stderr,
"*** git-tar-tree is now deprecated.\n"
"*** Running git-archive instead.\n***");
"*** \"git tar-tree\" is now deprecated.\n"
"*** Running \"git archive\" instead.\n***");
for (i = 0; i < nargc; i++) {
fputc(' ', stderr);
sq_quote_print(stderr, nargv[i]);

Просмотреть файл

@ -13,7 +13,7 @@
#include "fsck.h"
static int dry_run, quiet, recover, has_errors, strict;
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];

Просмотреть файл

@ -14,7 +14,7 @@
* Default to not allowing changes to the list of files. The
* tool doesn't actually care, but this makes it harder to add
* files to the revision control by mistake by doing something
* like "git-update-index *" and suddenly having all the object
* like "git update-index *" and suddenly having all the object
* files be revision controlled.
*/
static int allow_add;
@ -313,18 +313,18 @@ static void read_index_info(int line_termination)
/* This reads lines formatted in one of three formats:
*
* (1) mode SP sha1 TAB path
* The first format is what "git-apply --index-info"
* The first format is what "git apply --index-info"
* reports, and used to reconstruct a partial tree
* that is used for phony merge base tree when falling
* back on 3-way merge.
*
* (2) mode SP type SP sha1 TAB path
* The second format is to stuff git-ls-tree output
* The second format is to stuff "git ls-tree" output
* into the index file.
*
* (3) mode SP sha1 SP stage TAB path
* This format is to put higher order stages into the
* index file and matches git-ls-files --stage output.
* index file and matches "git ls-files --stage" output.
*/
errno = 0;
ul = strtoul(buf.buf, &ptr, 8);

Просмотреть файл

@ -496,6 +496,18 @@ static int hunk_comment_line(const char *bol)
return (isalpha(ch) || ch == '_' || ch == '$');
}
static void show_line_to_eol(const char *line, int len, const char *reset)
{
int saw_cr_at_eol = 0;
if (len < 0)
len = strlen(line);
saw_cr_at_eol = (len && line[len-1] == '\r');
printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
reset,
saw_cr_at_eol ? "\r" : "");
}
static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
int use_color)
{
@ -589,7 +601,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
else
putchar(' ');
}
printf("%s%s\n", ll->line, c_reset);
show_line_to_eol(ll->line, -1, c_reset);
ll = ll->next;
}
if (cnt < lno)
@ -613,7 +625,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
putchar(' ');
p_mask <<= 1;
}
printf("%.*s%s\n", sl->len, sl->bol, c_reset);
show_line_to_eol(sl->bol, sl->len, c_reset);
}
}
}

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

94
diff.c
Просмотреть файл

@ -95,32 +95,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
* to define a customized regexp to find the beginning of a function to
* be used for hunk header lines of "diff -p" style output.
*/
static struct funcname_pattern {
struct funcname_pattern_entry {
char *name;
char *pattern;
struct funcname_pattern *next;
int cflags;
};
static struct funcname_pattern_list {
struct funcname_pattern_list *next;
struct funcname_pattern_entry e;
} *funcname_pattern_list;
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
{
const char *name;
int namelen;
struct funcname_pattern *pp;
struct funcname_pattern_list *pp;
name = var + 5; /* "diff." */
namelen = ep - name;
for (pp = funcname_pattern_list; pp; pp = pp->next)
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
break;
if (!pp) {
pp = xcalloc(1, sizeof(*pp));
pp->name = xmemdupz(name, namelen);
pp->e.name = xmemdupz(name, namelen);
pp->next = funcname_pattern_list;
funcname_pattern_list = pp;
}
free(pp->pattern);
pp->pattern = xstrdup(value);
free(pp->e.pattern);
pp->e.pattern = xstrdup(value);
pp->e.cflags = cflags;
return 0;
}
@ -189,7 +194,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
if (!strcmp(ep, ".funcname")) {
if (!value)
return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value);
return parse_funcname_pattern(var, ep, value,
0);
} else if (!strcmp(ep, ".xfuncname")) {
if (!value)
return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value,
REG_EXTENDED);
}
}
}
@ -513,13 +524,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
{
int has_trailing_newline = (len > 0 && line[len-1] == '\n');
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);
}
@ -1375,42 +1393,40 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->is_binary;
}
static const char *funcname_pattern(const char *ident)
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
{
struct funcname_pattern *pp;
struct funcname_pattern_list *pp;
for (pp = funcname_pattern_list; pp; pp = pp->next)
if (!strcmp(ident, pp->name))
return pp->pattern;
if (!strcmp(ident, pp->e.name))
return &pp->e;
return NULL;
}
static struct builtin_funcname_pattern {
const char *name;
const char *pattern;
} builtin_funcname_pattern[] = {
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
{ "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" },
static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 },
{ "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$", 0 },
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
"new\\|return\\|switch\\|throw\\|while\\)\n"
"^[ ]*\\(\\([ ]*"
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
"[ ]*([^;]*\\)$" },
"[ ]*([^;]*\\)$", 0 },
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
"destructor\\|interface\\|implementation\\|"
"initialization\\|finalization\\)[ \t]*.*\\)$"
"\\|"
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
},
{ "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" },
{ "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" },
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$",
0 },
{ "php", "^[\t ]*\\(\\(function\\|class\\).*\\)", 0 },
{ "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$", 0 },
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 },
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 },
};
static const char *diff_funcname_pattern(struct diff_filespec *one)
static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
{
const char *ident, *pattern;
const char *ident;
const struct funcname_pattern_entry *pe;
int i;
diff_filespec_check_attr(one);
@ -1425,9 +1441,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
return funcname_pattern("default");
/* Look up custom "funcname.$ident" regexp from config. */
pattern = funcname_pattern(ident);
if (pattern)
return pattern;
pe = funcname_pattern(ident);
if (pe)
return pe;
/*
* And define built-in fallback patterns here. Note that
@ -1435,7 +1451,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
*/
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
if (!strcmp(ident, builtin_funcname_pattern[i].name))
return builtin_funcname_pattern[i].pattern;
return &builtin_funcname_pattern[i];
return NULL;
}
@ -1513,11 +1529,11 @@ static void builtin_diff(const char *name_a,
xdemitconf_t xecfg;
xdemitcb_t ecb;
struct emit_callback ecbdata;
const char *funcname_pattern;
const struct funcname_pattern_entry *pe;
funcname_pattern = diff_funcname_pattern(one);
if (!funcname_pattern)
funcname_pattern = diff_funcname_pattern(two);
pe = diff_funcname_pattern(one);
if (!pe)
pe = diff_funcname_pattern(two);
memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata));
@ -1529,8 +1545,8 @@ static void builtin_diff(const char *name_a,
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
if (funcname_pattern)
xdiff_set_find_func(&xecfg, funcname_pattern);
if (pe)
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
if (!diffopts)
;
else if (!prefixcmp(diffopts, "--unified="))

Просмотреть файл

@ -3304,7 +3304,7 @@ sub close_file {
my $out = syswrite($tmp_fh, $str, $res);
defined($out) && $out == $res
or croak("write ",
$tmp_fh->filename,
Git::temp_path($tmp_fh),
": $!\n");
}
defined $res or croak $!;
@ -3315,7 +3315,7 @@ sub close_file {
}
$hash = $::_repository->hash_and_insert_object(
$fh->filename);
Git::temp_path($fh));
$hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
Git::temp_release($fb->{base}, 1);
@ -4424,7 +4424,7 @@ sub config_pager {
sub run_pager {
return unless -t *STDOUT && defined $pager;
pipe my $rfd, my $wfd or return;
pipe my ($rfd, $wfd) or return;
defined(my $pid = fork) or ::fatal "Can't fork: $!";
if (!$pid) {
open STDOUT, '>&', $wfd or

Просмотреть файл

@ -58,7 +58,7 @@ require Exporter;
command_bidi_pipe command_close_bidi_pipe
version exec_path hash_object git_cmd_try
remote_refs
temp_acquire temp_release temp_reset);
temp_acquire temp_release temp_reset temp_path);
=head1 DESCRIPTION
@ -937,7 +937,7 @@ sub _close_cat_blob {
{ # %TEMP_* Lexical Context
my (%TEMP_LOCKS, %TEMP_FILES);
my (%TEMP_FILEMAP, %TEMP_FILES);
=item temp_acquire ( NAME )
@ -965,7 +965,7 @@ sub temp_acquire {
my $temp_fd = _temp_cache($name);
$TEMP_LOCKS{$temp_fd} = 1;
$TEMP_FILES{$temp_fd}{locked} = 1;
$temp_fd;
}
@ -991,16 +991,16 @@ the same string.
sub temp_release {
my ($self, $temp_fd, $trunc) = _maybe_self(@_);
if (ref($temp_fd) ne 'File::Temp') {
if (exists $TEMP_FILEMAP{$temp_fd}) {
$temp_fd = $TEMP_FILES{$temp_fd};
}
unless ($TEMP_LOCKS{$temp_fd}) {
unless ($TEMP_FILES{$temp_fd}{locked}) {
carp "Attempt to release temp file '",
$temp_fd, "' that has not been locked";
}
temp_reset($temp_fd) if $trunc and $temp_fd->opened;
$TEMP_LOCKS{$temp_fd} = 0;
$TEMP_FILES{$temp_fd}{locked} = 0;
undef;
}
@ -1009,9 +1009,9 @@ sub _temp_cache {
_verify_require();
my $temp_fd = \$TEMP_FILES{$name};
my $temp_fd = \$TEMP_FILEMAP{$name};
if (defined $$temp_fd and $$temp_fd->opened) {
if ($TEMP_LOCKS{$$temp_fd}) {
if ($TEMP_FILES{$$temp_fd}{locked}) {
throw Error::Simple("Temp file with moniker '",
$name, "' already in use");
}
@ -1021,12 +1021,13 @@ sub _temp_cache {
carp "Temp file '", $name,
"' was closed. Opening replacement.";
}
$$temp_fd = File::Temp->new(
TEMPLATE => 'Git_XXXXXX',
DIR => File::Spec->tmpdir
my $fname;
($$temp_fd, $fname) = File::Temp->tempfile(
'Git_XXXXXX', UNLINK => 1
) or throw Error::Simple("couldn't open new temp file");
$$temp_fd->autoflush;
binmode $$temp_fd;
$TEMP_FILES{$$temp_fd}{fname} = $fname;
}
$$temp_fd;
}
@ -1053,8 +1054,25 @@ sub temp_reset {
or throw Error::Simple("expected file position to be reset");
}
=item temp_path ( NAME )
=item temp_path ( FILEHANDLE )
Returns the filename associated with the given tempfile.
=cut
sub temp_path {
my ($self, $temp_fd) = _maybe_self(@_);
if (exists $TEMP_FILEMAP{$temp_fd}) {
$temp_fd = $TEMP_FILEMAP{$temp_fd};
}
$TEMP_FILES{$temp_fd}{fname};
}
sub END {
unlink values %TEMP_FILES if %TEMP_FILES;
unlink values %TEMP_FILEMAP if %TEMP_FILEMAP;
}
} # %TEMP_* Lexical Context

Просмотреть файл

@ -57,4 +57,10 @@ test_expect_success 'last regexp must not be negated' '
test_must_fail git diff --no-index Beer.java Beer-correct.java
'
test_expect_success 'alternation in pattern' '
git config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
git diff --no-index Beer.java Beer-correct.java |
grep "^@@.*@@ public static void main("
'
test_done

Просмотреть файл

@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' '
'
test_expect_success 'do not color trailing cr in context' '
git config --unset core.whitespace
rm -f .gitattributes &&
echo AAAQ | tr Q "\015" >G &&
git add G &&
echo BBBQ | tr Q "\015" >>G
git diff --color G | tr "\015" Q >output &&
grep "BBB.*${blue_grep}Q" output &&
grep "AAA.*\[mQ" output
'
test_done

Просмотреть файл

@ -369,4 +369,26 @@ test_expect_success \
'checkout with --track, but without -b, fails with too short tracked name' '
test_must_fail git checkout --track renamer'
test_expect_success 'checkout an unmerged path should fail' '
rm -f .git/index &&
O=$(echo original | git hash-object -w --stdin) &&
A=$(echo ourside | git hash-object -w --stdin) &&
B=$(echo theirside | git hash-object -w --stdin) &&
(
echo "100644 $A 0 fild" &&
echo "100644 $O 1 file" &&
echo "100644 $A 2 file" &&
echo "100644 $B 3 file" &&
echo "100644 $A 0 filf"
) | git update-index --index-info &&
echo "none of the above" >sample &&
cat sample >fild &&
cat sample >file &&
cat sample >filf &&
test_must_fail git checkout fild file filf &&
test_cmp sample fild &&
test_cmp sample filf &&
test_cmp sample file
'
test_done

Просмотреть файл

@ -141,7 +141,7 @@ EOF
test_expect_success \
'validate git rev-list output.' \
'diff current expected'
'test_cmp expected current'
test_expect_success 'partial commit that involves removal (1)' '
@ -151,7 +151,7 @@ test_expect_success 'partial commit that involves removal (1)' '
git commit -m "Partial: add elif" elif &&
git diff-tree --name-status HEAD^ HEAD >current &&
echo "A elif" >expected &&
diff expected current
test_cmp expected current
'
@ -160,7 +160,7 @@ test_expect_success 'partial commit that involves removal (2)' '
git commit -m "Partial: remove file" file &&
git diff-tree --name-status HEAD^ HEAD >current &&
echo "D file" >expected &&
diff expected current
test_cmp expected current
'
@ -171,7 +171,7 @@ test_expect_success 'partial commit that involves removal (3)' '
git commit -m "Partial: modify elif" elif &&
git diff-tree --name-status HEAD^ HEAD >current &&
echo "M elif" >expected &&
diff expected current
test_cmp expected current
'
@ -187,7 +187,7 @@ test_expect_success 'amend commit to fix author' '
expected &&
git commit --amend --author="$author" &&
git cat-file -p HEAD > current &&
diff expected current
test_cmp expected current
'
@ -256,7 +256,7 @@ test_expect_success 'amend commit to fix author' '
expected &&
git commit --amend --author="$author" &&
git cat-file -p HEAD > current &&
diff expected current
test_cmp expected current
'

Просмотреть файл

@ -9,7 +9,6 @@ use Test::More qw(no_plan);
use Cwd;
use File::Basename;
use File::Temp;
BEGIN { use_ok('Git') }
@ -35,7 +34,7 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color");
# Failure cases for config:
# Save and restore STDERR; we will probably extract this into a
# "dies_ok" method and possibly move the STDERR handling to Git.pm.
open our $tmpstderr, ">&", STDERR or die "cannot save STDERR"; close STDERR;
open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR;
eval { $r->config("test.dupstring") };
ok($@, "config: duplicate entry in scalar context fails");
eval { $r->config_bool("test.boolother") };
@ -66,21 +65,25 @@ is($r->ident_person("Name", "email", "123 +0000"), "Name <email>",
# objects and hashes
ok(our $file1hash = $r->command_oneline('rev-parse', "HEAD:file1"), "(get file hash)");
our $tmpfile = File::Temp->new;
is($r->cat_blob($file1hash, $tmpfile), 15, "cat_blob: size");
my $tmpfile = "file.tmp";
open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!";
is($r->cat_blob($file1hash, \*TEMPFILE), 15, "cat_blob: size");
our $blobcontents;
{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; }
{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; }
is($blobcontents, "changed file 1\n", "cat_blob: data");
seek $tmpfile, 0, 0;
close TEMPFILE or die "Failed writing to $tmpfile: $!";
is(Git::hash_object("blob", $tmpfile), $file1hash, "hash_object: roundtrip");
$tmpfile = File::Temp->new();
print $tmpfile my $test_text = "test blob, to be inserted\n";
open TEMPFILE, ">$tmpfile" or die "Can't open $tmpfile: $!";
print TEMPFILE my $test_text = "test blob, to be inserted\n";
close TEMPFILE or die "Failed writing to $tmpfile: $!";
like(our $newhash = $r->hash_and_insert_object($tmpfile), qr/[0-9a-fA-F]{40}/,
"hash_and_insert_object: returns hash");
$tmpfile = File::Temp->new;
is($r->cat_blob($newhash, $tmpfile), length $test_text, "cat_blob: roundtrip size");
{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; }
open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!";
is($r->cat_blob($newhash, \*TEMPFILE), length $test_text, "cat_blob: roundtrip size");
{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; }
is($blobcontents, $test_text, "cat_blob: roundtrip data");
close TEMPFILE;
unlink $tmpfile;
# paths
is($r->repo_path, "./.git", "repo_path");

Просмотреть файл

@ -218,7 +218,7 @@ static long ff_regexp(const char *line, long len,
return result;
}
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
{
int i;
struct ff_regs *regs;
@ -243,7 +243,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
expression = buffer = xstrndup(value, ep - value);
else
expression = value;
if (regcomp(&reg->re, expression, 0))
if (regcomp(&reg->re, expression, cflags))
die("Invalid regexp to look for hunk header: %s", expression);
free(buffer);
value = ep + 1;

Просмотреть файл

@ -16,6 +16,6 @@ int parse_hunk_header(char *line, int len,
int read_mmfile(mmfile_t *ptr, const char *filename);
int buffer_is_binary(const char *ptr, unsigned long size);
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line);
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
#endif