Use --left-right and --max-count for counting diverging commits
This commit is contained in:
parent
b72af2b9c7
commit
33c5630b02
|
@ -23,4 +23,12 @@ module BranchesHelper
|
||||||
def protected_branch?(project, branch)
|
def protected_branch?(project, branch)
|
||||||
ProtectedBranch.protected?(project, branch.name)
|
ProtectedBranch.protected?(project, branch.name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def diverging_count_label(count)
|
||||||
|
if count >= Repository::MAX_DIVERGING_COUNT
|
||||||
|
"#{Repository::MAX_DIVERGING_COUNT - 1}+"
|
||||||
|
else
|
||||||
|
count.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ class Repository
|
||||||
REF_MERGE_REQUEST = 'merge-requests'.freeze
|
REF_MERGE_REQUEST = 'merge-requests'.freeze
|
||||||
REF_KEEP_AROUND = 'keep-around'.freeze
|
REF_KEEP_AROUND = 'keep-around'.freeze
|
||||||
REF_ENVIRONMENTS = 'environments'.freeze
|
REF_ENVIRONMENTS = 'environments'.freeze
|
||||||
|
MAX_DIVERGING_COUNT = 1000
|
||||||
|
|
||||||
RESERVED_REFS_NAMES = %W[
|
RESERVED_REFS_NAMES = %W[
|
||||||
heads
|
heads
|
||||||
|
@ -278,11 +279,12 @@ class Repository
|
||||||
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
|
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
|
||||||
# Rugged seems to throw a `ReferenceError` when given branch_names rather
|
# Rugged seems to throw a `ReferenceError` when given branch_names rather
|
||||||
# than SHA-1 hashes
|
# than SHA-1 hashes
|
||||||
number_commits_behind = raw_repository
|
number_commits_behind, number_commits_ahead =
|
||||||
.count_commits_between(branch.dereferenced_target.sha, root_ref_hash)
|
raw_repository.count_commits_between(
|
||||||
|
root_ref_hash,
|
||||||
number_commits_ahead = raw_repository
|
branch.dereferenced_target.sha,
|
||||||
.count_commits_between(root_ref_hash, branch.dereferenced_target.sha)
|
left_right: true,
|
||||||
|
max_count: MAX_DIVERGING_COUNT)
|
||||||
|
|
||||||
{ behind: number_commits_behind, ahead: number_commits_ahead }
|
{ behind: number_commits_behind, ahead: number_commits_ahead }
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,16 +66,16 @@
|
||||||
= icon("trash-o")
|
= icon("trash-o")
|
||||||
|
|
||||||
- if branch.name != @repository.root_ref
|
- if branch.name != @repository.root_ref
|
||||||
.divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: number_commits_behind,
|
.divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind),
|
||||||
default_branch: @repository.root_ref,
|
default_branch: @repository.root_ref,
|
||||||
number_commits_ahead: number_commits_ahead } }
|
number_commits_ahead: diverging_count_label(number_commits_ahead) } }
|
||||||
.graph-side
|
.graph-side
|
||||||
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
|
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
|
||||||
%span.count.count-behind= number_commits_behind
|
%span.count.count-behind= diverging_count_label(number_commits_behind)
|
||||||
.graph-separator
|
.graph-separator
|
||||||
.graph-side
|
.graph-side
|
||||||
.bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" }
|
.bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" }
|
||||||
%span.count.count-ahead= number_commits_ahead
|
%span.count.count-ahead= diverging_count_label(number_commits_ahead)
|
||||||
|
|
||||||
|
|
||||||
- if commit
|
- if commit
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Improve the performance for counting diverging commits. Show 999+
|
||||||
|
if it is more than 1000 commits
|
||||||
|
merge_request: 15963
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -498,11 +498,13 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def count_commits(options)
|
def count_commits(options)
|
||||||
|
count_commits_options = process_count_commits_options(options)
|
||||||
|
|
||||||
gitaly_migrate(:count_commits) do |is_enabled|
|
gitaly_migrate(:count_commits) do |is_enabled|
|
||||||
if is_enabled
|
if is_enabled
|
||||||
count_commits_by_gitaly(options)
|
count_commits_by_gitaly(count_commits_options)
|
||||||
else
|
else
|
||||||
count_commits_by_shelling_out(options)
|
count_commits_by_shelling_out(count_commits_options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -540,8 +542,8 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
# Counts the amount of commits between `from` and `to`.
|
# Counts the amount of commits between `from` and `to`.
|
||||||
def count_commits_between(from, to)
|
def count_commits_between(from, to, options = {})
|
||||||
count_commits(ref: "#{from}..#{to}")
|
count_commits(from: from, to: to, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the SHA of the most recent common ancestor of +from+ and +to+
|
# Returns the SHA of the most recent common ancestor of +from+ and +to+
|
||||||
|
@ -1468,6 +1470,26 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_count_commits_options(options)
|
||||||
|
if options[:from] || options[:to]
|
||||||
|
ref =
|
||||||
|
if options[:left_right] # Compare with merge-base for left-right
|
||||||
|
"#{options[:from]}...#{options[:to]}"
|
||||||
|
else
|
||||||
|
"#{options[:from]}..#{options[:to]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
options.merge(ref: ref)
|
||||||
|
|
||||||
|
elsif options[:ref] && options[:left_right]
|
||||||
|
from, to = options[:ref].match(/\A([^\.]*)\.{2,3}([^\.]*)\z/)[1..2]
|
||||||
|
|
||||||
|
options.merge(from: from, to: to)
|
||||||
|
else
|
||||||
|
options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def log_using_shell?(options)
|
def log_using_shell?(options)
|
||||||
options[:path].present? ||
|
options[:path].present? ||
|
||||||
options[:disable_walk] ||
|
options[:disable_walk] ||
|
||||||
|
@ -1690,20 +1712,59 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def count_commits_by_gitaly(options)
|
def count_commits_by_gitaly(options)
|
||||||
gitaly_commit_client.commit_count(options[:ref], options)
|
if options[:left_right]
|
||||||
|
from = options[:from]
|
||||||
|
to = options[:to]
|
||||||
|
|
||||||
|
right_count = gitaly_commit_client
|
||||||
|
.commit_count("#{from}..#{to}", options)
|
||||||
|
left_count = gitaly_commit_client
|
||||||
|
.commit_count("#{to}..#{from}", options)
|
||||||
|
|
||||||
|
[left_count, right_count]
|
||||||
|
else
|
||||||
|
gitaly_commit_client.commit_count(options[:ref], options)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def count_commits_by_shelling_out(options)
|
def count_commits_by_shelling_out(options)
|
||||||
|
cmd = count_commits_shelling_command(options)
|
||||||
|
|
||||||
|
raw_output = IO.popen(cmd) { |io| io.read }
|
||||||
|
|
||||||
|
process_count_commits_raw_output(raw_output, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def count_commits_shelling_command(options)
|
||||||
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list]
|
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list]
|
||||||
cmd << "--after=#{options[:after].iso8601}" if options[:after]
|
cmd << "--after=#{options[:after].iso8601}" if options[:after]
|
||||||
cmd << "--before=#{options[:before].iso8601}" if options[:before]
|
cmd << "--before=#{options[:before].iso8601}" if options[:before]
|
||||||
cmd << "--max-count=#{options[:max_count]}" if options[:max_count]
|
cmd << "--max-count=#{options[:max_count]}" if options[:max_count]
|
||||||
|
cmd << "--left-right" if options[:left_right]
|
||||||
cmd += %W[--count #{options[:ref]}]
|
cmd += %W[--count #{options[:ref]}]
|
||||||
cmd += %W[-- #{options[:path]}] if options[:path].present?
|
cmd += %W[-- #{options[:path]}] if options[:path].present?
|
||||||
|
cmd
|
||||||
|
end
|
||||||
|
|
||||||
raw_output = IO.popen(cmd) { |io| io.read }
|
def process_count_commits_raw_output(raw_output, options)
|
||||||
|
if options[:left_right]
|
||||||
|
result = raw_output.scan(/\d+/).map(&:to_i)
|
||||||
|
|
||||||
raw_output.to_i
|
if result.sum != options[:max_count]
|
||||||
|
result
|
||||||
|
else # Reaching max count, right is not accurate
|
||||||
|
right_option =
|
||||||
|
process_count_commits_options(options
|
||||||
|
.except(:left_right, :from, :to)
|
||||||
|
.merge(ref: options[:to]))
|
||||||
|
|
||||||
|
right = count_commits_by_shelling_out(right_option)
|
||||||
|
|
||||||
|
[result.first, right] # left should be accurate in the first call
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raw_output.to_i
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def gitaly_ls_files(ref)
|
def gitaly_ls_files(ref)
|
||||||
|
|
|
@ -1030,14 +1030,52 @@ describe Gitlab::Git::Repository, seed_helper: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with max_count' do
|
||||||
|
it 'returns the number of commits with path ' do
|
||||||
|
options = { ref: 'master', max_count: 5 }
|
||||||
|
|
||||||
|
expect(repository.count_commits(options)).to eq(5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with path' do
|
context 'with path' do
|
||||||
it 'returns the number of commits with path ' do
|
it 'returns the number of commits with path ' do
|
||||||
options = { ref: 'master', path: "encoding" }
|
options = { ref: 'master', path: 'encoding' }
|
||||||
|
|
||||||
expect(repository.count_commits(options)).to eq(2)
|
expect(repository.count_commits(options)).to eq(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with option :from and option :to' do
|
||||||
|
it 'returns the number of commits ahead for fix-mode..fix-blob-path' do
|
||||||
|
options = { from: 'fix-mode', to: 'fix-blob-path' }
|
||||||
|
|
||||||
|
expect(repository.count_commits(options)).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the number of commits ahead for fix-blob-path..fix-mode' do
|
||||||
|
options = { from: 'fix-blob-path', to: 'fix-mode' }
|
||||||
|
|
||||||
|
expect(repository.count_commits(options)).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with option :left_right' do
|
||||||
|
it 'returns the number of commits for fix-mode...fix-blob-path' do
|
||||||
|
options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true }
|
||||||
|
|
||||||
|
expect(repository.count_commits(options)).to eq([1, 2])
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with max_count' do
|
||||||
|
it 'returns the number of commits with path ' do
|
||||||
|
options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true, max_count: 1 }
|
||||||
|
|
||||||
|
expect(repository.count_commits(options)).to eq([1, 1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with max_count' do
|
context 'with max_count' do
|
||||||
it 'returns the number of commits up to the passed limit' do
|
it 'returns the number of commits up to the passed limit' do
|
||||||
options = { ref: 'master', max_count: 10, after: Time.iso8601('2013-03-03T20:15:01+00:00') }
|
options = { ref: 'master', max_count: 10, after: Time.iso8601('2013-03-03T20:15:01+00:00') }
|
||||||
|
|
|
@ -2215,6 +2215,15 @@ describe Repository do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#diverging_commit_counts' do
|
||||||
|
it 'returns the commit counts behind and ahead of default branch' do
|
||||||
|
result = repository.diverging_commit_counts(
|
||||||
|
repository.find_branch('fix'))
|
||||||
|
|
||||||
|
expect(result).to eq(behind: 29, ahead: 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#cache_method_output', :use_clean_rails_memory_store_caching do
|
describe '#cache_method_output', :use_clean_rails_memory_store_caching do
|
||||||
let(:fallback) { 10 }
|
let(:fallback) { 10 }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue