Skip to content

Latest commit

 

History

286 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#+TITLE: treebundel

[[https://melpa.org/#/treebundel][file:https://melpa.org/packages/treebundel-badge.svg]]

This package is used for bundling related git-worktrees from multiple repositories together. It's a
bit of an opinionated workflow on how to manage and organize your projects. It helps switch quickly
between feature-related projects and ensure you're on the branch related to that feature. When
you're done with your changes, you can use the projects in the workspace and know which ones were
modified to simplify the process of getting the changes merged in together.

Additionally, git metadata (the =.git= directory) is shared between all projects. You can stash,
pop, and pull changes in from the same repository in other workspaces thanks to the power of
[[https://git-scm.com/docs/git-worktree][git-worktrees]].

* Contents
:PROPERTIES:
:TOC:      :include siblings :depth 0 :force ((nothing)) :ignore (this) :local (nothing)
:END:
:CONTENTS:
- [[#terminology][Terminology]]
- [[#installation][Installation]]
- [[#usage][Usage]]
- [[#configuration][Configuration]]
- [[#nifty-snippets][Nifty snippets]]
- [[#license][License]]
:END:

* Terminology

| Term        | Description                                                              |
|-------------+--------------------------------------------------------------------------|
| *Bare*      | A bare repository used as a source to create a *project*'s git-worktree. |
| *Project*   | A git-worktree checked out from a *bare* stored in a *workspace*.        |
| *Workspace* | A collection of *project*'s created from *bare*'s.                       |
| *Prefix*    | An string used to generated a default branch name for new projects.      |

The main workspace directory contains workspaces which each contains a collection of projects:

#+BEGIN_SRC
treebundel-workspace-root (default: "~/workspaces/")
   |
   L workspace1
   |    L project-one   (branch: "feature/workspace1")
   |    L project-two   (branch: "feature/workspace1")
   |    L project-three (branch: "feature/workspace1")
   |
   L workspace2
        L project-one   (branch: "feature/workspace2")
        L project-two   (branch: "feature/workspace2")
        L project-three (branch: "feature/workspace2")
#+END_SRC

* Installation

This package is available on [[https://melpa.org/][MELPA]].

** use-package

#+BEGIN_SRC emacs-lisp :results none
(use-package treebundel
  :ensure t)
#+END_SRC

** straight.el

Or you can install from source. Straight example:

#+BEGIN_SRC emacs-lisp :results none
(straight-use-package '(treebundel :type git :host github :repo "purplg/treebundel"))
;; -- Configuration goes here --
#+END_SRC

* Usage

The main commands for using treebundel.

- treebundel-open :: Open a project in a workspace.

- treebundel-open-project :: Open other project within current workspace. If you're already in a
  workspace, prompt to open a different project within that workspace.

- treebundel-add-project :: Add a project to a workspace. Will prompt you for a bare repository to
  add to your workspace.

- treebundel-remove-project :: Remove a project from a workspace. The project must not have any
  uncommitted changes for it to be removed.

- treebundel-delete-workspace :: Delete a workspace. Any projects within the workspace are checked to
  see if they're clean, and if so, all projects and the workspace itself are deleted. Anything
  committed is still saved in the respective projects' bare repository.

Assuming default configuration, the following steps will create a bare clone of the provided repo
URL to =~/workspaces/.bare/<repo-name>.git=, then create and open a worktree for a new branch called
=feature/<workspace-name>=.

1. Interactively call ~treebundel-add-project~.
2. Enter name for the new (or existing) workspace.
3. Select =[ clone ]=.
4. Enter the URL to clone for the repository to be added to the workspace.
5. Specify the name of the branch to checkout. By default, it'll pre-fill with
   <treebundel-branch-prefix>/<workspace-name>. You can also select an existing branch.
6. Specify the project name which will be the name of the worktree is created in.

You should then be prompted with your ~project-switch-project~ prompt to begin editing.

Whenever you need a different repository, you can call ~treebundel-open-project~ to open and adjacent
project in your current workspace or ~treebundel-open~ to open a project in a different workspace.

* Configuration

- treebundel-workspace-root :: *Default*: =“~/workspaces/”=

  The most important variable you probably want to configure is
  ~treebundel-workspace-root~. This configures where all of the treebundel workspaces are going to be
  located on your file system.

- treebundel-project-open-function :: *Default*: =#'project-switch-project=

  This is the function called when a project is opened. You could
  also just make this ~find-file~ to just open the file instantly or any other function that takes a
  file path.

- treebundel-fetch-on-add :: *Default*: =nil=

  Set to nil to disable the automatic ~git fetch~ when adding a project. When disabled, you may not
  be able to see new branches on remote without manually do a git fetch. You can interactively call
  the ~(treebundel-fetch-bare)~ command to manually update a repository.

- treebundel-bare-dir :: *Default*: =(file-name-concat treebundel-workspace-root “.bare”)=

  This is the directory that bare repository get cloned to. The intent is for
  this to be mostly transparent, hence the =.= prefix to make it hidden by default.

- treebundel-branch-prefix :: *Default*: =“feature/”=

  A string used to generate a default branch name created with treebundel. By default, it's
  =feature/= such that when you add a new project to a workspace, the new branch is name
  =feature/<workspace-name>=. You don't have to use this name, it's just pre-populated for
  convience. You can use dir-locals to set workspace-specific prefixes although this, unfortunately,
  prevents you from using dir-locals in your project since dir-locals only looks as the closest
  file.

** Hooks

- ~treebundel-before-workspace-open-functions~
- ~treebundel-before-project-open-functions~
- ~treebundel-after-project-open-hook~
- ~treebundel-after-workspace-open-hook~

These hooks are called before or after a project or workspace is
opened. =treebundel-before-workspace-open-functions= receives the name
of the workspace to be opened as a single argument and
=treebundel-before-project-open-functions= receives the workspace and
project name opened.

See the [[#project-tabs][Project Tabs]] example to see an example on how to use
=treebundel-before-project-open-functions= to create a new tab for every
project.

* Nifty snippets

This snippets can extend the usefulness of treebundel.

** Project Tabs

To create a new tab for every project opened with treebundel:

#+BEGIN_SRC emacs-lisp
(add-hook 'treebundel-before-project-open-functions
          (lambda (workspace project)
            (tab-bar-select-tab-by-name
             (format "%s/%s" workspace-name project-name))))
#+END_SRC

** Workspace Notes

This snippet will open a file within a =projects= directory in your =org-directory= an org file with the name of your workspace.

#+BEGIN_SRC emacs-lisp
(defun my/open-project-notes ()
    (interactive)
    (if-let ((workspace (or (treebundel-current-workspace)
                            (treebundel-read-workspace))))
        (find-file-other-window
         ;; e.g. ~/.org/projects/some-feature.org
         (file-name-concat org-directory
                           "projects"
                           (file-name-with-extension workspace "org")))
      (user-error "Not in a workspace")))
#+END_SRC

* License

MIT

About

Exploit git-worktrees to create inter-related project workspaces.

Resources

Stars

38 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages