= dof
image:https://img.shields.io/badge/License-Apache%202.0-blue.svg[link="http://www.apache.org/licenses/LICENSE-2.0"]
image:https://github.com/steffakasid/dof/actions/workflows/codeql-analysis.yml/badge.svg[link:https://github.com/steffakasid/dof/actions/workflows/codeql-analysis.yml]
image:https://github.com/steffakasid/dof/actions/workflows/release.yml/badge.svg[link:https://github.com/steffakasid/dof/actions/workflows/release.yml]
image:https://github.com/steffakasid/dof/actions/workflows/go-test.yml/badge.svg[link:https://github.com/steffakasid/dof/actions/workflows/go-test.yml]
dof is a CLI tool for managing dotfiles with a bare git repository. It maps a bare repository into a work tree and provides commands to initialize, checkout, add, synchronize, and manage dotfiles.
The tool is written in Go and uses `cobra` for CLI handling, `viper` for configuration, and `logrus` for logging.
== General usage
The typical workflow is:
* configure the repository path, branch, or profile.
* initialize or checkout the dotfile repository.
* add files with `dof add`.
* sync changes with `dof sync`.
* use `dof alias` for direct git commands when needed.
=== Initialize a new repository
When creating a new local dotfile repository:
* `dof init` - creates the bare repo and checks out the configured branch.
* `dof add <file>` - stages and commits a file into the dotfile repo.
* `dof alias remote add origin <git-url>` - add a remote repository.
* `dof sync` - push and pull changes on the configured branch.
If you use a remote repository, you may also need to set the upstream branch manually, for example:
[source,shell]
----
git config --global init.defaultBranch main
----
=== Checkout an existing repository
To connect to an existing remote dotfile repo:
* `dof checkout <git-remote-repo>` - clones the repo as a bare repository, renames existing local files as backups, and checks out the tracked dotfiles.
=== Synchronize changes
* `dof add <file>` - add and commit a file.
* `dof status` - show the git status for the current bare repository.
* `dof sync` - commit local changes, push to origin, and pull remote changes with rebase.
* `dof sync --push-only` - only commit and push local changes.
* `dof sync --pull-only` - only pull remote changes.
== Configuration
dof supports configuration in several ways:
* `--config <file>` or `-c` - use a custom config file.
* `--profile <name>` - select a named profile from the config.
* `--repository <path>` or `-r` - path to the bare git repository.
* `--branch <name>` or `-b` - git branch to track.
* environment variables prefixed with `DOF_`.
The default config file is `$HOME/.dof.yaml`.
Profiles are defined under `profiles.<name>` and can override `repository`, `branch`, and `skip_files`.
The `--profile` flag selects one named profile from this single config file. That means you can keep multiple repository definitions in one shared config and switch between them at runtime.
Example config:
[source,yaml]
----
repository: /home/user/.dof
branch: main
skip_files:
- README.md
- LICENSE
profiles:
work:
repository: /home/user/.dof-work
branch: work
skip_files:
- scm-info.yaml
- README.adoc
personal:
repository: /home/user/.dof-personal
branch: main
----
Use profiles like this:
* `dof --profile work init`
* `dof --profile personal sync`
=== Adding a profile
To add a new profile, open `$HOME/.dof.yaml` and add an entry under `profiles`:
[source,yaml]
----
profiles:
myprofile:
repository: /home/user/.dof-myprofile
branch: main
skip_files:
- README.md
----
Each profile can set any combination of `repository`, `branch`, and `skip_files`. Values you omit fall back to the top-level defaults.
Then use the profile with `--profile myprofile`:
[source,shell]
----
dof --profile myprofile init
dof --profile myprofile checkout git@github.com:user/dotfiles.git
dof --profile myprofile sync
----
=== Skipping files
Some dotfile repositories contain files that are useful on the remote (e.g. `README.md`, `LICENSE`, `scm-info.yaml`) but should not appear in the home directory. The `skip_files` option excludes these files from the working tree.
Add the files you want to skip to your config:
[source,yaml]
----
skip_files:
- README.md
- README.adoc
- LICENSE
- scm-info.yaml
----
This works by setting up git sparse-checkout in non-cone mode. Once applied, the excluded files stay absent across all git operations (checkout, pull, merge) without any extra wrapper logic.
The skip rules are applied automatically when you run `dof init` or `dof checkout`. If you change the `skip_files` list later, run `dof init` again to update the sparse-checkout rules.
To add `skip_files` to an existing repository that was already initialized, just add the list to your `$HOME/.dof.yaml` and run:
[source,shell]
----
dof init
----
This re-applies the sparse-checkout rules and removes the skipped files from your working tree. The files remain tracked in git and are still pushed to the remote — they just do not appear locally.
== Command overview
* `dof init` - initialize a bare dotfile repository.
* `dof checkout <git-repo-url>` - clone and checkout an existing bare repository.
* `dof add <file>` - add a file to the repository and commit it.
* `dof status` - show repository status.
* `dof sync` - sync local and remote changes.
* `dof alias ...` - run any git command against the configured bare repository.
* `dof completion <bash|zsh|fish|powershell>` - generate shell completion.
* `dof version` - print version and build metadata.
== Project structure
* `main.go` - application entrypoint.
* `cmd/` - CLI command implementations.
** `root.go` - root command, configuration and flags.
** `init.go` - repository initialization logic.
** `checkout.go` - checkout workflow for existing repos.
** `add.go` - add files to the repository.
** `sync.go` - sync workflow with remote.
** `status.go` - git status command.
** `alias.go` - arbitrary git command support.
** `completion.go` - shell completion generation.
** `version.go` - version command.
* `go.mod`, `go.sum` - module and dependency definitions.
== Dependencies
dof requires `git` to be installed and available on `PATH`.
Go dependencies:
* `github.com/spf13/cobra` - CLI command framework.
* `github.com/spf13/viper` - configuration and environment handling.
* `github.com/sirupsen/logrus` - logging.
* `github.com/stretchr/testify` - unit testing helpers.
Indirect dependencies include the Cobra/Viper ecosystem packages such as `fsnotify`, `pflag`, `afero`, and `yaml.v3`.
== Development
Build the project:
[source,shell]
----
go build -o dof ./...
----
Run the CLI:
[source,shell]
----
./dof --help
go run main.go --help
----
Run tests:
[source,shell]
----
go test ./...
----
Format the code:
[source,shell]
----
go fmt ./...
----
== Notes
dof is designed to work with one configured repository per invocation. Use profiles, `--repository`, or `--config` to switch between repositories on the same machine.
== GitHub Actions
This repository uses GitHub Actions for continuous integration, including Go tests, CodeQL analysis, and release workflow automation. It also builds binaries for release distribution.