Skip to content

Commit 6c5be97

Browse files
committed
Merge branch 'jc/undecided-is-not-necessarily-sha1-fix'
The base topic started to make it an error for a command to leave the hash algorithm unspecified, which revealed a few commands that were not ready for the change. Give users a knob to revert back to the "default is sha-1" behaviour as an escape hatch, and start fixing these breakages. * jc/undecided-is-not-necessarily-sha1-fix: apply: fix uninitialized hash function builtin/hash-object: fix uninitialized hash function builtin/patch-id: fix uninitialized hash function t1517: test commands that are designed to be run outside repository setup: add an escape hatch for "no more default hash algorithm" change
2 parents 988499e + 4674ab6 commit 6c5be97

File tree

7 files changed

+169
-0
lines changed

7 files changed

+169
-0
lines changed

builtin/apply.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "builtin.h"
22
#include "gettext.h"
33
#include "repository.h"
4+
#include "hash.h"
45
#include "apply.h"
56

67
static const char * const apply_usage[] = {
@@ -18,6 +19,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
1819
if (init_apply_state(&state, the_repository, prefix))
1920
exit(128);
2021

22+
/*
23+
* We could to redo the "apply.c" machinery to make this
24+
* arbitrary fallback unnecessary, but it is dubious that it
25+
* is worth the effort.
26+
* cf. https://lore.kernel.org/git/[email protected]/
27+
*/
28+
if (!the_hash_algo)
29+
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
30+
2131
argc = apply_parse_options(argc, argv,
2232
&state, &force_apply, &options,
2333
apply_usage);

builtin/hash-object.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
123123
else
124124
prefix = setup_git_directory_gently(&nongit);
125125

126+
if (nongit && !the_hash_algo)
127+
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
128+
126129
if (vpath && prefix) {
127130
vpath_free = prefix_filename(prefix, vpath);
128131
vpath = vpath_free;

builtin/patch-id.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "hash.h"
66
#include "hex.h"
77
#include "parse-options.h"
8+
#include "setup.h"
89

910
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
1011
{
@@ -237,6 +238,18 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix)
237238
argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
238239
patch_id_usage, 0);
239240

241+
/*
242+
* We rely on `the_hash_algo` to compute patch IDs. This is dubious as
243+
* it means that the hash algorithm now depends on the object hash of
244+
* the repository, even though git-patch-id(1) clearly defines that
245+
* patch IDs always use SHA1.
246+
*
247+
* NEEDSWORK: This hack should be removed in favor of converting
248+
* the code that computes patch IDs to always use SHA1.
249+
*/
250+
if (!the_hash_algo)
251+
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
252+
240253
generate_id_list(opts ? opts > 1 : config.stable,
241254
opts ? opts == 3 : config.verbatim);
242255
return 0;

repository.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,57 @@
2020
static struct repository the_repo;
2121
struct repository *the_repository = &the_repo;
2222

23+
/*
24+
* An escape hatch: if we hit a bug in the production code that fails
25+
* to set an appropriate hash algorithm (most likely to happen when
26+
* running outside a repository), we can tell the user who reported
27+
* the crash to set the environment variable to "sha1" (all lowercase)
28+
* to revert to the historical behaviour of defaulting to SHA-1.
29+
*/
30+
static void set_default_hash_algo(struct repository *repo)
31+
{
32+
const char *hash_name;
33+
int algo;
34+
35+
hash_name = getenv("GIT_TEST_DEFAULT_HASH_ALGO");
36+
if (!hash_name)
37+
return;
38+
algo = hash_algo_by_name(hash_name);
39+
if (algo == GIT_HASH_UNKNOWN)
40+
return;
41+
42+
repo_set_hash_algo(repo, algo);
43+
}
44+
2345
void initialize_repository(struct repository *repo)
2446
{
2547
repo->objects = raw_object_store_new();
2648
repo->remote_state = remote_state_new();
2749
repo->parsed_objects = parsed_object_pool_new();
2850
ALLOC_ARRAY(repo->index, 1);
2951
index_state_init(repo->index, repo);
52+
53+
/*
54+
* When a command runs inside a repository, it learns what
55+
* hash algorithm is in use from the repository, but some
56+
* commands are designed to work outside a repository, yet
57+
* they want to access the_hash_algo, if only for the length
58+
* of the hashed value to see if their input looks like a
59+
* plausible hash value.
60+
*
61+
* We are in the process of identifying such code paths and
62+
* giving them an appropriate default individually; any
63+
* unconverted code paths that try to access the_hash_algo
64+
* will thus fail. The end-users however have an escape hatch
65+
* to set GIT_TEST_DEFAULT_HASH_ALGO environment variable to
66+
* "sha1" to get back the old behaviour of defaulting to SHA-1.
67+
*
68+
* This escape hatch is deliberately kept unadvertised, so
69+
* that they see crashes and we can get a report before
70+
* telling them about it.
71+
*/
72+
if (repo == the_repository)
73+
set_default_hash_algo(repo);
3074
}
3175

3276
static void expand_base_dir(char **out, const char *in,

t/t1007-hash-object.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,10 @@ test_expect_success '--literally with extra-long type' '
260260
echo example | git hash-object -t $t --literally --stdin
261261
'
262262

263+
test_expect_success '--stdin outside of repository (uses SHA-1)' '
264+
nongit git hash-object --stdin <hello >actual &&
265+
echo "$(test_oid --hash=sha1 hello)" >expect &&
266+
test_cmp expect actual
267+
'
268+
263269
test_done

t/t1517-outside-repo.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/sh
2+
3+
test_description='check random commands outside repo'
4+
5+
TEST_PASSES_SANITIZE_LEAK=true
6+
. ./test-lib.sh
7+
8+
test_expect_success 'set up a non-repo directory and test file' '
9+
GIT_CEILING_DIRECTORIES=$(pwd) &&
10+
export GIT_CEILING_DIRECTORIES &&
11+
mkdir non-repo &&
12+
(
13+
cd non-repo &&
14+
# confirm that git does not find a repo
15+
test_must_fail git rev-parse --git-dir
16+
) &&
17+
test_write_lines one two three four >nums &&
18+
git add nums &&
19+
cp nums nums.old &&
20+
test_write_lines five >>nums &&
21+
git diff >sample.patch
22+
'
23+
24+
test_expect_success 'compute a patch-id outside repository (uses SHA-1)' '
25+
nongit env GIT_DEFAULT_HASH=sha1 \
26+
git patch-id <sample.patch >patch-id.expect &&
27+
nongit \
28+
git patch-id <sample.patch >patch-id.actual &&
29+
test_cmp patch-id.expect patch-id.actual
30+
'
31+
32+
test_expect_success 'hash-object outside repository (uses SHA-1)' '
33+
nongit env GIT_DEFAULT_HASH=sha1 \
34+
git hash-object --stdin <sample.patch >hash.expect &&
35+
nongit \
36+
git hash-object --stdin <sample.patch >hash.actual &&
37+
test_cmp hash.expect hash.actual
38+
'
39+
40+
test_expect_success 'apply a patch outside repository' '
41+
(
42+
cd non-repo &&
43+
cp ../nums.old nums &&
44+
git apply ../sample.patch
45+
) &&
46+
test_cmp nums non-repo/nums
47+
'
48+
49+
test_expect_success 'grep outside repository' '
50+
git grep --cached two >expect &&
51+
(
52+
cd non-repo &&
53+
cp ../nums.old nums &&
54+
git grep --no-index two >../actual
55+
) &&
56+
test_cmp expect actual
57+
'
58+
59+
test_done

t/t4204-patch-id.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,38 @@ test_expect_success 'patch-id handles diffs with one line of before/after' '
310310
test_config patchid.stable true &&
311311
calc_patch_id diffu1stable <diffu1
312312
'
313+
314+
test_expect_failure 'patch-id computes same ID with different object hashes' '
315+
test_when_finished "rm -rf repo-sha1 repo-sha256" &&
316+
317+
cat >diff <<-\EOF &&
318+
diff --git a/bar b/bar
319+
index bdaf90f..31051f6 100644
320+
--- a/bar
321+
+++ b/bar
322+
@@ -2 +2,2 @@
323+
b
324+
+c
325+
EOF
326+
327+
git init --object-format=sha1 repo-sha1 &&
328+
git -C repo-sha1 patch-id <diff >patch-id-sha1 &&
329+
git init --object-format=sha256 repo-sha256 &&
330+
git -C repo-sha256 patch-id <diff >patch-id-sha256 &&
331+
test_cmp patch-id-sha1 patch-id-sha256
332+
'
333+
334+
test_expect_success 'patch-id without repository' '
335+
cat >diff <<-\EOF &&
336+
diff --git a/bar b/bar
337+
index bdaf90f..31051f6 100644
338+
--- a/bar
339+
+++ b/bar
340+
@@ -2 +2,2 @@
341+
b
342+
+c
343+
EOF
344+
nongit git patch-id <diff
345+
'
346+
313347
test_done

0 commit comments

Comments
 (0)