Module: Utils::Git Private

Extended by:
SystemCommand::Mixin
Defined in:
utils/git.rb

Overview

This module is part of a private API. This module may only be used in the Homebrew/brew repository. Third parties should avoid using this module if possible, as it may be removed or changed without warning.

Helper functions for querying Git information.

See Also:

Class Method Summary collapse

Methods included from SystemCommand::Mixin

system_command, system_command!

Class Method Details

.available?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


15
16
17
# File 'utils/git.rb', line 15

def self.available?
  !version.null?
end

.changed_files(repository) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

The paths (relative to repository's root) changed in its working tree since it diverged from the upstream default branch. The base is the origin/HEAD merge-base rather than the local default branch ref, which is often stale (e.g. in worktrees and freshly-cloned taps); it falls back to main when origin/HEAD is unavailable.

Parameters:

Returns:



131
132
133
134
135
# File 'utils/git.rb', line 131

def self.changed_files(repository)
  base_ref = Utils.popen_read(git, "-C", repository, "merge-base", "origin/HEAD", "HEAD").chomp.presence
  base_ref ||= "main"
  Utils.popen_read(git, "-C", repository, "diff", "--name-only", "--no-relative", base_ref).split("\n")
end

.cherry_pick!(repo, *args, resolve: false, verbose: false) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Special case of git cherry-pick that permits non-verbose output and optional resolution on merge conflict.

Parameters:

  • repo (Pathname, String)
  • args (String)
  • resolve (Boolean) (defaults to: false)
  • verbose (Boolean) (defaults to: false)

Returns:



192
193
194
195
196
197
198
199
200
201
202
# File 'utils/git.rb', line 192

def self.cherry_pick!(repo, *args, resolve: false, verbose: false)
  cmd = [git.to_s, "-C", repo, "cherry-pick"] + args
  output = Utils.popen_read(*cmd, err: :out)
  if $CHILD_STATUS.success?
    puts output if verbose
    output
  else
    system git.to_s, "-C", repo.to_s, "cherry-pick", "--abort" unless resolve
    raise ErrorDuringExecution.new(cmd, status: $CHILD_STATUS, output: [[:stdout, output]])
  end
end

.clear_available_cachevoid

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



60
61
62
63
64
# File 'utils/git.rb', line 60

def self.clear_available_cache
  remove_instance_variable(:@version) if defined?(@version)
  remove_instance_variable(:@path) if defined?(@path)
  remove_instance_variable(:@git) if defined?(@git)
end

.count_coauthors(repository_path, person, from:, to:) ⇒ Integer

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



215
216
217
218
219
220
221
222
223
224
# File 'utils/git.rb', line 215

def self.count_coauthors(repository_path, person, from:, to:)
  return 0 if repository_path.blank?

  cmd = [git.to_s, "-C", repository_path.to_s, "log", "--oneline"]
  cmd << "--format='%(trailers:key=Co-authored-by:)''"
  cmd << "--before=#{to}" if to
  cmd << "--after=#{from}" if from

  Utils.safe_popen_read(*cmd).lines.count { |l| l.include?(person) }
end

.ensure_installed!void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'utils/git.rb', line 138

def self.ensure_installed!
  return if available?

  # we cannot install brewed git if homebrew/core is unavailable.
  if CoreTap.instance.installed?
    begin
      # Otherwise `git` will be installed from source in tests that need it. This is slow
      # and will also likely fail due to `OS::Linux` and `OS::Mac` being undefined.
      raise "Refusing to install Git on a generic OS." if ENV["HOMEBREW_TEST_GENERIC_OS"]

      require "formula"
      Formula["git"].ensure_installed!(executable: "git")
      clear_available_cache
    rescue
      raise "Git is unavailable"
    end
  end

  raise "Git is unavailable" unless available?
end

.file_at_commit(repo, file, commit) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



119
120
121
122
123
# File 'utils/git.rb', line 119

def self.file_at_commit(repo, file, commit)
  relative_file = Pathname(file)
  relative_file = relative_file.relative_path_from(repo) if relative_file.absolute?
  Utils.popen_read(git, "-C", repo, "show", "#{commit}:#{relative_file}")
end

.gitPathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



48
49
50
# File 'utils/git.rb', line 48

def self.git
  @git ||= T.let(HOMEBREW_SHIMS_PATH/"shared/git", T.nilable(Pathname))
end

.last_revision_commit_of_file(repo, file, before_commit: nil) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



70
71
72
73
74
75
76
77
78
# File 'utils/git.rb', line 70

def self.last_revision_commit_of_file(repo, file, before_commit: nil)
  args = if before_commit.nil?
    ["--skip=1"]
  else
    [before_commit.split("..").first]
  end

  Utils.popen_read(git, "-C", repo, "log", "--format=%h", "--abbrev=7", "--max-count=1", *args, "--", file).chomp
end

.last_revision_commit_of_files(repo, files, before_commit: nil) ⇒ Array<([String, nil], Array<String>)>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'utils/git.rb', line 87

def self.last_revision_commit_of_files(repo, files, before_commit: nil)
  args = if before_commit.nil?
    ["--skip=1"]
  else
    [before_commit.split("..").first]
  end

  # git log output format:
  #   <commit_hash>
  #   <file_path1>
  #   <file_path2>
  #   ...
  # return [<commit_hash>, [file_path1, file_path2, ...]]
  rev, *paths = Utils.popen_read(
    git, "-C", repo, "log",
    "--pretty=format:%h", "--abbrev=7", "--max-count=1",
    "--diff-filter=d", "--name-only", *args, "--", *files
  ).lines.map(&:chomp).reject(&:empty?)
  [rev, paths]
end

.last_revision_of_file(repo, file, before_commit: nil) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



112
113
114
115
116
# File 'utils/git.rb', line 112

def self.last_revision_of_file(repo, file, before_commit: nil)
  relative_file = Pathname(file).relative_path_from(repo)
  commit_hash = last_revision_commit_of_file(repo, relative_file, before_commit:)
  file_at_commit(repo, file, commit_hash)
end

.no_global_config_envHash{String => String}

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



20
21
22
# File 'utils/git.rb', line 20

def self.no_global_config_env
  { "GIT_CONFIG_GLOBAL" => no_global_config_file }
end

.no_global_config_fileString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



25
26
27
# File 'utils/git.rb', line 25

def self.no_global_config_file
  File::NULL
end

.pathString?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



40
41
42
43
44
45
# File 'utils/git.rb', line 40

def self.path
  return unless available?
  return @path if defined?(@path)

  @path = T.let(Utils.popen_read(git, "--homebrew=print-path").chomp.presence, T.nilable(String))
end

.remote_exists?(url) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


53
54
55
56
57
# File 'utils/git.rb', line 53

def self.remote_exists?(url)
  return true unless available?

  quiet_system "git", "ls-remote", url
end

.set_name_email!(author: true, committer: true) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.

Parameters:

  • author (Boolean) (defaults to: true)
  • committer (Boolean) (defaults to: true)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'utils/git.rb', line 160

def self.set_name_email!(author: true, committer: true)
  if Homebrew::EnvConfig.git_name
    ENV["GIT_AUTHOR_NAME"] = Homebrew::EnvConfig.git_name if author
    ENV["GIT_COMMITTER_NAME"] = Homebrew::EnvConfig.git_name if committer
  end

  if Homebrew::EnvConfig.git_committer_name && committer
    ENV["GIT_COMMITTER_NAME"] = Homebrew::EnvConfig.git_committer_name
  end

  if Homebrew::EnvConfig.git_email
    ENV["GIT_AUTHOR_EMAIL"] = Homebrew::EnvConfig.git_email if author
    ENV["GIT_COMMITTER_EMAIL"] = Homebrew::EnvConfig.git_email if committer
  end

  return unless committer
  return unless Homebrew::EnvConfig.git_committer_email

  ENV["GIT_COMMITTER_EMAIL"] = Homebrew::EnvConfig.git_committer_email
end

.setup_gpg!void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



182
183
184
185
186
187
# File 'utils/git.rb', line 182

def self.setup_gpg!
  gnupg_bin = Utils::Path.formula_opt_bin("gnupg")
  return unless gnupg_bin.directory?

  ENV["PATH"] = PATH.new(ENV.fetch("PATH")).prepend(gnupg_bin).to_s
end

.supports_partial_clone_sparse_checkout?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


205
206
207
208
209
# File 'utils/git.rb', line 205

def self.supports_partial_clone_sparse_checkout?
  # There is some support for partial clones prior to 2.20, but we avoid using it
  # due to performance issues
  version >= Version.new("2.20.0")
end

.versionVersion

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



30
31
32
33
34
35
36
37
# File 'utils/git.rb', line 30

def self.version
  @version ||= T.let(begin
    stdout, _, status = system_command(git, args: ["--version"], env: no_global_config_env,
                                            verbose: false, print_stderr: false).to_a
    version_str = status.success? ? stdout.chomp[/git version (\d+(?:\.\d+)*)/, 1] : nil
    version_str.nil? ? Version::NULL : Version.new(version_str)
  end, T.nilable(Version))
end