After moving more of my daily work to an Ubuntu workstation, one of the smaller questions was “how do I want to manage my Git repositories”
On Windows I used GitHub Desktop quite often. It provides a simple workflow for cloning repositories, reviewing changes, staging files, committing and pushing without having to think too much about the underlying Git commands.
My repositories however are mainly hosted on my self-hosted Forgejo instance, and on Linux the choice is slightly different.
I looked at dedicated Git clients such as GitKraken and a few alternatives, but eventually decided not to add another Git application at all.
The setup I ended up with is simply:
Ubuntu Workstation
|
+-- VS Code
| |
| +-- Source Control
| +-- Diff Viewer
| +-- Git Graph
| `-- Integrated Terminal
|
+-- Git CLI
|
`-- SSH
|
`-- Forgejo
For my use case this gives me almost everything I used GitHub Desktop for, while keeping normal Git available underneath.
Installing and Configuring Git
Git was already installed on my Ubuntu workstation:
git --version
which returned:
git version 2.53.0
I also checked my existing global configuration:
git config --global --list --show-origin
My basic identity was already configured:
user.name=Michael
user.email=forgejo@example.com
A few additional defaults are useful:
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global fetch.prune true
git config --global core.autocrlf input
The important one for Linux/Windows interoperability is:
core.autocrlf=input
Git will convert CRLF line endings to LF when committing but will not convert files back to CRLF when checking them out on Linux.
Using a Dedicated SSH Key for Forgejo
I prefer using separate SSH keys for different purposes instead of sharing one key between everything.
First I checked whether the workstation already contained SSH keys:
ls -la ~/.ssh
In my case there were no client keys yet, so I created a dedicated Ed25519 key for Forgejo:
ssh-keygen \
-t ed25519 \
-C "forgejo@example.com" \
-f ~/.ssh/id_ed25519_forgejo
This creates:
~/.ssh/id_ed25519_forgejo
~/.ssh/id_ed25519_forgejo.pub
The .pub file is the public key and can be added to the Forgejo account.
The private key stays on the workstation.
To display the public key:
cat ~/.ssh/id_ed25519_forgejo.pub
I then added it in Forgejo under:
User Settings
-> SSH / GPG Keys
-> Add Key
Creating an SSH Alias
Instead of remembering the IP address, port and SSH identity for every repository, I added an entry to:
~/.ssh/config
Example:
Host forgejo
HostName 192.168.10.10
Port 30143
User git
IdentityFile ~/.ssh/id_ed25519_forgejo
IdentitiesOnly yes
I also restricted the configuration file permissions:
chmod 600 ~/.ssh/config
The effective configuration can be checked with:
ssh -G forgejo | grep -E '^(hostname|user|port|identityfile) '
This should show something similar to:
hostname 192.168.10.10
user git
port 30143
identityfile ~/.ssh/id_ed25519_forgejo
The connection itself can then be tested with:
ssh -T forgejo
The alias is useful because it also makes Git repository URLs much cleaner.
Instead of:
ssh://git@192.168.10.10:30143/Michael/k8s-gitops.git
I can use:
forgejo:Michael/k8s-gitops.git
Keeping Repositories in One Directory
I created a simple directory for my local Git repositories:
mkdir -p ~/git-repos
cd ~/git-repos
From there I cloned one of my existing Forgejo repositories:
git clone forgejo:Michael/k8s-gitops.git
Git successfully cloned the repository:
Cloning into 'k8s-gitops' ...
Receiving objects: 100%
Resolving deltas: 100%
Afterwards I verified the repository:
cd k8s-gitops
git status
git branch --show-current
git remote -v
The result should look similar to:
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
main
origin forgejo:Michael/k8s-gitops.git (fetch)
origin forgejo:Michael/k8s-gitops.git (push)
The important part here is the remote:
forgejo:Michael/k8s-gitops.git
Git automatically resolves forgejo through ~/.ssh/config.
Opening the Repository in VS Code
From the repository directory:
code .
VS Code automatically detects that the directory contains a Git repository.
On the first opening I ran into one more small detail: VS Code opened the directory in Restricted Mode.
The Source Control view showed:
None of the registered source control providers work in Restricted Mode.
Since this is my own local repository, I selected:
Manage Workspace Trust
and trusted the folder.
Afterwards VS Code immediately enabled its Git integration.
The Source Control pane now showed:
CHANGES
Commit Message
Commit
and the Git Graph displayed the existing commit history and the current main branch.
No additional Git extension was required.
A Few VS Code Git Settings
For now I keep the Git setup intentionally simple.
The settings I use are:
Git: Autofetch Enabled
Git: Confirm Sync Enabled
Git: Enable Smart Commit Disabled
Autofetch
Autofetch lets VS Code periodically fetch remote changes.
This does not modify my working tree like a pull would. It only updates the knowledge about the remote repository.
Confirm Sync
I leave confirmation enabled so that synchronization does not happen accidentally.
Smart Commit
I disable Smart Commit.
I prefer explicitly selecting and staging the files that belong to a commit rather than letting VS Code automatically include all modified files.
This is especially useful for infrastructure repositories where a working directory can easily contain several unrelated YAML, Terraform or documentation changes.
VS Code and Git CLI Together
One reason I like this setup is that VS Code does not hide Git.
I can use the graphical interface when it is convenient and immediately switch to the integrated terminal when I want more detail.
My normal workflow looks roughly like this:
git pull
|
v
Edit files in VS Code
|
v
Review Diff
|
v
Stage selected files
|
v
Commit
|
v
Push to Forgejo
Before starting work:
git status
git pull
While working:
git diff
After committing:
git log -5 --oneline
git status
For day-to-day commits I can use the VS Code Source Control interface.
For troubleshooting or more advanced Git operations I still have the full Git CLI directly underneath it.
The Final Setup
The resulting setup is surprisingly small:
Ubuntu
|
+-- ~/git-repos/
| |
| +-- k8s-gitops/
| +-- k8s-infra/
| +-- rancher-mgmt/
| `-- ...
|
+-- Git CLI
|
+-- VS Code
|
`-- ~/.ssh/
|
+-- config
+-- id_ed25519_forgejo
`-- id_ed25519_forgejo.pub
Forgejo remains a completely normal Git remote.
There is no Forgejo-specific client required and no dependency on GitHub Desktop.
Final Thoughts
This started as a search for a Linux replacement for GitHub Desktop.
In the end I decided that I did not actually need one.
VS Code already gives me the visual parts I liked about GitHub Desktop: file changes, diffs, staging, commits and repository history.
For me the combination is actually a better fit for an Ubuntu workstation:
VS Code for convenience.
Git CLI for control.
SSH for authentication.
Forgejo for hosting.
It also has another useful side effect: instead of learning how a specific Git client represents Git operations, I continue learning Git itself.