polarmutex / git-worktree.nvim

MIT License
54 stars 14 forks source link

Add support for a `.shared` directory #16

Open calebdw opened 4 months ago

calebdw commented 4 months ago

Hello!

I'm in the process of migration all of my repos over to bare repos with worktrees, and something I come across is that in some repos I have gitignored, untracked files that need to be in every worktree (think .env files, etc.).

What I propose is this: if a .shared directory exists in the same directory as all the other worktrees, then the contents of the directory would be symlinked into a new worktree when it is created. Nested paths could be supported as well so .shared/docker/certs/local.crt could be symlinked to main/docker/certs/local.crt

Now I know I can use a hook to do this, but this seems a common enough use case that it would be great if this plugin could provide first class support for it.

Thanks!

calebdw commented 3 months ago

For reference, here's how I've implemented this locally using the created hook:

--- Symlink shared files to the worktree.
--- @param root string
--- @param worktree string
--- @return nil
local function symlink_shared_files(root, worktree)
  local shared = root..'/.shared'
  util.symlink_files(shared, root..'/'..worktree, true, true)
end

local gwt = require('git-worktree')
gwt.setup(opts)

gwt.on_tree_change(function(op, meta)
  if op == gwt.Operations.Create then
    symlink_shared_files(gwt:get_root(), meta.path)
  end
end)

-- in my utils

--- This recursively symlinks files from a src directory to a dest directory.
--- @param src string
--- @param dest string
--- @param relative? boolean
--- @param force? boolean
--- @return nil
function M.symlink_files(src, dest, relative, force)
  relative = relative ~= false
  force = force == true

  local Job = require('plenary.job')
  local Path = require('plenary.path')
  local scan = require('plenary.scandir')

  local src_path = Path:new(src)
  local dest_path = Path:new(dest)

  if not src_path:exists() then
    vim.notify('Shared directory does not exist: ' .. src, vim.log.levels.DEBUG)
    return
  end

  scan.scan_dir_async(src_path:absolute(), {
    hidden = true,
    add_dirs = false,
    on_insert = function(entry)
      local target = dest_path:joinpath(Path:new(entry):make_relative(src_path:absolute()))

      local args = { '-s' }
      if relative then table.insert(args, '-r') end
      if force then table.insert(args, '-f') end

      table.insert(args, entry)
      table.insert(args, target:absolute())

      Job:new({
        command = 'ln',
        args = args,
        on_exit = function(_, code)
          if code == 0 then return end
          vim.schedule(function()
            vim.notify(
              'Failed to symlink ' .. entry .. ' -> ' .. target:absolute(),
              vim.log.levels.ERROR
            )
          end)
        end,
      }):start()
    end,
  })
end
polarmutex commented 2 months ago

I will take a look at this soon, sorry been busy