Skip to content

hraban/git-hly

Repository files navigation

Git utilities by Hraban Luyat

Collection of Git utilities that can’t be found in vanilla Git or Magit:

git children
list all child branches of a commit
git graft
cut & paste an entire subtree of git branches
git pullfetch
git fetch and pull combo
git split
split a commit up into 1 commit per file

Commands

git hly: Top-level wrapper

To get a list of all subcommands, refer to git hly:

$ git hly
No such command: NIL

Valid commands:

- children
- graft
- pullfetch
- split


For in-depth help, pass --help to a subcommand.

git children: List all child branches of a commit

Usage

git childen REF

Non inclusive, i.e. the output does not include the branch you passed, itself.

Example

For this repo:

A -> B -> master -> C -> D -> origin/master
            \
              --> E -> branch1 -> F -> branch2
                         \
                           -----> G -> branch3

This command:

git children master

Will return:

branch1
branch2
branch3

git graft: Cut & paste an entire subtree of git branches

Typical use case: you have a long list of PRs which depend on each other; when origin/master is updated, you want to rebase all of them to the new origin/master. Instead of rebasing each branch individually, you want to “snip” the bottom off the old master, and “glue” it back onto the new one.

Usage

git graft ROOT ONTO
ROOT
the first commit under (and including) which all local branches will be selected.
ONTO
the commit onto which the subtree will be moved.

This git-graft won’t actually run the commands: it just prints them to stdout. You’re meant to manually copy & paste them to your shell. This is a temporary hack to allow a human to sanity check the results, and it provides rollback.

Advanced

Once you get comfortable with the tool, you can pipe directly to bash:

git graft ROOT ONTO | bash

This will print undo commands, so in case of trouble you can always rollback.

Example

say after a git fetch, you end up with:

A -> B -> master -> C -> D -> origin/master
            \
              --> E -> branch1 -> F -> branch2
                         \
                           -----> G -> branch3

Execute this:

git graft E origin/master

And you will get a bunch of git commands on stdout. Execute them all, and you should end up with:

... -> D -> origin/master -> E -> branch1 -> F -> branch2
                                    \
                                      -----> G -> branch3

Every local branch under (and including) branch1 will be moved, so be careful choosing something like (e.g.) master. It will work if all branches under master are indeed feature branches that you “own”, but if you locally checked out someone else’s branch, it will also be rebased.

Git-graft also prints “undo” commands, commented out. These are not expected to be necessary for normal operation, but if something goes wrong midway through a big graft, you can use those commands to go back to the pre-graft state.

The argument to git-graft, the root, is inclusive. This is at odds with git conventions, where you normally specify a commit’s “parent”, under which all relevant commits are found. The reason is that sometimes, e.g. the example above, choosing the parent can lead to too many branches being included: you’d get origin/master, and all potential other local branches already ported onto it.

git pullfetch: Git fetch and git pull combo

When cooperating with others on a busy repo this command helps “pull all changes.” Update master if it’s been updated, purge deleted branches, etc.

Usage:

git pullfetch

git split: Split HEAD into one commit per file

Useful for splitting up a convoluted commit as part of a larger rebase workflow.

See https://stackoverflow.com/questions/40698651/how-to-split-every-commit-by-file.

Installation

Stand-alone binary

Tip

This is easiest!

  1. Download the latest release for Linux or Mac
  2. Unpack and place in your PATH (e.g.: /usr/bin)

Or you can just invoke it directly, like ./git-hly.

Nix

Note

If you don’t know Nix, don’t worry about this. If you do, this is the way to go!

This project is available through Nix.

Non-flakes (aka. “channel based”)

Old-school Nix:

Install globally:

nix-env -if https://github.com/hraban/git-hly/archive/master.tar.gz

Or just build it in a temporary directory to play around with it:

nix-build https://github.com/hraban/git-hly/archive/master.tar.gz

The binary can be found in ./result/bin/. Copy it somewhere to your PATH.

Flakes

Do you use the hip new Nix Flakes? You can install this package in your profile:

nix profile install github:hraban/git-hly

Or you can just run it stand-alone (but it won’t integrate with the top-level git CLI):

nix run github:hraban/git-hly -- ...

Or you can build it locally and copy the binary out of ./result/bin to your PATH:

nix build github:hraban/git-hly

NixOS / nix-darwin / …

If you use these I’m sure you don’t need my help :)

Native

Warning

This is hard, I can’t think of why anybody would want to do this. Good luck.

Building this project natively is complicated and very dependent on your local setup. You need a more recent version of ASDF than comes bundled with SBCL. I recommend loading the project up in SLIME, with a new ASDF version pre-loaded. You can compile it to a binary using (asdf:make "git-hly").

License

git-hly - Hraban’s Git utilities Copyright © 2022–2024 Hraban Luyat

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.