Installation

Gentoo

snippet.bash
emerge -av app-emacs/magit

Arch

snippet.bash
pacman -Syu magit

MELPA

Get the latest and greatest version of Magit, independent of the platform you are using from MELPA.

snippet.bash
M-x package-install RET magit

Configuration

snippet.lisp
;; MAGIT CONFIGURATION
;; --------------------------------------
(require 'magit)
 
;; Key bindings
(global-set-key (kbd "C-x g") 'magit-status)
 
;; Set the repository list
(setq magit-repository-directories
    ('~/dotfiles/' . 1)
    ('~/dotfiles/emacs.d/.emacs.d' . 1)) ;; Hidden directories did not seem to be captured automatically

Usage

Until you learn/commit to memory all of the key sequences the most useful way to use/navigate Magit is using the pop-ups. These are invoked using certain keys and are worth learning first.

Key Popup
b Branch
B bisecting
c committing
d diffing
E edif
f fetching
F pulling
l logging
m merging
M remoting
P pushing
o submoduling
r rebasing
w apply patches
W format patches
t tagging
z stashing

Listing Repositories

Magit can list the repositories that are define by magit-repository-directories and this should be set in your Magit configuration (see example above). You will be presented with a list of possible repositories that are found in those paths as shown below…

…and can select a repository by using the keys to navigate to one and hitting RET a view of the repository will open in a new window…

Repository View

In a repository view you can use various keys to invoke different actions, many will open a popup buffer showing you the possible options, key actions are listed in the table below.

Key Action
b Branch pop-up
c Commit pop-up

Stashes

You can view stashes using z and then follow the commands in the transient buffer to take actions.

Popups

Pull (`F`)

Key Action
p Pull from the push-remote of the current branch.
u Pull from the upstream of the current branch.
e Pull from a branch read in the minibuffer.

Push (`P`)

Key Action
C variables
p Push the current branch (master) to branch.<name>.pushRemote or if that is unset to remote.pushDefault.
u Push the current branch (master) to its upstream.
e Push the current branch (master) to elsewhere.
o Push an arbitrary branch or commit somewhere.
r Push one or multiple refspecs to a remote, both of which are read in the minibuffer.
m Push all matching branches to another repository.
t Push all tags to another repository.
T Push a tag to another repository.

Branch (`b`)

To create a new branch hit n in the branch pop-up, you will be asked where you wish to branch from, commonly this will be master (after having ensured you are up-to-date with master!) and you will then be prompted for a name of the new branch. You can then switch to this branch using l (to checkout a new local branch).

Key Action
d Edit branch description
u
r Rebase status
p Push remote
b Checkout
l Checkout local branch
c Checkout new branch
w Checkout new worktree
y Checkout pull-request
s Create new spin-off
n Create new branch
W Create new worktree
Y Create from pull-request
m Rename
x Reset
k Delete
C Configure…

Rebase (`r`)

Key Action
p Rebase the current branch onto branch.<name>.pushRemote. If that variable is unset, then rebase onto remote.pushDefault.
u Rebase the current branch onto its upstream branch.
e Rebase the current branch onto a branch read in the minibuffer.
i Interactively.
m Modify a commit.
s Subset.
w Reword a commit.
k Remove a commit.
f Autosquash

Interactive Rebasing (`r i`)

After initiating an interactive rebase you need to move the selected line to the last commit you wish to rebase and hit C-c C-c a buffer will appear listing the commits above the one you selected and you can then choose what to do with them.

Key Action
r Reword, edit message of commit on current line.
s Squash, will meld commit on current line into previous commit, and edit message.
e Stop at the commit on the current line.

The “trick” here if you wish to squash multiple commits is to set the very top commit to be reworded (r) and mark all others to be squashed (s), once done hit C-c C-c to perform the rebase and you will be asked prompted for a commit message which will by default list the commits that are being squashed

Diffing

You can use magit to look at differences between commits very easily. In the magit buffer hit Tab on a file that has changed, whether staged or not, and it expands and shows you the changes. Once committed you have to go into the commit (just hit Return or got into the log with l if the commit you want to look at isn't listed) but can see the same thing.

Diffing between branches

Based on the answer here this is very neat.

  • d to invoke Magit's diff transient buffer which shows you the options available.
  • -- to select a specific file.
  • -w to ignore white space.
  • r to select the range, which asks you for the thing you wish to compare the current file on the selected branch to, whether this is an older commit or the HEAD of a different branch.

Rebasing

Often you'll find that others have worked on features from a branch you have forked from and merged their changes before you and you may want to incorporate their changes into your branch. This is done with rebasing. To rebase your local branch on theirs and manually resolve the conflicts. You could switch branch (B) to the common source, pull (F, switch back to yours (B) and then undertake an interactive rebase (r i), but there is a shortcut to doing this which is to pull from the branch on which you wish to rebase whilst checked out on your current branch. In the Magit Status buffer you use F to pull but instead of u to pull from the upstream of the current branch you use e (which invokes magit-pull-branch) and you are prompted for the branch you wish to pull from. Update the status buffer and you may be informed of there are unstaged changes, these will likely be merge conflicts which you will have to resolve manually before staging, committing and pushing your branch.

.

Cherry Picking

You can pull across a commit from another branch by Cherry Picking which is initiated with A A when in the Magit status buffer. On initiation you are prompted for the branch you wish to cherry pick from, select the branch and by default the last commit is selected as that to cherry pick from. If conflicts are detected you need to resolve these manually, and in doing so Magit will automatically stage the changes for you. Once any conflicts are resolved in the Magit status buffer hit A again and you will be prompted for an action, A will Continue the cherry pick but you can also abort or skip.

Cherry picking older commits

TODO

Cherry picking specific files from a commit

It is also possible to cherry pick individual files if you want to move a file on one branch (A) to another (B). M-x magit-checkout-file allows individual files from a specified repository to be pulled across.

Checkout

Checking out in Git involves switching branches

Squashing Commits

I always forget how to squash commits (which is surprising as I seem to need to do it often) so have simplified the process described at Squashing Commits with Magit.

  1. In the Magit buffer hit l l to bring up the log history.
  2. On the oldest commit you want to squash hit r i to starting rebasing interactively.
  3. Move the cursor down to the last line you wish to squash (if there is a specific commit you wish to squash into the most recent you can move it up to the most recent using M-p).
  4. Use s to select commits to squash.
  5. Use C-c C-c to make a commit, you'll get the commit messages of those you selected presented, type a new one or just use one of the old ones.

Typically you will need to interact with “forges” such as Github and GitLab (or similar). Thankfully there are a wealth of tools to facilitate this.

Squashing commits after pushing

If you perform a rebase locally and then try to push them to origin it will fail because your local branch no longer has the commits made on the remote origin (even if the changes are still there since all you've done is squash them into a single commit). To resolve this you need to push with the following…

snippet.bash
git push origin +<branch>

The key to the above is the + preceding the branch you are pushing to on the remote (typically the branch your local is tracking). This ensures that the push only goes to that branch alone. Solution, as is so often the case, from StackOverflow.

Forge

Configuration

Start by telling git what your username for each forge is, this can be done globally or on a per repository basis.

snippet.bash
# Globally
git config --global [github|gitlab].user <username>
# Per repo
cd path/to/repo
git config --local [github|gitlab].user <username>

Repositories

For each forge you can set which host you wish to use, although if you use the github or gitlab forge's they have a default host set (api.github.com and gitlab.com/api/v4 respectively). If you need to set the host explicitly for a repository you can do so…

snippet.bash
cd path/to/repo
git config --local [github|gitlab].host <host>

Links

Forge Interaction

emacs/magit.txt · Last modified: 2022/07/18 12:54 by admin
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0