Skip to content
This repository

Emacs Got Git

Egg is not a git porcelain. It shares the same goals with git aliases , make it more convenient to perform common git operations . To use egg, simply compile the egg.el file then load the egg.elc file. You can put the egg.elc file somewhere in your emacs load-path and add (require 'egg) in your .emacs file.

Once activated, egg will turn on egg-minor-mode when a file was open in a git repository.

Minor mode key-bindings

The git action that operation on a single file, are bound (via the egg-minor-mode) to a command starting with C-x v. The C-x prefix, however, is customizable. M-x customize-group RET egg would let you customize that prefix and many other options.

key lisp description
C-x v d egg-status shows the repo’s current status. git status && git diff && git diff --cached && ...
C-x v c egg-commit-log-edit start editing the commit message for the current staged changes. With a prefix (C-u C-x v c), amend HEAD instead.
git commit -e …
C-x v i
egg-file-stage-current-file
stage new changes of the current file.
git add
C-x v l
egg-log
shows HEAD’s history . With a prefix (C-u C-x v l), show history of all refs.
git log
C-x v o
egg-file-checkout-other-version
checkout another version of the current file.
git checkout REV file
C-x v u
egg-file-cancel-modifications
unconditionally delete unstaged modifications in the current file. git checkout …
C-x v v
egg-next-action
perform the next logical action.
 git dwim
C-x v =
egg-file-diff
compare file with index or other commits.
 git diff…
C-x v ~
egg-file-version-other-window
show other version of the current file.
 git checkout…
C-x v b
egg-start-new-branch start a new branch from the current HEAD.
git checkout -b new_branch
C-x v a
egg-file-toggle-blame-mode enable/disable blame attributions (using overlays) in the current buffer.
git blame

Blame view mode

When blame-mode is on, the buffer is marked read-only. Disabling blame-mode will restore the original read-only mode of the buffer.

The Status Buffer

the status buffer is launched by the egg-status command. The primary usage for the status buffer:

  • file-by-file or hunk-by-hunk index manipulation.
    • stage a single unstaged hunk: add a single hunk from the a file to the index
    • remove a single unstaged hunk: remove hunk of delta between the index and the file.
    • unstage a single staged hunk: move a hunk from the index to the file.
    • update the index with the (new) contents of a file.
    • revert the contents of a file to match the index
    • revert the contents of a file in the index to match the contents of the file in HEAD.
  • resolve merge
    • locate conflict marks in a file
    • resolve merge using ediff3
  • resolve/continue/skip/abort rebase
    • locate conflict marks in a file
    • resolve rebase using ediff3

Status Buffer Screenshot during rebase

During a normal edit/stage/commit cycle, the status buffer displayed 3 sections:

  • Unstaged Changes section. this section show the delta between the files and the index.
  • Staged Changes section. this section show the delta between the index and HEAD.
  • Untracked Files section. this section files that are neither tracked nor ignored in the repository.

Status Buffer Screenshot showing the unstaged delta.

Many many parts of the status-buffer has local keymap. Example: the ‘s’ key may be bound to different elisp commands depending where the cursor currently is.

Common key-bindings for the status buffer

key lisp description
n
egg-buffer-cmd-navigate-next
move the cursor to the next section
p
egg-buffer-cmd-navigate-prev
move the cursor to the previous section
g
egg-buffer-cmd-refresh
redisplay the contents of the status buffer
q
quit-window
burry the status buffer
p
egg-buffer-cmd-navigate-next
move the cursor to the previous section
c
egg-commit-log-edit
start editing the commit message for the current staged changes. With a prefix (C-u C-x v c), amend HEAD instead.
git commit -e …
l
egg-log
shows HEAD’s history . With a prefix (C-u C-x v l), show history of all refs.
git log
S
egg-stage-all-files
Stage all modified tracked files.
git add

The diff header

The diff header has local keymap which bind many commands to operate on the a whole contents (vs a hunk) of the file.

key lisp description
h
egg-section-cmd-toggle-hide-show
hide/show the entire diff of this file
H
egg-section-cmd-toggle-hide-show-children
hide/show all the hunks (but keep header visible) of this file
RET
egg-diff-section-cmd-visit-file-other-window
open the file in another window
f
egg-diff-section-cmd-visit-file
open the file

In the Staged Changes section, the diff header has the following extra bindings:

s
egg-diff-section-cmd-unstage
unstage the staged changes ( git reset )

In the Unstaged Changes section, the diff header has the following extra bindings:

u
egg-diff-section-cmd-undo
throw away unstaged changes (git checkout)
s
egg-diff-section-cmd-stage
stage the changes ( git add )

The unmerged diff header

If the unstaged changes are actually unmerged changes, the combined-diff header has the following extra extra bindings (in addition to the bindings of a unstaged diff header)

=
egg-diff-section-cmd-ediff3
launch ediff3 with ours staged contents, current-file and theirs staged_ contents

Actually, the entire unmerged diff for the file (vs just the header) has the above extra binding.

The hunk

The diff hunk has local keymap which bind many commands to operate on the an individual diff hunk.

The visiting commands such as egg-hunk-section-cmd-visit-file-other-window try hard to locate the cursor at the exact line where the cursor was in the hunk. But since the diff between the index and HEAD can’t really be translated into the wordir’s file, the hunk-line location can fail.

key lisp description
h
egg-section-cmd-toggle-hide-show
hide/show this hunk
RET
egg-hunk-section-cmd-visit-file-other-window
open the file in another window and locate the current hunk
f
egg-hunk-section-cmd-visit-file
open the file and locate the current hunk

In the Staged Changes section, the hunk has the following extra bindings:

s
egg-hunk-section-cmd-unstage
unstage the staged hunk ( git apply --reverse )

In the Unstaged Changes section, the has the following extra bindings:

u
egg-hunk-section-cmd-undo
throw away the changes in this hunk (patch --reverse)
s
egg-hunk-section-cmd-stage
stage the changes in this hunk( git apply --cached)

The Log Buffer

the log buffer is launched by the egg-logcommand. The primary usage for the log buffer:

  • local push (updating a ref using HEAD or another ref)
  • remote push (updating a remote repository)
  • fetch
  • merge
  • rebase
  • create tags and branches
  • review history

Log Buffer Screenshot

The log-buffer shows history of HEAD (or with other refs). If egg-log was launched with a prefix (i.e. C-u), it will show the combined history of all refs. Some pickaxing commands like egg-search-history will pop up a log-buffer showing the history of HEAD and the pickaxed commit.

Generally, a line in the log-buffer represent a commit. The (short version of the) sha1 is shown just before the subject. If the commit are referred to by some refs, then refs would be listed just before the sha1. Their colours can be customized for easy differentiating between tags, heads and remotes.

The primary purpose of log buffer is for browing commit. Typing SPC on a commit line will fetch and show the details of commit under the cursor.

The commit line has following local key-bindings:

key lisp description
h
egg-section-cmd-toggle-hide-show
hide/show the details of this commit
H
egg-section-cmd-toggle-hide-show-children
hide/show all the diffs of this commits (when details were fetched)
B
egg-log-buffer-create-new-branch
Create a new branch starting at this commit (git branch). To create the new branch even if it would mean overwriting an existing one (with same name), use a prefix like C-u (e.g. C-u B
b
egg-log-buffer-start-new-branch
Create and switch a new branch starting at this commit (git checkout -b). To create the new branch even if it would mean overwriting an existing one (with same name), use a prefix (e.g. C-u b
o
egg-log-buffer-checkout-commit
Checkout the ref under the cursor or this commit (this might detach HEAD)
t
egg-log-buffer-tag-commit
create a light-weight tag pointing at this commit (git tag). To create the new tag even if it would mean overwriting an existing one (with same name), use a prefix (e.g. C-u t)
a
egg-log-buffer-attach-head
anchor HEAD at this commit (git reset). This command will detach HEAD. Use egg-log-buffer-checkout-commit instead if you want to attach HEAD to a branch. Normally, this command will only move HEAD and leave the index and the work dir untouched (git reset -soft). A prefix will launch a variant of this command.C-u a will reset the index as well as HEAD (git reset -mixed). C-u C-u a will reset HEAD, the index and the work dir to the current commit (git reset -hard).
m
egg-log-buffer-merge
merge this commit to HEAD (git merge). To disable auto-commit, use a prefix (e.g. C-u m)
r
egg-log-buffer-rebase
rebase HEAD on top this commit(git rebase). To the specify the starting commit (of the sequence of commits ending at HEAD, to be rebased onto the commit under the cursor), use a prefix (e.g. C-u r)

If the cursor was on top of a ref. Then the following extra bindings are defined locally:

key lisp description
x
egg-log-buffer-rm-ref
delete the ref under the cursor (git tag -d, git branch -d, git branch -rd). To ignore safety check, use a prefix (e.g. C-u x)
u
egg-log-buffer-push-to-local
local upload: use this ref to update another ref (git push . this:that ). This normally require a fast-forward update, to force non-ff update, use a prefix (e.g. C-u u)

If the ref under the cursor was local ref. Then the following extra extra bindings are defined:

d
egg-log-buffer-push-head-to-local
local download: use head to update the ref under the cursor.(git push HEAD:this ). This normally requires a fast-forward update, to force non-ff update, use a prefix (e.g. C-u d)
U
egg-log-buffer-push-to-remote
remote upload: update the tracking target of ref under the cursor. If the ref under the cursor wasn’t a remote tracking branch, the command will prompt for remote and target names. This command normally requires a fast-forward update, to force non-ff update, use a prefix (e.g. C-u U)

If the ref under the cursor was instead a remote ref. Then the following extra extra bindings are defined:

d
egg-log-buffer-fetch-remote
remote download: download and update the ref under the cursor(git fetch)
Something went wrong with that request. Please try again.