1

I'm a little confused by the answers I see using:

git push -D

I'd like to delete all the branches returned from this result:

git branch -r --merged

Can't I simply combine them a la:

git push -D git branch -r --merged

Or is there a more elegant solution? And what about some query more complex that say deletes any unmerged branches without commits for the last 3 weeks? Here's my query for returning the list by commit date:

git branch -r --format="${commiterdate:iso8601},%commiterdate:relative)-%(refname.short)" --no-merged | sort
fumeng
  • 1,771
  • 5
  • 22
  • 61
  • 3
    For a remote named `origin`, You might want to try `git for-each-ref --format="%(refname:lstrip=-1)" --merged=master refs/remotes/origin` to retrieve the list of remote branches merged in `master` (assuming `master`, you didn't mention "merged" *in what*), without the `origin/` prefix, then send that list into your push-delete command. (`git push --delete origin $()`). But be **sure** to have the list exactly right before you actually do the pushing. – Romain Valeri Jun 02 '23 at 22:43
  • 2
    (As a sidenote, you have 2 typos in your `format` (a `$` instead of `%` right at the begining of the format, then a bit further `refname.short` with a dot instead of the colon)) – Romain Valeri Jun 02 '23 at 22:48

1 Answers1

1

Let's begin with the second complex query:

git log --remotes --decorate-refs-exclude=tags/* --decorate-refs-exclude=heads/* --no-walk --before=3week --no-merges --pretty=%D | tr , '\n' | xargs -n1 git branch -r -D

Why we begin with it? Because it includes both merged and non-merged branches with commits older than 3 weeks which you both want to delete. We could filter only non-merged branches here through git branch -r --no-merged but it doesn't make much sense for your particular task you want to achieve.

So here first we obtain last commits (--no-walk) older than 3 weeks (--before=3week) in remote branches (--remotes) and print decorated ref names (--pretty=%D). We filter out tags and local branches from the decorated refs with --decorate-refs-exclude=tags/* --decorate-refs-exclude=heads/*. Also we could probably want to skip merges (--no-merges) since they probably don't reflect actual work on branches. So we get something like that:

origin/MH-7788
origin/mh-7852-2
origin/mh-7854-manchkin-edit, origin/manchkin-edit
origin/isua-delete
origin/MH-7811
origin/MH-7853
origin/widgets-delete

Then we split several refs in a line:

tr , '\n'

So we get our list of remote branches to delete:

origin/MH-7788
origin/mh-7852-2
origin/mh-7854-manchkin-edit
 origin/manchkin-edit
origin/isua-delete
origin/MH-7811
origin/MH-7853
origin/widgets-delete

Then we just use xargs to tell git to delete each branch (we don't care about space padding here, xargs trims them:

xargs -n1 git branch -r -D 

So you deleted all remote branches (both merged and non-merged) with the last commit older than 3 weeks. Now just finish the job with deleting merged remotes:

git branch -r --merged | xargs -n1 git branch -r -D

How to filter the log

Ok, the job is done but I've decided to delete MERGED branches older than 3 months. First I want to get a list of them with the commit date and the commiter:

comm -12 <(git log --remotes --decorate-refs-exclude=tags/* --decorate-refs-exclude=heads/* --no-walk --no-merges --before=3month --pretty=%D | tr , '\n' | xargs -n1 | sort) <(git branch -r --merged | xargs -n1 | sort) | xargs -I {} sh -c "echo {} | tr '\n' '|'; git --no-pager log -1 --no-merges --pretty='%cd|%cN' {}" | sort -k2 -r -t "|" | column -t -s "|"

Here I compare our first query with git branch -r --merged to get common lines that would match the both queries. Then I do some double job unfortunately and ask git for log again for each branch but now it's formatted. I want to prefix a log line with the branch name so I echo a branch with a new line deletion. Since the whole line is printed inside a separate shell we have a git pager interfering (I have less) so we should ask git not to use the pager. I have | delimited fields as a result. First I sort by the date column then print as a table with column.

As a result I get:

origin/mh-7724-reverts      2023-02-28  Natalia Baganova
origin/top-btn              2023-02-21  zayceva
origin/MH-7718              2023-02-16  George Barlukov
origin/MH-7667              2023-02-07  George Barlukov
origin/MH-7689              2023-02-01  George Barlukov
origin/MH-7398-v3           2023-01-26  George Barlukov
origin/MH-7398-v2           2023-01-23  George Barlukov
origin/MH-7596              2023-01-19  George
origin/email-popup          2023-01-18  George
origin/FR-1016              2022-12-26  Dilya
origin/FR-995_kaz-cdek      2022-12-20  over_ilaj

Now when I examined the report I can delete the branches:

comm -12 <(git log --remotes --decorate-refs-exclude=tags/* --decorate-refs-exclude=heads/* --no-walk --no-merges --before=3month --pretty=%D | tr , '\n' | xargs -n1 | sort) <(git branch -r --merged | xargs -n1 | sort) | xargs -n1 git branch -r -D

Deleted remote-tracking branch origin/FR-1016 (was de5b5f618).
Deleted remote-tracking branch origin/FR-120_regions (was 5432cc4f5).
Deleted remote-tracking branch origin/FR-192_gmaps2 (was 08b31703b).
Deleted remote-tracking branch origin/FR-194_kiev_maps (was f67ba0240).
Deleted remote-tracking branch origin/FR-199_logout (was 2b8c28939).
Deleted remote-tracking branch origin/FR-224_bags (was f61d180d8).
Deleted remote-tracking branch origin/FR-993-1 (was c259a2dfa).
Deleted remote-tracking branch origin/FR-994_kazpost (was 701e3544e).
Deleted remote-tracking branch origin/FR-995_kaz-cdek (was 1dda904fc).
Deleted remote-tracking branch origin/MH-7292-fix (was 383dade6b).
Deleted remote-tracking branch origin/MH-7398-v2 (was d638591e7).
Deleted remote-tracking branch origin/MH-7398-v3 (was c68b976a8).
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
  • thank you very much for the detailed explanation! – fumeng Jun 05 '23 at 13:13
  • 1
    @fumeng you are welcome. actually thank you since i'm learning git right now and you helped me a lot to exercise. but we have some problem. seems `git branch -r -D` doesn't work since after `git fetch` i got the deleted remote branches again. i'll investigate the problem and return back to you with an update to my answer and add here a comment when it's done. stay tuned! – Alexander Nenashev Jun 05 '23 at 13:23
  • Remote-tracking branches are not meant to be created/deleted by hand. They're updated when you fetch, and you can prune them with `-p` to reflect deleted remote branches. Just delete remote branches with some version of `git push` then your (local) remote-tracking branches will be ready for the pruning. – Romain Valeri Jun 29 '23 at 08:26
  • @AlexanderNenashev I can relate, that's also how I learned 80% of what I know about git. SO is the best school! :-) – Romain Valeri Jun 29 '23 at 08:28