# patchy
`patchy` makes it easy to maintain personal forks in which you merge some pull requests of your liking to have more features than other people.
- [Why should I use it?](#why-should-i-use-it)
- [Usage](#usage)
- [Config](#config)
- [Patches](#patches)
- [Versioning](#versioning)
- [Installation](#installation)
- [Binary](#binary)
- [Homebrew](#homebrew)
- [Cargo](#cargo)
- [PowerShell](#powershell)
- [Nix](#nix)
- [Merge conflicts](#merge-conflicts)
## Why should I use it?
- Merge multiple pull requests and commits into a single repo effortlessly
- Sync those pull requests and the main branch with a single command
- Add new pull requests and update existing ones easily
## Usage
Go to a git repo, and initialize the config file:
```bash
patchy init
```
Invoke `patchy` by running the following command:
```bash
patchy run
```
### Config
I'm using the [Helix Editor](https://github.com/helix-editor/helix) but there are some pull requests which add awesome features.
I found myself very frequently doing the same tasks in order to sync the 4 pull requests I like to use and keep them up to date. With patchy, I just run one command and it handles the rest.
Here's my config:
```toml
# main repository to fetch from
repo = "helix-editor/helix"
# the repository's branch
remote-branch = "master"
# This is the branch where you will see all result from patchy's work. Set it to any branch you want.
# WARNING: Make sure you do not store any important work on this branch. It will be erased.
local-branch = "patchy"
# List of pull requests which you would like to merge
# TIP: Add comments above pull requests to help yourself understand which PRs do what
pull-requests = [
# syntax highlighting for nginx files
"12309",
# adds file explorer
"11285",
# global status line
"8908",
# command expansions
"11164",
]
# An optional list of patches to apply, more on them later
patches = ["remove-tab"]
```
Running `patchy run` outputs:

With this, all I will need to do is run `patchy run` and it will automatically update all of the pull requests and sync the master branch to the latest changes.
### Patches
You might want to apply some changes to your repo, but it's not a pull request. No worries! `patchy` is built for this.
Create a patch from a commit:
```bash
# obtain commit hashes e.g. from `git log`
patchy gen-patch <hash-of-commit>
```
For example, I'm running:
```bash
patchy gen-patch 7bb8ec5a77769d88855d41dd5fecfaece54cf471
```
It generated a file, `.patchy/feat-swap-light-and-dark-colors.patch`:
```patch
diff --git a/README.md m/README.md
index 11a909b2..4eae6a8d 100644
--- a/README.md
+++ m/README.md
@@ -2,8 +2,8 @@
<h1>
<picture>
- <source media="(prefers-color-scheme: dark)" srcset="logo_dark.svg">
<source media="(prefers-color-scheme: light)" srcset="logo_light.svg">
+ <source media="(prefers-color-scheme: dark)" srcset="logo_dark.svg">
<img alt="Helix" height="128" src="logo_light.svg">
</picture>
</h1>
```
To use your new `.patch`, edit your `.patchy/config.toml` like so:
```diff
--- patches = []
+++ patches = [ "feat-swap-light-and-dark-colors" ]
```
### Versioning
Each pull request's branch contains commits. By default, we will always use the latest commit. However you can pin a commit to a specific version with the following syntax:
```toml
remote-branch = "main @ cfd225baedbb5fb9cbc9742f91244fa50882b580"
pull-requests = [
"145 @ fccc58957eece10d0818dfa000bf5123e26ee32f",
"88 @ a556aeef3736a3b6b79bb9507d26224f5c0c3449"
]
```
Where the hashes represent each `sha1` hash of every commit.
This is handy if you don't want things to randomly break when some of the pull requests push a new change.
## Installation
Patchy can be installed on Linux, Windows and macOS.
### Binary
Install the binary directly into your system, available for macOS and Linux.
Recommended for Linux users.
```bash
### Homebrew
Recommended for macOS users.
```bash
brew install nik-rev/tap/patchy-bin
```
### Cargo
```bash
cargo install patchy-bin
```
### PowerShell
Recommended for Windows users.
```powershell
### Nix
```bash
nix profile install github:nik-rev/patchy/main
```
<details>
<summary>
Example usage with flakes
</summary>
If the software you are using has a `flake.nix` which automatically builds this software, then using patchy with it is straightforward.
1. Use patchy to create your own remote fork.
Let's say you fork the [`helix-editor/helix`](https://github.com/helix-editor/helix) and your fork is located at `your-username/helix`, the patchy branch is called `patchy`
1. Add your fork's input in your `flake.nix` as follows:
```nix
inputs.helix.url = "github:your-username/helix/patchy";
```
1. Use the input in your home-manager:
```nix
programs.helix.package = inputs.helix.packages.${pkgs.system}.helix;
```
This is easier when the target repository has a `flake.nix` which fully builds the software. Which, the [`helix-editor/helix`](https://github.com/helix-editor/helix) does have for example.
</details>
## Merge conflicts
If you merge a lot of PRs, it's likely some of them will clash with eachother and there will be conflicts.
Say you merge 10 pull requests, 3 of which couldn't be merged due to merge conflicts. The other 7 will be merged, while branches for those 3 will exist and you will be able to merge them yourself.
```
✗ Could not merge branch 11164/command-expansion into the current branch for pull request #11164 Command expansion v2 since the merge is non-trivial.
You will need to merge it yourself:
git merge --squash 11164/command-expansion
Note: To learn how to merge only once and re-use for subsequent invocations of patchy, see Merge conflicts (github)
```
<details>
<summary>
Fixing merge conflicts and retaining the fixes, declaratively
</summary>
Okay, now merge the branch:
```bash
git merge --squash 11164/command-expansion
```
We need `--squash` since `patchy gen-patch` does not work on Merge commits. But using `--squash` makes it into a non-merge commit.
Now fix the merge conflicts.
Then, commit your changes:
```
git commit -m "merge branch 11164/command-expansion"
```
This creates the following commit:
```
2fb6c3c7 (HEAD -> patchy) Merge branch '11164/command-expansion' into patchy
```
Now that you have this commit, let's generate a `.patch` file for it:
```
> patchy gen-patch 2fb6c3c7 --patch-filename=merge-11164
✓ Created patch file at .patchy/merge-11164.patch
```
Now, you can go ahead and add the patch to your config:
```diff
- pull-requests = [ "1234", "1111", "11164" ]
+ pull-requests = [ "1234", "1111" ]
- patches = [ ]
+ patches = [ "merge-11164" ]
```
When you do this, you won't need to solve this merge conflict anymore as the `merge-11164` patch includes both the entire pull request as well as how it was merged.
Note that if you change the _order_ of your pull requests in `pull-requests` you may see merge conflicts again. It is recommended to keep the order the same once you fix the conflicts.
</details>