Skip to content

Commit

Permalink
status: reject deserialize in V2 and conflicts
Browse files Browse the repository at this point in the history
Teach status deserialize code to reject status cache
when printing in porcelain V2 and there are unresolved
conflicts in the cache file.  A follow-on task might
extend the cache format to include this additiona data.

See code for longer explanation.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
  • Loading branch information
jeffhostetler authored and vdye committed Jul 19, 2023
1 parent e421b5c commit bac50c5
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 3 deletions.
90 changes: 89 additions & 1 deletion t/t7522-serialized-status.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ test_expect_success 'setup' '
test_oid_cache <<-EOF
branch_oid sha1:68d4a437ea4c2de65800f48c053d4d543b55c410
x_base sha1:587be6b4c3f93f93c489c0111bba5596147a26cb
x_ours sha1:b68025345d5301abad4d9ec9166f455243a0d746
x_theirs sha1:975fbec8256d3e8a3797e7a3611380f27c49f4ac
branch_oid sha256:6b95e4b1ea911dad213f2020840f5e92d3066cf9e38cf35f79412ec58d409ce4
x_base sha256:14f5162e2fe3d240d0d37aaab0f90e4af9a7cfa79639f3bab005b5bfb4174d9f
x_ours sha256:3a404ba030a4afa912155c476a48a253d4b3a43d0098431b6d6ca6e554bd78fb
x_theirs sha256:44dc634218adec09e34f37839b3840bad8c6103693e9216626b32d00e093fa35
EOF
'

Expand Down Expand Up @@ -171,7 +177,7 @@ test_expect_success 'verify no-ahead-behind and serialized status integration' '
'

test_expect_success 'verify new --serialize=path mode' '
#test_when_finished "rm serialized_status.dat expect new_change.txt output.1 output.2" &&
test_when_finished "rm serialized_status.dat expect new_change.txt output.1 output.2" &&
cat >expect <<-\EOF &&
? expect
? output.1
Expand All @@ -193,4 +199,86 @@ test_expect_success 'verify new --serialize=path mode' '
test_cmp expect output.2
'

test_expect_success 'merge conflicts' '
# create a merge conflict.
git init -b main conflicts &&
echo x >conflicts/x.txt &&
git -C conflicts add x.txt &&
git -C conflicts commit -m x &&
git -C conflicts branch a &&
git -C conflicts branch b &&
git -C conflicts checkout a &&
echo y >conflicts/x.txt &&
git -C conflicts add x.txt &&
git -C conflicts commit -m a &&
git -C conflicts checkout b &&
echo z >conflicts/x.txt &&
git -C conflicts add x.txt &&
git -C conflicts commit -m b &&
test_must_fail git -C conflicts merge --no-commit a &&
# verify that regular status correctly identifies it
# in each format.
cat >expect.v2 <<EOF &&
u UU N... 100644 100644 100644 100644 $(test_oid x_base) $(test_oid x_ours) $(test_oid x_theirs) x.txt
EOF
git -C conflicts status --porcelain=v2 >observed.v2 &&
test_cmp expect.v2 observed.v2 &&
cat >expect.long <<EOF &&
On branch b
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: x.txt
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git -C conflicts status --long >observed.long &&
test_cmp expect.long observed.long &&
cat >expect.short <<EOF &&
UU x.txt
EOF
git -C conflicts status --short >observed.short &&
test_cmp expect.short observed.short &&
# save status data in serialized cache.
git -C conflicts status --serialize >serialized &&
# make some dirt in the worktree so we can tell whether subsequent
# status commands used the cached data or did a fresh status.
echo dirt >conflicts/dirt.txt &&
# run status using the cached data.
git -C conflicts status --long --deserialize=../serialized >observed.long &&
test_cmp expect.long observed.long &&
git -C conflicts status --short --deserialize=../serialized >observed.short &&
test_cmp expect.short observed.short &&
# currently, the cached data does not have enough information about
# merge conflicts for porcelain V2 format. (And V2 format looks at
# the index to get that data, but the whole point of the serialization
# is to avoid reading the index unnecessarily.) So V2 always rejects
# the cached data when there is an unresolved conflict.
cat >expect.v2.dirty <<EOF &&
u UU N... 100644 100644 100644 100644 $(test_oid x_base) $(test_oid x_ours) $(test_oid x_theirs) x.txt
? dirt.txt
EOF
git -C conflicts status --porcelain=v2 --deserialize=../serialized >observed.v2 &&
test_cmp expect.v2.dirty observed.v2
'

test_done
28 changes: 26 additions & 2 deletions wt-status-deserialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
/*
* Build a string-list of (count) <changed-item> lines from the input.
*/
static int wt_deserialize_v1_changed_items(struct wt_status *s, int fd, int count)
static int wt_deserialize_v1_changed_items(const struct wt_status *cmd_s,
struct wt_status *s, int fd, int count)
{
struct wt_status_serialize_data *sd;
char *p;
Expand Down Expand Up @@ -236,6 +237,29 @@ static int wt_deserialize_v1_changed_items(struct wt_status *s, int fd, int coun
oid_to_hex(&d->oid_index),
item->string,
(d->rename_source ? d->rename_source : ""));

if (d->stagemask &&
cmd_s->status_format == STATUS_FORMAT_PORCELAIN_V2) {
/*
* We have an unresolved conflict and the user wants
* to see porcelain V2 output. The cached status data
* does not contain enough information for V2 (because
* the main status computation does not capture it).
* We only get a single change record for the file with
* a single SHA -- we don't get the stage [123] mode
* and SHA data. The V2 detail-line print code looks
* up this information directly from the index. The
* whole point of this serialization cache is to avoid
* reading the index, so the V2 print code gets zeros.
* So we reject the status cache and let the fallback
* code run.
*/
trace_printf_key(
&trace_deserialize,
"reject: V2 format and umerged file: %s",
item->string);
return DESERIALIZE_ERR;
}
}

return DESERIALIZE_OK;
Expand Down Expand Up @@ -388,7 +412,7 @@ static int wt_deserialize_v1(const struct wt_status *cmd_s, struct wt_status *s,
while ((line = my_packet_read_line(fd, &line_len))) {
if (skip_prefix(line, "changed ", &arg)) {
nr_changed = (int)strtol(arg, NULL, 10);
if (wt_deserialize_v1_changed_items(s, fd, nr_changed)
if (wt_deserialize_v1_changed_items(cmd_s, s, fd, nr_changed)
== DESERIALIZE_ERR)
return DESERIALIZE_ERR;
continue;
Expand Down

0 comments on commit bac50c5

Please sign in to comment.