Anist is a command-line tool designed to streamline workflows with stacked diffs in Phabricator and Arcanist. It provides advanced automation for common tasks when working with stacked commits, allowing developers to focus on code rather than managing version control processes.
uv is a faster, more reliable Python package installer and resolver:
# Install anist using uv
uv pip install git+https://github.com/risperss/anist.git
# Or, if you've cloned the repo
cd ~/repos/anist
uv pip install -e .# Install directly from GitHub
pip install git+https://github.com/risperss/anist.git
# Or, if you've cloned the repo
cd ~/repos/anist
pip install -e .-
Clone the repository
git clone https://github.com/risperss/anist.git cd ~/repos/anist
-
Install the package
# Using uv uv pip install -e . # Using pip pip install -e .
After installation, the anist command will be available from any directory.
Anist uses a modern CLI interface built with Typer, offering rich help text and intuitive command structure with colorful output.
The commit command automates the process of editing a specific commit in a stack of commits.
anist commit -n <position>
-n, --number- Position of the commit to edit (1 = first commit after master)
- Stashes any unstaged changes
- Stashes any staged changes
- Automatically performs an interactive rebase to the specified commit
- Applies your previously staged changes to the target commit
- Automatically stages, amends, and continues the rebase
- Restores any unstaged changes
Edit the second commit in your stack:
anist commit -n 2Make changes to your first commit:
anist commit -n 1The diff command creates or updates Phabricator diffs for specific commits or entire stacks.
anist diff [OPTIONS]
-n, --number- Position of the commit to process (1 = first commit after master) [default: 1]-m, --message- Update message for the diff [default: "anist default message"]--create- Create a new diff instead of updating an existing one--full-stack- Process all commits in the stack
- Safely stashes any uncommitted changes
- For each targeted commit:
- Checks out the commit
- Finds the corresponding diff ID (if updating)
- Runs appropriate arc commands
- Returns to the original branch
- Restores any stashed changes
Update the diff for the third commit in your stack:
anist diff -n 3 -m "Fixed validation logic"Create a new diff for the first commit:
anist diff -n 1 --create -m "Initial implementation"Update all diffs in your stack:
anist diff --full-stack -m "Address code review feedback"Create new diffs for all commits in your stack:
anist diff --full-stack --create -m "New feature implementation"When working on a large feature that's split into several logical commits:
- Create your stack of commits normally
- Use
anist diff --full-stack --createto submit the entire stack for review - When you receive feedback on a specific commit:
- Use
anist commit -n <position>to make changes to that commit - Use
anist diff -n <position>to update just that diff
- Use
If you need to make changes to a commit in the middle of your stack:
- Stage your changes (
git add <files>) - Run
anist commit -n <position> - The tool will automatically handle the complex rebase process
- Run
anist diff -n <position>to update the corresponding diff
After addressing review feedback across multiple commits:
anist diff --full-stack -m "Address code review feedback"This updates all diffs in your stack with a single command.
The commit command:
- Uses Git's interactive rebase feature with custom automation
- Creates a temporary rebase script that marks only your target commit for editing
- Properly stashes both staged and unstaged changes separately, maintaining their status
- Applies staged changes with
--indexto keep them staged during amend - Automatically continues the rebase when changes are applied successfully
- Reapplies unstaged changes after the rebase is complete
The diff command:
- Uses two methods to identify the correct diff for a commit:
- Parses
arc listoutput to match commit messages with diff descriptions - Looks for "Differential Revision: D123" in commit messages
- Parses
- Handles checkout and restoration of your workspace state
- Uses Arcanist's API for creating and updating diffs
If merge conflicts occur during a commit edit:
- The tool will pause the automation
- Notify you of conflicts
- Apply your unstaged changes (if any)
- Let you resolve conflicts manually
- Provide instructions for completing the process
For stacks with many commits, use --full-stack with care:
# First update just the first commit
anist diff -n 1 -m "Fix core logic"
# Then, if that looks good, update the rest
anist diff --full-stack -m "Update dependent changes"If you have a stack of commits that haven't been submitted to Phabricator:
# Create diffs for all commits in the stack
anist diff --full-stack --createAfter making changes that affect multiple files within a single commit:
# Stage all changes
git add -u
# Apply to specific commit
anist commit -n 3
# Update the diff
anist diff -n 3 -m "Refactored authentication logic"If you notice that your staged changes become unstaged after running anist commit:
- Make sure you're using the latest version of
anistwhich properly preserves staging status - You can always re-stage the changes with
git add <files>if needed - The improved stash handling now correctly maintains the staged vs. unstaged status of files
When updating a diff and anist can't find the corresponding diff ID:
- Check that the diff exists with
arc list - Ensure the commit message is similar to the diff title
- If needed, use
--createto create a new diff instead
If the automatic rebase encounters problems:
- The tool will attempt to restore your working state
- Check
git statusto see the current state - Either resolve conflicts or run
git rebase --abort - Try again with smaller changes
If the tool crashes or encounters an unrecoverable error:
- Check your stash list with
git stash list - Look for entries with "anist" in their description
- Apply them with
git stash apply stash@{n}
Anist is installed globally, so you can use it in any Git repository:
- Make sure you're in the root directory of your Git repository
- Run any anist command as usual:
cd ~/your-project anist diff -n 2 -m "Update feature"
-
Clone the repo and install in development mode:
git clone https://github.com/risperss/anist.git cd ~/repos/anist uv pip install -e .
-
Make changes to the code
-
Run
anistto test your changes (the installed command will use your modified code) -
To quickly reinstall after making structural changes:
uv pip uninstall anist && uv pip install -e .
src/__init__.py- Package initializationcli.py- Command-line interface using Typercommit.py- Commit editing functionalitydiff.py- Diff management functionalityutils.py- Utility functions
By default, anist uses "master" as the base branch. If your repository uses a different base branch (e.g., "main"), you'll need to modify the code in src/utils.py to change references from "master" to your base branch name.
With Anist, managing complex stacked diffs in Phabricator becomes significantly more streamlined, allowing developers to focus on writing code rather than managing complex version control operations.