I have been using the setup described on the top comment here to manage my dotfiles using git. In short, I have this in my .bashrc:

alias config='/usr/bin/env git --git-dir=$HOME/.myconf/ --work-tree=$HOME'

I then can run any git command using config add <file>, etc. Is there anyway to get this working with magit, so I can commit changes to my configuration files without dropping into a shell?

  • Setting magit-git-global-arguments as a directory-local variable may be an option.
    – phils
    Feb 10 '17 at 10:57
  • Did you solve the issue? I also want to track my dot files via magit Sep 5 '18 at 7:15
  • Unfortunately not. This is an ongoing source of friction for me.
    – nbren12
    Sep 6 '18 at 16:32

In reviewing the magit project and its code, clearly the magit project opinion is to not set global configuration of the git directory, and with clear reasons. (#2939, #3516)

That said, this is your Emacs, and RMS et al want you to hack it. If you are running an Emacs session exclusively for the purpose of editing a repository with a nonstandard git directory, then magit's magit-git-global-arguments configuration provides a suitable hook.

;;; Configure magit to use .myconf (and not .git) as the git
;;; directory when a .myconf directory is found in the current
;;; working directory (which Emacs calls its `default-directory'
;;; per buffer) and there is no .git directory.
;;; For example, if dotfiles are tracked with a git directory at
;;; $HOME/.myconf, and the Emacs process starts from $HOME (and
;;; nothing in its configuration changes its `default-directory'
;;; in the current buffer), this will configure magit to use
;;; .myconf as the git directory.
;;; NOTE: This setting will apply for the entire Emacs process,
;;; regardless of magit invocation in other directories.
(unless (boundp 'myconf-magit-hook?)
  ;; Only run this hook once, even if Emacs reloads configuration.
  (eval-after-load 'magit
    '(let ((myconf-path (expand-file-name ".myconf")))
       (when (and (file-exists-p myconf-path)
                  (not (file-exists-p ".git")))
         ;; Insert git directory and working tree into magit's git
         ;; global arguments, while preserving magit's existing
         ;; command-line settings; `add-to-list' adds to the
         ;; beginning of the list.
         (add-to-list 'magit-git-global-arguments
                      (format "--work-tree=%s"
                              ;; Drop trailing slash.
                               ;; Get directory part (`dirname`).
                               (file-name-directory myconf-path))))
         (add-to-list 'magit-git-global-arguments
                      (format "--git-dir=%s" myconf-path)))))
  (setq myconf-magit-hook? t))

I tested this on GNU Emacs 26.1 with Magit 2.90.1, and I made it a point to avoid any Emacs Lisp features added in the past few years.

It would be convenient to configure magit to look for a nonstandard .git directory in the current buffer's default-directory, but short of monkeypatching (or a fork / pull request), I don't know of a way to configure that (given how global variables are used). Note that magit's design is intended to support multiple repositories within the same Emacs process, and has first-class interactions for a list of repositories.

I have been tracking $HOME files with git and a nonstandard git directory for 9 years. The use case: It's extremely common to run git in a subdirectory of $HOME and a nonstandard git directory for dotfiles will ensure that git never accidentally runs against the $HOME repository when there's no intermediate .git directory when git walks up the directory tree. It's clear from the OP's alias command that this is exactly the use case.

Personally, I run an Emacs session per project.

  • Of course, @tarsius (with another answer here) is magit's maintainer, so I'll defer to him. The proposed use of magit-git-global-arguments matches the documented intent of the variable, while preserving its defaults.
    – rduplain
    Jan 5 '19 at 10:23
  • An alternative approach would be an alias (config-emacs or similar to match the OP alias) to load emacs with an environment variable set, and use (getenv ...) in your Emacs init to determine whether to add the magit hook. It's up to you whether you want to be explicit in starting (via alias) an Emacs process just to edit dotfiles, or to have your Emacs figure it out based on your working directory.
    – rduplain
    Jan 6 '19 at 0:05
  • I do run a global Emacs handling many repos/workdirs -- one emacs session per project is not viable for me. I tried making it buffer-local but that doesn't work (except for the initial setup) since of course sub-commands run afterwards are not run in the context of the visible buffer. Oct 25 '19 at 0:46
  • For what it's worth, I'm able to move between standard/nonstandard projects within the same Emacs session using the config that I've listed here. While magit-git-global-arguments is set for the entire Emacs session, the magit buffers initialize correctly and continue to function. I say "for what it's worth" because this is undocumented behavior and therefore could break without warning.
    – rduplain
    Nov 15 '19 at 10:11

This won't work. I recommend you set it up like this instead:

cd $HOME
cat "gitdir: ./.myconf" > .git
cd .myconf                     # conceptually, not really necessary
git config core.worktree ./

At that point git and thus magit know that $HOME is a working tree and where the data is.

Then again, it seems that's what you are trying to prevent (at least for git, why not for magit also?). Because otherwise what is the benefit of storing the git data in $HOME/.myconf instead of in $HOME/.git?

If that is so, then I have another question: what's the benefit of that? I mean I see the appeal of vcsh (which also won't work with Magit), it allows you to use different repositories for the configuration files of multiple packages even though they are all in the same place. But from what you have said, it doesn't appear that this is what you are after.

So it seems the answer is "you can't". In theory you could advice a bunch of Magit functions, and that might kind of work - but there would be bugs, and you would be solely responsible for dealing with them. I would strongly recommend against attempting this.

  • too bad this won't work. I will have to think about whether the non-standard .myconf name is really necessary.
    – nbren12
    Feb 10 '17 at 17:59
  • The benefit is that you can use multiple repositories to make a unified $HOME of config files. See manpages.debian.org/jessie/vcsh/vcsh.1.en.html
    – p_wiersig
    Feb 11 '17 at 14:08
  • 1
    @p_wiersig As I have mentioned in my answer, I don't think op is actually interested in doing that. However if you do want to do that, then I would still recommend the ".git is a file, set core.worktree approach". Because this has come up before I am even providing a proof-of-concept implementation: github.com/magit/magit/issues/460#issuecomment-36139308.
    – tarsius
    Feb 11 '17 at 14:16

I use slightly-modifed @rduplain's approach with tweaking magit-git-global-arguments. This allows for working with standard and non-standard directories at different times within the same Emacs session (not concurrently), at the small price of having a separate shortcut for launching Magit with non-standard directory configured.

;; prepare the arguments
(setq dotfiles-git-dir (concat "--git-dir=" (expand-file-name "~/.dotfiles")))
(setq dotfiles-work-tree (concat "--work-tree=" (expand-file-name "~")))

;; function to start magit on dotfiles
(defun dotfiles-magit-status ()
  (add-to-list 'magit-git-global-arguments dotfiles-git-dir)
  (add-to-list 'magit-git-global-arguments dotfiles-work-tree)
  (call-interactively 'magit-status))
(global-set-key (kbd "F5 d") 'dotfiles-magit-status)

;; wrapper to remove additional args before starting magit
(defun magit-status-with-removed-dotfiles-args ()
  (setq magit-git-global-arguments (remove dotfiles-git-dir magit-git-global-arguments))
  (setq magit-git-global-arguments (remove dotfiles-work-tree magit-git-global-arguments))
  (call-interactively 'magit-status))
;; redirect global magit hotkey to our wrapper
(global-set-key (kbd "C-x g") 'magit-status-with-removed-dotfiles-args)
(define-key magit-file-mode-map (kbd "C-x g") 'magit-status-with-removed-dotfiles-args)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.