@@ -177,7 +177,8 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
177177}
178178
179179static int create_default_files (const char * template_path ,
180- const char * original_git_dir )
180+ const char * original_git_dir ,
181+ const struct repository_format * fmt )
181182{
182183 struct stat st1 ;
183184 struct strbuf buf = STRBUF_INIT ;
@@ -187,6 +188,7 @@ static int create_default_files(const char *template_path,
187188 int reinit ;
188189 int filemode ;
189190 struct strbuf err = STRBUF_INIT ;
191+ int repo_version = GIT_REPO_VERSION ;
190192
191193 /* Just look for `init.templatedir` */
192194 init_db_template_dir = NULL ; /* re-set in case it was set before */
@@ -244,11 +246,23 @@ static int create_default_files(const char *template_path,
244246 exit (1 );
245247 }
246248
249+ #ifndef ENABLE_SHA256
250+ if (fmt -> hash_algo != GIT_HASH_SHA1 )
251+ die (_ ("The hash algorithm %s is not supported in this build." ), hash_algos [fmt -> hash_algo ].name );
252+ #endif
253+
254+ if (fmt -> hash_algo != GIT_HASH_SHA1 )
255+ repo_version = GIT_REPO_VERSION_READ ;
256+
247257 /* This forces creation of new config file */
248258 xsnprintf (repo_version_string , sizeof (repo_version_string ),
249- "%d" , GIT_REPO_VERSION );
259+ "%d" , repo_version );
250260 git_config_set ("core.repositoryformatversion" , repo_version_string );
251261
262+ if (fmt -> hash_algo != GIT_HASH_SHA1 )
263+ git_config_set ("extensions.objectformat" ,
264+ hash_algos [fmt -> hash_algo ].name );
265+
252266 /* Check filemode trustability */
253267 path = git_path_buf (& buf , "config" );
254268 filemode = TEST_FILEMODE ;
@@ -340,12 +354,26 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
340354 write_file (git_link , "gitdir: %s" , git_dir );
341355}
342356
357+ static void validate_hash_algorithm (struct repository_format * repo_fmt , int hash )
358+ {
359+ /*
360+ * If we already have an initialized repo, don't allow the user to
361+ * specify a different algorithm, as that could cause corruption.
362+ * Otherwise, if the user has specified one on the command line, use it.
363+ */
364+ if (repo_fmt -> version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt -> hash_algo )
365+ die (_ ("attempt to reinitialize repository with different hash" ));
366+ else if (hash != GIT_HASH_UNKNOWN )
367+ repo_fmt -> hash_algo = hash ;
368+ }
369+
343370int init_db (const char * git_dir , const char * real_git_dir ,
344- const char * template_dir , unsigned int flags )
371+ const char * template_dir , int hash , unsigned int flags )
345372{
346373 int reinit ;
347374 int exist_ok = flags & INIT_DB_EXIST_OK ;
348375 char * original_git_dir = real_pathdup (git_dir , 1 );
376+ struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT ;
349377
350378 if (real_git_dir ) {
351379 struct stat st ;
@@ -378,9 +406,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
378406 * config file, so this will not fail. What we are catching
379407 * is an attempt to reinitialize new repository with an old tool.
380408 */
381- check_repository_format (NULL );
409+ check_repository_format (& repo_fmt );
382410
383- reinit = create_default_files (template_dir , original_git_dir );
411+ validate_hash_algorithm (& repo_fmt , hash );
412+
413+ reinit = create_default_files (template_dir , original_git_dir , & repo_fmt );
384414
385415 create_object_directory ();
386416
@@ -482,6 +512,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
482512 const char * work_tree ;
483513 const char * template_dir = NULL ;
484514 unsigned int flags = 0 ;
515+ const char * object_format = NULL ;
516+ int hash_algo = GIT_HASH_UNKNOWN ;
485517 const struct option init_db_options [] = {
486518 OPT_STRING (0 , "template" , & template_dir , N_ ("template-directory" ),
487519 N_ ("directory from which templates will be used" )),
@@ -494,6 +526,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
494526 OPT_BIT ('q' , "quiet" , & flags , N_ ("be quiet" ), INIT_DB_QUIET ),
495527 OPT_STRING (0 , "separate-git-dir" , & real_git_dir , N_ ("gitdir" ),
496528 N_ ("separate git dir from working tree" )),
529+ OPT_STRING (0 , "object-format" , & object_format , N_ ("hash" ),
530+ N_ ("specify the hash algorithm to use" )),
497531 OPT_END ()
498532 };
499533
@@ -546,6 +580,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
546580 free (cwd );
547581 }
548582
583+ if (object_format ) {
584+ hash_algo = hash_algo_by_name (object_format );
585+ if (hash_algo == GIT_HASH_UNKNOWN )
586+ die (_ ("unknown hash algorithm '%s'" ), object_format );
587+ }
588+
549589 if (init_shared_repository != -1 )
550590 set_shared_repository (init_shared_repository );
551591
@@ -597,5 +637,5 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
597637 UNLEAK (work_tree );
598638
599639 flags |= INIT_DB_EXIST_OK ;
600- return init_db (git_dir , real_git_dir , template_dir , flags );
640+ return init_db (git_dir , real_git_dir , template_dir , hash_algo , flags );
601641}
0 commit comments