@@ -12,43 +12,35 @@ class Base
1212
1313 # (see Git.bare)
1414 def self . bare ( git_dir , options = { } )
15- self . new ( { :repository => git_dir } . merge ( options ) )
15+ normalize_paths ( options , default_repository : git_dir , bare : true )
16+ self . new ( options )
1617 end
1718
1819 # (see Git.clone)
1920 def self . clone ( repository , name , options = { } )
20- self . new ( Git ::Lib . new ( nil , options [ :log ] ) . clone ( repository , name , options ) )
21+ new_options = Git ::Lib . new ( nil , options [ :log ] ) . clone ( repository , name , options )
22+ normalize_paths ( new_options , bare : options [ :bare ] || options [ :mirror ] )
23+ self . new ( new_options )
2124 end
2225
2326 # Returns (and initialize if needed) a Git::Config instance
2427 #
2528 # @return [Git::Config] the current config instance.
2629 def self . config
27- return @@config ||= Config . new
30+ @@config ||= Config . new
2831 end
2932
3033 # (see Git.init)
31- def self . init ( directory , options = { } )
32- options [ :working_directory ] ||= directory
33- options [ :repository ] ||= File . join ( options [ :working_directory ] , '.git' )
34-
35- FileUtils . mkdir_p ( options [ :working_directory ] ) if options [ :working_directory ] && !File . directory? ( options [ :working_directory ] )
34+ def self . init ( directory = '.' , options = { } )
35+ normalize_paths ( options , default_working_directory : directory , default_repository : directory , bare : options [ :bare ] )
3636
3737 init_options = {
3838 :bare => options [ :bare ] ,
3939 :initial_branch => options [ :initial_branch ] ,
4040 }
4141
42- options . delete ( :working_directory ) if options [ :bare ]
43-
44- # Submodules have a .git *file* not a .git folder.
45- # This file's contents point to the location of
46- # where the git refs are held (In the parent repo)
47- if options [ :working_directory ] && File . file? ( File . join ( options [ :working_directory ] , '.git' ) )
48- git_file = File . open ( '.git' ) . read [ 8 ..-1 ] . strip
49- options [ :repository ] = git_file
50- options [ :index ] = git_file + '/index'
51- end
42+ directory = options [ :bare ] ? options [ :repository ] : options [ :working_directory ]
43+ FileUtils . mkdir_p ( directory ) unless File . exist? ( directory )
5244
5345 # TODO: this dance seems awkward: this creates a Git::Lib so we can call
5446 # init so we can create a new Git::Base which in turn (ultimately)
@@ -66,21 +58,8 @@ def self.init(directory, options = {})
6658 end
6759
6860 # (see Git.open)
69- def self . open ( working_dir , options = { } )
70- # TODO: move this to Git.open?
71-
72- options [ :working_directory ] ||= working_dir
73- options [ :repository ] ||= File . join ( options [ :working_directory ] , '.git' )
74-
75- # Submodules have a .git *file* not a .git folder.
76- # This file's contents point to the location of
77- # where the git refs are held (In the parent repo)
78- if options [ :working_directory ] && File . file? ( File . join ( options [ :working_directory ] , '.git' ) )
79- git_file = File . open ( '.git' ) . read [ 8 ..-1 ] . strip
80- options [ :repository ] = git_file
81- options [ :index ] = git_file + '/index'
82- end
83-
61+ def self . open ( working_dir , options = { } )
62+ normalize_paths ( options , default_working_directory : working_dir )
8463 self . new ( options )
8564 end
8665
@@ -571,7 +550,6 @@ def with_temp_working &blk
571550 with_working ( temp_dir , &blk )
572551 end
573552
574-
575553 # runs git rev-parse to convert the objectish to a full sha
576554 #
577555 # @example
@@ -596,6 +574,93 @@ def current_branch
596574 self . lib . branch_current
597575 end
598576
599- end
577+ private
578+
579+ # Normalize options before they are sent to Git::Base.new
580+ #
581+ # Updates the options parameter by setting appropriate values for the following keys:
582+ # * options[:working_directory]
583+ # * options[:repository]
584+ # * options[:index]
585+ #
586+ # All three values will be set to absolute paths. An exception is that
587+ # :working_directory will be set to nil if bare is true.
588+ #
589+ private_class_method def self . normalize_paths (
590+ options , default_working_directory : nil , default_repository : nil , bare : false
591+ )
592+ normalize_working_directory ( options , default : default_working_directory , bare : bare )
593+ normalize_repository ( options , default : default_repository , bare : bare )
594+ normalize_index ( options )
595+ end
596+
597+ # Normalize options[:working_directory]
598+ #
599+ # If working with a bare repository, set to `nil`.
600+ # Otherwise, set to the first non-nil value of:
601+ # 1. `options[:working_directory]`,
602+ # 2. the `default` parameter, or
603+ # 3. the current working directory
604+ #
605+ # Finally, if options[:working_directory] is a relative path, convert it to an absoluite
606+ # path relative to the current directory.
607+ #
608+ private_class_method def self . normalize_working_directory ( options , default :, bare : false )
609+ working_directory =
610+ if bare
611+ nil
612+ else
613+ File . expand_path ( options [ :working_directory ] || default || Dir . pwd )
614+ end
600615
616+ options [ :working_directory ] = working_directory
617+ end
618+
619+ # Normalize options[:repository]
620+ #
621+ # If working with a bare repository, set to the first non-nil value out of:
622+ # 1. `options[:repository]`
623+ # 2. the `default` parameter
624+ # 3. the current working directory
625+ #
626+ # Otherwise, set to the first non-nil value of:
627+ # 1. `options[:repository]`
628+ # 2. `.git`
629+ #
630+ # Next, if options[:repository] refers to a *file* and not a *directory*, set
631+ # options[:repository] to the contents of that file. This is the case when
632+ # working with a submodule or a secondary working tree (created with git worktree
633+ # add). In these cases the repository is actually contained/nested within the
634+ # parent's repository directory.
635+ #
636+ # Finally, if options[:repository] is a relative path, convert it to an absolute
637+ # path relative to:
638+ # 1. the current directory if working with a bare repository or
639+ # 2. the working directory if NOT working with a bare repository
640+ #
641+ private_class_method def self . normalize_repository ( options , default :, bare : false )
642+ repository =
643+ if bare
644+ File . expand_path ( options [ :repository ] || default || Dir . pwd )
645+ else
646+ File . expand_path ( options [ :repository ] || '.git' , options [ :working_directory ] )
647+ end
648+
649+ if File . file? ( repository )
650+ repository = File . expand_path ( File . open ( repository ) . read [ 8 ..-1 ] . strip , options [ :working_directory ] )
651+ end
652+
653+ options [ :repository ] = repository
654+ end
655+
656+ # Normalize options[:index]
657+ #
658+ # If options[:index] is a relative directory, convert it to an absolute
659+ # directory relative to the repository directory
660+ #
661+ private_class_method def self . normalize_index ( options )
662+ index = File . expand_path ( options [ :index ] || 'index' , options [ :repository ] )
663+ options [ :index ] = index
664+ end
665+ end
601666end
0 commit comments