Merge branches 'lt/crlf' and 'jc/apply-config'
* lt/crlf: Teach core.autocrlf to 'git apply' t0020: add test for auto-crlf Make AutoCRLF ternary variable. Lazy man's auto-CRLF * jc/apply-config: t4119: test autocomputing -p<n> for traditional diff input. git-apply: guess correct -p<n> value for non-git patches. git-apply: notice "diff --git" patch again Fix botched "leak fix" t4119: add test for traditional patch and different p_value apply: fix memory leak in prefix_one() git-apply: require -p<n> when working in a subdirectory. git-apply: do not lose cwd when run from a subdirectory. Teach 'git apply' to look at $HOME/.gitconfig even outside of a repository Teach 'git apply' to look at $GIT_DIR/config
This commit is contained in:
commit
ef1a5c2fa8
3
Makefile
3
Makefile
@ -266,7 +266,8 @@ LIB_OBJS = \
|
|||||||
revision.o pager.o tree-walk.o xdiff-interface.o \
|
revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||||
write_or_die.o trace.o list-objects.o grep.o \
|
write_or_die.o trace.o list-objects.o grep.o \
|
||||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o
|
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
|
||||||
|
convert.o
|
||||||
|
|
||||||
BUILTIN_OBJS = \
|
BUILTIN_OBJS = \
|
||||||
builtin-add.o \
|
builtin-add.o \
|
||||||
|
153
builtin-apply.c
153
builtin-apply.c
@ -28,6 +28,7 @@ static int newfd = -1;
|
|||||||
|
|
||||||
static int unidiff_zero;
|
static int unidiff_zero;
|
||||||
static int p_value = 1;
|
static int p_value = 1;
|
||||||
|
static int p_value_known;
|
||||||
static int check_index;
|
static int check_index;
|
||||||
static int write_index;
|
static int write_index;
|
||||||
static int cached;
|
static int cached;
|
||||||
@ -144,6 +145,7 @@ struct patch {
|
|||||||
unsigned long deflate_origlen;
|
unsigned long deflate_origlen;
|
||||||
int lines_added, lines_deleted;
|
int lines_added, lines_deleted;
|
||||||
int score;
|
int score;
|
||||||
|
unsigned int is_toplevel_relative:1;
|
||||||
unsigned int inaccurate_eof:1;
|
unsigned int inaccurate_eof:1;
|
||||||
unsigned int is_binary:1;
|
unsigned int is_binary:1;
|
||||||
unsigned int is_copy:1;
|
unsigned int is_copy:1;
|
||||||
@ -311,11 +313,54 @@ static char * find_name(const char *line, char *def, int p_value, int terminate)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int count_slashes(const char *cp)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
while ((ch = *cp++))
|
||||||
|
if (ch == '/')
|
||||||
|
cnt++;
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the string after "--- " or "+++ ", guess the appropriate
|
||||||
|
* p_value for the given patch.
|
||||||
|
*/
|
||||||
|
static int guess_p_value(const char *nameline)
|
||||||
|
{
|
||||||
|
char *name, *cp;
|
||||||
|
int val = -1;
|
||||||
|
|
||||||
|
if (is_dev_null(nameline))
|
||||||
|
return -1;
|
||||||
|
name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
|
||||||
|
if (!name)
|
||||||
|
return -1;
|
||||||
|
cp = strchr(name, '/');
|
||||||
|
if (!cp)
|
||||||
|
val = 0;
|
||||||
|
else if (prefix) {
|
||||||
|
/*
|
||||||
|
* Does it begin with "a/$our-prefix" and such? Then this is
|
||||||
|
* very likely to apply to our directory.
|
||||||
|
*/
|
||||||
|
if (!strncmp(name, prefix, prefix_length))
|
||||||
|
val = count_slashes(prefix);
|
||||||
|
else {
|
||||||
|
cp++;
|
||||||
|
if (!strncmp(cp, prefix, prefix_length))
|
||||||
|
val = count_slashes(prefix) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the name etc info from the --/+++ lines of a traditional patch header
|
* Get the name etc info from the --/+++ lines of a traditional patch header
|
||||||
*
|
*
|
||||||
* NOTE! This hardcodes "-p1" behaviour in filename detection.
|
|
||||||
*
|
|
||||||
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
|
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
|
||||||
* files, we can happily check the index for a match, but for creating a
|
* files, we can happily check the index for a match, but for creating a
|
||||||
* new file we should try to match whatever "patch" does. I have no idea.
|
* new file we should try to match whatever "patch" does. I have no idea.
|
||||||
@ -326,6 +371,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
|
|||||||
|
|
||||||
first += 4; /* skip "--- " */
|
first += 4; /* skip "--- " */
|
||||||
second += 4; /* skip "+++ " */
|
second += 4; /* skip "+++ " */
|
||||||
|
if (!p_value_known) {
|
||||||
|
int p, q;
|
||||||
|
p = guess_p_value(first);
|
||||||
|
q = guess_p_value(second);
|
||||||
|
if (p < 0) p = q;
|
||||||
|
if (0 <= p && p == q) {
|
||||||
|
p_value = p;
|
||||||
|
p_value_known = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (is_dev_null(first)) {
|
if (is_dev_null(first)) {
|
||||||
patch->is_new = 1;
|
patch->is_new = 1;
|
||||||
patch->is_delete = 0;
|
patch->is_delete = 0;
|
||||||
@ -787,6 +842,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
|||||||
{
|
{
|
||||||
unsigned long offset, len;
|
unsigned long offset, len;
|
||||||
|
|
||||||
|
patch->is_toplevel_relative = 0;
|
||||||
patch->is_rename = patch->is_copy = 0;
|
patch->is_rename = patch->is_copy = 0;
|
||||||
patch->is_new = patch->is_delete = -1;
|
patch->is_new = patch->is_delete = -1;
|
||||||
patch->old_mode = patch->new_mode = 0;
|
patch->old_mode = patch->new_mode = 0;
|
||||||
@ -831,6 +887,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
|||||||
die("git diff header lacks filename information (line %d)", linenr);
|
die("git diff header lacks filename information (line %d)", linenr);
|
||||||
patch->old_name = patch->new_name = patch->def_name;
|
patch->old_name = patch->new_name = patch->def_name;
|
||||||
}
|
}
|
||||||
|
patch->is_toplevel_relative = 1;
|
||||||
*hdrsize = git_hdr_len;
|
*hdrsize = git_hdr_len;
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
@ -1393,28 +1450,39 @@ static void show_stats(struct patch *patch)
|
|||||||
free(qname);
|
free(qname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
|
static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
unsigned long got;
|
unsigned long got;
|
||||||
|
unsigned long nsize;
|
||||||
|
char *nbuf;
|
||||||
|
unsigned long size = *size_p;
|
||||||
|
char *buf = *buf_p;
|
||||||
|
|
||||||
switch (st->st_mode & S_IFMT) {
|
switch (st->st_mode & S_IFMT) {
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
return readlink(path, buf, size);
|
return readlink(path, buf, size) != size;
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
fd = open(path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return error("unable to open %s", path);
|
return error("unable to open %s", path);
|
||||||
got = 0;
|
got = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int ret = xread(fd, (char *) buf + got, size - got);
|
int ret = xread(fd, buf + got, size - got);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
break;
|
break;
|
||||||
got += ret;
|
got += ret;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
return got;
|
nsize = got;
|
||||||
|
nbuf = buf;
|
||||||
|
if (convert_to_git(path, &nbuf, &nsize)) {
|
||||||
|
free(buf);
|
||||||
|
*buf_p = nbuf;
|
||||||
|
*alloc_p = nsize;
|
||||||
|
*size_p = nsize;
|
||||||
|
}
|
||||||
|
return got != size;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1910,7 +1978,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
|||||||
size = st->st_size;
|
size = st->st_size;
|
||||||
alloc = size + 8192;
|
alloc = size + 8192;
|
||||||
buf = xmalloc(alloc);
|
buf = xmalloc(alloc);
|
||||||
if (read_old_data(st, patch->old_name, buf, alloc) != size)
|
if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
|
||||||
return error("read of %s failed", patch->old_name);
|
return error("read of %s failed", patch->old_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2232,7 +2300,7 @@ static void patch_stats(struct patch *patch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_file(struct patch *patch)
|
static void remove_file(struct patch *patch, int rmdir_empty)
|
||||||
{
|
{
|
||||||
if (write_index) {
|
if (write_index) {
|
||||||
if (remove_file_from_cache(patch->old_name) < 0)
|
if (remove_file_from_cache(patch->old_name) < 0)
|
||||||
@ -2240,7 +2308,7 @@ static void remove_file(struct patch *patch)
|
|||||||
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
|
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
|
||||||
}
|
}
|
||||||
if (!cached) {
|
if (!cached) {
|
||||||
if (!unlink(patch->old_name)) {
|
if (!unlink(patch->old_name) && rmdir_empty) {
|
||||||
char *name = xstrdup(patch->old_name);
|
char *name = xstrdup(patch->old_name);
|
||||||
char *end = strrchr(name, '/');
|
char *end = strrchr(name, '/');
|
||||||
while (end) {
|
while (end) {
|
||||||
@ -2282,12 +2350,22 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
|
|||||||
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
|
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
char *nbuf;
|
||||||
|
unsigned long nsize;
|
||||||
|
|
||||||
if (S_ISLNK(mode))
|
if (S_ISLNK(mode))
|
||||||
/* Although buf:size is counted string, it also is NUL
|
/* Although buf:size is counted string, it also is NUL
|
||||||
* terminated.
|
* terminated.
|
||||||
*/
|
*/
|
||||||
return symlink(buf, path);
|
return symlink(buf, path);
|
||||||
|
nsize = size;
|
||||||
|
nbuf = (char *) buf;
|
||||||
|
if (convert_to_working_tree(path, &nbuf, &nsize)) {
|
||||||
|
free((char *) buf);
|
||||||
|
buf = nbuf;
|
||||||
|
size = nsize;
|
||||||
|
}
|
||||||
|
|
||||||
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
|
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -2373,7 +2451,7 @@ static void write_out_one_result(struct patch *patch, int phase)
|
|||||||
{
|
{
|
||||||
if (patch->is_delete > 0) {
|
if (patch->is_delete > 0) {
|
||||||
if (phase == 0)
|
if (phase == 0)
|
||||||
remove_file(patch);
|
remove_file(patch, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (patch->is_new > 0 || patch->is_copy) {
|
if (patch->is_new > 0 || patch->is_copy) {
|
||||||
@ -2386,7 +2464,7 @@ static void write_out_one_result(struct patch *patch, int phase)
|
|||||||
* thing: remove the old, write the new
|
* thing: remove the old, write the new
|
||||||
*/
|
*/
|
||||||
if (phase == 0)
|
if (phase == 0)
|
||||||
remove_file(patch);
|
remove_file(patch, 0);
|
||||||
if (phase == 1)
|
if (phase == 1)
|
||||||
create_file(patch);
|
create_file(patch);
|
||||||
}
|
}
|
||||||
@ -2508,6 +2586,32 @@ static int use_patch(struct patch *p)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prefix_one(char **name)
|
||||||
|
{
|
||||||
|
char *old_name = *name;
|
||||||
|
if (!old_name)
|
||||||
|
return;
|
||||||
|
*name = xstrdup(prefix_filename(prefix, prefix_length, *name));
|
||||||
|
free(old_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prefix_patches(struct patch *p)
|
||||||
|
{
|
||||||
|
if (!prefix || p->is_toplevel_relative)
|
||||||
|
return;
|
||||||
|
for ( ; p; p = p->next) {
|
||||||
|
if (p->new_name == p->old_name) {
|
||||||
|
char *prefixed = p->new_name;
|
||||||
|
prefix_one(&prefixed);
|
||||||
|
p->new_name = p->old_name = prefixed;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prefix_one(&p->new_name);
|
||||||
|
prefix_one(&p->old_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||||
{
|
{
|
||||||
unsigned long offset, size;
|
unsigned long offset, size;
|
||||||
@ -2530,11 +2634,14 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
|||||||
break;
|
break;
|
||||||
if (apply_in_reverse)
|
if (apply_in_reverse)
|
||||||
reverse_patches(patch);
|
reverse_patches(patch);
|
||||||
|
if (prefix)
|
||||||
|
prefix_patches(patch);
|
||||||
if (use_patch(patch)) {
|
if (use_patch(patch)) {
|
||||||
patch_stats(patch);
|
patch_stats(patch);
|
||||||
*listp = patch;
|
*listp = patch;
|
||||||
listp = &patch->next;
|
listp = &patch->next;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
/* perhaps free it a bit better? */
|
/* perhaps free it a bit better? */
|
||||||
free(patch);
|
free(patch);
|
||||||
skipped_patch++;
|
skipped_patch++;
|
||||||
@ -2595,9 +2702,16 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
|||||||
int read_stdin = 1;
|
int read_stdin = 1;
|
||||||
int inaccurate_eof = 0;
|
int inaccurate_eof = 0;
|
||||||
int errs = 0;
|
int errs = 0;
|
||||||
|
int is_not_gitdir = 0;
|
||||||
|
|
||||||
const char *whitespace_option = NULL;
|
const char *whitespace_option = NULL;
|
||||||
|
|
||||||
|
prefix = setup_git_directory_gently(&is_not_gitdir);
|
||||||
|
prefix_length = prefix ? strlen(prefix) : 0;
|
||||||
|
git_config(git_apply_config);
|
||||||
|
if (apply_default_whitespace)
|
||||||
|
parse_whitespace_option(apply_default_whitespace);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
char *end;
|
char *end;
|
||||||
@ -2617,6 +2731,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
|||||||
}
|
}
|
||||||
if (!prefixcmp(arg, "-p")) {
|
if (!prefixcmp(arg, "-p")) {
|
||||||
p_value = atoi(arg + 2);
|
p_value = atoi(arg + 2);
|
||||||
|
p_value_known = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--no-add")) {
|
if (!strcmp(arg, "--no-add")) {
|
||||||
@ -2648,10 +2763,14 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--index")) {
|
if (!strcmp(arg, "--index")) {
|
||||||
|
if (is_not_gitdir)
|
||||||
|
die("--index outside a repository");
|
||||||
check_index = 1;
|
check_index = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--cached")) {
|
if (!strcmp(arg, "--cached")) {
|
||||||
|
if (is_not_gitdir)
|
||||||
|
die("--cached outside a repository");
|
||||||
check_index = 1;
|
check_index = 1;
|
||||||
cached = 1;
|
cached = 1;
|
||||||
continue;
|
continue;
|
||||||
@ -2700,14 +2819,6 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
|||||||
inaccurate_eof = 1;
|
inaccurate_eof = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_index && prefix_length < 0) {
|
|
||||||
prefix = setup_git_directory();
|
|
||||||
prefix_length = prefix ? strlen(prefix) : 0;
|
|
||||||
git_config(git_apply_config);
|
|
||||||
if (!whitespace_option && apply_default_whitespace)
|
|
||||||
parse_whitespace_option(apply_default_whitespace);
|
|
||||||
}
|
|
||||||
if (0 < prefix_length)
|
if (0 < prefix_length)
|
||||||
arg = prefix_filename(prefix, prefix_length, arg);
|
arg = prefix_filename(prefix, prefix_length, arg);
|
||||||
|
|
||||||
|
5
cache.h
5
cache.h
@ -211,6 +211,7 @@ extern const char *apply_default_whitespace;
|
|||||||
extern int zlib_compression_level;
|
extern int zlib_compression_level;
|
||||||
extern size_t packed_git_window_size;
|
extern size_t packed_git_window_size;
|
||||||
extern size_t packed_git_limit;
|
extern size_t packed_git_limit;
|
||||||
|
extern int auto_crlf;
|
||||||
|
|
||||||
#define GIT_REPO_VERSION 0
|
#define GIT_REPO_VERSION 0
|
||||||
extern int repository_format_version;
|
extern int repository_format_version;
|
||||||
@ -478,4 +479,8 @@ extern int nfvasprintf(char **str, const char *fmt, va_list va);
|
|||||||
extern void trace_printf(const char *format, ...);
|
extern void trace_printf(const char *format, ...);
|
||||||
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
|
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
|
||||||
|
|
||||||
|
/* convert.c */
|
||||||
|
extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep);
|
||||||
|
extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep);
|
||||||
|
|
||||||
#endif /* CACHE_H */
|
#endif /* CACHE_H */
|
||||||
|
9
config.c
9
config.c
@ -326,6 +326,15 @@ int git_default_config(const char *var, const char *value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(var, "core.autocrlf")) {
|
||||||
|
if (value && !strcasecmp(value, "input")) {
|
||||||
|
auto_crlf = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto_crlf = git_config_bool(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(var, "user.name")) {
|
if (!strcmp(var, "user.name")) {
|
||||||
strlcpy(git_default_name, value, sizeof(git_default_name));
|
strlcpy(git_default_name, value, sizeof(git_default_name));
|
||||||
return 0;
|
return 0;
|
||||||
|
186
convert.c
Normal file
186
convert.c
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#include "cache.h"
|
||||||
|
/*
|
||||||
|
* convert.c - convert a file when checking it out and checking it in.
|
||||||
|
*
|
||||||
|
* This should use the pathname to decide on whether it wants to do some
|
||||||
|
* more interesting conversions (automatic gzip/unzip, general format
|
||||||
|
* conversions etc etc), but by default it just does automatic CRLF<->LF
|
||||||
|
* translation when the "auto_crlf" option is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct text_stat {
|
||||||
|
/* CR, LF and CRLF counts */
|
||||||
|
unsigned cr, lf, crlf;
|
||||||
|
|
||||||
|
/* These are just approximations! */
|
||||||
|
unsigned printable, nonprintable;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
|
||||||
|
{
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
memset(stats, 0, sizeof(*stats));
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
unsigned char c = buf[i];
|
||||||
|
if (c == '\r') {
|
||||||
|
stats->cr++;
|
||||||
|
if (i+1 < size && buf[i+1] == '\n')
|
||||||
|
stats->crlf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
stats->lf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == 127)
|
||||||
|
/* DEL */
|
||||||
|
stats->nonprintable++;
|
||||||
|
else if (c < 32) {
|
||||||
|
switch (c) {
|
||||||
|
/* BS, HT, ESC and FF */
|
||||||
|
case '\b': case '\t': case '\033': case '\014':
|
||||||
|
stats->printable++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stats->nonprintable++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stats->printable++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The same heuristics as diff.c::mmfile_is_binary()
|
||||||
|
*/
|
||||||
|
static int is_binary(unsigned long size, struct text_stat *stats)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((stats->printable >> 7) < stats->nonprintable)
|
||||||
|
return 1;
|
||||||
|
/*
|
||||||
|
* Other heuristics? Average line length might be relevant,
|
||||||
|
* as might LF vs CR vs CRLF counts..
|
||||||
|
*
|
||||||
|
* NOTE! It might be normal to have a low ratio of CRLF to LF
|
||||||
|
* (somebody starts with a LF-only file and edits it with an editor
|
||||||
|
* that adds CRLF only to lines that are added..). But do we
|
||||||
|
* want to support CR-only? Probably not.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
|
||||||
|
{
|
||||||
|
char *buffer, *nbuf;
|
||||||
|
unsigned long size, nsize;
|
||||||
|
struct text_stat stats;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME! Other pluggable conversions should go here,
|
||||||
|
* based on filename patterns. Right now we just do the
|
||||||
|
* stupid auto-CRLF one.
|
||||||
|
*/
|
||||||
|
if (!auto_crlf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = *sizep;
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
buffer = *bufp;
|
||||||
|
|
||||||
|
gather_stats(buffer, size, &stats);
|
||||||
|
|
||||||
|
/* No CR? Nothing to convert, regardless. */
|
||||||
|
if (!stats.cr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're currently not going to even try to convert stuff
|
||||||
|
* that has bare CR characters. Does anybody do that crazy
|
||||||
|
* stuff?
|
||||||
|
*/
|
||||||
|
if (stats.cr != stats.crlf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And add some heuristics for binary vs text, of course...
|
||||||
|
*/
|
||||||
|
if (is_binary(size, &stats))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok, allocate a new buffer, fill it in, and return true
|
||||||
|
* to let the caller know that we switched buffers on it.
|
||||||
|
*/
|
||||||
|
nsize = size - stats.crlf;
|
||||||
|
nbuf = xmalloc(nsize);
|
||||||
|
*bufp = nbuf;
|
||||||
|
*sizep = nsize;
|
||||||
|
do {
|
||||||
|
unsigned char c = *buffer++;
|
||||||
|
if (c != '\r')
|
||||||
|
*nbuf++ = c;
|
||||||
|
} while (--size);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
|
||||||
|
{
|
||||||
|
char *buffer, *nbuf;
|
||||||
|
unsigned long size, nsize;
|
||||||
|
struct text_stat stats;
|
||||||
|
unsigned char last;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME! Other pluggable conversions should go here,
|
||||||
|
* based on filename patterns. Right now we just do the
|
||||||
|
* stupid auto-CRLF one.
|
||||||
|
*/
|
||||||
|
if (auto_crlf <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = *sizep;
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
buffer = *bufp;
|
||||||
|
|
||||||
|
gather_stats(buffer, size, &stats);
|
||||||
|
|
||||||
|
/* No LF? Nothing to convert, regardless. */
|
||||||
|
if (!stats.lf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Was it already in CRLF format? */
|
||||||
|
if (stats.lf == stats.crlf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If we have any bare CR characters, we're not going to touch it */
|
||||||
|
if (stats.cr != stats.crlf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (is_binary(size, &stats))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok, allocate a new buffer, fill it in, and return true
|
||||||
|
* to let the caller know that we switched buffers on it.
|
||||||
|
*/
|
||||||
|
nsize = size + stats.lf - stats.crlf;
|
||||||
|
nbuf = xmalloc(nsize);
|
||||||
|
*bufp = nbuf;
|
||||||
|
*sizep = nsize;
|
||||||
|
last = 0;
|
||||||
|
do {
|
||||||
|
unsigned char c = *buffer++;
|
||||||
|
if (c == '\n' && last != '\r')
|
||||||
|
*nbuf++ = '\r';
|
||||||
|
*nbuf++ = c;
|
||||||
|
last = c;
|
||||||
|
} while (--size);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
17
diff.c
17
diff.c
@ -1378,6 +1378,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
|||||||
reuse_worktree_file(s->path, s->sha1, 0)) {
|
reuse_worktree_file(s->path, s->sha1, 0)) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int fd;
|
int fd;
|
||||||
|
char *buf;
|
||||||
|
unsigned long size;
|
||||||
|
|
||||||
if (lstat(s->path, &st) < 0) {
|
if (lstat(s->path, &st) < 0) {
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
err_empty:
|
err_empty:
|
||||||
@ -1410,7 +1413,19 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
|||||||
s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
|
s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
s->should_munmap = 1;
|
s->should_munmap = 1;
|
||||||
/* FIXME! CRLF -> LF conversion goes here, based on "s->path" */
|
|
||||||
|
/*
|
||||||
|
* Convert from working tree format to canonical git format
|
||||||
|
*/
|
||||||
|
buf = s->data;
|
||||||
|
size = s->size;
|
||||||
|
if (convert_to_git(s->path, &buf, &size)) {
|
||||||
|
munmap(s->data, s->size);
|
||||||
|
s->should_munmap = 0;
|
||||||
|
s->data = buf;
|
||||||
|
s->size = size;
|
||||||
|
s->should_free = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char type[20];
|
char type[20];
|
||||||
|
16
entry.c
16
entry.c
@ -78,6 +78,9 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
|
|||||||
path, sha1_to_hex(ce->sha1));
|
path, sha1_to_hex(ce->sha1));
|
||||||
}
|
}
|
||||||
switch (ntohl(ce->ce_mode) & S_IFMT) {
|
switch (ntohl(ce->ce_mode) & S_IFMT) {
|
||||||
|
char *buf;
|
||||||
|
unsigned long nsize;
|
||||||
|
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
if (to_tempfile) {
|
if (to_tempfile) {
|
||||||
strcpy(path, ".merge_file_XXXXXX");
|
strcpy(path, ".merge_file_XXXXXX");
|
||||||
@ -89,7 +92,18 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
|
|||||||
return error("git-checkout-index: unable to create file %s (%s)",
|
return error("git-checkout-index: unable to create file %s (%s)",
|
||||||
path, strerror(errno));
|
path, strerror(errno));
|
||||||
}
|
}
|
||||||
/* FIXME: LF -> CRLF conversion goes here, based on "ce->name" */
|
|
||||||
|
/*
|
||||||
|
* Convert from git internal format to working tree format
|
||||||
|
*/
|
||||||
|
buf = new;
|
||||||
|
nsize = size;
|
||||||
|
if (convert_to_working_tree(ce->name, &buf, &nsize)) {
|
||||||
|
free(new);
|
||||||
|
new = buf;
|
||||||
|
size = nsize;
|
||||||
|
}
|
||||||
|
|
||||||
wrote = write_in_full(fd, new, size);
|
wrote = write_in_full(fd, new, size);
|
||||||
close(fd);
|
close(fd);
|
||||||
free(new);
|
free(new);
|
||||||
|
@ -28,6 +28,7 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
|
|||||||
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
||||||
int pager_in_use;
|
int pager_in_use;
|
||||||
int pager_use_color = 1;
|
int pager_use_color = 1;
|
||||||
|
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||||
|
|
||||||
static const char *git_dir;
|
static const char *git_dir;
|
||||||
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
|
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
|
||||||
|
23
sha1_file.c
23
sha1_file.c
@ -2082,7 +2082,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
|
|||||||
{
|
{
|
||||||
unsigned long size = st->st_size;
|
unsigned long size = st->st_size;
|
||||||
void *buf;
|
void *buf;
|
||||||
int ret;
|
int ret, re_allocated = 0;
|
||||||
|
|
||||||
buf = "";
|
buf = "";
|
||||||
if (size)
|
if (size)
|
||||||
@ -2091,11 +2091,30 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
|
|||||||
|
|
||||||
if (!type)
|
if (!type)
|
||||||
type = blob_type;
|
type = blob_type;
|
||||||
/* FIXME: CRLF -> LF conversion here for blobs! We'll need the path! */
|
|
||||||
|
/*
|
||||||
|
* Convert blobs to git internal format
|
||||||
|
*/
|
||||||
|
if (!strcmp(type, blob_type)) {
|
||||||
|
unsigned long nsize = size;
|
||||||
|
char *nbuf = buf;
|
||||||
|
if (convert_to_git(NULL, &nbuf, &nsize)) {
|
||||||
|
if (size)
|
||||||
|
munmap(buf, size);
|
||||||
|
size = nsize;
|
||||||
|
buf = nbuf;
|
||||||
|
re_allocated = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (write_object)
|
if (write_object)
|
||||||
ret = write_sha1_file(buf, size, type, sha1);
|
ret = write_sha1_file(buf, size, type, sha1);
|
||||||
else
|
else
|
||||||
ret = hash_sha1_file(buf, size, type, sha1);
|
ret = hash_sha1_file(buf, size, type, sha1);
|
||||||
|
if (re_allocated) {
|
||||||
|
free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
if (size)
|
if (size)
|
||||||
munmap(buf, size);
|
munmap(buf, size);
|
||||||
return ret;
|
return ret;
|
||||||
|
217
t/t0020-crlf.sh
Executable file
217
t/t0020-crlf.sh
Executable file
@ -0,0 +1,217 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='CRLF conversion'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
append_cr () {
|
||||||
|
sed -e 's/$/Q/' | tr Q '\015'
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_cr () {
|
||||||
|
tr '\015' Q <"$1" | grep Q >/dev/null &&
|
||||||
|
tr '\015' Q <"$1" | sed -ne 's/Q$//p'
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
|
||||||
|
git repo-config core.autocrlf false &&
|
||||||
|
|
||||||
|
for w in Hello world how are you; do echo $w; done >one &&
|
||||||
|
mkdir dir &&
|
||||||
|
for w in I am very very fine thank you; do echo $w; done >dir/two &&
|
||||||
|
git add . &&
|
||||||
|
|
||||||
|
git commit -m initial &&
|
||||||
|
|
||||||
|
one=`git rev-parse HEAD:one` &&
|
||||||
|
dir=`git rev-parse HEAD:dir` &&
|
||||||
|
two=`git rev-parse HEAD:dir/two` &&
|
||||||
|
|
||||||
|
for w in Some extra lines here; do echo $w; done >>one &&
|
||||||
|
git diff >patch.file &&
|
||||||
|
patched=`git hash-object --stdin <one` &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
echo happy.
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update with autocrlf=input' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
git repo-config core.autocrlf input &&
|
||||||
|
|
||||||
|
for f in one dir/two
|
||||||
|
do
|
||||||
|
append_cr <$f >tmp && mv -f tmp $f &&
|
||||||
|
git update-index -- $f || {
|
||||||
|
echo Oops
|
||||||
|
false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
done &&
|
||||||
|
|
||||||
|
differs=`git diff-index --cached HEAD` &&
|
||||||
|
test -z "$differs" || {
|
||||||
|
echo Oops "$differs"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update with autocrlf=true' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
git repo-config core.autocrlf true &&
|
||||||
|
|
||||||
|
for f in one dir/two
|
||||||
|
do
|
||||||
|
append_cr <$f >tmp && mv -f tmp $f &&
|
||||||
|
git update-index -- $f || {
|
||||||
|
echo "Oops $f"
|
||||||
|
false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
done &&
|
||||||
|
|
||||||
|
differs=`git diff-index --cached HEAD` &&
|
||||||
|
test -z "$differs" || {
|
||||||
|
echo Oops "$differs"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'checkout with autocrlf=true' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf true &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
for f in one dir/two
|
||||||
|
do
|
||||||
|
remove_cr "$f" >tmp && mv -f tmp $f &&
|
||||||
|
git update-index -- $f || {
|
||||||
|
echo "Eh? $f"
|
||||||
|
false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
done &&
|
||||||
|
test "$one" = `git hash-object --stdin <one` &&
|
||||||
|
test "$two" = `git hash-object --stdin <dir/two` &&
|
||||||
|
differs=`git diff-index --cached HEAD` &&
|
||||||
|
test -z "$differs" || {
|
||||||
|
echo Oops "$differs"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'checkout with autocrlf=input' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf input &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
for f in one dir/two
|
||||||
|
do
|
||||||
|
if remove_cr "$f" >/dev/null
|
||||||
|
then
|
||||||
|
echo "Eh? $f"
|
||||||
|
false
|
||||||
|
break
|
||||||
|
else
|
||||||
|
git update-index -- $f
|
||||||
|
fi
|
||||||
|
done &&
|
||||||
|
test "$one" = `git hash-object --stdin <one` &&
|
||||||
|
test "$two" = `git hash-object --stdin <dir/two` &&
|
||||||
|
differs=`git diff-index --cached HEAD` &&
|
||||||
|
test -z "$differs" || {
|
||||||
|
echo Oops "$differs"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch (autocrlf=input)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf input &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply patch.file &&
|
||||||
|
test "$patched" = "`git hash-object --stdin <one`" || {
|
||||||
|
echo "Eh? apply without index"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch --cached (autocrlf=input)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf input &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply --cached patch.file &&
|
||||||
|
test "$patched" = `git rev-parse :one` || {
|
||||||
|
echo "Eh? apply with --cached"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch --index (autocrlf=input)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf input &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply --index patch.file &&
|
||||||
|
test "$patched" = `git rev-parse :one` &&
|
||||||
|
test "$patched" = `git hash-object --stdin <one` || {
|
||||||
|
echo "Eh? apply with --index"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch (autocrlf=true)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf true &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply patch.file &&
|
||||||
|
test "$patched" = "`remove_cr one | git hash-object --stdin`" || {
|
||||||
|
echo "Eh? apply without index"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch --cached (autocrlf=true)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf true &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply --cached patch.file &&
|
||||||
|
test "$patched" = `git rev-parse :one` || {
|
||||||
|
echo "Eh? apply without index"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply patch --index (autocrlf=true)' '
|
||||||
|
|
||||||
|
rm -f tmp one dir/two &&
|
||||||
|
git repo-config core.autocrlf true &&
|
||||||
|
git read-tree --reset -u HEAD &&
|
||||||
|
|
||||||
|
git apply --index patch.file &&
|
||||||
|
test "$patched" = `git rev-parse :one` &&
|
||||||
|
test "$patched" = "`remove_cr one | git hash-object --stdin`" || {
|
||||||
|
echo "Eh? apply with --index"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
162
t/t4119-apply-config.sh
Executable file
162
t/t4119-apply-config.sh
Executable file
@ -0,0 +1,162 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 Junio C Hamano
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description='git-apply --whitespace=strip and configuration file.
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
mkdir sub &&
|
||||||
|
echo A >sub/file1 &&
|
||||||
|
cp sub/file1 saved &&
|
||||||
|
git add sub/file1 &&
|
||||||
|
echo "B " >sub/file1 &&
|
||||||
|
git diff >patch.file
|
||||||
|
'
|
||||||
|
|
||||||
|
# Also handcraft GNU diff output; note this has trailing whitespace.
|
||||||
|
cat >gpatch.file <<\EOF &&
|
||||||
|
--- file1 2007-02-21 01:04:24.000000000 -0800
|
||||||
|
+++ file1+ 2007-02-21 01:07:44.000000000 -0800
|
||||||
|
@@ -1 +1 @@
|
||||||
|
-A
|
||||||
|
+B
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sed -e 's|file1|sub/&|' gpatch.file >gpatch-sub.file &&
|
||||||
|
sed -e '
|
||||||
|
/^--- /s|file1|a/sub/&|
|
||||||
|
/^+++ /s|file1|b/sub/&|
|
||||||
|
' gpatch.file >gpatch-ab-sub.file &&
|
||||||
|
|
||||||
|
check_result () {
|
||||||
|
if grep " " "$1"
|
||||||
|
then
|
||||||
|
echo "Eh?"
|
||||||
|
false
|
||||||
|
elif grep B "$1"
|
||||||
|
then
|
||||||
|
echo Happy
|
||||||
|
else
|
||||||
|
echo "Huh?"
|
||||||
|
false
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'apply --whitespace=strip' '
|
||||||
|
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
git apply --whitespace=strip patch.file &&
|
||||||
|
check_result sub/file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply --whitespace=strip from config' '
|
||||||
|
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
git apply patch.file &&
|
||||||
|
check_result sub/file1
|
||||||
|
'
|
||||||
|
|
||||||
|
D=`pwd`
|
||||||
|
|
||||||
|
test_expect_success 'apply --whitespace=strip in subdir' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config --unset-all apply.whitespace
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
cd sub &&
|
||||||
|
git apply --whitespace=strip ../patch.file &&
|
||||||
|
check_result file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'apply --whitespace=strip from config in subdir' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
cd sub &&
|
||||||
|
git apply ../patch.file &&
|
||||||
|
check_result file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'same in subdir but with traditional patch input' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
cd sub &&
|
||||||
|
git apply ../gpatch.file &&
|
||||||
|
check_result file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'same but with traditional patch input of depth 1' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
cd sub &&
|
||||||
|
git apply ../gpatch-sub.file &&
|
||||||
|
check_result file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'same but with traditional patch input of depth 2' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
cd sub &&
|
||||||
|
git apply ../gpatch-ab-sub.file &&
|
||||||
|
check_result file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'same but with traditional patch input of depth 1' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
git apply -p0 gpatch-sub.file &&
|
||||||
|
check_result sub/file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'same but with traditional patch input of depth 2' '
|
||||||
|
|
||||||
|
cd "$D" &&
|
||||||
|
git config apply.whitespace strip &&
|
||||||
|
rm -f sub/file1 &&
|
||||||
|
cp saved sub/file1 &&
|
||||||
|
git update-index --refresh &&
|
||||||
|
|
||||||
|
git apply gpatch-ab-sub.file &&
|
||||||
|
check_result sub/file1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
Loading…
x
Reference in New Issue
Block a user