diff options
| -rw-r--r-- | attr.c | 73 | ||||
| -rw-r--r-- | attr.h | 6 | ||||
| -rwxr-xr-x | t/t0020-crlf.sh | 31 | ||||
| -rw-r--r-- | unpack-trees.c | 3 | 
4 files changed, 95 insertions, 18 deletions
@@ -1,3 +1,4 @@ +#define NO_THE_INDEX_COMPATIBILITY_MACROS  #include "cache.h"  #include "attr.h" @@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)  	return res;  } +static enum git_attr_direction direction; +static struct index_state *use_index; +  static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)  {  	FILE *fp = fopen(path, "r"); @@ -340,9 +344,10 @@ static void *read_index_data(const char *path)  	unsigned long sz;  	enum object_type type;  	void *data; +	struct index_state *istate = use_index ? use_index : &the_index;  	len = strlen(path); -	pos = cache_name_pos(path, len); +	pos = index_name_pos(istate, path, len);  	if (pos < 0) {  		/*  		 * We might be in the middle of a merge, in which @@ -350,15 +355,15 @@ static void *read_index_data(const char *path)  		 */  		int i;  		for (i = -pos - 1; -		     (pos < 0 && i < active_nr && -		      !strcmp(active_cache[i]->name, path)); +		     (pos < 0 && i < istate->cache_nr && +		      !strcmp(istate->cache[i]->name, path));  		     i++) -			if (ce_stage(active_cache[i]) == 2) +			if (ce_stage(istate->cache[i]) == 2)  				pos = i;  	}  	if (pos < 0)  		return NULL; -	data = read_sha1_file(active_cache[pos]->sha1, &type, &sz); +	data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);  	if (!data || type != OBJ_BLOB) {  		free(data);  		return NULL; @@ -366,27 +371,17 @@ static void *read_index_data(const char *path)  	return data;  } -static struct attr_stack *read_attr(const char *path, int macro_ok) +static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)  {  	struct attr_stack *res;  	char *buf, *sp;  	int lineno = 0; -	res = read_attr_from_file(path, macro_ok); -	if (res) -		return res; - -	res = xcalloc(1, sizeof(*res)); - -	/* -	 * There is no checked out .gitattributes file there, but -	 * we might have it in the index.  We allow operation in a -	 * sparsely checked out work tree, so read from it. -	 */  	buf = read_index_data(path);  	if (!buf) -		return res; +		return NULL; +	res = xcalloc(1, sizeof(*res));  	for (sp = buf; *sp; ) {  		char *ep;  		int more; @@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)  	return res;  } +static struct attr_stack *read_attr(const char *path, int macro_ok) +{ +	struct attr_stack *res; + +	if (direction == GIT_ATTR_CHECKOUT) { +		res = read_attr_from_index(path, macro_ok); +		if (!res) +			res = read_attr_from_file(path, macro_ok); +	} +	else { +		res = read_attr_from_file(path, macro_ok); +		if (!res) +			/* +			 * There is no checked out .gitattributes file there, but +			 * we might have it in the index.  We allow operation in a +			 * sparsely checked out work tree, so read from it. +			 */ +			res = read_attr_from_index(path, macro_ok); +	} +	if (!res) +		res = xcalloc(1, sizeof(*res)); +	return res; +} +  #if DEBUG_ATTR  static void debug_info(const char *what, struct attr_stack *elem)  { @@ -428,6 +447,15 @@ static void debug_set(const char *what, const char *match, struct git_attr *attr  #define debug_set(a,b,c,d) do { ; } while (0)  #endif +static void drop_attr_stack(void) +{ +	while (attr_stack) { +		struct attr_stack *elem = attr_stack; +		attr_stack = elem->prev; +		free_attr_elem(elem); +	} +} +  static void bootstrap_attr_stack(void)  {  	if (!attr_stack) { @@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)  	return 0;  } + +void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) +{ +	enum git_attr_direction old = direction; +	direction = new; +	if (new != old) +		drop_attr_stack(); +	use_index = istate; +} @@ -31,4 +31,10 @@ struct git_attr_check {  int git_checkattr(const char *path, int, struct git_attr_check *); +enum git_attr_direction { +	GIT_ATTR_CHECKIN, +	GIT_ATTR_CHECKOUT +}; +void git_attr_set_direction(enum git_attr_direction, struct index_state *); +  #endif /* ATTR_H */ diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 1be7446d8d..4e72b53140 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -429,6 +429,37 @@ test_expect_success 'in-tree .gitattributes (4)' '  	}  ' +test_expect_success 'checkout with existing .gitattributes' ' + +	git config core.autocrlf true && +	git config --unset core.safecrlf && +	echo ".file2 -crlfQ" | q_to_cr >> .gitattributes && +	git add .gitattributes && +	git commit -m initial && +	echo ".file -crlfQ" | q_to_cr >> .gitattributes && +	echo "contents" > .file && +	git add .gitattributes .file && +	git commit -m second && + +	git checkout master~1 && +	git checkout master && +	test "$(git diff-files --raw)" = "" + +' + +test_expect_success 'checkout when deleting .gitattributes' ' + +	git rm .gitattributes && +	echo "contentsQ" | q_to_cr > .file2 && +	git add .file2 && +	git commit -m third + +	git checkout master~1 && +	git checkout master && +	remove_cr .file2 >/dev/null + +' +  test_expect_success 'invalid .gitattributes (must not crash)' '  	echo "three +crlf" >>.gitattributes && diff --git a/unpack-trees.c b/unpack-trees.c index 86e28650b8..6847c2d966 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -7,6 +7,7 @@  #include "unpack-trees.h"  #include "progress.h"  #include "refs.h" +#include "attr.h"  /*   * Error messages expected by scripts out of plumbing commands such as @@ -86,6 +87,7 @@ static int check_updates(struct unpack_trees_options *o)  		cnt = 0;  	} +	git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);  	for (i = 0; i < index->cache_nr; i++) {  		struct cache_entry *ce = index->cache[i]; @@ -110,6 +112,7 @@ static int check_updates(struct unpack_trees_options *o)  		}  	}  	stop_progress(&progress); +	git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);  	return errs != 0;  }  | 
