Skip to content

File history for renamed files, with '--follow' equivalent to show the complete history #34686

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions modules/git/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,25 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file

// CommitsCountOptions the options when counting commits
type CommitsCountOptions struct {
RepoPath string
Not string
Revision []string
RelPath []string
Since string
Until string
RepoPath string
Not string
Revision []string
RelPath []string
Since string
Until string
FollowRename bool
}

// CommitsCount returns number of total commits of until given revision.
func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error) {
cmd := NewCommand("rev-list", "--count")
var cmd *Command
followRename := len(opts.RelPath) > 0 && opts.FollowRename

if followRename {
cmd = NewCommand("--no-pager", "log", "--pretty=format:%H")
} else {
cmd = NewCommand("rev-list", "--count")
}

cmd.AddDynamicArguments(opts.Revision...)

Expand All @@ -181,14 +189,19 @@ func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error)
}

if len(opts.RelPath) > 0 {
if opts.FollowRename {
cmd.AddOptionValues("--follow")
}
cmd.AddDashesAndList(opts.RelPath...)
}

stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: opts.RepoPath})
if err != nil {
return 0, err
}

if followRename {
return int64(len(strings.Split(stdout, "\n"))), nil
}
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
}

Expand Down
45 changes: 31 additions & 14 deletions modules/git/repo_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,22 +205,29 @@ func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bo
}

// FileCommitsCount return the number of files at a revision
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
func (repo *Repository) FileCommitsCount(revision, file string, followRename ...bool) (int64, error) {
_followRename := false
if len(followRename) > 0 {
_followRename = followRename[0]
}

return CommitsCount(repo.Ctx,
CommitsCountOptions{
RepoPath: repo.Path,
Revision: []string{revision},
RelPath: []string{file},
RepoPath: repo.Path,
Revision: []string{revision},
RelPath: []string{file},
FollowRename: _followRename,
})
}

type CommitsByFileAndRangeOptions struct {
Revision string
File string
Not string
Page int
Since string
Until string
Revision string
File string
Not string
Page int
Since string
Until string
FollowRename bool
}

// CommitsByFileAndRange return the commits according revision file and the page
Expand All @@ -232,9 +239,18 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
}()
go func() {
stderr := strings.Builder{}
gitCmd := NewCommand("rev-list").
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
var gitCmd *Command

if !opts.FollowRename {
gitCmd = NewCommand("rev-list")
} else {
gitCmd = NewCommand("--no-pager", "log").
AddOptionFormat("--pretty=format:%%H").
AddOptionFormat("--follow")
}
gitCmd.AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)

gitCmd.AddDynamicArguments(opts.Revision)

if opts.Not != "" {
Expand All @@ -253,7 +269,8 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {

if err != nil && !(opts.FollowRename && err == io.ErrUnexpectedEOF) {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
} else {
_ = stdoutWriter.Close()
Expand All @@ -270,7 +287,7 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
shaline := make([]byte, length+1)
for {
n, err := io.ReadFull(stdoutReader, shaline)
if err != nil || n < length {
if (err != nil && !(opts.FollowRename && err == io.ErrUnexpectedEOF)) || n < length {
if err == io.EOF {
err = nil
}
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,7 @@ editor.revert = Revert %s onto:

commits.desc = Browse source code change history.
commits.commits = Commits
commits.history_follow_rename = Include renames
commits.no_commits = No commits in common. "%s" and "%s" have entirely different histories.
commits.nothing_to_compare = These branches are equal.
commits.search.tooltip = You can prefix keywords with "author:", "committer:", "after:", or "before:", e.g. "revert author:Alice before:2019-01-13".
Expand Down
78 changes: 38 additions & 40 deletions options/locale/locale_uk-UA.ini
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ passcode=Код доступу
webauthn_insert_key=Вставте ключ безпеки
webauthn_sign_in=Натисніть кнопку на вашому ключі безпеки. Якщо ваш ключ без фізичної кнопки, поновно вставте ключ.
webauthn_press_button=Будь ласка, натисніть кнопку на вашому ключі безпеки…
webauthn_use_twofa=Використовуйте дво-факторний код із Вашого телефона
webauthn_use_twofa=Використовуйте двофакторний код із Вашого телефона
webauthn_error=Не вдалося прочитати ваш ключ безпеки.
webauthn_unsupported_browser=Ваш браузер наразі не підтримує WebAuthn.
webauthn_error_unknown=Сталася невідома помилка. Будь ласка, спробуйте ще раз.
Expand All @@ -51,11 +51,11 @@ webauthn_error_empty=Ви повинні встановити назву для
webauthn_error_timeout=Час очікування вичерпано, перш ніж ваш ключ було прочитано. Перезавантажте сторінку та спробуйте ще раз.
webauthn_reload=Оновити

repository=Репозиторій
repository=Сховище
organization=Організація
mirror=Дзеркало
issue_milestone=Етап
new_repo=Новий репозиторій
new_repo=Нове сховище
new_migrate=Нова міграція
new_mirror=Нове дзеркало
new_org=Нова організація
Expand Down Expand Up @@ -131,9 +131,9 @@ artifacts=Артефакти
expired=Прострочено
confirm_delete_artifact=Справді видалити артефакт '%s' ?

archived=Архівовані
archived=Архівовано

concept_code_repository=Репозиторій
concept_code_repository=Сховище
concept_user_organization=Організація

show_timestamps=Показувати часові мітки
Expand All @@ -148,7 +148,7 @@ value=Значення

filter=Фільтр
filter.clear=Очистити фільтр
filter.is_archived=Архівовані
filter.is_archived=Архівовано
filter.not_archived=Не архівовано
filter.is_fork=Відгалужено
filter.not_fork=Не відгалужено
Expand Down Expand Up @@ -224,70 +224,68 @@ app_desc=Зручний власний сервіс хостингу репоз
install=Легко встановити
platform=Платформонезалежність
lightweight=Невибагливість
lightweight_desc=Gitea має низькі вимоги до ресурсів та може працювати на недорогому Raspberry Pi. Збережіть свою машину енергію!
license=Відкритий вихідний код

[install]
install=Встановлення
installing_desc=Встановлення, будь ласка, зачекайте...
title=Початкова конфігурація
docker_helper=Якщо ви запускаєте Gitea всередині Docker, будь ласка уважно прочитайте <a target="_blank" rel="noopener" href="%s">документацію</a> перед тим, як щось змінити на цій сторінці.
require_db_desc=Gitea вимагає MySQL, PostgreSQL, MSSQL, SQLite3 або TiDB (протокол MySQL).
docker_helper=Якщо ви запускаєте Gitea у Docker, будь ласка, прочитайте <a target="_blank" rel="noopener noreferrer" href="%s">документацію</a> перед тим, як змінювати будь-які налаштування.
require_db_desc=Gitea потребує MySQL, PostgreSQL, MSSQL, SQLite3 або TiDB (протокол MySQL).
db_title=Налаштування бази даних
db_type=Тип бази даних
host=Хост
user=Ім'я кристувача
password=Пароль
db_name=Ім'я бази даних
db_name=Назва бази даних
db_schema=Схема
db_schema_helper=Залиште пустим для бази даних за замовчуванням ("публічна").
db_schema_helper=Залиште пустим для типової схеми бази даних ("публічна").
ssl_mode=SSL
path=Шлях
sqlite_helper=Шлях до файлу для бази даних SQLite3.<br>Введіть абсолютний шлях, якщо ви запускаєте Gіtea як сервіс.
sqlite_helper=Шлях до файлу бази даних SQLite3.<br>Введіть абсолютний шлях, якщо ви запускаєте Gіtea як сервіс.
reinstall_error=Ви намагаєтеся встановити в наявну базу даних Gitea
reinstall_confirm_message=Повторне встановлення в наявну базу даних Gitea може спричинити багато проблем. В більшості випадків, ви повинні використовувати свій наявний "app.ini" для запуску Gitea. Якщо ви знаєте, що робите, спробуйте наступне:
reinstall_confirm_check_1=Дані зашифровані з використанням SECRET_KEY з app.ini можуть бути втрачені: користувачі не зможуть увійти з 2FA/OTP і дзеркала можуть працювати некоректно. Встановлюючи цей прапорець, ви підтверджуєте, що в поточному файлі app.ini вказано правильне значення SECRET_KEY.
reinstall_confirm_check_2=Репозиторії та налаштування необхідно повторно синхронізувати. Встановлюючи цей прапорець, ви підтверджуєте, що ви синхронізуватимете хуки репозиторіїв та authorized_keys вручну. Ви підтверджуєте, що налаштування репозиторію і дзеркала є правильними.
reinstall_confirm_check_3=Ви підтверджуєте, що повністю впевнені в тому, що для цього екземпляра Gitea вказано правильне розташування app.ini та екземпляр слід встановити повторно. Ви підтверджуєте, що усвідомлюєте вищенаведені ризики.
reinstall_confirm_check_1=Дані, зашифровані за допомогою SECRET_KEY в app.ini, можуть бути втрачені: користувачі не зможуть увійти за допомогою 2FA/OTP, а дзеркала можуть працювати некоректно. Встановивши цей прапорець, ви підтверджуєте, що поточний файл app.ini містить правильний SECRET_KEY.
reinstall_confirm_check_2=Можливо, потрібно буде повторно синхронізувати сховища та налаштування. Встановивши цей прапорець, ви підтверджуєте, що будете ресинхронізувати хуки для сховищ і файл authorized_keys вручну. Ви підтверджуєте, що забезпечите правильність налаштувань сховища і дзеркала.
reinstall_confirm_check_3=Ви підтверджуєте, що абсолютно впевнені, що Gitea працює з правильним розташуванням файлу app.ini, і що вам потрібно перевстановити програму. Ви підтверджуєте, що усвідомлюєте вищевказані ризики.
err_empty_db_path=Шлях до файлу бази даних SQLite3 не може бути порожнім.
no_admin_and_disable_registration=Ви не можете вимкнути реєстрацію до створення облікового запису адміністратора.
no_admin_and_disable_registration=Ви не можете вимкнути реєстрацію без створення облікового запису адміністратора.
err_empty_admin_password=Пароль адміністратора не може бути порожнім.
err_empty_admin_email=Електронна адреса адміністратора не може бути порожньою.
err_admin_name_is_reserved=Неправильне ім'я користувача-адміністратора - ім'я зарезервоване
err_admin_name_pattern_not_allowed=Ім'я адміністратора недійсне, це ім'я підпадає під зарезервований шаблон
err_admin_name_is_invalid=Неправильне ім'я користувача-адміністратора
err_admin_name_is_reserved=Неправильне ім'я користувача адміністратора - ім'я зарезервовано
err_admin_name_pattern_not_allowed=Ім'я користувача адміністратора недійсне, воно відповідає зарезервованому шаблону
err_admin_name_is_invalid=Недійсне ім'я користувача адміністратора

general_title=Загальні налаштування
app_name=Назва сайту
app_name_helper=Тут ви можете ввести назву своєї компанії.
repo_path=Кореневий шлях репозиторія
repo_path_helper=Всі вилучені Git репозиторії будуть збережені в цей каталог.
lfs_path=Кореневої шлях Git LFS
lfs_path_helper=У цій папці будуть зберігатися файли Git LFS. Залиште порожнім, щоб вимкнути LFS.
run_user=Запуск від імені Користувача
repo_path=Кореневий шлях сховища
repo_path_helper=До цього каталогу буде збережено віддалені сховища Git.
lfs_path=Кореневий шлях Git LFS
lfs_path_helper=У цій теці будуть зберігатися файли Git LFS. Залиште порожнім, щоб вимкнути.
run_user=Виконати як
domain=Домен сервера
domain_helper=Домен або адреса хоста сервера.
domain_helper=Домен або хост-адреса сервера.
ssh_port=Порт SSH сервера
ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб вимкнути SSH.
http_port=Gitea HTTP порт
http_port_helper=Номер порту, який буде прослуховуватися Giteas веб-сервером.
http_port_helper=Номер порту, який буде прослуховуватися сервером Giteas.
app_url=Базова URL-адреса Gitea
app_url_helper=Базова адреса для HTTP(S) клонування через URL та повідомлень електронної пошти.
log_root_path=Шлях до лог файлу
log_root_path_helper=Файли журналу будуть записані в цей каталог.

optional_title=Додаткові налаштування
email_title=Налаштування Email
smtp_addr=SMTP хост
smtp_port=SMTP порт
smtp_from=Відправляти Email від імені
app_url_helper=Базова адреса для URL-адрес клонів HTTP(S) та сповіщень електронною поштою.
log_root_path=Шлях до журналу
log_root_path_helper=Файли журналу будуть записані в цю теку.

optional_title=Необов'язкові налаштування
email_title=Налаштування електронної пошти
smtp_addr=Сервер SMTP
smtp_port=Порт SMTP
smtp_from_invalid=Адреса "Надіслати листа як" недійсна
smtp_from_helper=Електронна пошта для використання в Gіtea. Введіть звичайну електронну адресу або використовуйте формат: "Ім'я" <[email protected]>.
mailer_user=SMTP Ім'я кристувача
mailer_password=SMTP Пароль
register_confirm=Потрібно підтвердити електронну пошту для реєстрації
smtp_from_helper=Адреса електронної пошти, яку буде використовувати Gitea. Введіть звичайну адресу електронної пошти або використовуйте формат «Ім'я» <[email protected]>.
mailer_user=Ім'я користувача SMTP
mailer_password=Пароль SMTP
register_confirm=Вимагати підтвердження електронною поштою для реєстрації
mail_notify=Увімкнути сповіщення електронною поштою
server_service_title=Сервер і налаштування зовнішніх служб
server_service_title=Налаштування сервера і сторонніх сервісів
offline_mode=Увімкнути локальний режим
offline_mode_popup=Відключити сторонні мережі доставки контенту і обслуговувати всі ресурси локально.
disable_gravatar=Вимкнути Gravatar
Expand Down
Loading
Loading