Skip to content

Commit

Permalink
Merge branch 'jc/undecided-is-not-necessarily-sha1-fix' into seen
Browse files Browse the repository at this point in the history
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.

Comments?

* 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
  • Loading branch information
gitster committed May 14, 2024
2 parents 0578610 + 5b0ec43 commit 44ccbb4
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 2 deletions.
4 changes: 4 additions & 0 deletions builtin/apply.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "gettext.h"
#include "repository.h"
#include "hash.h"
#include "apply.h"

static const char * const apply_usage[] = {
Expand All @@ -18,6 +19,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
if (init_apply_state(&state, the_repository, prefix))
exit(128);

if (!the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);

argc = apply_parse_options(argc, argv,
&state, &force_apply, &options,
apply_usage);
Expand Down
3 changes: 3 additions & 0 deletions builtin/hash-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
else
prefix = setup_git_directory_gently(&nongit);

if (nongit && !the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);

if (vpath && prefix) {
vpath_free = prefix_filename(prefix, vpath);
vpath = vpath_free;
Expand Down
13 changes: 13 additions & 0 deletions builtin/patch-id.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "hash.h"
#include "hex.h"
#include "parse-options.h"
#include "setup.h"

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

/*
* We rely on `the_hash_algo` to compute patch IDs. This is dubious as
* it means that the hash algorithm now depends on the object hash of
* the repository, even though git-patch-id(1) clearly defines that
* patch IDs always use SHA1.
*
* NEEDSWORK: This hack should be removed in favor of converting
* the code that computes patch IDs to always use SHA1.
*/
if (!the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);

generate_id_list(opts ? opts > 1 : config.stable,
opts ? opts == 3 : config.verbatim);
return 0;
Expand Down
1 change: 1 addition & 0 deletions environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const char *getenv_safe(struct strvec *argv, const char *name);
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"

/*
* Environment variable used to propagate the --no-advice global option to the
Expand Down
40 changes: 40 additions & 0 deletions repository.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "abspath.h"
#include "environment.h"
#include "repository.h"
#include "object-store-ll.h"
#include "config.h"
Expand All @@ -19,13 +20,52 @@
static struct repository the_repo;
struct repository *the_repository = &the_repo;

static void set_default_hash_algo(struct repository *repo)
{
const char *hash_name;
int algo;

hash_name = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
if (!hash_name)
return;
algo = hash_algo_by_name(hash_name);

/*
* NEEDSWORK: after all, falling back to SHA-1 by assigning
* GIT_HASH_SHA1 to algo here, instead of returning, may give
* us better behaviour.
*/
if (algo == GIT_HASH_UNKNOWN)
return;

repo_set_hash_algo(repo, algo);
}

void initialize_repository(struct repository *repo)
{
repo->objects = raw_object_store_new();
repo->remote_state = remote_state_new();
repo->parsed_objects = parsed_object_pool_new();
ALLOC_ARRAY(repo->index, 1);
index_state_init(repo->index, repo);

/*
* When a command runs inside a repository, it learns what
* hash algorithm is in use from the repository, but some
* commands are designed to work outside a repository, yet
* they want to access the_hash_algo, if only for the length
* of the hashed value to see if their input looks like a
* plausible hash value.
*
* We are in the process of identifying the codepaths and
* giving them an appropriate default individually; any
* unconverted codepath that tries to access the_hash_algo
* will thus fail. The end-users however have an escape hatch
* to set GIT_DEFAULT_HASH environment variable to "sha1" get
* back the old behaviour of defaulting to SHA-1.
*/
if (repo == the_repository)
set_default_hash_algo(repo);
}

static void expand_base_dir(char **out, const char *in,
Expand Down
2 changes: 0 additions & 2 deletions setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1913,8 +1913,6 @@ const char *get_template_dir(const char *option_template)
#define TEST_FILEMODE 1
#endif

#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"

static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
DIR *dir)
{
Expand Down
6 changes: 6 additions & 0 deletions t/t1007-hash-object.sh
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,10 @@ test_expect_success '--literally with extra-long type' '
echo example | git hash-object -t $t --literally --stdin
'

test_expect_success '--stdin outside of repository' '
nongit git hash-object --stdin <hello >actual &&
echo "$(test_oid hello)" >expect &&
test_cmp expect actual
'

test_done
61 changes: 61 additions & 0 deletions t/t1517-outside-repo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/sh

test_description='check random commands outside repo'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_expect_success 'set up a non-repo directory and test file' '
GIT_CEILING_DIRECTORIES=$(pwd) &&
export GIT_CEILING_DIRECTORIES &&
mkdir non-repo &&
(
cd non-repo &&
# confirm that git does not find a repo
test_must_fail git rev-parse --git-dir
) &&
test_write_lines one two three four >nums &&
git add nums &&
cp nums nums.old &&
test_write_lines five >>nums &&
git diff >sample.patch
'

test_expect_success 'compute a patch-id outside repository' '
git patch-id <sample.patch >patch-id.expect &&
(
cd non-repo &&
git patch-id <../sample.patch >../patch-id.actual
) &&
test_cmp patch-id.expect patch-id.actual
'

test_expect_success 'hash-object outside repository' '
git hash-object --stdin <sample.patch >hash.expect &&
(
cd non-repo &&
git hash-object --stdin <../sample.patch >../hash.actual
) &&
test_cmp hash.expect hash.actual
'

test_expect_success 'apply a patch outside repository' '
(
cd non-repo &&
cp ../nums.old nums &&
git apply ../sample.patch
) &&
test_cmp nums non-repo/nums
'

test_expect_success 'grep outside repository' '
git grep --cached two >expect &&
(
cd non-repo &&
cp ../nums.old nums &&
git grep --no-index two >../actual
) &&
test_cmp expect actual
'

test_done
34 changes: 34 additions & 0 deletions t/t4204-patch-id.sh
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,38 @@ test_expect_success 'patch-id handles diffs with one line of before/after' '
test_config patchid.stable true &&
calc_patch_id diffu1stable <diffu1
'

test_expect_failure 'patch-id computes same ID with different object hashes' '
test_when_finished "rm -rf repo-sha1 repo-sha256" &&
cat >diff <<-\EOF &&
diff --git a/bar b/bar
index bdaf90f..31051f6 100644
--- a/bar
+++ b/bar
@@ -2 +2,2 @@
b
+c
EOF
git init --object-format=sha1 repo-sha1 &&
git -C repo-sha1 patch-id <diff >patch-id-sha1 &&
git init --object-format=sha256 repo-sha256 &&
git -C repo-sha256 patch-id <diff >patch-id-sha256 &&
test_cmp patch-id-sha1 patch-id-sha256
'

test_expect_success 'patch-id without repository' '
cat >diff <<-\EOF &&
diff --git a/bar b/bar
index bdaf90f..31051f6 100644
--- a/bar
+++ b/bar
@@ -2 +2,2 @@
b
+c
EOF
nongit git patch-id <diff
'

test_done

0 comments on commit 44ccbb4

Please sign in to comment.