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

Already on GitHub? Sign in to your account

maintenance: add prune-remote-refs task #1838

Open
wants to merge 1 commit into
base: master
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
20 changes: 20 additions & 0 deletions Documentation/git-maintenance.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,26 @@ pack-refs::
need to iterate across many references. See linkgit:git-pack-refs[1]
for more information.

prune-remote-refs::
The `prune-remote-refs` task runs `git remote prune` on each remote
repository registered in the local repository. This task helps clean
up deleted remote branches, improving the performance of operations
that iterate through the refs. See linkgit:git-remote[1] for more
information. This task is disabled by default.
+
NOTE: This task is opt-in to prevent unexpected removal of remote refs
for users of git-maintenance. For most users, configuring `fetch.prune=true`
is a acceptable solution, as it will automatically clean up stale remote-tracking
branches during normal fetch operations. However, this task can be useful in
specific scenarios:
+
--
* When using selective fetching (e.g., `git fetch origin +foo:refs/remotes/origin/foo`)
where `fetch.prune` would only affect refs that are explicitly fetched.
* When third-party tools might perform unexpected full fetches, and you want
periodic cleanup independently of fetch operations.
--

OPTIONS
-------
--auto::
Expand Down
32 changes: 32 additions & 0 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "lockfile.h"
#include "parse-options.h"
#include "run-command.h"
#include "remote.h"
#include "sigchain.h"
#include "strvec.h"
#include "commit.h"
Expand Down Expand Up @@ -913,6 +914,30 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
return 0;
}

static int prune_remote(struct remote *remote, void *cb_data UNUSED)
{
struct child_process child = CHILD_PROCESS_INIT;

if (!remote->url.nr)
return 0;

child.git_cmd = 1;
strvec_pushl(&child.args, "remote", "prune", remote->name, NULL);

return !!run_command(&child);
}

static int maintenance_task_prune_remote(struct maintenance_run_opts *opts,
struct gc_config *cfg UNUSED)
{
if (for_each_remote(prune_remote, opts)) {
error(_("failed to prune remotes"));
return 1;
}

return 0;
}

/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)

Expand Down Expand Up @@ -1375,6 +1400,7 @@ enum maintenance_task_label {
TASK_GC,
TASK_COMMIT_GRAPH,
TASK_PACK_REFS,
TASK_PRUNE_REMOTE_REFS,

/* Leave as final value */
TASK__COUNT
Expand Down Expand Up @@ -1411,6 +1437,10 @@ static struct maintenance_task tasks[] = {
maintenance_task_pack_refs,
pack_refs_condition,
},
[TASK_PRUNE_REMOTE_REFS] = {
"prune-remote-refs",
maintenance_task_prune_remote,
},
};

static int compare_tasks_by_selection(const void *a_, const void *b_)
Expand Down Expand Up @@ -1505,6 +1535,8 @@ static void initialize_maintenance_strategy(void)
tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
tasks[TASK_PACK_REFS].enabled = 1;
tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
tasks[TASK_PRUNE_REMOTE_REFS].enabled = 0;
tasks[TASK_PRUNE_REMOTE_REFS].schedule = SCHEDULE_DAILY;
}
}

Expand Down
44 changes: 44 additions & 0 deletions t/t7900-maintenance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,50 @@ test_expect_success 'pack-refs task' '
test_subcommand git pack-refs --all --prune <pack-refs.txt
'

test_expect_success 'prune-remote-refs task not enabled by default' '
git clone . prune-test &&
(
cd prune-test &&
GIT_TRACE2_EVENT="$(pwd)/prune.txt" git maintenance run 2>err &&
test_subcommand ! git remote prune origin <prune.txt
)
'

test_expect_success 'prune-remote-refs task cleans stale remote refs' '
test_commit initial &&
# Create two separate remote repos
git clone . remote1 &&
git clone . remote2 &&
git clone . prune-test-clean &&
(
cd prune-test-clean &&
git config maintenance.prune-remote-refs.enabled true &&
# Add both remotes
git remote add remote1 "../remote1" &&
git remote add remote2 "../remote2" &&
# Create and push branches to both remotes
git branch -f side2 HEAD &&
git push remote1 side2 &&
git push remote2 side2 &&
# Rename branches in each remote to simulate a stale branch
git -C ../remote1 branch -m side2 side3 &&
git -C ../remote2 branch -m side2 side4 &&
GIT_TRACE2_EVENT="$(pwd)/prune.txt" git maintenance run --task=prune-remote-refs &&
# Verify pruning happened for both remotes
test_subcommand git remote prune remote1 <prune.txt &&
test_subcommand git remote prune remote2 <prune.txt &&
test_must_fail git rev-parse refs/remotes/remote1/side2 &&
test_must_fail git rev-parse refs/remotes/remote2/side2
)
'

test_expect_success '--auto and --schedule incompatible' '
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
test_grep "at most one" err
Expand Down
Loading