Sunday, January 4, 2009

Introduction to Egg

Work in Progress


Introduction

Egg is an Emacs interface to git. It's a suite composed of a minor-mode and various special-buffers presenting different UIs to help the user performing many git operations.
  • egg-minor-mode: providing git-specific vc-look-alike interface including similar key-bindings, a minor-mode menu and history annotations (blame).
  • egg's status-buffer:
    • index manipulation/commit preparation
    • interactive rebase stepping
    • merge conflict resolution
    • stashing work-in-progress
    • adding ignore pattern
    • staging new files
    • ediff or ediff3 launching. (e.g. 3-way ediff of work-dir/INDEX/HEAD, 3-way ediff of work-dir/theirs/ours)
  • egg's log-buffer
    • browse repo's history
    • ref (tag, branch, etc) creation and deletion
    • push and fetch
    • start merge/rebase/interactive-rebase session
    • attach/detach HEAD
    • search history (pickaxe)
    • compare revisions
  • egg's file-log-buffer: restricted version of the log-buffer, used to browse history of a single file.
  • egg's reflog-buffer: restricted variation of the log-buffer, used to browse the git's reflog and re-attach HEAD.
  • egg's query:commit-buffer: restricted variation of the log-buffer, used to browse history-search's results (pickaxe)
  • egg's stash-buffer: a log-buffer look-a-like, used to browse and apply stash entries to work-dir
  • egg-grep: a compile-mode which can grep files in non-checkout git revisions.
  • egg's commit-log-edit buffer: used to compose the commit-message for the upcoming commit. it can do some minor index manipulation.
  • egg's tag:msg-buffer: used to compose the message of an annotated tag
  • egg's diff-buffer: used to view the delta between file or repo revisions
Prerequisites
Egg doesn't provide an abstraction on top of git. Instead it assumes the user is familiar with git (and of course, emacs). Thus, egg claims it shares the same goals as git's aliases and is not another git porcelain.


Installation
  1. download egg.el (and egg-grep.el)
  2. compile it and put int somewhere in your emacs's load-path.
  3. put(require 'egg) in your .emacs
  4. run M-x customize-group egg at least once.
    • egg-git-command should be set to the proper command to invoke git. The default is "git". Same deal for egg-patch-command, although it's not as critical to egg as the first one.
    • turn-on egg-enable-tooltip to help self-familiarizing with egg. Egg's keymap is very context dependent. Tooltip balloons will shows the local keymap at the location of the cursor (point).
    • disable egg-confirm-next-action once familiar with egg. egg-next-action will then execute its guessed action immediately.
    • egg-minor-mode prefix is defaulted to "C-x v". However one can change the value by customizing egg-mode-key-prefix.
Minor-mode
When properly activated, open a file from a git repository would show Git:branch-name or (Egg, if egg hasn't yet had a chance to query the repo-status) in the mode-line and Egg (Git) menu on the menu-bar.

The menu show many of the git operations mapped by Egg and their invocation keys. Egg tries to keeps the key bindings similar to VC: "C-x v =". The most interesting command is egg-next-action and its keys "C-x v v". Using the menu-bar, egg-next-action will execute without confirmation (because it already showed the user what the next action is in menu.) If invoked using the keyboard, egg-next-action will ask the user for confirmation before executing the guessed next-action. The user then has the choice of accepting the guess or request egg to show a list of action candidates actions with the guessed candidate on the top.

It has always been the design objective of Egg:
  • help users to familiarize themselves with egg (using menu, help text, tooltip, etc.)
  • make the common operations a couple of keystrokes away and expeditive.

The Status Buffer

The most important egg's special buffer is the status-buffer. It's launched by typing "C-x v d" when editing with egg-minor-mode. The status-buffer contains 4 sub-sections: the repo section, the unstaged section, the staged section and the untracked section.

The repo section shows the name of the branch on which HEAD is attached to. Otherwise, it will says that HEAD is detached. There's also a Help section showing the bindings available in the buffer. Many blocks in the status buffer (and other egg special buffers) can be hidden. The picture on the right show the Help block was hidden and well as the delta of the file README.markdown and the first hunk of egg.el in the unstaged section. The "h" key and the middle mouse button toggle the hidden/shown state of a block. The customizable variable egg-buffer-hide-section-type-on-start can be used to control the initial (hidden/shown) state of different section types in egg's special buffers. In the status-buffer, as in other egg's special-buffers, the "n" and "p" keys let you navigate to the next and previous blocks while the "g" will refresh the display and the "q" will quit the window. If there was a rebase session in progress, the repo section will also show the current rebase step and more binding will be available to support rebase operations.

The two unstaged and staged sections let user do 3-way manipulation of the trio work-dir/INDEX/HEAD using the mostly "s" key and sometimes the "u" key. The "s" key behaves differently in the staged and unstaged section. In the unstaged section, it will stage the block (a file or a hunk) into which it was typed. In the staged section, it will unstage the block instead. A block of changes is ether a file-delta or a hunk. By example, in the unstaged section, typing the "s" key (stage) on the diff header of a file will add the contents of the file from the work-dir to the index. If "s" was typed into a hunk, then that hunk instead of the entire file-delta will be applied to the index. Typing "u" into the a diff-header in the unstaged section will basically restore the contents of the file back into its state in the INDEX. Typing "u" in an unstaged hunk will undo the changes shown by that hunk. Finally, typing the RET key will try to locate the line in the delta hunk back into its original file.


The Diff Buffer

Another common command is the diff command. It's bound to "C-x v =" in egg's minor-mode use the egg's diff-buffer to show the difference between the file or repository revisions. When editing a file, "C-x v =" (egg-file-diff), by default will show the delta between the current in the work-dir and its contents in the INDEX. With a prefix (i.e. "C-u C-x v ="), the command will prompt for the old version (the new version of the file being its contents in the work-dir).

The diff-buffer is similar to a restricted version of the status buffer. The status-buffer shows two comparisons, work-dir vs INDEX and INDEX vs HEAD. The diff-buffer only show one comparison and depending on the actual entities being compared, the "s" and the "u" key will behave differently. By example, when showing the diff between two arbitrary revisions, the "s" and "u" keys will be inactive. As in the status-buffer, there's a little block of help text show the key binding on different parts of the buffer. The "n", "p", "g" and "q" In the diff-buffer, and other egg buffers, the "n" and "p" keys move the cursor from one block to the other.

The Commit Buffer

The commit buffer is launched by the keys "C-x v c" in egg-minor-mode or "c" from the status-buffer. At the top of the commit-buffer, egg informs the user the branch the commit will be add to. The commit message shall be typed between the two dashed lines. That space will expand automatically when the users type newline. Below the message input area is the 3 sections already seen in the status-buffer: unstaged, staged and untracked. They are shown in the commit-buffer to let the user a overview on what will and will not be in the new commit. They also let the user do minor last-minute INDEX manipulations if required. If launched with a prefix, i.e. "C-u C-x v c" or "C-u c", the upcoming commit operation will amend the last commit of the branch. Egg will also pre-load the last-commit's message into the input area so the user can re-edit it if required. In the input area, the "M-n" and "M-p" keys will cycle through the previously typed commit messages while the usual keys "n", "p", "s", "u", "g" and "q" are active outside the input area and they behave similarly as in the status-buffer.

The Log Buffer

One of git's best features is its design of the refs system: simple, efficient and powerful. Egg's log-buffer let the user tap into that resource. The log buffer provide bindings to let user manipulate and control git's refs (branch, tag, annotated tags),: creating and removing, pushing and fetching, merging and rebasing, attaching and detaching HEAD, etc.

to be completed...

11 comments:

  1. Egg does not seem to cope with files a further directory deeper. e.g of we have ~/d/.git, then opening a file in ~/d/e/ will not trigger Egg mode. Any chance of a fix for this?

    ReplyDelete
  2. Hi. Just wanted to say that I like the look of Egg and could definitely see myself using it save for one bug. I can't push my local commits to the server. When I type U or C-v U or C-v v U or any other combination I could find, it merely says "This is a readonly buffer" or somesuch. Would love to see a fix for this!

    ReplyDelete
  3. I really like egg!
    There's just one thing I'm missing: I'd like to always add a "Signed-off-by:..." line to my commit messaged (automagically, of course).
    How can that be done? Thanks. Stefan

    ReplyDelete
  4. Nice work here! Is there a way to add the Untracked Files that show up in the egg status buffer?

    ReplyDelete
  5. Great stuff. But I can't find a description of how to do an interactive rebase in egg. How do you mark using . * and + do perform the operation?

    ReplyDelete
  6. Thank you for your work. Egg is very interesting. There is something it seems to be missing: launching ediff between two revisions, with the files side by side (not just the delta into a single buffer). Just like ediff-revision does.

    ReplyDelete
  7. I have been using Egg for some time now. It is probably the best Git mode for Emacs, but there seem to be no development anymore. Is the project still alive?

    ReplyDelete
  8. Hey egg would not activate when I opened a file in a git directory, so I changed the following line

    (when (string-match "\\`git version 1.6."

    to

    (when (string-match "git version 1.6."

    and now it seems to load fine.


    I haven't done much with egg, but it looks very interesting, thanks for writing it

    ReplyDelete
  9. sorry about all the white space in the previous post, I'm kind of tired....

    ReplyDelete
  10. I liked egg pretty much, but ever since mocing to Emacs 23, it has not worked properly, as I cannot get the push/pull to work at all, and the local and remote branch names are not shown in the log buffer any more. Any plans to make egg Emacs23-compatible? Git-version I'm running is 1.6.5,

    Best,

    HK.

    ReplyDelete
  11. Egg is pretty nice, but I can't figure out how to diff between branches with egg. It is easy to compare revisions in the same branch from the egg-log buffer, but how to compare different branches?

    ReplyDelete