Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor how working, repository, and index directories are initialized #544

Merged
merged 1 commit into from Dec 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
135 changes: 100 additions & 35 deletions lib/git/base.rb
Expand Up @@ -12,43 +12,35 @@ class Base

# (see Git.bare)
def self.bare(git_dir, options = {})
self.new({:repository => git_dir}.merge(options))
normalize_paths(options, default_repository: git_dir, bare: true)
self.new(options)
end

# (see Git.clone)
def self.clone(repository, name, options = {})
self.new(Git::Lib.new(nil, options[:log]).clone(repository, name, options))
new_options = Git::Lib.new(nil, options[:log]).clone(repository, name, options)
normalize_paths(new_options, bare: options[:bare] || options[:mirror])
self.new(new_options)
end

# Returns (and initialize if needed) a Git::Config instance
#
# @return [Git::Config] the current config instance.
def self.config
return @@config ||= Config.new
@@config ||= Config.new
end

# (see Git.init)
def self.init(directory, options = {})
options[:working_directory] ||= directory
options[:repository] ||= File.join(options[:working_directory], '.git')

FileUtils.mkdir_p(options[:working_directory]) if options[:working_directory] && !File.directory?(options[:working_directory])
def self.init(directory = '.', options = {})
normalize_paths(options, default_working_directory: directory, default_repository: directory, bare: options[:bare])

init_options = {
:bare => options[:bare],
:initial_branch => options[:initial_branch],
}

options.delete(:working_directory) if options[:bare]

# Submodules have a .git *file* not a .git folder.
# This file's contents point to the location of
# where the git refs are held (In the parent repo)
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
git_file = File.open('.git').read[8..-1].strip
options[:repository] = git_file
options[:index] = git_file + '/index'
end
directory = options[:bare] ? options[:repository] : options[:working_directory]
FileUtils.mkdir_p(directory) unless File.exist?(directory)

# TODO: this dance seems awkward: this creates a Git::Lib so we can call
# init so we can create a new Git::Base which in turn (ultimately)
Expand All @@ -66,21 +58,8 @@ def self.init(directory, options = {})
end

# (see Git.open)
def self.open(working_dir, options={})
# TODO: move this to Git.open?

options[:working_directory] ||= working_dir
options[:repository] ||= File.join(options[:working_directory], '.git')

# Submodules have a .git *file* not a .git folder.
# This file's contents point to the location of
# where the git refs are held (In the parent repo)
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
git_file = File.open('.git').read[8..-1].strip
options[:repository] = git_file
options[:index] = git_file + '/index'
end

def self.open(working_dir, options = {})
normalize_paths(options, default_working_directory: working_dir)
self.new(options)
end

Expand Down Expand Up @@ -571,7 +550,6 @@ def with_temp_working &blk
with_working(temp_dir, &blk)
end


# runs git rev-parse to convert the objectish to a full sha
#
# @example
Expand All @@ -596,6 +574,93 @@ def current_branch
self.lib.branch_current
end

end
private

# Normalize options before they are sent to Git::Base.new
#
# Updates the options parameter by setting appropriate values for the following keys:
# * options[:working_directory]
# * options[:repository]
# * options[:index]
#
# All three values will be set to absolute paths. An exception is that
# :working_directory will be set to nil if bare is true.
#
private_class_method def self.normalize_paths(
options, default_working_directory: nil, default_repository: nil, bare: false
)
normalize_working_directory(options, default: default_working_directory, bare: bare)
normalize_repository(options, default: default_repository, bare: bare)
normalize_index(options)
end

# Normalize options[:working_directory]
#
# If working with a bare repository, set to `nil`.
# Otherwise, set to the first non-nil value of:
# 1. `options[:working_directory]`,
# 2. the `default` parameter, or
# 3. the current working directory
#
# Finally, if options[:working_directory] is a relative path, convert it to an absoluite
# path relative to the current directory.
#
private_class_method def self.normalize_working_directory(options, default:, bare: false)
working_directory =
if bare
nil
else
File.expand_path(options[:working_directory] || default || Dir.pwd)
end

options[:working_directory] = working_directory
end

# Normalize options[:repository]
#
# If working with a bare repository, set to the first non-nil value out of:
# 1. `options[:repository]`
# 2. the `default` parameter
# 3. the current working directory
#
# Otherwise, set to the first non-nil value of:
# 1. `options[:repository]`
# 2. `.git`
#
# Next, if options[:repository] refers to a *file* and not a *directory*, set
# options[:repository] to the contents of that file. This is the case when
# working with a submodule or a secondary working tree (created with git worktree
# add). In these cases the repository is actually contained/nested within the
# parent's repository directory.
#
# Finally, if options[:repository] is a relative path, convert it to an absolute
# path relative to:
# 1. the current directory if working with a bare repository or
# 2. the working directory if NOT working with a bare repository
#
private_class_method def self.normalize_repository(options, default:, bare: false)
repository =
if bare
File.expand_path(options[:repository] || default || Dir.pwd)
else
File.expand_path(options[:repository] || '.git', options[:working_directory])
end

if File.file?(repository)
repository = File.expand_path(File.open(repository).read[8..-1].strip, options[:working_directory])
end

options[:repository] = repository
end

# Normalize options[:index]
#
# If options[:index] is a relative directory, convert it to an absolute
# directory relative to the repository directory
#
private_class_method def self.normalize_index(options)
index = File.expand_path(options[:index] || 'index', options[:repository])
options[:index] = index
end
end
end
3 changes: 1 addition & 2 deletions tests/units/test_init.rb
Expand Up @@ -45,8 +45,7 @@ def test_git_init
def test_git_init_bare
in_temp_dir do |path|
repo = Git.init(path, :bare => true)
assert(File.directory?(File.join(path, '.git')))
assert(File.exist?(File.join(path, '.git', 'config')))
assert(File.exist?(File.join(path, 'config')))
Copy link
Member Author

@jcouball jcouball Dec 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git.init should create the new, bare repository in the directory given by path and not in the .git subdirectory of path. This was a bug.

assert_equal('true', repo.config('core.bare'))
end
end
Expand Down
2 changes: 1 addition & 1 deletion tests/units/test_thread_safety.rb
Expand Up @@ -24,7 +24,7 @@ def test_git_init_bare
threads.each(&:join)

dirs.each do |dir|
Git.bare("#{dir}/.git").ls_files
Git.bare(dir).ls_files
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git.init should create the new, bare repository in the directory given by dir and not in the .git subdirectory of dir. This was a bug.

end
end
end