gitdesk
A GitHub Desktop-style git client that runs in your terminal. Use the mouse or the keyboard.
Setup
- Install Python 3.9+. That's not needed if you use the built exe.
- Install the one dependency:
python -m pip install -r requirements.txt(or just run gitdesk once and say yes when it offers to install it). - git: if it isn't installed, gitdesk offers to install it for you when it starts.
It does the same if your git is older than 2.25.
- Windows: installs Git for Windows (which includes Git LFS) with
winget, after the usual permission prompt. gitdesk picks it up straight away. Without winget, it opens the download page. - Linux: installs
gitandgit-lfswith apt, dnf, yum, pacman, zypper or apk, using sudo. - macOS: uses Homebrew, or Apple's command line tools.
- Windows: installs Git for Windows (which includes Git LFS) with
- Your name and email: the first time you commit or create a repository, gitdesk asks for them if git doesn't know them yet. They're saved for all your repositories.
Build a standalone executable (optional)
This makes a single file that runs without Python or Textual installed.
- Windows: double-click
build.bat. In PowerShell type.\build.bat; PowerShell won't run it without the.\. You getdist\gitdesk.exe. - Linux / macOS: run
./build.sh. You getdist/gitdesk.
build.py does the work, and the .bat/.sh just start it. It:
- sets up its own environment in
.build; - installs PyInstaller and Textual;
- builds the exe;
- test-starts the new exe to make sure it works;
- logs everything to
build.log.
If something goes wrong it says why in plain English (old exe still open, antivirus,
OneDrive, no internet...). Send build.log over if the reason isn't clear.
Build on the system you want to run it on: a Windows exe has to be built on Windows. The exe takes a second or two to start because it unpacks itself first.
Run
| Windows | gitdesk.bat inside a repo folder, or gitdesk.bat C:\path\to\repo. Windows Terminal gives the best mouse support and symbols. |
| Linux / macOS | python3 gitdesk.py inside a repo, or python3 gitdesk.py ~/path/to/repo |
Tip: put this folder on your PATH (Windows), or symlink it on Linux/macOS
(ln -s "$PWD/gitdesk.py" ~/.local/bin/gitdesk). Then you can type gitdesk in any repo.
What's on screen
-
Top bar:
- Current repository: click it to open the picker. It lists your recent repos and has Add local repository…, New repository… and Clone repository….
- Current branch: click to switch branches or create one.
- Fetch / Pull / Push / Publish: one button that changes with the state of your branch, like GitHub Desktop's. If the repo has no remote yet, it shows No remote: click it to add the URL of an empty repo you created on GitHub or Gitea, then publish.
- More: lists every action.
-
Startup: gitdesk reopens the repository you had open last. If you start it inside a repo folder, or pass a path (
gitdesk C:\path\to\repo), it opens that one instead. -
Add local repository (
o): type a path, or click Choose… to pick the folder. If the folder isn't a git repository yet, it offers Create a repository here: the files already in it go into the first commit (pick the Unity .gitignore for a Unity project so Library/ and Temp/ stay out). -
Choose… buttons (Add local, New repository, Clone) open the normal folder picker: the Explorer "Select Folder" window on Windows, Finder on macOS, and zenity/kdialog on Linux desktops. With no desktop (e.g. over SSH) you get a folder browser inside the terminal. On Windows the Explorer picker needs Python's tkinter, which the python.org installer includes by default. Without it you get the older Windows folder dialog instead. The same goes for the exe: build it with a Python that has tkinter.
-
New repository: choose a name, description and folder, a README, a .gitignore template (Unity, Python, Node, Visual Studio), an MIT license, and an optional remote URL. It makes the first commit for you.
-
Clone repository: paste an HTTPS or SSH URL. The folder name fills in automatically and progress shows in the top bar. If the server needs a password, use Retry in terminal.
-
Changes tab: changed files with checkboxes. Ticked files go into the commit. Click a file to see its diff, then Discard it if you don't want those changes. Discard keeps a backup in Stashed changes, so it can be undone. More → Discard ticked changes does several files at once. Below the list are Stash all / Stashed, and the commit summary + description.
-
Right-click a changed file (or press
m/ Shift+F10) for the same menu as GitHub Desktop:- Discard changes…
- Ignore file, Ignore folder ▸ (pick which parent folder), or Ignore all .ext files.
Each one adds a line to the repo's
.gitignore. - Copy file path / relative path
- Show in Explorer, Open in VS Code, Open with default program
Ignoring a file git already tracks doesn't hide its changes, so if the new rule covers tracked files, gitdesk offers Stop tracking. The files stay on your disk and leave the repository in your next commit.
-
History tab: recent commits (↑ = not pushed yet). Click one to see what changed, or View on GitHub to open that commit's page.
-
View on GitHub (
g, More menu, or the card on the "No local changes" screen) opens the repo's web page, worked out from the remote URL. It works for GitHub, Gitea, GitLab and Bitbucket, over SSH or HTTPS, and any token in the URL is left out. If the address can't be worked out (e.g. SSH goes through a separate hostname), set it once:git config gitdesk.webUrl https://git.example.com/owner/repo -
Log (
l): shows every git command gitdesk ran and what git printed.
Behaviour
- It refreshes every 3 seconds and fetches in the background every 5 minutes.
- Pull blocked by your local changes: it offers Stash, pull & re-apply.
- If re-applying clashes, the file shows the
<<<<<<< ======= >>>>>>>markers. - Fix the file, then click Mark as resolved. The stash is kept until you drop it.
- If re-applying clashes, the file shows the
- Pull hits a merge conflict: choose Resolve conflicts (fix files, Mark as resolved, Commit merge) or Abort merge.
- Push when the remote has newer commits: it offers Pull, then push.
- Switching branch blocked by your changes: it offers Stash & switch.
- A network command needs a password, token, SSH passphrase or host-key confirmation: click Retry in terminal. gitdesk steps aside so git can ask you, then comes back.
- Push refused as too big over HTTPS (HTTP 413), e.g. by Cloudflare's 100 MB upload limit:
gitdesk offers Push over SSH with the SSH address filled in. You can change the address,
and it's remembered per repo.
- Tick Always push this repository over SSH to set git's push URL, so pushes go over SSH while fetches stay on HTTPS.
- If the site is behind Cloudflare, SSH needs an address that reaches the server directly: a DNS-only hostname or the server's IP.
- "Filename too long" (Windows): Unity projects often have paths past Windows' 260-character
limit. As soon as git reports one, gitdesk runs
git config --global core.longpaths trueand tells you. Then:- if the action hadn't changed anything yet (stash, commit, refresh), it runs it again;
- if it got part-way (e.g. switched branch but couldn't write some files), it re-creates just the missing files;
- if a clone downloaded but couldn't write its files, it writes them and opens the repo.
- Another program has the repository busy (GitHub Desktop, VS Code, Unity, OneDrive,
antivirus): gitdesk waits and retries for a few seconds. If a
.git/index.lockis left behind by a crashed git, it offers Remove lock file & retry.
Keys: f fetch · p pull · u push · b branch · s stash · t stashes · d discard ·
o add local repo · n new repo · c clone · g view on web · l log · r refresh · space tick/untick file · m file menu · q quit
Set up SSH for git (Windows, optional)
git-ssh-setup.ps1 sets up SSH, so pushes and Git LFS don't ask for your passphrase
every time. It's handy when HTTPS pushes are refused as too big (see Push over SSH below).
Run it: double-click git-ssh-setup.cmd. Run it as your normal user, not
"Run as administrator". From PowerShell, use:
powershell -NoProfile -ExecutionPolicy Bypass -File .\git-ssh-setup.ps1
The bypass applies to that one run only. Your system's execution policy isn't changed.
It asks for the SSH host. You can type git.example.com, git.example.com:2222, or paste an
SSH clone URL. Next time it offers the host you used last: press Enter to keep it, or type
another one to set up a second server. Then it:
- turns on Windows'
ssh-agentservice. This step shows a UAC prompt, and only when the service needs turning on. If the OpenSSH client is missing, it installs that too. - creates an ed25519 key
~/.ssh/id_ed25519_gitea(it asks for a passphrase), or reuses the one that's already there. - loads the key into ssh-agent. Windows keeps it loaded across reboots.
- adds a
Hostentry for the server to~/.ssh/config. If one already exists, it leaves it alone and shows what it would have written. - points git at Windows' OpenSSH (
core.sshCommand), so git uses the agent. It also setslfs.ssh.automultiplex false, which stops Git LFS transfers over SSH from hanging. - shows your public key and copies it to the clipboard. Add it in Gitea: your avatar > Settings > SSH / GPG Keys > Add Key.
- verifies the key in Gitea (optional). Click Verify next to the key, paste the token into the script, then paste the signature it copies back into Gitea.
- tests the connection with
ssh -T.
You can run it again safely. It reuses the key, doesn't add it to the agent twice, and never
changes an existing ~/.ssh/config entry.
| Option | What it does |
|---|---|
-HostName git.example.com |
Skips the host prompt. -HostName "" skips the config entry and the test. |
-Port 2222 |
SSH port (default 22). |
-User git |
SSH user (default git, which is right for Gitea, GitHub and GitLab). |
-KeyName id_ed25519_github |
Key file name in ~/.ssh (default id_ed25519_gitea). |
-Comment "label" |
Label shown in Gitea's key list (default user@computer). |
-Force |
Replaces the existing key instead of reusing it. |
-NoVerify |
Skips the Gitea verify step (e.g. for GitHub). |
-Token <hex> |
Signs this Gitea verify token without asking for it. |
-NoTest |
Skips the connection test. |
Gitea's verify token expires quickly. If Gitea rejects the signature, click Verify again and run it again with only the new token:
powershell -NoProfile -ExecutionPolicy Bypass -File .\git-ssh-setup.ps1 -NoTest -Token <new token>
If the site is behind Cloudflare's proxy, use a hostname or IP that reaches the server directly. SSH doesn't go through the proxy.