prunable = "!f() { \
: git log ; \
target=\"$1\"; \
[ -z \"$target\" ] && target=$(git for-each-ref --format=\"%(refname:short)\" --count=1 refs/remotes/m/); \
if [ -z \"$target\" ]; then echo \"No remote branches found in refs/remotes/m/\"; return 1; fi; \
echo \"# git branch --merged shows merged if same commit ID only\" ;\
echo \"# if rebased, git cherry can show branch HEAD is merged\" ;\
echo \"# git log grep will check latest commit subject only. if amended, this status won't be accurate\" ;\
echo \"# Comparing against $target...\"; \
echo \"# git branch --merged:\"; \
git branch --merged $target ;\
echo \" ,- git cherry\" ; \
echo \" | ,- git log grep latest message\"; \
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do \
if git cherry \"$target\" \"$branch\" | tail -n 1 | grep -q \"^-\"; then \
cr=""; \
else \
cr=""; \
fi ; \
c=$(git rev-parse --short $branch) ; \
subject=$(git log -1 --format=%s \"$branch\" | sed 's/[][(){}.^$\*+?|\\/]/\\\\&/g') ; \
if git log --grep=\"^$subject$\" --oneline \"$target\" | grep -q .; then \
printf \"$cr $c %-20s $subject\\n\" $branch; \
else \
printf \"$cr \\033[0;33m$c \\033[0;32m%-20s\\033[0m $subject\\n\" $branch; \
fi; \
done; \
}; f"
(some emojis missing in above. see gist)
https://gist.github.com/lawm/8087252b4372759b2fe3b4052bf7e45...It prints the results of 3 methods:
1. git branch --merged
2. git cherry
3. grep upstream git log for a commit with the same commit subject
Has some caveats, like if upstream's commit was amended or the actual code change is different, it can have a false positive, or if there are multiple commits on your local branch, only the top commit is checked
function Rename-GitBranches {
git branch --list "my-branch-prefix/*" | Out-GridView -Title "Branches to Zoo?" -OutputMode Multiple | % { git branch -m $_.Trim() "zoo/$($_.Trim())" }
}
`Out-GridView` gives a very simple dialog box to (multi) select branch names I want to mark finished.I'm a branch hoarder in a squash merge repo and just prepend a `zoo/` prefix. `zoo/` generally sorts to the bottom of branch lists and I can collapse it as a folder in many UIs. I have found this useful in several ways:
1) It makes `git rebase --interactive` much easier when working with stacked branches by taking advantage of `--update-refs`. Merges do all that work for you by finding their common base/ancestor. Squash merging you have to remember which commits already merged to drop from your branch. With `--update-refs` if I find it trying to update a `zoo/` branch I know I can drop/delete every commit up to that update-ref line and also delete the update-ref.
2) I sometimes do want to find code in intermediate commits that never made it into the squashed version. Maybe I tried an experiment in a commit in a branch, then deleted that experiment in switching directions in a later commit. Squashing removes all evidence of that deleted experiment, but I can still find it if I remember the `zoo/` branch name.
All this extra work for things that merge commits gives you for free/simpler just makes me dislike squash merging repos more.
# ~/.gitconfig
[alias]
gone = ! "git fetch -p && git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '$2 == \"[gone]\" {print $1}' | xargs -r git branch -D"
Then you just `git gone` every once in a while, when you're between features.> What tools are the best to do the equivalent but for squash-merged branches detections?
Hooking on remote branch deletion is what most people do, under the assumption that you tend to clean out the branches of your PRs after a while. But of course if you don't do that it doesn't work.
Are you sure? I almost exclusively rebase-merge, and I use ‘git branch --merged‘ all the time. It works perfectly fine for me.
Also conceptually it seems to make sense to me: you rebase your commits onto the tip of the target branch, so you can trivially follow the link from the tip of your source branch to the tip of your target branch, which as I understand it is what the command checks for.
let t = "origin/dev"; git for-each-ref refs/heads/ --format="%(refname:short)" | lines | where {|b| $b !~ 'dev' and (git merge-tree --write-tree $t $b | lines | first) == (git rev-parse $"($t)^{tree}") }
Does a 3-way in-mem merge against (in my case) dev. If there's code in the branch that isn't in the target it won't show up.Pipe right to deletion if brave, or to a choice-thingy if prudent :)
To avoid losing any work, I have a habit of never keeping branches local-only for long. Additionally this relies on https://docs.github.com/en/repositories/configuring-branches...
What tools are the best to do the equivalent but for squash-merged branches detections?
Note: this problem is harder than it seems to do safely, because e.g. I can have a branch `foo` locally that was squash-merged on remote, but before it happened, I might have added a few more commits locally and forgot to push. So naively deleting `foo` locally may make me lose data.