+ # Pijul for Git users
+
+ ## Introduction
+
+ Pijul is an in-development distributed version control system that
+ implements repositories using a different [model][model] than
+ Git's. This model enables [cool features][why-pijul] and avoids
+ [common problems][bad-merge] which we are going to explore in this
+ tutorial. (The good stuff appears from the "Maybe we don't need
+ branches" section.) It is assumed that the reader uses Git in a
+ daily base, i.e. knows not only how to commit, push and pull but
+ also has had the need to cherry-pick commits and rebase branches
+ at least once.
+
+ ## Creating a repo
+
+ ```
+ $ mkdir pijul-tutorial
+ $ cd pijul-tutorial
+ $ pijul init
+ ```
+
+ Nothing new here.
+
+ ## Adding files to the repository
+
+ Just like in Git after we create a file it must be explicitly
+ added to the repository:
+
+ ```
+ $ pijul add <files>
+ ```
+
+ There's a difference though: in Pijul a file is just a UNIX file,
+ i.e. directories are also files so we don't need to create `.keep`
+ files to add *empty* directories to our repos. Try this:
+
+ ```
+ $ mkdir a-dir
+ $ touch a-dir/a-file
+ $ pijul add a-dir/
+ $ pijul status
+ ```
+
+ The output will be:
+
+ ```
+ On branch master
+
+ Changes not yet recorded:
+ (use "pijul record ..." to record a new patch)
+
+ new file: a-dir
+
+ Untracked files:
+ (use "pijul add <file>..." to track them)
+
+ a-dir/a-file
+ ```
+
+ To add files recursively we must use the `--recursive` flag.
+
+ ## Signing keys
+
+ Pijul can sign patches automatically, so let's create a signing key
+ before we record our first patch:
+
+ ```
+ $ pijul key gen --signing
+ ```
+
+ The key pair will be located in `~/.local/share/pijul/config`. At
+ the moment the private key is created without a password so treat
+ it with care.
+
+ ## Recording patches
+
+ From the user perspective this is the equivalent to Git's commit
+ operation but it is interactive by default:
+
+ ```
+ $ pijul record
+
+ added file a-dir
+
+ Shall I record this change? (1/2) [ynkadi?] y
+
+ added file a-dir/a-file
+
+ Shall I record this change? (2/2) [ynkadi?] y
+
+ What is your name <and email address>? Someone's name
+ What is the name of this patch? Add a dir and a file
+ Recorded patch 6fHCAzzT5UYCsSJi7cpNEqvZypMw1maoLgscWgi7m5JFsDjKcDNk7A84Cj93ZrKcmqHyPxXZebmvFarDA5tuX1jL
+ ```
+
+ Here `y` means yes, `n` means no, `k` means undo and remake last
+ decision, `a` means include this and all remaining patches, `d`
+ means include neither this patch nor the remaining patches and `i`
+ means ignore this file locally (i.e. it is added to
+ `.pijul/local/ignore`).
+
+ Let's change `a-file`:
+
+ ```
+ $ echo Hello > a-dir/a-file
+
+ $ pijul record
+ In file "a-dir/a-file"
+
+ + Hello
+
+ Shall I record this change? (1/1) [ynkad?] y
+
+ What is the name of this patch? Add a greeting
+ Recorded patch 9NrFXxyNATX5qgdq4tywLU1ZqTLMbjMCjrzS3obcV2kSdGKEHzC8j4i8VPBpCq8Qjs7WmCYt8eCTN6s1VSqjrBB4
+ ```
+
+ ## Ignoring files
+
+ We saw that when recording a patch we can chose to locally ignore
+ a file, but we can also create a `.pijulignore` or `.ignore` file
+ in the root of our repository and record it. All those files
+ accept the same patterns as a `.gitignore` file.
+
+ Just like in Git if we want to ignore a file that was recorded in
+ a previous patch we must remove that file from the repository.
+
+ ## Removing files from the repository
+
+ ```
+ $ pijul remove <files>
+ ```
+
+ The files will be shown as untracked again whether they were
+ recorded with a previous patch or not, so this has the effect of
+ `git reset <files>` or `git rm --cached` depending on the previous
+ state of these files.
+
+ ## Removing a patch
+
+ ```
+ $ pijul unrecord
+ ```
+
+ This command is interactive. Alternatively, one can use `pijul
+ unrecord <patch>` to remove one or more patches, knowing their hash.
+ Patch hashes can be obtained with `pijul log`.
+
+ Unrecording and recording the same patch again will leave the
+ repository in the same state.
+
+ There are cases where a patch depends on a previous one.
+ For example if a patch edits (and only edits) file A it will
+ depend on the patch that created that file. We can see these
+ dependencies with `pijul dependencies` and they are managed
+ automatically. This is why `pijul unrecord <patch>` might
+ sometimes refuse to work.
+
+ ## Discarding changes
+
+ ```
+ $ pijul revert
+ ```
+
+ This is like `git checkout` applied to files (instead of
+ branches).
+
+ ## Branches
+
+ To create a new branch we use the `pijul fork <branch-name>`
+ command and to switch to another branch we use `pijul
+ checkout <branch-name>`.
+
+ To apply a patch from another branch we use the `pijul apply
+ <patch-hash>` command. Notice that this doesn't produce a
+ different patch with a different hash like `git cherry-pick` does.
+
+ Finally to delete a branch we have the `delete-branch` subcommand,
+ but:
+
+ ## Maybe we don't need branches
+
+ Because in Git each commit is related to a parent (except for the
+ first one), branches are useful to avoid mixing up unrelated work.
+ We don't want our history to look like this:
+
+ ```
+ * More work for feature 3
+ |
+ * More work for feature 1
+ |
+ * Work for feature 3
+ |
+ * Work for feature 2
+ |
+ * Work for feature 1
+ ```
+
+ And if we need to push a fix for a bug ASAP we don't want to also
+ push commits that still are a work in progress so we create
+ branches for every new feature and work in them in isolation.
+
+ But in Pijul patches usually commute: in the same way that 3 + 4 +
+ 8 produces exactly the same result than 4 + 3 + 8, if we apply
+ patch B to our repo before we apply patch A and then C the result
+ will be exactly the same that our coworkers will get if they apply
+ patch A before patch C and then patch B. Now if patch C has a
+ dependency called D (as we saw in Removing a patch) they cannot
+ commute, but the entire graph commutes with other patches, i.e if
+ I apply patch A before patch B and then patches CD I would get the
+ same repository state than if I applied patch B before patches CD
+ and then patch A. So Alice could have the same history as in the
+ previous example while Bob could have
+
+ ```
+ * More work for feature 1
+ |
+ * Work for feature 2
+ |
+ * More work for feature 3
+ |
+ * Work for feature 3
+ |
+ * Work for feature 1
+ ```
+
+ And the repos would be equivalents; that is, the files would be the
+ same. Why is that useful?
+
+ We can start working on a new feature without realizing
+ that it is actually a new feature and that we need a new branch.
+ We can create all the patches we need for that feature (e.g. the
+ patches that implement it, the patches that fix the bugs
+ introduced by it, and the patches that fix typos) in whatever
+ order we want. Then we can unrecord these patches and record them
+ again as just one patch without a rebase. (There's actually no
+ rebase operation in Pijul.)
+
+ But this model really shines when we start to work with:
+
+ ## Remotes
+
+ At the moment, pushing works over SSH, the server only needs to have
+ Pijul installed. [The Nest][nest] is a free service that hosts public
+ repositories. We can reuse our current SSH key pair or create a new
+ pair with
+
+ ```
+ $ pijul key gen --ssh
+ ```
+
+ This new key pair will be stored in the same directory used for
+ the signing keys and we can add it to [The Nest][nest] like we do
+ with SSH keys in GitHub.
+
+ Now that we have an account on [The Nest][nest] we can upload our
+ signing key with `pijul key upload`.
+
+ Now let's push something:
+
+ ```
+ $ pijul push <our-nest-user-name>@nest.pijul.com:<our-repo>
+ ```
+
+ Unless we pass the `--all` flag Pijul will ask us which patches we
+ want to push. So we can keep a patch locally, unrecord it, record
+ it again, decide that actually we don't need it and kill it
+ forever or push it a year later when we finally decide that the
+ world needs it. All without branches.
+
+ If we don't want to specify the remote every time we push we can
+ set it as default with the `--set-default` flag.
+
+ Of course to pull changes we have the `pijul pull` command.
+
+ Both commands have `--from-branch` (source branch),
+ `--to-branch` (destination branch) and `--set-remote` (create a
+ local name for the remote) options.
+
+ BTW if we can keep patches for ourselves can we pull only the
+ patches we want? Yes, that's called "partial clone". [It was
+ introduced in version 0.11][partial-clone] and works like this:
+
+ ```
+ $ pijul pull --path <patch-hash> <remote>
+ ```
+
+ Of course it will bring the patch and all its dependencies.
+
+ As we have seen we neither need branches, cherry-picking nor
+ rebasing because of the patch theory behind Pijul.
+
+ ## Contributing with a remote
+
+ With Pijul we don't need forking either. The steps to contribute
+ to a repo are:
+
+ 1. Clone it with `pijul clone <repo-url>`
+ 2. Make some patches!
+ 3. Go to the page of the repo in [The Nest][nest] and open a
+ new discussion
+ 4. [The Nest][nest] will create a branch with the number of the
+ discussion as a name
+ 5. Push the patches with `pijul push
+ <our-user-name>@nest.pijul.com:<repo-owner-user-name>/<repo-name>
+ --to-branch :<discussion-number>`
+
+ Then the repo owner could apply our patches to the master branch.
+ You can also attach patches from your repos to a discussion when
+ you create or participate in one.
+
+ ## Tags
+
+ A tag in Pijul is a patch that specifies that all the previous
+ patches depend on each other to recreate the current state of the
+ repo.
+
+ To create a tag we have the `pijul tag` command which will ask for
+ a tag name.
+
+ After new patches are added to the repo we can recreate the state
+ of any tag by creating a new branch:
+
+ ```
+ pijul fork --patch <hash-of-the-tag> <name-of-the-new-branch>
+ ```
+
+ Because tags are just patches we can look for their hashes with
+ `pijul log`.
+
+ ## In summary
+
+ Forget about bad merges, feature branches, rebasing and conflicts
+ produced by merges after cherry-picking.
+
+ ## Learning more
+
+ [Pijul has an on-line manual][manual] but currently it is a
+ little bit outdated. The best way to learn more is by
+ executing `pijul help`. This will list all the subcommands and we
+ can read more about any of them by running `pijul help
+ <subcommand>`.
+
+ The subcommands are interactive by default but we can pass data to
+ them directly from the command line to avoid being asked
+ questions. All these options are explained in each subcommand's help.
+
+ For more information on the theory behind Pijul refer to Joe
+ Neeman's [blog post on the matter][theory]. He also wrote a post
+ [that explains how Pijul implements it][implementation].
+
+ ## A work in progress
+
+ As we said Pijul is an in-development tool: [the UI could
+ change in the future][ui-changes] and there are some missing
+ features. ([Something][bisect] like `bisect` would be super
+ helpful.) But that's also an opportunity: the developers seem
+ quite open to [receive feedback][discourse].
+
+ [bad-merge]: https://tahoe-lafs.org/~zooko/badmerge/simple.html
+ [bisect]: https://discourse.pijul.org/t/equivalent-of-checking-out-an-old-commit/176
+ [discourse]: https://discourse.pijul.org
+ [implementation]: https://jneem.github.io/pijul/
+ [nest]: https://nest.pijul.com
+ [manual]: https://pijul.org/manual/
+ [model]: https://pijul.org/model/
+ [partial-clone]: https://pijul.org/posts/2018-11-20-pijul-0.11/
+ [theory]: https://jneem.github.io/merging/
+ [ui-changes]: https://discourse.pijul.org/t/equivalent-of-checking-out-an-old-commit/176
+ [why-pijul]: https://pijul.org/manual/why_pijul.html