192 lines
11 KiB
Markdown
192 lines
11 KiB
Markdown
# gitdesk
|
|
|
|
A GitHub Desktop-style git client that runs in your terminal. Use the mouse or the keyboard.
|
|
|
|
## Setup
|
|
|
|
1. Install Python 3.9+. That's not needed if you use the built exe.
|
|
2. 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).
|
|
3. **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 `git` and `git-lfs` with apt, dnf, yum, pacman, zypper or apk, using sudo.
|
|
- **macOS:** uses Homebrew, or Apple's command line tools.
|
|
4. **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 get `dist\gitdesk.exe`.
|
|
- **Linux / macOS:** run `./build.sh`. You get `dist/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.
|
|
- **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 true`
|
|
and 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.lock` is 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:
|
|
|
|
1. turns on Windows' `ssh-agent` service. This step shows a UAC prompt, and only when the
|
|
service needs turning on. If the OpenSSH client is missing, it installs that too.
|
|
2. creates an ed25519 key `~/.ssh/id_ed25519_gitea` (it asks for a passphrase), or reuses the
|
|
one that's already there.
|
|
3. loads the key into ssh-agent. Windows keeps it loaded across reboots.
|
|
4. adds a `Host` entry for the server to `~/.ssh/config`. If one already exists, it leaves it
|
|
alone and shows what it would have written.
|
|
5. points git at Windows' OpenSSH (`core.sshCommand`), so git uses the agent. It also sets
|
|
`lfs.ssh.automultiplex false`, which stops Git LFS transfers over SSH from hanging.
|
|
6. shows your public key and copies it to the clipboard. Add it in Gitea: your avatar >
|
|
Settings > SSH / GPG Keys > Add Key.
|
|
7. 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.
|
|
8. 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.
|