Skip to content

Commit 47ea024

Browse files
committed
Remove useless branches in a repository
The purpose of `clear-local` command is to remove branches that have unexisting upstreams. And it starts asking for deleting branches if they aren't merged. But this behavior is overengineering and, usually, all these branches have to be removed. As the solution, the `prune-repository` command is introduced which makes safe automatic cleanup of all useless branches. Also, it doesn't try to save your working state by using pipes. This is because that if `prune-repository` is executed, then the repository should not have uncommitted changes, otherwise, it will fail.
1 parent c75b7ee commit 47ea024

7 files changed

Lines changed: 139 additions & 142 deletions

docs/commands.md

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ There are commands used in various situations such as
1818
clone-repository Clones a repository and configures it.
1919
init-repository Initializes a new repository and configures it.
2020
acquire-repository Configures current repository.
21-
clear-local Removes obsolete local branches.
21+
prune-repository Removes useless local branches.
2222

2323
manage a personal work
2424
start-work Creates a new branch.
@@ -118,29 +118,6 @@ git diff --cached --check
118118
git commit --amend
119119
```
120120

121-
# `clear-local`
122-
123-
```bash
124-
usage: git elegant clear-local
125-
```
126-
127-
Identifies local branches for which remote branches were removed. Then, it
128-
removes them by invoking `git branch -d`. If there are unmerged branches, you
129-
have to choose either batch or one-by-one deletion procedure using
130-
`git branch -D`.
131-
132-
Prior to the execution, a current state is saved (a branch with modifications).
133-
After the successful accepting a work, the state will be restored. In the case
134-
of a failure, you need to go to the desired branch and apply a stash if needed.
135-
136-
Approximate commands flow is
137-
```bash
138-
==>> git elegant clear-local
139-
git branch -d task-24
140-
git branch -d 2349
141-
git branch -D task-1
142-
```
143-
144121
# `clone-repository`
145122

146123
```bash
@@ -243,6 +220,33 @@ Approximate commands flow is
243220
git rebase --interactive @~5
244221
```
245222

223+
# `prune-repository`
224+
225+
```bash
226+
usage: git elegant prune-repository
227+
```
228+
229+
Identifies useless branches within the current repository and removes them. A
230+
branch is useless if it either has configured an unavailable upstream branch (1)
231+
or does not have new commits comparing to `master` branch (2).
232+
233+
1 - Usually, a local branch has this state when an appropriate remote branch was
234+
merged to a remote target branch and was removed. Since these manipulations were
235+
made on server side, the local branch is still present, but useless.
236+
237+
2 - This kind of branches appears when a branch is created for some purposes but
238+
does not have any commits nowadays. So, it is useless.
239+
240+
Approximate commands flow is
241+
```bash
242+
==>> git elegant prune-repository
243+
git checkout master
244+
git fetch --all
245+
git branch --delete --force task-24
246+
git branch --delete --force 2349
247+
git branch --delete --force task-1
248+
```
249+
246250
# `release-work`
247251

248252
```bash

libexec/git-elegant

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,6 @@ _error-if-empty() {
4040
fi
4141
}
4242

43-
__loop_ask() {
44-
local c="$1"; shift
45-
local m="$1"; shift
46-
[ -z "$1" ] && return 0
47-
for i in $@; do
48-
question-text "$m [$i] (y/n):"
49-
read answer
50-
if [[ "${answer}" == "y" ]]; then
51-
eval "$c $i"
52-
fi
53-
done
54-
}
55-
56-
__loop() {
57-
local c="$1"; shift
58-
[ -z "$1" ] && return 0
59-
for i in $@; do
60-
eval "$c $i"
61-
done
62-
}
63-
64-
__batch() {
65-
local MM="$1"; shift
66-
local AM="$1"; shift
67-
local CM="$1"; shift
68-
question-text "$MM (y/n): "
69-
read answer
70-
if [[ "${answer}" == "y" ]]; then
71-
__loop "$CM" $@
72-
else
73-
__loop_ask "$CM" "$AM" $@
74-
fi
75-
}
76-
7743
branch-from-remote-reference() {
7844
# usage: branch-from-remote-reference <full reference name>
7945
echo ${1} | sed "s|^[a-zA-Z0-9_-]*/||g"
@@ -109,7 +75,7 @@ There are commands used in various situations such as
10975
$(--print-command-in-usage clone-repository)
11076
$(--print-command-in-usage init-repository)
11177
$(--print-command-in-usage acquire-repository)
112-
$(--print-command-in-usage clear-local)
78+
$(--print-command-in-usage prune-repository)
11379
11480
manage a personal work
11581
$(--print-command-in-usage start-work)

libexec/git-elegant-clear-local

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
command-purpose() {
5+
cat <<MESSAGE
6+
Removes useless local branches.
7+
MESSAGE
8+
}
9+
10+
command-synopsis() {
11+
cat <<MESSAGE
12+
usage: git elegant prune-repository
13+
MESSAGE
14+
}
15+
16+
command-description() {
17+
cat<<MESSAGE
18+
Identifies useless branches within the current repository and removes them. A
19+
branch is useless if it either has configured an unavailable upstream branch (1)
20+
or does not have new commits comparing to \`master\` branch (2).
21+
22+
1 - Usually, a local branch has this state when an appropriate remote branch was
23+
merged to a remote target branch and was removed. Since these manipulations were
24+
made on server side, the local branch is still present, but useless.
25+
26+
2 - This kind of branches appears when a branch is created for some purposes but
27+
does not have any commits nowadays. So, it is useless.
28+
29+
Approximate commands flow is
30+
\`\`\`bash
31+
==>> git elegant prune-repository
32+
git checkout master
33+
git fetch --all
34+
git branch --delete --force task-24
35+
git branch --delete --force 2349
36+
git branch --delete --force task-1
37+
\`\`\`
38+
MESSAGE
39+
}
40+
41+
default() {
42+
git-verbose checkout ${MASTER}
43+
git-verbose fetch --all
44+
for branch in $(git for-each-ref --format "%(refname:short)" refs/heads/**); do
45+
if [[ ${branch} == ${MASTER} ]]; then continue; fi
46+
if [[ -n $(git config --get branch.${branch}.merge) ]]; then
47+
if git rev-parse --abbrev-ref ${branch}@{upstream} >/dev/null 2>&1; then
48+
# the branch has existing upstream; keep it
49+
continue
50+
fi
51+
else
52+
if [[ ! $(git merge-base ${MASTER} ${branch}) == $(git rev-parse ${branch}) ]]; then
53+
# the branch has new commits; keep it
54+
continue
55+
fi
56+
fi
57+
git-verbose branch --delete --force ${branch}
58+
done
59+
}

tests/git-elegant-clear-local.bats

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bats -ex
2+
3+
load addons-common
4+
load addons-read
5+
load addons-fake
6+
load addons-repo
7+
8+
setup() {
9+
repo-new
10+
}
11+
12+
teardown() {
13+
fake-clean
14+
repo-clean
15+
}
16+
17+
@test "'prune-repository': a branch is removed when it doesn't have an upstream and new commits" {
18+
repo "git checkout -b equal-to-master"
19+
repo "git checkout master"
20+
check git-elegant prune-repository
21+
[[ ${status} -eq 0 ]]
22+
[[ ${lines[@]} =~ "git branch --delete --force equal-to-master" ]]
23+
}
24+
25+
@test "'prune-repository': a branch is alive when it doesn't have an upstream and has a new commit" {
26+
repo "git checkout -b commit"
27+
repo-commit-file "commit"
28+
check git-elegant prune-repository
29+
[[ ${status} -eq 0 ]]
30+
[[ ! ${lines[@]} =~ "git branch --delete --force commit" ]]
31+
}
32+
33+
@test "'prune-repository': a branch is removed when it has a gone upstream" {
34+
repo "git checkout -b upstream"
35+
repo "git checkout master"
36+
fake-pass "git config --get branch.upstream.merge" "upstream"
37+
fake-fail "git rev-parse --abbrev-ref upstream@{upstream}"
38+
check git-elegant prune-repository
39+
[[ ${status} -eq 0 ]]
40+
[[ ${lines[@]} =~ "git branch --delete --force upstream" ]]
41+
}
42+
43+
@test "'prune-repository': a branch is alive when it has an active upstream" {
44+
repo "git checkout -b upstream"
45+
fake-pass "git config --get branch.upstream.merge" "upstream"
46+
fake-pass "git rev-parse --abbrev-ref upstream@{upstream}"
47+
check git-elegant prune-repository
48+
[[ ${status} -eq 0 ]]
49+
[[ ! ${lines[@]} =~ "git branch --delete --force upstream" ]]
50+
}

tests/git-elegant-show-commands.bats

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ teardown() {
1818
"deliver-work"
1919
"accept-work"
2020
"obtain-work"
21-
"clear-local"
21+
"prune-repository"
2222
"show-commands"
2323
"amend-work"
2424
"show-release-notes"

0 commit comments

Comments
 (0)