patch-id: fix stable patch id for binary / header-only
Patch-ids for binary patches are found by hashing the object ids of the before and after objects in succession. However in the --stable case, there is a bug where hunks are not flushed for binary and header-only patch ids, which would always result in a patch-id of 0000. The --unstable case is currently correct. Reorder the logic to branch into 3 cases for populating the patch body: header-only which populates nothing, binary which populates the object ids, and normal which populates the text diff. All branches will end up flushing the hunk. Don't populate the ---a/ and +++b/ lines for binary diffs, to correspond to those lines not being present in the "git diff" text output. This is necessary because we advertise that the patch-id calculated internally and used in format-patch is the same that what the builtin "git patch-id" would produce when piped from a diff. Update the test to run on both binary and normal files. Signed-off-by: Jerry Zhang <jerry@skydio.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
a0feb8611d
commit
0570be79ea
58
diff.c
58
diff.c
@@ -6221,46 +6221,46 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
|
|||||||
if (p->one->mode == 0) {
|
if (p->one->mode == 0) {
|
||||||
patch_id_add_string(&ctx, "newfilemode");
|
patch_id_add_string(&ctx, "newfilemode");
|
||||||
patch_id_add_mode(&ctx, p->two->mode);
|
patch_id_add_mode(&ctx, p->two->mode);
|
||||||
patch_id_add_string(&ctx, "---/dev/null");
|
|
||||||
patch_id_add_string(&ctx, "+++b/");
|
|
||||||
the_hash_algo->update_fn(&ctx, p->two->path, len2);
|
|
||||||
} else if (p->two->mode == 0) {
|
} else if (p->two->mode == 0) {
|
||||||
patch_id_add_string(&ctx, "deletedfilemode");
|
patch_id_add_string(&ctx, "deletedfilemode");
|
||||||
patch_id_add_mode(&ctx, p->one->mode);
|
patch_id_add_mode(&ctx, p->one->mode);
|
||||||
patch_id_add_string(&ctx, "---a/");
|
|
||||||
the_hash_algo->update_fn(&ctx, p->one->path, len1);
|
|
||||||
patch_id_add_string(&ctx, "+++/dev/null");
|
|
||||||
} else {
|
|
||||||
patch_id_add_string(&ctx, "---a/");
|
|
||||||
the_hash_algo->update_fn(&ctx, p->one->path, len1);
|
|
||||||
patch_id_add_string(&ctx, "+++b/");
|
|
||||||
the_hash_algo->update_fn(&ctx, p->two->path, len2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff_header_only)
|
if (diff_header_only) {
|
||||||
continue;
|
/* don't do anything since we're only populating header info */
|
||||||
|
} else if (diff_filespec_is_binary(options->repo, p->one) ||
|
||||||
if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
|
|
||||||
fill_mmfile(options->repo, &mf2, p->two) < 0)
|
|
||||||
return error("unable to read files to diff");
|
|
||||||
|
|
||||||
if (diff_filespec_is_binary(options->repo, p->one) ||
|
|
||||||
diff_filespec_is_binary(options->repo, p->two)) {
|
diff_filespec_is_binary(options->repo, p->two)) {
|
||||||
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid),
|
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid),
|
||||||
the_hash_algo->hexsz);
|
the_hash_algo->hexsz);
|
||||||
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid),
|
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid),
|
||||||
the_hash_algo->hexsz);
|
the_hash_algo->hexsz);
|
||||||
continue;
|
} else {
|
||||||
|
if (p->one->mode == 0) {
|
||||||
|
patch_id_add_string(&ctx, "---/dev/null");
|
||||||
|
patch_id_add_string(&ctx, "+++b/");
|
||||||
|
the_hash_algo->update_fn(&ctx, p->two->path, len2);
|
||||||
|
} else if (p->two->mode == 0) {
|
||||||
|
patch_id_add_string(&ctx, "---a/");
|
||||||
|
the_hash_algo->update_fn(&ctx, p->one->path, len1);
|
||||||
|
patch_id_add_string(&ctx, "+++/dev/null");
|
||||||
|
} else {
|
||||||
|
patch_id_add_string(&ctx, "---a/");
|
||||||
|
the_hash_algo->update_fn(&ctx, p->one->path, len1);
|
||||||
|
patch_id_add_string(&ctx, "+++b/");
|
||||||
|
the_hash_algo->update_fn(&ctx, p->two->path, len2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
|
||||||
|
fill_mmfile(options->repo, &mf2, p->two) < 0)
|
||||||
|
return error("unable to read files to diff");
|
||||||
|
xpp.flags = 0;
|
||||||
|
xecfg.ctxlen = 3;
|
||||||
|
xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
|
||||||
|
if (xdi_diff_outf(&mf1, &mf2, NULL,
|
||||||
|
patch_id_consume, &data, &xpp, &xecfg))
|
||||||
|
return error("unable to generate patch-id diff for %s",
|
||||||
|
p->one->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
xpp.flags = 0;
|
|
||||||
xecfg.ctxlen = 3;
|
|
||||||
xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
|
|
||||||
if (xdi_diff_outf(&mf1, &mf2, NULL,
|
|
||||||
patch_id_consume, &data, &xpp, &xecfg))
|
|
||||||
return error("unable to generate patch-id diff for %s",
|
|
||||||
p->one->path);
|
|
||||||
|
|
||||||
if (stable)
|
if (stable)
|
||||||
flush_one_hunk(oid, &ctx);
|
flush_one_hunk(oid, &ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,15 +43,16 @@ test_expect_success 'setup: 500 lines' '
|
|||||||
git add newfile &&
|
git add newfile &&
|
||||||
git commit -q -m "add small file" &&
|
git commit -q -m "add small file" &&
|
||||||
|
|
||||||
git cherry-pick main >/dev/null 2>&1
|
git cherry-pick main >/dev/null 2>&1 &&
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'setup attributes' '
|
git branch -f squashed main &&
|
||||||
echo "file binary" >.gitattributes
|
git checkout -q -f squashed &&
|
||||||
|
git reset -q --soft HEAD~2 &&
|
||||||
|
git commit -q -m squashed
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'detect upstream patch' '
|
test_expect_success 'detect upstream patch' '
|
||||||
git checkout -q main &&
|
git checkout -q main^{} &&
|
||||||
scramble file &&
|
scramble file &&
|
||||||
git add file &&
|
git add file &&
|
||||||
git commit -q -m "change big file again" &&
|
git commit -q -m "change big file again" &&
|
||||||
@@ -61,14 +62,27 @@ test_expect_success 'detect upstream patch' '
|
|||||||
test_must_be_empty revs
|
test_must_be_empty revs
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'detect upstream patch binary' '
|
||||||
|
echo "file binary" >.gitattributes &&
|
||||||
|
git checkout -q other^{} &&
|
||||||
|
git rebase main &&
|
||||||
|
git rev-list main...HEAD~ >revs &&
|
||||||
|
test_must_be_empty revs &&
|
||||||
|
test_when_finished "rm .gitattributes"
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'do not drop patch' '
|
test_expect_success 'do not drop patch' '
|
||||||
git branch -f squashed main &&
|
|
||||||
git checkout -q -f squashed &&
|
|
||||||
git reset -q --soft HEAD~2 &&
|
|
||||||
git commit -q -m squashed &&
|
|
||||||
git checkout -q other^{} &&
|
git checkout -q other^{} &&
|
||||||
test_must_fail git rebase squashed &&
|
test_must_fail git rebase squashed &&
|
||||||
git rebase --quit
|
test_when_finished "git rebase --abort"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'do not drop patch binary' '
|
||||||
|
echo "file binary" >.gitattributes &&
|
||||||
|
git checkout -q other^{} &&
|
||||||
|
test_must_fail git rebase squashed &&
|
||||||
|
test_when_finished "git rebase --abort" &&
|
||||||
|
test_when_finished "rm .gitattributes"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|||||||
Reference in New Issue
Block a user