Skip to content

Instantly share code, notes, and snippets.

@jeremyf
Created December 2, 2021 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyf/b22f02d14ca06f213ce07ee8a3532da0 to your computer and use it in GitHub Desktop.
Save jeremyf/b22f02d14ca06f213ce07ee8a3532da0 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby -w
##############################################################
#
# Begin Commentary
#
##############################################################
#
# First, if you want to use this, I recommend you change the
# the file mode to executable:
#
# `chmod +x local-branches-with-missing-remote`
#
# This command writes to STDOUT a list of local branches that
# have upstream tracking branches, but who's upstream branches
# are now gone.
#
# Fair warning, this perhaps follows some of my internalized
# assumptions about repository setup.
#
# I would love if there already existed a function that does
# this, but part of why I write code is to also practice
# algorithms and critical thinking.
#
# Example to list local branches with missing remotes:
#
# $ cd ~/git/forem ; local-branches-with-missing-remote
#
# Example to delete local branches with missing remotes:
#
# $ local-branches-with-missing-remote | xargs git remote -D
#
#
##############################################################
#
# Begin Function
#
##############################################################
#
# Prune the remote branches that are gone. Also, don't worry
# about the output
`git remote update origin --prune >/dev/null 2>&1`
# The remote branch lines are of the form:
#
# - space
# - origin/branch-name
#
# Note: by convention, origin is the upstream I'm concerned
# about
remote_branches = `git branch --remotes`
.split("\n")
.map(&:strip)
# The verbose branch lines are of the form:
#
# - Branch Name
# - many spaces
# - SHA of latest commit
# - space
# - OPTIONAL: "[Remote Name]"
# - space
# - Subject of latest commit
local_verbose_branches = `git branch -vv`
.split("\n")
.map { |b| b.gsub(/^\*? +/, '').strip }
local_verbose_branches.each do |verbose_branch|
# Definitely don't want to delete this local branch.
next if verbose_branch.start_with?("main")
# Though I no longer use "master" for my projects, there are
# some outliers that do.
next if verbose_branch.start_with?("master")
# I might have a local branch that doesn't have a remote
# tracking branch. Skip those
next unless verbose_branch.include?("[origin")
branch_name = verbose_branch.split(/ +/)[0]
# Test if local branch has a remote branch
next if remote_branches.detect do |rb|
rb.include?(branch_name)
end
# Output the branch name for a local branch with what
# appears to be a removed upstream branch (e.g., the
# upstream branch was likely merged and deleted)
puts branch_name
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment