Skip to content

akirak/git-identity.el

Repository files navigation

git-identity.el

https://melpa.org/packages/git-identity-badge.svg

https://github.com/akirak/git-identity.el/workflows/CI/badge.svg?branch=master

Git now has includeIf option, so you don’t need this package.

This Emacs package lets you manage local Git identities, i.e. user.name and user.email options in .git/config, from inside Emacs. It is primarily intended for users who meet all of the following assumptions:

  • You use Emacs.
  • You (almost always) use magit for Git operations on your machine(s).
  • You have to handle multiple Git identities on the same machine(s).

I found a CLI tool for the same purpose named karn, but since Emacs users are likely to run Git operations from inside Emacs (and the interface is probably Magit), it would be better if you had a solution integrated into Emacs. You only need to set a name and an email address before you perform git-commit, and if you use Emacs and Magit, it can be implemented by advising magit-commit. This package solves the problem. Now you don’t need a global Git configuration file to set your name and email address.

Features

  • You can configure multiple identities in your custom-file or in your init file. No extra dotfile is needed. If you work on multiple machines with different set of identities, you can maintain per-host configuration by just having separate custom files.
  • You can associate identities with repository host names and/or local working tree locations.
  • git-identity-magit-mode adds a :before hook to magit-commit to ensure that a given repository gets an expected identity before git-commit is run.
  • For manual operation, it provides a command to select an identity in the current repository interactively.
  • It provides a command (actually a hydra) to review your identity quickly and set a new one if necessary.

Installation

Install git-identity from MELPA.

Configuration

  1. Set git-identity-default-username, which is used as the default user name for all repositories.
  2. Configure git-identity-list variable. You can use customize-variable. Each entry consists of a mandatory e-mail address and options. The user name is optional, and if it is omitted, the default user name is set along with the e-mail address. You can associate repository hosts and/or local repository locations with the identity, which are used to pick an identity for a given repository.
  3. Optionally, you can start git-identity-magit-mode in your ~/.emacs.d/.init.el, which turns on the hook run before magit-status.

Below is an example configuration using use-package:

(use-package git-identity
  :after magit
  :config
  (git-identity-magit-mode 1)
  ;; Bind I to git-identity-info in magit-status
  (define-key magit-status-mode-map (kbd "I") 'git-identity-info)
  :custom
  ;; Warn if the global identity setting violates your policy
  (git-identity-verify t)
  ;; The default user name
  (git-identity-default-username "Akira Komamura"))

;; And set git-identity-list in your custom-file or init file
(setq git-identity-list
      '(("[email protected]"
         :domains ("github.com")
         ;; The identity is applied if the remote URL contains this organization as directory
         :exclude-organizations ("my-company-org")
         :dirs ("~/.emacs.d" "~/personal"))
        ("[email protected]"
         :domains ("github.com")
         ;; The identity is applied if the remote URL contains this organization as directory
         :organizations ("my-company-org"))
        ("[email protected]"
         :domains ("mycompany.com")
         :dirs ("~/work"))
        ("[email protected]"
         ;; Chinese name for cool Chinese sites!
         :name "刘文彬")))

Note: The format of git-identity-list is going to be changed in an upcoming version. See #2 for details.

You can restrict an identity to a certain organization (by setting :organizations) and prevent it from setting in an organization (by setting :exclude-organizations), but those options are effective if and only if you set correct :domains. For example, you can have separate identities on GitHub both for personal and for your company, but you have to include github.com in :domains of both identities. Note: Organization names are case-insensitive.

Caveat: These settings are only effective in your local repositories. Let’s assume you join a GitHub organization with your personal account and make commits for the organization locally using an alternative e-mail address. If you approve and merge PRs on the web application, GitHub will make merge commits on behalf of your personal account with your primary e-mail address. If you really want to use separate identities on the same service, you will need mutliple accounts.

Usage

Interactive use

If you turn on git-identity-magit-mode, git-identity checks for an identity every time magit-commit is invoked. If there is no local identity setting but a global one, the latter is used, so it won’t prompt for an identity.

You can also set the identity manually through git-identity-set-identity command.

To check what name and e-mail address are set on the repository, use git-identity-info command.

As a library

This package also exposes functions, which you can use as a library for writing your functions.

Parsing URLs

You can use the following functions from the package to extract a components from a Git URL:

  • git-identity-git-url-host returns the host name of a URL.
  • git-identity-git-url-directory returns the path, excluding the name.

See below for examples:

(git-identity-git-url-host "[email protected]:owner/repo.git") => "github.com"
(git-identity-git-url-host "[email protected]:1234123412341234.git") => "gist.github.com"
(git-identity-git-url-directory "[email protected]:owner/repo.git") => "owner"
(git-identity-git-url-directory "https://github.com:22/owner/repo.git/") => "owner"
(git-identity-git-url-directory "ssh://[email protected]:22/path/to/repo.git/") => "path/to"

The functions support most of the Git URLs defined in the man page of git-push (1). Below are examples:

ssh://github.com/path/to/repo.git
git://github.com/owner/repo.git
ftps://github.com:22/owner/repo.git/
[email protected]:owner/repo.git
github.com:owner/repo.git
[email protected]:1234123412341234.git
[email protected]:/owner/repo.git
hg::https://hg.sr.ht/~geyaeb/haskell-pdftotext

It also supports URLs of Git repositories created using git-remote-hg, which means you can use the package on Mercurial repositories.

Detecting an identity

You can use git-identity-guess-identity function to detect an identity of the repository. When it is run without arguments, it returns an identity of the current repository.

Furthermore, there is git-identity-ancestor-directories-from-url function, which returns a list of ancestor directories of an identity in your configuration matching a Git URL. This can be used to determine the clone destination of a repository respecting your configuration.

Changelog

0.2.0 [2021-09-05 Sun]

  • Add: Make several functions public by renaming. git-identity-username, git-identity-email, git-identity-guess-identity, git-identity-git-url-host, and git-identity-git-url-directory.
  • Add git-identity-ancestor-directories-from-url function.
  • Change: If there are multiple identities matching the same domain of a URL, pick one without organizations.

0.1.2 [2020-12-23 Wed]

  • Add support for organizations and multiple identities on the same hosts

0.1.1 [2020-01-25 Sat]

  • Fix the bug of duplicate confirmation in setting an expected identity.
  • Fix the bug of trying to set an identity when the global identity is the same as an expected identity.
  • Add a separate git-identity-magit.el for a linting reason.

License

GPL v3