Skip to content
/ gilt Public

💻 Command Line tool for easy git navigation

License

Notifications You must be signed in to change notification settings

ajcrites/gilt

Repository files navigation

gilt (pre alpha)

gilt is an interactive command line UI for working with git.

build status coverage version license PRs welcome

gilt

I generally work in the terminal and use git on the command line. This does most of what I need it to do, but I always felt a little guilty watching some of my peers use cool git GUIs and be able to do some nice things like view diffs or checkout commits with a single click whereas I would have to copy some output into new commands to do this as an extra step.

I haven't found an equivalent command line interactive git tool that has all the functionality I wanted, so I decided to create one. I bring you gilt, built using blessed.

Don't feel guilty about using the command line for version control! Feel gilty.

Purpose

gilt was created as a command line alternative for interactive git GUIs. It attempts to simplify navigating and working with git in common ways while not losing any git command line functionality or flexibility at all.

Essentially what gilt does is run your intended git command, parse its output, and lay over an interactive TUI (terminal user interface).

gilt is not currently intended to a full wrapper for git and passes commands through as a convenience. Please continue to use git as your command for your normal workflows and use gilt when you want its special functionality.

Usage

gilt [git-command]

For example, use gilt log --pretty=oneline or gilt status -s.

See below for a list of available gilt commands.

Most commands allow scrolling through selected blocks (commit hashes, files, etc.) using j/down and k/up. Default interaction is done through Enter.

You may quit gilt at any time using any of q Esc, or Ctrlc.

Installation

You will need Node.js to run gilt. It's only been tested on 9.4 at this point, but it should work with most newer versions.

yarn global add gilt

...or equivalent should be all you need to get going.

Copying to Clipboard

If you are using OS X, you'll have to install reattach-to-user-namespace which you can do with homebrew.

This is currently not supported on other OSen.

Available Commands

gilt is in active development and new commands may be added or the functionality of existing commands may be changed or removed. If gilt is not able to parse the output of a command, it will simply attempt to pass it through to the user.

Currently, gilt does not page output of passed through commands. This means that if you want to use your built-in git pager, you're better off just using git unsupported-command rather than using gilt.

gilt also attempts to guess the base git command that is being used by git aliases. For example, if you have [alias] lg = log --color --graph --abbrev-commit, gilt lg will be able to determine that this is the output of a git log command and parse and treat it as such so it should work similar to if you had just used git log or the same as git log --color --graph --abrev-commit.

Note: due to the complexity and variability of git aliases, the intended command may not be properly determined by gilt. In this case, it will just pass the output through.

log

gilt log will parse output to find commit hashes and allow you to scroll through these hashes and interact with them using the following key commands:

  • j, down - select next hash.
  • k, up - select previous hash.
  • u, Page Up - move up 5 hashes
  • d, Page Down - move down 5 hashes
  • enter, f - view diff of selected hash.
    • specifically, this runs git -c core.pager='less -+F' show -w <commit>.
  • c - checkout the selected hash.
  • r - perform an interactive rebase from this commit.
  • y - copy the selected hash to the clipboard.

status

gilt status will parse output to find filenames and allow you to scroll through these files and interact with them using the following key commands:

  • j, down - select next file.
  • k, up - select previous file.
  • u, Page Up - move up 5 files
  • d, Page Down - move down 5 files
  • enter, e - runs $EDITOR <selected-file>.
  • f - view diff of the current file
    • specifically, this runs git -c core.pager='less -+F' diff -w <file>.
  • x - remove the selected file (you are prompted for y/n first).
  • y - copy the selected filename to the clipboard.

Note: You must set your $EDITOR environment variable to use the editor functionality.

Note: Due to the wide variety of ways that git status can be used to format output as well as the seemingly infinite number of ways filenames can be specified, it's very easy for gilt to recieve some false positives or miss some actual filenames in the output. It should do a decent job of getting filenames for gilt status or gilt status -s.

Known Issues

  • Pass through commands are not paged.
  • The mouse doesn't interact with gilt command output at all.
  • The user's pager is not used for git output from within gilt. Instead, less -+F is used because if the output were less than one page the process would exit immediately and return to gilt without displaying anything.
  • Copying to clipboard requires reattach-to-user-namespace on OS X and is not supported on any other OS.

Upcoming Additions

  • Search + highlight and select functionality
    • for log
    • for status
  • Add parsing of sub-blocks such as authors, branch names, and more.
    • for log
    • for status
  • Add ability to select more than one block
    • toggle
    • shift
  • Add more commands
  • Automated testing of some kind
  • Mouse interactions
  • Page pass through output
  • Retain original git output
  • Use user defined pager for diff of git log.
  • Add API docs
  • Create a website

Development

To get set up for development, simply clone the repo and yarn install and you should be good to go.

yarn prepublishOnly will create the output command in lib/index.js which you can run as an executable.

I recommend running yarn link to link the repository for local development which should allow you use gilt on the command line. Then run npx tsc-watch and any changes you make to the source should update gilt.

Adding Custom Parsers

If you're not satisfied with an existing parser or you want to add a new parser for yourself, you can write your own command using gilt.

Gilt offers a bit of flexibility in terms of how you set up handling for commands. You can use the built in gilt API to determine what command the user is trying, run the command, and use the built-in gilt functionality.

For example, you may want to parse the output of a git subcommand and you may want to set up navigation and key/mouse bindings for a subcommand or both.

#!/usr/bin/env node
// better-gilt

// implement parser for git lg

import { parseArgs, run } from 'gilt';
import { Gilt } from 'gilt/Gilt';

import { betterParser, BetterCommand } from './better-gilt';

// Get the git subcommand the user is trying to run
const fullCommand = parseArgs();
// The git subcommand itself, e.g. `'log'`, `'status'`
const gitCommand = fullCommand[0];

class BetterGilt extends Gilt {
    run(fullCommand) {
        // Sets up blessed / command line interface
        this.start(fullCommand);

        // Set the content for the command line interface.
        // The imaginary `betterParser` parses the output to create Blocks
        this.navigator.setContent(this.content, betterParser(this.content));

        // BetterCommand extends Command and implements the `run` method which
        // sets up key bindings and other interface functionality
        const command = new BetterCommand(this.program, this.navigator);
        command.run();
    }
}

const betterGilt = new BetterGilt;

if ('lg' === gitCommand) {
    betterGilt.run();
} else {
    // Fall back to the default gilt functionality for all other commands
    run();
}

You must run the Navigator.setContent method with parameters of the content to display and an array of "data blocks" which are representations of the key list elements of the output of the command -- for example, commit hashes and filenames. See Block for the interface. A block has a block property which is a string of the acutual element (the hash or filename) and an offset which is its position in output used by navigation.

You can make the content and blocks anything you want, but these are usually the output of the git subcommand and the blocks representing the navigation elements of that content.

You can also extend Command to create a command that sets up key bindings and interacts with the display. You must inject a Program and Navigator into the constructor of your command. This will give you access to blessed operators on the program/navigator allowing you to set up key bindings, etc. while using the program and navigator APIs.