Skip to content

Commit c8ada15

Browse files
committed
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
2 parents 8f3ba42 + 2c65d90 commit c8ada15

File tree

9 files changed

+174
-14
lines changed

9 files changed

+174
-14
lines changed

apply.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4643,6 +4643,7 @@ static int apply_patch(struct apply_state *state,
46434643
struct patch *list = NULL, **listp = &list;
46444644
int skipped_patch = 0;
46454645
int res = 0;
4646+
int flush_attributes = 0;
46464647

46474648
state->patch_input_file = filename;
46484649
if (read_patch_file(&buf, fd) < 0)
@@ -4670,6 +4671,14 @@ static int apply_patch(struct apply_state *state,
46704671
patch_stats(state, patch);
46714672
*listp = patch;
46724673
listp = &patch->next;
4674+
4675+
if ((patch->new_name &&
4676+
ends_with_path_components(patch->new_name,
4677+
GITATTRIBUTES_FILE)) ||
4678+
(patch->old_name &&
4679+
ends_with_path_components(patch->old_name,
4680+
GITATTRIBUTES_FILE)))
4681+
flush_attributes = 1;
46734682
}
46744683
else {
46754684
if (state->apply_verbosity > verbosity_normal)
@@ -4746,6 +4755,8 @@ static int apply_patch(struct apply_state *state,
47464755
if (state->summary && state->apply_verbosity > verbosity_silent)
47474756
summary_patch_list(list);
47484757

4758+
if (flush_attributes)
4759+
reset_parsed_attributes();
47494760
end:
47504761
free_patch_list(list);
47514762
strbuf_release(&buf);

convert.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "pkt-line.h"
99
#include "sub-process.h"
1010
#include "utf8.h"
11+
#include "ll-merge.h"
1112

1213
/*
1314
* convert.c - convert a file when checking it out and checking it in.
@@ -1293,10 +1294,11 @@ struct conv_attrs {
12931294
const char *working_tree_encoding; /* Supported encoding or default encoding if NULL */
12941295
};
12951296

1297+
static struct attr_check *check;
1298+
12961299
static void convert_attrs(const struct index_state *istate,
12971300
struct conv_attrs *ca, const char *path)
12981301
{
1299-
static struct attr_check *check;
13001302
struct attr_check_item *ccheck = NULL;
13011303

13021304
if (!check) {
@@ -1339,6 +1341,23 @@ static void convert_attrs(const struct index_state *istate,
13391341
ca->crlf_action = CRLF_AUTO_INPUT;
13401342
}
13411343

1344+
void reset_parsed_attributes(void)
1345+
{
1346+
struct convert_driver *drv, *next;
1347+
1348+
attr_check_free(check);
1349+
check = NULL;
1350+
reset_merge_attributes();
1351+
1352+
for (drv = user_convert; drv; drv = next) {
1353+
next = drv->next;
1354+
free((void *)drv->name);
1355+
free(drv);
1356+
}
1357+
user_convert = NULL;
1358+
user_convert_tail = NULL;
1359+
}
1360+
13421361
int would_convert_to_git_filter_fd(const struct index_state *istate, const char *path)
13431362
{
13441363
struct conv_attrs ca;

convert.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ void convert_to_git_filter_fd(const struct index_state *istate,
9494
int would_convert_to_git_filter_fd(const struct index_state *istate,
9595
const char *path);
9696

97+
/*
98+
* Reset the internal list of attributes used by convert_to_git and
99+
* convert_to_working_tree.
100+
*/
101+
void reset_parsed_attributes(void);
102+
97103
/*****************************************************************
98104
*
99105
* Streaming conversion support

ll-merge.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ struct ll_merge_driver {
3232
char *cmdline;
3333
};
3434

35+
static struct attr_check *merge_attributes;
36+
static struct attr_check *load_merge_attributes(void)
37+
{
38+
if (!merge_attributes)
39+
merge_attributes = attr_check_initl("merge", "conflict-marker-size", NULL);
40+
return merge_attributes;
41+
}
42+
43+
void reset_merge_attributes(void)
44+
{
45+
attr_check_free(merge_attributes);
46+
merge_attributes = NULL;
47+
}
48+
3549
/*
3650
* Built-in low-levels
3751
*/
@@ -354,7 +368,7 @@ int ll_merge(mmbuffer_t *result_buf,
354368
struct index_state *istate,
355369
const struct ll_merge_options *opts)
356370
{
357-
static struct attr_check *check;
371+
struct attr_check *check = load_merge_attributes();
358372
static const struct ll_merge_options default_opts;
359373
const char *ll_driver_name = NULL;
360374
int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
@@ -369,9 +383,6 @@ int ll_merge(mmbuffer_t *result_buf,
369383
normalize_file(theirs, path, istate);
370384
}
371385

372-
if (!check)
373-
check = attr_check_initl("merge", "conflict-marker-size", NULL);
374-
375386
git_check_attr(istate, path, check);
376387
ll_driver_name = check->items[0].value;
377388
if (check->items[1].value) {

ll-merge.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ int ll_merge(mmbuffer_t *result_buf,
2626
const struct ll_merge_options *opts);
2727

2828
int ll_merge_marker_size(struct index_state *istate, const char *path);
29+
void reset_merge_attributes(void);
2930

3031
#endif

path.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,31 +1221,52 @@ static inline int chomp_trailing_dir_sep(const char *path, int len)
12211221
}
12221222

12231223
/*
1224-
* If path ends with suffix (complete path components), returns the
1225-
* part before suffix (sans trailing directory separators).
1226-
* Otherwise returns NULL.
1224+
* If path ends with suffix (complete path components), returns the offset of
1225+
* the last character in the path before the suffix (sans trailing directory
1226+
* separators), and -1 otherwise.
12271227
*/
1228-
char *strip_path_suffix(const char *path, const char *suffix)
1228+
static ssize_t stripped_path_suffix_offset(const char *path, const char *suffix)
12291229
{
12301230
int path_len = strlen(path), suffix_len = strlen(suffix);
12311231

12321232
while (suffix_len) {
12331233
if (!path_len)
1234-
return NULL;
1234+
return -1;
12351235

12361236
if (is_dir_sep(path[path_len - 1])) {
12371237
if (!is_dir_sep(suffix[suffix_len - 1]))
1238-
return NULL;
1238+
return -1;
12391239
path_len = chomp_trailing_dir_sep(path, path_len);
12401240
suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
12411241
}
12421242
else if (path[--path_len] != suffix[--suffix_len])
1243-
return NULL;
1243+
return -1;
12441244
}
12451245

12461246
if (path_len && !is_dir_sep(path[path_len - 1]))
1247-
return NULL;
1248-
return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
1247+
return -1;
1248+
return chomp_trailing_dir_sep(path, path_len);
1249+
}
1250+
1251+
/*
1252+
* Returns true if the path ends with components, considering only complete path
1253+
* components, and false otherwise.
1254+
*/
1255+
int ends_with_path_components(const char *path, const char *components)
1256+
{
1257+
return stripped_path_suffix_offset(path, components) != -1;
1258+
}
1259+
1260+
/*
1261+
* If path ends with suffix (complete path components), returns the
1262+
* part before suffix (sans trailing directory separators).
1263+
* Otherwise returns NULL.
1264+
*/
1265+
char *strip_path_suffix(const char *path, const char *suffix)
1266+
{
1267+
ssize_t offset = stripped_path_suffix_offset(path, suffix);
1268+
1269+
return offset == -1 ? NULL : xstrndup(path, offset);
12491270
}
12501271

12511272
int daemon_avoid_alias(const char *p)

path.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,7 @@ const char *git_path_merge_head(struct repository *r);
193193
const char *git_path_fetch_head(struct repository *r);
194194
const char *git_path_shallow(struct repository *r);
195195

196+
197+
int ends_with_path_components(const char *path, const char *components);
198+
196199
#endif /* PATH_H */

t/t3400-rebase.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,42 @@ test_expect_success 'rebase --am and --show-current-patch' '
301301
)
302302
'
303303

304+
test_expect_success 'rebase --am and .gitattributes' '
305+
test_create_repo attributes &&
306+
(
307+
cd attributes &&
308+
test_commit init &&
309+
git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
310+
git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
311+
312+
test_commit second &&
313+
git checkout -b test HEAD^ &&
314+
315+
echo "*.txt filter=test" >.gitattributes &&
316+
git add .gitattributes &&
317+
test_commit third &&
318+
319+
echo "This text is smudged." >a.txt &&
320+
git add a.txt &&
321+
test_commit fourth &&
322+
323+
git checkout -b removal HEAD^ &&
324+
git rm .gitattributes &&
325+
git add -u &&
326+
test_commit fifth &&
327+
git cherry-pick test &&
328+
329+
git checkout test &&
330+
git rebase master &&
331+
grep "smudged" a.txt &&
332+
333+
git checkout removal &&
334+
git reset --hard &&
335+
git rebase master &&
336+
grep "clean" a.txt
337+
)
338+
'
339+
304340
test_expect_success 'rebase--merge.sh and --show-current-patch' '
305341
test_create_repo conflict-merge &&
306342
(

t/t4150-am.sh

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,4 +1061,56 @@ test_expect_success 'am --quit keeps HEAD where it is' '
10611061
test_cmp expected actual
10621062
'
10631063

1064+
test_expect_success 'am and .gitattibutes' '
1065+
test_create_repo attributes &&
1066+
(
1067+
cd attributes &&
1068+
test_commit init &&
1069+
git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
1070+
git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
1071+
1072+
test_commit second &&
1073+
git checkout -b test HEAD^ &&
1074+
1075+
echo "*.txt filter=test conflict-marker-size=10" >.gitattributes &&
1076+
git add .gitattributes &&
1077+
test_commit third &&
1078+
1079+
echo "This text is smudged." >a.txt &&
1080+
git add a.txt &&
1081+
test_commit fourth &&
1082+
1083+
git checkout -b removal HEAD^ &&
1084+
git rm .gitattributes &&
1085+
git add -u &&
1086+
test_commit fifth &&
1087+
git cherry-pick test &&
1088+
1089+
git checkout -b conflict third &&
1090+
echo "This text is different." >a.txt &&
1091+
git add a.txt &&
1092+
test_commit sixth &&
1093+
1094+
git checkout test &&
1095+
git format-patch --stdout master..HEAD >patches &&
1096+
git reset --hard master &&
1097+
git am patches &&
1098+
grep "smudged" a.txt &&
1099+
1100+
git checkout removal &&
1101+
git reset --hard &&
1102+
git format-patch --stdout master..HEAD >patches &&
1103+
git reset --hard master &&
1104+
git am patches &&
1105+
grep "clean" a.txt &&
1106+
1107+
git checkout conflict &&
1108+
git reset --hard &&
1109+
git format-patch --stdout master..HEAD >patches &&
1110+
git reset --hard fourth &&
1111+
test_must_fail git am -3 patches &&
1112+
grep "<<<<<<<<<<" a.txt
1113+
)
1114+
'
1115+
10641116
test_done

0 commit comments

Comments
 (0)