Add documentation
This commit is contained in:
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
book
|
||||||
9
docs/book.toml
Normal file
9
docs/book.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[book]
|
||||||
|
authors = ["Hannes Körber"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "src"
|
||||||
|
title = "Git Repo Manager"
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
mathjax-support = true
|
||||||
7
docs/src/SUMMARY.md
Normal file
7
docs/src/SUMMARY.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
- [Overview](./overview.md)
|
||||||
|
- [Getting started](./getting_started.md)
|
||||||
|
- [Repository trees](./repos.md)
|
||||||
|
- [Git Worktrees](./worktrees.md)
|
||||||
|
- [FAQ](./faq.md)
|
||||||
10
docs/src/faq.md
Normal file
10
docs/src/faq.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# FAQ
|
||||||
|
|
||||||
|
## Why is the nightly toolchain required?
|
||||||
|
|
||||||
|
Building GRM currently requires nightly features due to the usage of
|
||||||
|
[`std::path::Path::is_symlink()`](https://doc.rust-lang.org/std/fs/struct.FileType.html#method.is_symlink).
|
||||||
|
See the [tracking issue](https://github.com/rust-lang/rust/issues/85748).
|
||||||
|
|
||||||
|
`is_symlink()` is actually available in rustc 1.57, so it will be on stable in
|
||||||
|
the near future. This would mean that GRM can be built using the stable toolchain!
|
||||||
22
docs/src/getting_started.md
Normal file
22
docs/src/getting_started.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Quickstart
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Building GRM currently requires the nightly Rust toolchain. The easiest way
|
||||||
|
is using [`rustup`](https://rustup.rs/). Make sure that rustup is properly installed.
|
||||||
|
|
||||||
|
Make sure that the nightly toolchain is installed:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rustup toolchain install nightly
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo +nightly install --git https://github.com/hakoerber/git-repo-manager.git --branch master
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're brave, you can also run the development build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo +nightly install --git https://github.com/hakoerber/git-repo-manager.git --branch develop
|
||||||
|
```
|
||||||
33
docs/src/overview.md
Normal file
33
docs/src/overview.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
Welcome! This is the documentation for [Git Repo
|
||||||
|
Manager](https://github.com/hakoerber/git-repo-manager/) (GRM for short), a
|
||||||
|
tool that helps you manage git repositories.
|
||||||
|
|
||||||
|
GRM helps you manage git repositories in a declarative way. Configure your
|
||||||
|
repositories in a TOML file, GRM does the rest. Take a look at [the example
|
||||||
|
configuration](https://github.com/hakoerber/git-repo-manager/blob/master/example.config.toml)
|
||||||
|
to get a feel for the way you configure your repositories. See the [repository
|
||||||
|
tree chapter](./repos.md) for details.
|
||||||
|
|
||||||
|
GRM also provides some tooling to work with single git repositories using
|
||||||
|
`git-worktree`. See [the worktree chapter](./worktree.md) for more details.
|
||||||
|
|
||||||
|
## Why use GRM?
|
||||||
|
|
||||||
|
If you're working with a lot of git repositories, GRM can help you to manage them
|
||||||
|
in an easy way:
|
||||||
|
|
||||||
|
* You want to easily clone many repositories to a new machine.
|
||||||
|
* You want to change remotes for multiple repositories (e.g. because your GitLab
|
||||||
|
domain changed).
|
||||||
|
* You want to get an overview over all repositories you have, and check whether
|
||||||
|
you forgot to commit or push something.
|
||||||
|
|
||||||
|
If you want to work with [git worktrees](https://git-scm.com/docs/git-worktree)
|
||||||
|
in a streamlined, easy way, GRM provides you with an opinionated workflow. It's
|
||||||
|
especially helpful when the following describes you:
|
||||||
|
|
||||||
|
* You're juggling a lot of git branches, switching between them a lot.
|
||||||
|
* When switching branches, you'd like to just leave your work as-is, without
|
||||||
|
using the stash or temporary commits.
|
||||||
76
docs/src/repos.md
Normal file
76
docs/src/repos.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Managing tree of git repositories
|
||||||
|
|
||||||
|
When managing multiple git repositories with GRM, you'll generally have a
|
||||||
|
configuration file containing information about all the repos you have. GRM then
|
||||||
|
makes sure that you repositories match that config. If they don't exist yet, it
|
||||||
|
will clone them. It will also make sure that all remotes are configured properly.
|
||||||
|
|
||||||
|
Let's try it out:
|
||||||
|
|
||||||
|
## Get the example configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ curl --proto '=https' --tlsv1.2 -sSfO https://raw.githubusercontent.com/hakoerber/git-repo-manager/master/example.config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you're ready to run the first sync. This will clone all configured repositories
|
||||||
|
and set up the remotes.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ grm repo sync --config example.config.toml
|
||||||
|
[⚙] Cloning into "/home/me/projects/git-repo-manager" from "https://code.hkoerber.de/hannes/git-repo-manager.git"
|
||||||
|
[✔] git-repo-manager: Repository successfully cloned
|
||||||
|
[⚙] git-repo-manager: Setting up new remote "github" to "https://github.com/hakoerber/git-repo-manager.git"
|
||||||
|
[✔] git-repo-manager: OK
|
||||||
|
[⚙] Cloning into "/home/me/projects/dotfiles" from "https://github.com/hakoerber/dotfiles.git"
|
||||||
|
[✔] dotfiles: Repository successfully cloned
|
||||||
|
[✔] dotfiles: OK
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run it again, it will report no changes:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm repo sync --config example.config.toml
|
||||||
|
[✔] git-repo-manager: OK
|
||||||
|
[✔] dotfiles: OK
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate your own configuration
|
||||||
|
|
||||||
|
Now, if you already have a few repositories, it would be quite laborious to write
|
||||||
|
a configuration from scratch. Luckily, GRM has a way to generate a configuration
|
||||||
|
from an existing file tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ grm repo find ~/your/project/root > config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
This will detect all repositories and remotes and write them to `config.toml`.
|
||||||
|
|
||||||
|
### Show the state of your projects
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ grm repo status --config example.config.toml
|
||||||
|
╭──────────────────┬──────────┬────────┬───────────────────┬────────┬─────────╮
|
||||||
|
│ Repo ┆ Worktree ┆ Status ┆ Branches ┆ HEAD ┆ Remotes │
|
||||||
|
╞══════════════════╪══════════╪════════╪═══════════════════╪════════╪═════════╡
|
||||||
|
│ git-repo-manager ┆ ┆ ✔ ┆ branch: master ┆ master ┆ github │
|
||||||
|
│ ┆ ┆ ┆ <origin/master> ✔ ┆ ┆ origin │
|
||||||
|
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
|
||||||
|
│ dotfiles ┆ ┆ ✔ ┆ ┆ Empty ┆ origin │
|
||||||
|
╰──────────────────┴──────────┴────────┴───────────────────┴────────┴─────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use `status` without `--config` to check the repository you're currently
|
||||||
|
in:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd ~/example-projects/dotfiles
|
||||||
|
$ grm repo status
|
||||||
|
╭──────────┬──────────┬────────┬──────────┬───────┬─────────╮
|
||||||
|
│ Repo ┆ Worktree ┆ Status ┆ Branches ┆ HEAD ┆ Remotes │
|
||||||
|
╞══════════╪══════════╪════════╪══════════╪═══════╪═════════╡
|
||||||
|
│ dotfiles ┆ ┆ ✔ ┆ ┆ Empty ┆ origin │
|
||||||
|
╰──────────┴──────────┴────────┴──────────┴───────┴─────────╯
|
||||||
|
```
|
||||||
|
|
||||||
207
docs/src/worktrees.md
Normal file
207
docs/src/worktrees.md
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# Git Worktrees
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
The default workflow when using git is having your repository in a single directory.
|
||||||
|
Then, you can check out a certain reference (usually a branch), which will update
|
||||||
|
the files in the directory to match the state of that reference. Most of the time,
|
||||||
|
this is exactly what you need and works perfectly. But especially when you're using
|
||||||
|
with branches a lot, you may notice that there is a lot of work required to make
|
||||||
|
everything run smootly.
|
||||||
|
|
||||||
|
Maybe you experienced the following: You're working on a feature branch. Then,
|
||||||
|
for some reason, you have to change branches (maybe to investigate some issue).
|
||||||
|
But you get the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
error: Your local changes to the following files would be overwritten by checkout
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can create a temporary commit or stash your changes. In any case, you have
|
||||||
|
some mental overhead before you can work on something else. Especially with stashes,
|
||||||
|
you'll have to remember to do a `git stash pop` before resuming your work (I
|
||||||
|
cannot count the number of times where is "rediscovered" some code hidden in some
|
||||||
|
old stash I forgot about.
|
||||||
|
|
||||||
|
And even worse: If you're currently in the process of resolving merge conflicts or an
|
||||||
|
interactive rebase, there is just no way to "pause" this work to check out a
|
||||||
|
different branch.
|
||||||
|
|
||||||
|
Sometimes, it's crucial to have an unchanging state of your repository until some
|
||||||
|
long-running process finishes. I'm thinking of Ansible and Terraform runs. I'd
|
||||||
|
rather not change to a different branch while ansible or Terraform are running as
|
||||||
|
I have no idea how those tools would behave (and I'm not too eager to find out).
|
||||||
|
|
||||||
|
In any case, Git Worktrees are here for the rescue:
|
||||||
|
|
||||||
|
## What are git worktrees?
|
||||||
|
|
||||||
|
[Git Worktrees](https://git-scm.com/docs/git-worktree) allow you to have multiple
|
||||||
|
independent checkouts of your repository on different directories. You can have
|
||||||
|
multiple directories that correspond to different references in your repository.
|
||||||
|
Each worktree has it's independent working tree (duh) and index, so there is no
|
||||||
|
to run into conflicts. Changing to a different branch is just a `cd` away (if
|
||||||
|
the worktree is already set up).
|
||||||
|
|
||||||
|
## Worktrees in GRM
|
||||||
|
|
||||||
|
GRM exposes an opinionated way to use worktrees in your repositories. Opinionated,
|
||||||
|
because there is a single invariant that makes reasoning about your worktree
|
||||||
|
setup quite easy:
|
||||||
|
|
||||||
|
**The branch inside the worktree is always the same as the directory name of the worktree.**
|
||||||
|
|
||||||
|
In other words: If you're checking out branch `mybranch` into a new worktree, the
|
||||||
|
worktree directory will be named `mybranch`.
|
||||||
|
|
||||||
|
GRM can be used with both "normal" and worktree-enabled repositories. But note
|
||||||
|
that a single repository can be either the former or the latter. You'll have to
|
||||||
|
decide during the initial setup which way you want to go for that repository.
|
||||||
|
|
||||||
|
If you want to clone your repository in a worktree-enabled way, specify
|
||||||
|
`worktree_setup = true` for the repository in your `config.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[trees.repos]]
|
||||||
|
name = "git-repo-manager"
|
||||||
|
worktree_setup = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, when you run a `grm sync`, you'll notice that the directory of the repository
|
||||||
|
is empty! Well, not totally, there is a hidden directory called `.git-main-working-tree`.
|
||||||
|
This is where the repository actually "lives" (it's a bare checkout).
|
||||||
|
|
||||||
|
### Creating a new worktree
|
||||||
|
|
||||||
|
To actually work, you'll first have to create a new worktree checkout. All
|
||||||
|
worktree-related commands are available as subcommands of `grm worktree` (or
|
||||||
|
`grm wt` for short):
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt add mybranch
|
||||||
|
[✔] Worktree mybranch created
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see that there is now a directory called `mybranch` that contains a checkout
|
||||||
|
of your repository, using the branch `mybranch`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cd ./mybranch && git status
|
||||||
|
On branch mybranch
|
||||||
|
nothing to commit, working tree clean
|
||||||
|
```
|
||||||
|
|
||||||
|
You can work in this repository as usual. Make changes, commit them, revert them,
|
||||||
|
whatever you're up to :)
|
||||||
|
|
||||||
|
Just note that you *should* not change the branch inside the worktree
|
||||||
|
directory. There is nothing preventing you from doing so, but you will notice
|
||||||
|
that you'll run into problems when trying to remove a worktree (more on that
|
||||||
|
later). It may also lead to confusing behaviour, as there can be no two
|
||||||
|
worktrees that have the same branch checked out. So if you decide to use the
|
||||||
|
worktree setup, go all in, let `grm` manage your branches and bury `git branch`
|
||||||
|
(and `git checkout -b`).
|
||||||
|
|
||||||
|
You will notice that there is no tracking branch set up for the new branch. You
|
||||||
|
can of course set up one manually after creating the worktree, but there is an
|
||||||
|
easier way, using the `--track` flag during creation. Let's create another
|
||||||
|
worktree. Go back to the root of the repository, and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ grm wt add mybranch2 --track origin/mybranch2
|
||||||
|
[✔] Worktree mybranch2 created
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see that this branch is now tracking `mybranch` on the `origin` remote:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cd ./mybranch2 && git status
|
||||||
|
On branch mybranch
|
||||||
|
|
||||||
|
Your branch is up to date with 'origin/mybranch2'.
|
||||||
|
nothing to commit, working tree clean
|
||||||
|
```
|
||||||
|
|
||||||
|
The behaviour of `--track` differs depending on the existence of the remote branch:
|
||||||
|
|
||||||
|
* If the remote branch already exists, `grm` uses it as the base of the new
|
||||||
|
local branch.
|
||||||
|
* If the remote branch does not exist (as in our example), `grm` will create a
|
||||||
|
new remote tracking branch, using the default branch (either `main` or `master`)
|
||||||
|
as the base
|
||||||
|
|
||||||
|
### Showing the status of your worktrees
|
||||||
|
|
||||||
|
There is a handy little command that will show your an overview over all worktrees
|
||||||
|
in a repository, including their status (i.e. changes files). Just run the following
|
||||||
|
in the root of your repository:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt status
|
||||||
|
╭───────────┬────────┬──────────┬──────────────────╮
|
||||||
|
│ Worktree ┆ Status ┆ Branch ┆ Remote branch │
|
||||||
|
╞═══════════╪════════╪══════════╪══════════════════╡
|
||||||
|
│ mybranch ┆ ✔ ┆ mybranch ┆ │
|
||||||
|
│ mybranch2 ┆ ✔ ┆ mybranch ┆ origin/mybranch2 │
|
||||||
|
╰───────────┴────────┴──────────┴──────────────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
The "Status" column would show any uncommitted changes (new / modified / deleted
|
||||||
|
files) and the "Remote branch" would show differences to the remote branch (e.g.
|
||||||
|
if there are new pushes to the remote branch that are not yet incorporated into
|
||||||
|
your local branch).
|
||||||
|
|
||||||
|
|
||||||
|
### Deleting worktrees
|
||||||
|
|
||||||
|
If you're done with your worktrees, use `grm wt delete` to delete them. Let's
|
||||||
|
start with `mybranch2`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt delete mybranch2
|
||||||
|
[✔] Worktree mybranch2 deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
Easy. On to `mybranch`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt delete mybranch
|
||||||
|
[!] Changes in worktree: No remote tracking branch for branch mybranch found. Refusing to delete
|
||||||
|
```
|
||||||
|
|
||||||
|
Hmmm. `grm` tells you:
|
||||||
|
|
||||||
|
"Hey, there is no remote branch that you could have pushed
|
||||||
|
your changes to. I'd rather not delete work that you cannot recover."
|
||||||
|
|
||||||
|
Note that `grm` is very cautious here. As your repository will not be deleted,
|
||||||
|
you could still recover the commits via [`git-reflog`](https://git-scm.com/docs/git-reflog).
|
||||||
|
But better safe then sorry! Note that you'd get a similar error message if your
|
||||||
|
worktree had any uncommitted files, for the same reason. Now you can either
|
||||||
|
commit & push your changes, or your tell `grm` that you know what you're doing:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt delete mybranch --force
|
||||||
|
[✔] Worktree mybranch deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
If you just want to delete all worktrees that do not contain any changes, you
|
||||||
|
can also use the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grm wt clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual access
|
||||||
|
|
||||||
|
GRM isn't doing any magic, it's just git under the hood. If you need to have access
|
||||||
|
to the underlying git repository, you can always do this:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git --git-dir ./.git-main-working-tree [...]
|
||||||
|
```
|
||||||
|
|
||||||
|
This should never be required (whenever you have to do this, you can consider
|
||||||
|
this a bug in GRM and open an [issue](https://github.com/hakoerber/git-repo-manager/issues/new),
|
||||||
|
but it may help in a pinch.
|
||||||
|
|
||||||
Reference in New Issue
Block a user