зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/attributes-checkout'
* jc/attributes-checkout: Add a test for checking whether gitattributes is honored by checkout. Read attributes from the index that is being checked out
This commit is contained in:
Коммит
6ba8b079cb
73
attr.c
73
attr.c
|
@ -1,3 +1,4 @@
|
||||||
|
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "attr.h"
|
#include "attr.h"
|
||||||
|
|
||||||
|
@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
|
||||||
return res;
|
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)
|
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(path, "r");
|
FILE *fp = fopen(path, "r");
|
||||||
|
@ -340,9 +344,10 @@ static void *read_index_data(const char *path)
|
||||||
unsigned long sz;
|
unsigned long sz;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
void *data;
|
void *data;
|
||||||
|
struct index_state *istate = use_index ? use_index : &the_index;
|
||||||
|
|
||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
pos = cache_name_pos(path, len);
|
pos = index_name_pos(istate, path, len);
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
/*
|
/*
|
||||||
* We might be in the middle of a merge, in which
|
* 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;
|
int i;
|
||||||
for (i = -pos - 1;
|
for (i = -pos - 1;
|
||||||
(pos < 0 && i < active_nr &&
|
(pos < 0 && i < istate->cache_nr &&
|
||||||
!strcmp(active_cache[i]->name, path));
|
!strcmp(istate->cache[i]->name, path));
|
||||||
i++)
|
i++)
|
||||||
if (ce_stage(active_cache[i]) == 2)
|
if (ce_stage(istate->cache[i]) == 2)
|
||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return NULL;
|
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) {
|
if (!data || type != OBJ_BLOB) {
|
||||||
free(data);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -366,27 +371,17 @@ static void *read_index_data(const char *path)
|
||||||
return data;
|
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;
|
struct attr_stack *res;
|
||||||
char *buf, *sp;
|
char *buf, *sp;
|
||||||
int lineno = 0;
|
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);
|
buf = read_index_data(path);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return res;
|
return NULL;
|
||||||
|
|
||||||
|
res = xcalloc(1, sizeof(*res));
|
||||||
for (sp = buf; *sp; ) {
|
for (sp = buf; *sp; ) {
|
||||||
char *ep;
|
char *ep;
|
||||||
int more;
|
int more;
|
||||||
|
@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||||
return res;
|
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
|
#if DEBUG_ATTR
|
||||||
static void debug_info(const char *what, struct attr_stack *elem)
|
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)
|
#define debug_set(a,b,c,d) do { ; } while (0)
|
||||||
#endif
|
#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)
|
static void bootstrap_attr_stack(void)
|
||||||
{
|
{
|
||||||
if (!attr_stack) {
|
if (!attr_stack) {
|
||||||
|
@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
6
attr.h
6
attr.h
|
@ -31,4 +31,10 @@ struct git_attr_check {
|
||||||
|
|
||||||
int git_checkattr(const char *path, int, 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 */
|
#endif /* ATTR_H */
|
||||||
|
|
|
@ -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)' '
|
test_expect_success 'invalid .gitattributes (must not crash)' '
|
||||||
|
|
||||||
echo "three +crlf" >>.gitattributes &&
|
echo "three +crlf" >>.gitattributes &&
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "unpack-trees.h"
|
#include "unpack-trees.h"
|
||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
|
#include "attr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error messages expected by scripts out of plumbing commands such as
|
* 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;
|
cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
|
||||||
for (i = 0; i < index->cache_nr; i++) {
|
for (i = 0; i < index->cache_nr; i++) {
|
||||||
struct cache_entry *ce = index->cache[i];
|
struct cache_entry *ce = index->cache[i];
|
||||||
|
|
||||||
|
@ -110,6 +112,7 @@ static int check_updates(struct unpack_trees_options *o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stop_progress(&progress);
|
stop_progress(&progress);
|
||||||
|
git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
|
||||||
return errs != 0;
|
return errs != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче