Skip to content

Commit b7d2a15

Browse files
committed
Merge branch 'pt/am-builtin-abort-fix'
"git am" that was recently reimplemented in C had a performance regression in "git am --abort" that goes back to the version before an attempted (and failed) patch application. * pt/am-builtin-abort-fix: am --skip/--abort: merge HEAD/ORIG_HEAD tree into index
2 parents 788f211 + 3ecc704 commit b7d2a15

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

builtin/am.c

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,16 +1962,49 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
19621962
return 0;
19631963
}
19641964

1965+
/**
1966+
* Merges a tree into the index. The index's stat info will take precedence
1967+
* over the merged tree's. Returns 0 on success, -1 on failure.
1968+
*/
1969+
static int merge_tree(struct tree *tree)
1970+
{
1971+
struct lock_file *lock_file;
1972+
struct unpack_trees_options opts;
1973+
struct tree_desc t[1];
1974+
1975+
if (parse_tree(tree))
1976+
return -1;
1977+
1978+
lock_file = xcalloc(1, sizeof(struct lock_file));
1979+
hold_locked_index(lock_file, 1);
1980+
1981+
memset(&opts, 0, sizeof(opts));
1982+
opts.head_idx = 1;
1983+
opts.src_index = &the_index;
1984+
opts.dst_index = &the_index;
1985+
opts.merge = 1;
1986+
opts.fn = oneway_merge;
1987+
init_tree_desc(&t[0], tree->buffer, tree->size);
1988+
1989+
if (unpack_trees(1, t, &opts)) {
1990+
rollback_lock_file(lock_file);
1991+
return -1;
1992+
}
1993+
1994+
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
1995+
die(_("unable to write new index file"));
1996+
1997+
return 0;
1998+
}
1999+
19652000
/**
19662001
* Clean the index without touching entries that are not modified between
19672002
* `head` and `remote`.
19682003
*/
19692004
static int clean_index(const unsigned char *head, const unsigned char *remote)
19702005
{
1971-
struct lock_file *lock_file;
19722006
struct tree *head_tree, *remote_tree, *index_tree;
19732007
unsigned char index[GIT_SHA1_RAWSZ];
1974-
struct pathspec pathspec;
19752008

19762009
head_tree = parse_tree_indirect(head);
19772010
if (!head_tree)
@@ -1996,18 +2029,8 @@ static int clean_index(const unsigned char *head, const unsigned char *remote)
19962029
if (fast_forward_to(index_tree, remote_tree, 0))
19972030
return -1;
19982031

1999-
memset(&pathspec, 0, sizeof(pathspec));
2000-
2001-
lock_file = xcalloc(1, sizeof(struct lock_file));
2002-
hold_locked_index(lock_file, 1);
2003-
2004-
if (read_tree(remote_tree, 0, &pathspec)) {
2005-
rollback_lock_file(lock_file);
2032+
if (merge_tree(remote_tree))
20062033
return -1;
2007-
}
2008-
2009-
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
2010-
die(_("unable to write new index file"));
20112034

20122035
remove_branch_state();
20132036

t/t4151-am-abort.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,28 @@ test_expect_success 'am --abort on unborn branch will keep local commits intact'
168168
test_cmp expect actual
169169
'
170170

171+
test_expect_success 'am --skip leaves index stat info alone' '
172+
git checkout -f --orphan skip-stat-info &&
173+
git reset &&
174+
test_commit skip-should-be-untouched &&
175+
test-chmtime =0 skip-should-be-untouched.t &&
176+
git update-index --refresh &&
177+
git diff-files --exit-code --quiet &&
178+
test_must_fail git am 0001-*.patch &&
179+
git am --skip &&
180+
git diff-files --exit-code --quiet
181+
'
182+
183+
test_expect_success 'am --abort leaves index stat info alone' '
184+
git checkout -f --orphan abort-stat-info &&
185+
git reset &&
186+
test_commit abort-should-be-untouched &&
187+
test-chmtime =0 abort-should-be-untouched.t &&
188+
git update-index --refresh &&
189+
git diff-files --exit-code --quiet &&
190+
test_must_fail git am 0001-*.patch &&
191+
git am --abort &&
192+
git diff-files --exit-code --quiet
193+
'
194+
171195
test_done

0 commit comments

Comments
 (0)