Merge branch 'bc/reread-attributes-during-rebase'

The "git am" based backend of "git rebase" ignored the result of
updating ".gitattributes" done in one step when replaying
subsequent steps.

* bc/reread-attributes-during-rebase:
  am: reload .gitattributes after patching it
  path: add a function to check for path suffix
This commit is contained in:
Junio C Hamano 2019-09-09 12:26:40 -07:00
commit c8ada15456
9 changed files with 183 additions and 23 deletions

11
apply.c
View File

@ -4643,6 +4643,7 @@ static int apply_patch(struct apply_state *state,
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
int res = 0;
int flush_attributes = 0;
state->patch_input_file = filename;
if (read_patch_file(&buf, fd) < 0)
@ -4670,6 +4671,14 @@ static int apply_patch(struct apply_state *state,
patch_stats(state, patch);
*listp = patch;
listp = &patch->next;
if ((patch->new_name &&
ends_with_path_components(patch->new_name,
GITATTRIBUTES_FILE)) ||
(patch->old_name &&
ends_with_path_components(patch->old_name,
GITATTRIBUTES_FILE)))
flush_attributes = 1;
}
else {
if (state->apply_verbosity > verbosity_normal)
@ -4746,6 +4755,8 @@ static int apply_patch(struct apply_state *state,
if (state->summary && state->apply_verbosity > verbosity_silent)
summary_patch_list(list);
if (flush_attributes)
reset_parsed_attributes();
end:
free_patch_list(list);
strbuf_release(&buf);

View File

@ -8,6 +8,7 @@
#include "pkt-line.h"
#include "sub-process.h"
#include "utf8.h"
#include "ll-merge.h"
/*
* convert.c - convert a file when checking it out and checking it in.
@ -1293,10 +1294,11 @@ struct conv_attrs {
const char *working_tree_encoding; /* Supported encoding or default encoding if NULL */
};
static struct attr_check *check;
static void convert_attrs(const struct index_state *istate,
struct conv_attrs *ca, const char *path)
{
static struct attr_check *check;
struct attr_check_item *ccheck = NULL;
if (!check) {
@ -1339,6 +1341,23 @@ static void convert_attrs(const struct index_state *istate,
ca->crlf_action = CRLF_AUTO_INPUT;
}
void reset_parsed_attributes(void)
{
struct convert_driver *drv, *next;
attr_check_free(check);
check = NULL;
reset_merge_attributes();
for (drv = user_convert; drv; drv = next) {
next = drv->next;
free((void *)drv->name);
free(drv);
}
user_convert = NULL;
user_convert_tail = NULL;
}
int would_convert_to_git_filter_fd(const struct index_state *istate, const char *path)
{
struct conv_attrs ca;

View File

@ -94,6 +94,12 @@ void convert_to_git_filter_fd(const struct index_state *istate,
int would_convert_to_git_filter_fd(const struct index_state *istate,
const char *path);
/*
* Reset the internal list of attributes used by convert_to_git and
* convert_to_working_tree.
*/
void reset_parsed_attributes(void);
/*****************************************************************
*
* Streaming conversion support

View File

@ -32,6 +32,20 @@ struct ll_merge_driver {
char *cmdline;
};
static struct attr_check *merge_attributes;
static struct attr_check *load_merge_attributes(void)
{
if (!merge_attributes)
merge_attributes = attr_check_initl("merge", "conflict-marker-size", NULL);
return merge_attributes;
}
void reset_merge_attributes(void)
{
attr_check_free(merge_attributes);
merge_attributes = NULL;
}
/*
* Built-in low-levels
*/
@ -354,7 +368,7 @@ int ll_merge(mmbuffer_t *result_buf,
struct index_state *istate,
const struct ll_merge_options *opts)
{
static struct attr_check *check;
struct attr_check *check = load_merge_attributes();
static const struct ll_merge_options default_opts;
const char *ll_driver_name = NULL;
int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
@ -369,9 +383,6 @@ int ll_merge(mmbuffer_t *result_buf,
normalize_file(theirs, path, istate);
}
if (!check)
check = attr_check_initl("merge", "conflict-marker-size", NULL);
git_check_attr(istate, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {

View File

@ -26,5 +26,6 @@ int ll_merge(mmbuffer_t *result_buf,
const struct ll_merge_options *opts);
int ll_merge_marker_size(struct index_state *istate, const char *path);
void reset_merge_attributes(void);
#endif

57
path.c
View File

@ -1220,6 +1220,43 @@ static inline int chomp_trailing_dir_sep(const char *path, int len)
return len;
}
/*
* If path ends with suffix (complete path components), returns the offset of
* the last character in the path before the suffix (sans trailing directory
* separators), and -1 otherwise.
*/
static ssize_t stripped_path_suffix_offset(const char *path, const char *suffix)
{
int path_len = strlen(path), suffix_len = strlen(suffix);
while (suffix_len) {
if (!path_len)
return -1;
if (is_dir_sep(path[path_len - 1])) {
if (!is_dir_sep(suffix[suffix_len - 1]))
return -1;
path_len = chomp_trailing_dir_sep(path, path_len);
suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
}
else if (path[--path_len] != suffix[--suffix_len])
return -1;
}
if (path_len && !is_dir_sep(path[path_len - 1]))
return -1;
return chomp_trailing_dir_sep(path, path_len);
}
/*
* Returns true if the path ends with components, considering only complete path
* components, and false otherwise.
*/
int ends_with_path_components(const char *path, const char *components)
{
return stripped_path_suffix_offset(path, components) != -1;
}
/*
* If path ends with suffix (complete path components), returns the
* part before suffix (sans trailing directory separators).
@ -1227,25 +1264,9 @@ static inline int chomp_trailing_dir_sep(const char *path, int len)
*/
char *strip_path_suffix(const char *path, const char *suffix)
{
int path_len = strlen(path), suffix_len = strlen(suffix);
ssize_t offset = stripped_path_suffix_offset(path, suffix);
while (suffix_len) {
if (!path_len)
return NULL;
if (is_dir_sep(path[path_len - 1])) {
if (!is_dir_sep(suffix[suffix_len - 1]))
return NULL;
path_len = chomp_trailing_dir_sep(path, path_len);
suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
}
else if (path[--path_len] != suffix[--suffix_len])
return NULL;
}
if (path_len && !is_dir_sep(path[path_len - 1]))
return NULL;
return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
return offset == -1 ? NULL : xstrndup(path, offset);
}
int daemon_avoid_alias(const char *p)

3
path.h
View File

@ -193,4 +193,7 @@ const char *git_path_merge_head(struct repository *r);
const char *git_path_fetch_head(struct repository *r);
const char *git_path_shallow(struct repository *r);
int ends_with_path_components(const char *path, const char *components);
#endif /* PATH_H */

View File

@ -301,6 +301,42 @@ test_expect_success 'rebase --am and --show-current-patch' '
)
'
test_expect_success 'rebase --am and .gitattributes' '
test_create_repo attributes &&
(
cd attributes &&
test_commit init &&
git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
test_commit second &&
git checkout -b test HEAD^ &&
echo "*.txt filter=test" >.gitattributes &&
git add .gitattributes &&
test_commit third &&
echo "This text is smudged." >a.txt &&
git add a.txt &&
test_commit fourth &&
git checkout -b removal HEAD^ &&
git rm .gitattributes &&
git add -u &&
test_commit fifth &&
git cherry-pick test &&
git checkout test &&
git rebase master &&
grep "smudged" a.txt &&
git checkout removal &&
git reset --hard &&
git rebase master &&
grep "clean" a.txt
)
'
test_expect_success 'rebase--merge.sh and --show-current-patch' '
test_create_repo conflict-merge &&
(

View File

@ -1061,4 +1061,56 @@ test_expect_success 'am --quit keeps HEAD where it is' '
test_cmp expected actual
'
test_expect_success 'am and .gitattibutes' '
test_create_repo attributes &&
(
cd attributes &&
test_commit init &&
git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
test_commit second &&
git checkout -b test HEAD^ &&
echo "*.txt filter=test conflict-marker-size=10" >.gitattributes &&
git add .gitattributes &&
test_commit third &&
echo "This text is smudged." >a.txt &&
git add a.txt &&
test_commit fourth &&
git checkout -b removal HEAD^ &&
git rm .gitattributes &&
git add -u &&
test_commit fifth &&
git cherry-pick test &&
git checkout -b conflict third &&
echo "This text is different." >a.txt &&
git add a.txt &&
test_commit sixth &&
git checkout test &&
git format-patch --stdout master..HEAD >patches &&
git reset --hard master &&
git am patches &&
grep "smudged" a.txt &&
git checkout removal &&
git reset --hard &&
git format-patch --stdout master..HEAD >patches &&
git reset --hard master &&
git am patches &&
grep "clean" a.txt &&
git checkout conflict &&
git reset --hard &&
git format-patch --stdout master..HEAD >patches &&
git reset --hard fourth &&
test_must_fail git am -3 patches &&
grep "<<<<<<<<<<" a.txt
)
'
test_done