NeogitOrg / neogit

An interactive and powerful Git interface for Neovim, inspired by Magit
MIT License
3.91k stars 230 forks source link

Support for `--bare` git repos #332

Open mangelozzi opened 2 years ago

mangelozzi commented 2 years ago

Is your feature request related to a problem? Please describe.

Using git to manage configuration dot files in ones home dir is tricky when trying to version control files directly in one's $HOME dir. This has lead to a common idiom where people use a bare repo for their dot files, e.g. the first 3 matches from a google search:

The problem with this is that one has to manually specify the repo path when peforming git actions, e.g.

git --git-dir=$HOME/.dotfiles --work-tree=$HOME add /some/file.py

Which is usally handled by an alias:

alias config="git --git-dir=$HOME/.dotfiles --work-tree=$HOME"

I love Neogit and would like to be able to use it with my dot files, but as far as I tell, it only works by using your cwd, there is not way to specify which repo to use.

Describe the solution you'd like

An option to dynamically specify the repo to use with Neogit, so one use Neogit as it is currently with the cwd, but also be able to create mappings to open Neogit on a specified repo outside of the cwd (related to #305 ), or oin a bare repo.

Describe alternatives you've considered Crying

sindrets commented 2 years ago

@mangelozzi Bare git repos work perfectly fine in Neogit. You just have to let git know where both the work tree, and the git dir is. You can do this quite easily by setting the environment variables GIT_WORK_TREE and GIT_DIR. I use a bare git repo for my own dotfiles, and this is what I do. You can set environment variables from lua like so:

vim.env.GIT_DIR = "/path/to/git_dir"
vim.env.GIT_WORK_TREE = vim.fn.expand("~")

Put this in something like a session file, and have nvim source it when opened in specific directory (your home directory or ~/.dotfiles or similar).


Another thing to note is that in newer versions of git you can configure your dotfiles repo to have a detached work tree instead of being a bare repo. This works the same way as a bare repo, except you no longer need to specify where the work tree is (i.e. you don't need to define GIT_WORK_TREE or --work-tree). You only need to specify the git dir such that git can use the local repo config.

You do this by disabling core.bare and defining core.worktree.

Example:

; /path/to/git_dir/config

[core]
    bare = false
    worktree = /home/your_username

Or from the shell:

$ git config core.bare false
$ git config core.worktree "/home/your_username"
sindrets commented 2 years ago

but also be able to create mappings to open Neogit on a specified repo outside of the cwd

You can already do this:

:Neogit cwd=/path/to/repo
tastytea commented 2 years ago

You can do this quite easily by setting the environment variables GIT_WORK_TREE and GIT_DIR.

That would set these variables for all buffers in neovim, right? Unless you re-set them on buffer changes, which i find not very elegant.

:Neogit cwd=/path/to/repo

That fails with:

Error executing luv callback:
...ck/packer/start/plenary.nvim/lua/plenary/async/async.lua:14: The coroutine failed with this message: vim/shared.lua:0: s: expected string, got nil
stack traceback:
        [C]: in function 'error'
        ...ck/packer/start/plenary.nvim/lua/plenary/async/async.lua:14: in function 'callback_or_next'
        ...ck/packer/start/plenary.nvim/lua/plenary/async/async.lua:40: in function 'cb'
        ...vim/site/pack/packer/start/neogit/lua/neogit/process.lua:16: in function 'raise_if_fully_closed'
        ...vim/site/pack/packer/start/neogit/lua/neogit/process.lua:49: in function <...vim/site/pack/packer/start/neogit/lua/neogit/process.lua:43>

here when i specify my dotfiles repo (with core.worktree set and command-line git working). Specifying cwd with “normal” repos works.

sindrets commented 2 years ago

[:Neogit cwd={path} fails] when I specify my dotfiles repo

@tastytea It certainly shouldn't fail with a stacktrace in that scenario - that's a bug - but you're trying to us the cwd= option in the wrong way. You're pointing it to a git dir. You're supposed to point it either to the top-level, or a subdirectory of a working tree. As such the cwd= won't work for bare repos, or repos with detached work trees without letting git know where the git dir is (which you can do with GIT_DIR).

That would set these variables for all buffers in neovim, right? Unless you re-set them on buffer changes, which i find not very elegant.

I'm suggesting you have a script (like a session file) that sets these environment variables only when you open nvim in a specific path. I.e. your home directory. That way, when you need to manage your dotfiles in nvim just open nvim with that path as the cwd. You can easily set up a shell alias as well to make this easily accessible:

alias nvdot="nvim --cmd 'cd ~'"

I really like this setup because it's a lot more comprehensive than just setting the git dir for neogit. This makes it such that all git related plugins (gitsigns, Fugitive, etc.) work with the dotfiles repo. As well as shell commands, even without a shell alias. Meaning you can actually use :!git commands.

mangelozzi commented 2 years ago

but also be able to create mappings to open Neogit on a specified repo outside of the cwd

You can already do this:

:Neogit cwd=/path/to/repo

Does it work for you with a bare repo? I tried the following, none work, they either open up to nil or to a blank commit popup:

vim.api.nvim_set_keymap('n', '<leader>I', ":lua require('neogit').open({ kind = 'tab', cwd='/home/michael/.dotfiles' })<CR>", {noremap = true})
vim.api.nvim_set_keymap('n', '<leader>I', ":lua require('neogit').open({ kind = 'tab', cwd='/home/michael/.config' })<CR>", {noremap = true})

Maybe the command doesnt work for bare repos?

UPDATE: I see you state above that unfortunately:

cwd= won't work for bare repos

mangelozzi commented 2 years ago

Put this in something like a session file, and have nvim source it when opened in specific directory (your home directory or ~/.dotfiles or similar).

Thanks for the help. Would you please share how you do this with your setup?

For now I set up these aliases:

alias gitdot='export GIT_DIR=~/.dotfiles GIT_WORK_TREE=~'
alias gitproj='export GIT_DIR=~/project/.git GIT_WORK_TREE=~/project'
mangelozzi commented 2 years ago

Another thing to note is that in newer versions of git you can configure your dotfiles repo to have a detached work tree instead of being a bare repo. This works the same way as a bare repo, except you no longer need to specify where the work tree is (i.e. you don't need to define GIT_WORK_TREE or --work-tree). You only need to specify the git dir such that git can use the local repo config.

You do this by disabling core.bare and defining core.worktree.

Thanks for the hot tip. Still need to wrap my head around git worktrees. I watched a video a while ago about how awesome they are and still did not get it.

sindrets commented 2 years ago

Thanks for the help. Would you please share how you do this with your setup?

@mangelozzi I have a more involved setup that is triggered by an autocommand, and automatically sources an rc-file if it exists in the current working directory.

But you can do something similar a lot more simple. Define an autocommand that triggers on VimEnter:

vim.api.nvim_create_autocmd("VimEnter", {
  callback = function()
    if vim.fn.filereadable(".nvimrc.lua") == 1 then
      vim.cmd("source .nvimrc.lua")
    end
  end,
})

And then in the rc-file you define the environment variables:

-- ~/.nvimrc.lua
vim.env.GIT_DIR = vim.fn.expand("~/.dotfiles")
vim.env.GIT_WORK_TREE = vim.fn.expand("~")

For now I set up these aliases:

alias gitdot='export GIT_DIR=~/.dotfiles GIT_WORK_TREE=~'
alias gitproj='export GIT_DIR=~/project/.git GIT_WORK_TREE=~/project'

You probably don't want to export environment variables from an alias, because they're gonna remain for the rest of the terminal session, or until you have unset them. I only use an alias to start nvim with a specific working directory, and then my autocommand automatically sources the rc-file that sets the environment variables inside nvim. That alias looks like this:

alias nvdot="nvim --cmd 'cd ~'"
tastytea commented 2 years ago

Executing arbitary code is very dangerous (although you're probably saved by “security by obscurity” as long no-one else uses the same file name for this).

You probably don't want to export environment variables from an alias, because they're gonna remain for the rest of the terminal session, or until you have unset them.

This way the variables will only live for as long as the command:

alias nvdot="GIT_DIR=${HOME}/.dotfiles GIT_WORK_TREE=${HOME} nvim"

However, that is only usable if a separate instance of neovim is used for working with dotfiles. When files from several different git-controlled projects are worked on in the same editor instance, git can only be used for the dotfiles from within neovim.

That's why i think it would be useful to be able to tell neogit the --git-dir. Or, maybe more generally useful: Introduce a variable or parameter for passing command line options to git.

sindrets commented 2 years ago

@tastytea Arbitrary code execution by injecting code into a config file is not a vulnerability nvim is immune to in the first place. There are plenty of directories from which nvim will automatically source code. Every directory on your 'runtimepath' for one.

The only other way this could be exploited is if I download a project, and somehow I don't notice that it contains a malicious rc-file, and then I open the project as the current working directory. At that point I'll take the fall. You are far more likely to install a plugin that contains malicious code.

However, that is only usable if a separate instance of neovim is used for working with dotfiles. When files from several different git-controlled projects are worked on in the same editor instance, git can only be used for the dotfiles from within neovim.

Yes. And that's perfect for my workflow. Neovim starts in mere milliseconds, and it takes me about a second to bring up my dotfiles in a new tab in the terminal. However, it might not be for everyone.

That's why i think it would be useful to be able to tell neogit the --git-dir. Or, maybe more generally useful: Introduce a variable or parameter for passing command line options to git.

I agree, this is the way to go if something like this were to be implemented.