More tweaks. I am more or less happy now.

This commit is contained in:
James Smith 2023-01-28 22:39:06 +02:00
parent 01775362b3
commit 617eeb2c71
2 changed files with 50 additions and 48 deletions

View File

@ -1,29 +1,18 @@
# git-tidy # git-tidy
Have you ever come back to a git repo after a while, started developing, and I wrote this utility to save myself some repetitive typing, because I often come
then realised you weren't on the main branch, or your branch was missing the back to a repo after a while of not using it, and in the meanwhile a remote may
latest changes, so you ended up with merge conflicts? have moved on or I'm not sure what state it's in.
Or have you ever finished working on a feature, completed a pull-request online, So this gets it cleaned up relatively quickly.
and wanted an easy way to clean up your local repo from all the unused
references that have accumulated themselves?
Then `git-tidy` is for you! It's more or less the equivalent of
This is a simple Python script which you can install by copying (or symlinking)
anywhere on your path (I recommend ~/bin/, but something like /usr/local/bin/
would also work).
Entering
```bash ```bash
git tidy git checkout main
git fetch --all --purge # purge is to delete unnecessary remote refs
git merge origin/main main --ff-only
git branch --merged | grep -v main | xargs git branch -d
``` ```
at the terminal will:
- Check out the default branch, usually `main`
- if this is not configured, it will try to figure out what it should be,
- Pull to make sure that you're up-to-date with the default branch,
- Delete all branches that have already been merged into the default, and,
- Delete all references which have been removed from the remote as well,
leaving you with a pristine, tidy repository in order to continue your with some extra convenience and (I hope) safety features.
development.

View File

@ -10,7 +10,7 @@
# You should have received a copy of the GNU General Public License along with git-tidy. If not, see # You should have received a copy of the GNU General Public License along with git-tidy. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
"""git-tidy module.""" """git-tidy utility."""
import subprocess import subprocess
import sys import sys
@ -54,11 +54,22 @@ def run(command: Union[List[str], str]) -> Tuple[int, str]:
def get_default_branch() -> str: def get_default_branch() -> str:
"""Return the name of the repo's default branch.""" """Return the name of the repo's default branch.
First try the config, if that doesn't work, check existing branches for
some common defaults. If there aren't any or they're ambiguous, ask the
user.
Returns
-------
str
The name of the default branch with which we'll work for the rest of
the exercise.
"""
returncode, configured_default_branch = run(["git", "config", "--get", "--local", "tidy.defaultbranch"]) returncode, configured_default_branch = run(["git", "config", "--get", "--local", "tidy.defaultbranch"])
if returncode == 128: if returncode == 128:
# The --local flag caused this to fail because we're not in a git repository. # The --local flag caused this to fail because we're not in a git repository.
print(configured_default_branch, file=sys.stderr) print("fatal: not inside a repository", file=sys.stderr)
sys.exit(returncode) sys.exit(returncode)
# If we're in a repository, we need a list of branches, either as a # If we're in a repository, we need a list of branches, either as a
@ -77,13 +88,13 @@ def get_default_branch() -> str:
return configured_default_branch return configured_default_branch
print( print(
f"{configured_default_branch} configured as defauly branch for tidying purposes, but it doesn't exist!", f"{configured_default_branch} configured as default branch for tidying purposes, but it doesn't exist! "
"Attempting to reconfigure....",
file=sys.stderr, file=sys.stderr,
) )
# TODO: There is probably a clean way to fix this.
sys.exit(-1)
print("No default branch for git-tidy configured, will try to figure out which to use...") else:
print("No default branch for git-tidy configured, will try to figure out which to use...")
candidates = [] candidates = []
@ -94,27 +105,24 @@ def get_default_branch() -> str:
if len(candidates) == 1: if len(candidates) == 1:
# Only one branch name matches, so we'll go with that one. # Only one branch name matches, so we'll go with that one.
print(f"Using branch {candidates[0]}...")
run(["git", "config", "--add", "tidy.defaultbranch", candidates[0]]) run(["git", "config", "--add", "tidy.defaultbranch", candidates[0]])
return candidates[0] return candidates[0]
if len(candidates) == 0: # If there's no clear default, let the user select which one to use:
print("No candidate branches!", file=sys.stderr)
sys.exit(-1)
# If we don't have one or zero, which do we have?
selection = -1 selection = -1
while (selection < 0) or (selection >= len(candidates)): while (selection < 0) or (selection >= len(candidates)):
print( print("Unable to determine default branch automatically. Please select one:")
f"{'Several' if len(candidates) > 1 else 'No'} potential default branch candidates found. " for n, branch in enumerate(branch_list):
"Please select one:" print(f"{n}: {branch}")
)
for n, candidate in enumerate(candidates):
print(f"{n}: {candidate}")
# TODO: This breaks if the user is stupid and doesn't input an int. raw_input = input("Which to choose?")
selection = int(input("Which to choose?")) try:
selection = int(raw_input)
except ValueError:
continue
return candidates[selection] return branch_list[selection]
if __name__ == "__main__": if __name__ == "__main__":
@ -125,14 +133,19 @@ if __name__ == "__main__":
# Check which remote it's configured with. # Check which remote it's configured with.
_, remote = run(["git", "config", "--get", f"branch.{default_branch}.remote"]) _, remote = run(["git", "config", "--get", f"branch.{default_branch}.remote"])
print(f"{default_branch} is connected to {remote}")
print(f"{default_branch} is configured for remote {remote}")
# Get latest changes from remote, clear up unnecessary stuff. # Get latest changes from remote, clear up unnecessary stuff.
run(["git", "fetch", "--all", "--prune"]) returncode, output = run(["git", "fetch", "--all", "--prune"])
run( if returncode != 0: # possibly a problem in contacting the remote?
["git", "merge", "--ff-only", f"{remote}/{default_branch}", default_branch] print(output, file=sys.stderr)
) # TODO: Handle what happens if the ff fails. sys.exit(returncode)
print(output) # I like to see what `git fetch` has accomplished.
returncode, output = run(["git", "merge", "--ff-only", f"{remote}/{default_branch}", default_branch])
if returncode != 0: # Probably fast-forwarding won't work.
print(output, file=sys.stderr)
sys.exit(returncode)
# Check which branches are `--merged` and clean them up. # Check which branches are `--merged` and clean them up.
_, merged_branches_raw = run(["git", "branch", "--merged"]) _, merged_branches_raw = run(["git", "branch", "--merged"])