How-To

How to Set Up a Linux Development Environment with VS Code and Git in 2026

20 min read

The Back Room Tech is reader-supported. We may earn a commission when you buy through links on our site. Learn more.

A development PC can become a junk drawer: old extensions, extra credential helpers, and runtime managers fighting the system Python. This setup keeps the base small and easy to audit.

The main path was tested on Ubuntu 24.04 LTS. Other steps cover Debian, Fedora, RHEL-based systems, openSUSE, Windows, macOS, and the browser editor. You’ll finish with VS Code, sensible Git defaults, secure remote access, and a reusable setup script.

What Are VS Code, Git, and Linux Development Tools?

Visual Studio Code is Microsoft’s free desktop code editor. It handles editing, debugging, terminals, extensions, and visual source control. Its Git interface requires a separate Git install. This catches people when the editor works but the Source Control view doesn’t.

Git tracks project history and sends changes to remote services. Tools such as build-essential, make, gcc, g++, tmux, and archive utilities handle routine jobs. You’ll use them to build software, run tests, unpack releases, and keep remote sessions alive.

Prerequisites

  • A supported Debian, Ubuntu, Fedora, RHEL-family, or openSUSE-family desktop
  • A 64-bit x86 or Arm processor with the matching package architecture
  • An account with sudo access
  • An internet connection
  • About 2 GB of free disk space
  • A Git hosting account if you need remote repositories
  • Your commit name and email address
  • A backup or snapshot before applying workstation-wide changes

A laptop dock, USB-C Ethernet adapter, 2.5GbE switch, and UPS may suit a workstation that builds containers or large repositories. They won’t improve Git. They may save a large image pull when somebody trips over the power strip.

Step-by-Step Guide

Step 1: Choose Manual Setup or Fleet Provisioning

Set up one personal workstation by hand. You can inspect each prompt, choose useful extensions, and create the SSH key on its final machine. Allow 20-30 minutes.

For several managed PCs, put packages and shared settings in Ansible, cloud-init, or another configuration tool. Keep private keys, access tokens, personal email addresses, and credential stores out of fleet scripts. A handy script can become an incident report rather quickly when it contains secrets.

Identify the Linux family and CPU architecture:

cat /etc/os-release
uname -m

Expected output varies by machine:

NAME=”Ubuntu”
VERSION=”24.04.3 LTS (Noble Numbat)”
ID=ubuntu

x86_64

Use a DEB package for Debian or Ubuntu. Use an RPM for Fedora, RHEL, Rocky Linux, AlmaLinux, or openSUSE. Choose an Arm build when uname -m reports aarch64 or arm64. Persistence won’t make an amd64 package compatible.

The official tarball works without root access and suits portable installs, but you must manage updates. Snap gives several distributions one install path. Its sandbox and automatic updates differ from native packages. For managed PCs, the official APT or RPM repository is easier to audit and patch than separate downloads.

Official VS Code download page showing Windows, macOS, Linux DEB and RPM choices plus available processor architectures

Step 2: Install Base Tools on Debian or Ubuntu

Refresh the package list before asking APT to install anything:

sudo apt update

Representative output:

Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists… Done
All packages are up to date.

Install Git, build tools, certificate support, and common archive utilities:

sudo apt install -y git build-essential ca-certificates gnupg wget apt-transport-https unzip zip

Expected output varies with the packages already present:

The following NEW packages will be installed:
build-essential git …
Setting up git (…distribution version…) …

build-essential installs the standard Debian and Ubuntu build tools, including GCC, G++, and Make. The -y flag accepts the package manager’s prompt. Check the proposed changes before putting this command in a larger script.

Step 3: Add Microsoft’s Official APT Repository

Create a separate keyring and download Microsoft’s signing key:

sudo install -d -m 0755 /etc/apt/keyrings
wget -qO /tmp/packages.microsoft.asc https://packages.microsoft.com/keys/microsoft.asc
gpg --dearmor < /tmp/packages.microsoft.asc | sudo tee /etc/apt/keyrings/packages.microsoft.gpg > /dev/null
sudo chmod 0644 /etc/apt/keyrings/packages.microsoft.gpg

Expected output:

No output means the keyring was created successfully.

The repository entry names this keyring, so APT trusts the key only there. gpg --dearmor converts the ASCII key to APT’s binary format. Mode 0644 lets APT read the file but limits write access.

Note: this guide stores the key at /etc/apt/keyrings/packages.microsoft.gpg. Microsoft’s current official Linux setup documentation instead shows /usr/share/keyrings/microsoft.gpg as the example path for manual installation. Both locations are valid places to store an APT keyring, but they are not the same path, so don’t assume this guide’s path matches Microsoft’s documented example if you’re cross-checking against their instructions or writing scripts that reference a specific file location.

Add the stable VS Code repository:

printf '%s\n' 'Types: deb' 'URIs: https://packages.microsoft.com/repos/code' 'Suites: stable' 'Components: main' 'Architectures: amd64 arm64 armhf' 'Signed-By: /etc/apt/keyrings/packages.microsoft.gpg' | sudo tee /etc/apt/sources.list.d/vscode.sources

Expected output:

Types: deb
URIs: https://packages.microsoft.com/repos/code
Suites: stable
Components: main
Architectures: amd64 arm64 armhf
Signed-By: /etc/apt/keyrings/packages.microsoft.gpg

Install VS Code:

sudo apt update
sudo apt install -y code

Representative output:

Get:1 https://packages.microsoft.com/repos/code stable InRelease
Setting up code (…current stable version…) …

The repository lets apt upgrade install later signed releases. Check the official Linux setup documentation before a fleet rollout because keys and repository steps can change. Finding that out across 80 laptops is tedious.

Ubuntu desktop application menu showing Visual Studio Code installed and ready to launch

Step 4: Install from Microsoft’s RPM Repository

On Fedora or a RHEL-family system, import the Microsoft signing key:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc

Expected output:

No output indicates that the key was imported.

Add the official repository:

sudo tee /etc/yum.repos.d/vscode.repo > /dev/null <<'EOF'
[code]
name=Visual Studio Code
baseurl=https://packages.microsoft.com/yumrepos/vscode
enabled=1
autorefresh=1
type=rpm-md
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
EOF

Expected output:

No output indicates that /etc/yum.repos.d/vscode.repo was written.

Install the build tools and VS Code on Fedora:

sudo dnf install -y git gcc gcc-c++ make ca-certificates wget unzip zip code

Representative output:

Installed:
code-… git-… gcc-… make-…
Complete!

The same dnf command works on RHEL, Rocky Linux, or AlmaLinux when the required repositories are active. Package access varies by release and subscription. Treat a missing package as a repository issue before blaming DNF.

On openSUSE, use the official RPM repository with zypper:

sudo zypper addrepo https://packages.microsoft.com/yumrepos/vscode vscode
sudo zypper refresh
sudo zypper install git gcc gcc-c++ make code

Representative output:

Repository ‘vscode’ successfully added
Retrieving repository ‘vscode’ metadata …
Installation of code-… completed.

Keep signature checks on. If the repository reports a signature error, fix the key or repository definition. Disabling checks turns a useful safeguard into decorative text.

Step 5: Verify VS Code and Git

Check both command-line tools before changing any settings:

code --version
git --version

Representative output follows. Exact versions depend on the current VS Code release and your distribution:

1.xx.x

git version 2.xx.x

Sanitized terminal showing successful code --version and git --version results with variable versions labeled

Open VS Code:

code

Expected result:

VS Code opens; the terminal may produce no output.

If both version checks work and the app opens, the install path is sound. Fix failures now. More extensions rarely cure a basic path problem.

Step 6: Apply a Minimal Extension Policy

Open Extensions from the Activity Bar or press Ctrl+Shift+X. Install an extension when an active project needs it. Importing somebody’s list of 70 extensions often ends with a Friday afternoon spent finding the one that changed your formatter.

A defensible policy is:

  • Start with no third-party extensions.
  • Add one maintained language extension for each language you use.
  • Add Remote SSH, Dev Containers, or WSL support only when that workflow exists.
  • Review the publisher, permissions, release activity, and workspace-trust effects.
  • Remove unused extensions quarterly.

List installed extensions from the terminal:

code --list-extensions

Expected output is empty or contains one extension identifier per line:

publisher.extension-name

Extensions run code with broad access to your workspace. They also add startup time, updates, and possible conflicts. Five extensions you understand usually beat 40 installed on recommendation.

VS Code Extensions view showing the search field and installed-extension area without account or private workspace details

Step 7: Create an Ed25519 SSH Key Safely

Check for existing keys before making one:

find "$HOME/.ssh" -maxdepth 1 -type f -name 'id_*' -print 2>/dev/null

Possible output:

/home/your-user/.ssh/id_ed25519
/home/your-user/.ssh/id_ed25519.pub

If those files exist, don’t overwrite them. Confirm their purpose and reuse the key, or choose a distinct name such as id_ed25519_work. Overwriting one key can break access to every system that trusts it.

Create the directory when needed:

install -d -m 0700 "$HOME/.ssh"

Expected output:

No output indicates success.

Generate a key only when the target path is free:

ssh-keygen -t ed25519 -a 100 -C "YOUR_EMAIL_ADDRESS" -f "$HOME/.ssh/id_ed25519"

Expected interactive result:

Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/your-user/.ssh/id_ed25519
Your public key has been saved in /home/your-user/.ssh/id_ed25519.pub

Ed25519 keys are strong, small, fast, and widely supported by current Git hosts. The -a 100 option raises the password-derivation rounds, so offline password guesses cost more. Key loading also takes slightly longer, though the delay is small on current hardware.

The files have separate jobs:

  • ~/.ssh/id_ed25519 is the private key. Never upload, email, commit, or display it.
  • ~/.ssh/id_ed25519.pub is the public key. Add this file to the Git host.

Show the public key for copying:

cat "$HOME/.ssh/id_ed25519.pub"

Expected format:

ssh-ed25519 AAAA…redacted… YOUR_EMAIL_ADDRESS

Open the Git host’s account settings and find its SSH keys page. Create an entry and paste the single public-key line. Keep the private file on your workstation. That sounds basic until a private key appears in a ticket attachment.

Check the fingerprint without showing private data:

ssh-keygen -lf "$HOME/.ssh/id_ed25519.pub"

Representative output:

256 SHA256:REDACTED YOUR_EMAIL_ADDRESS (ED25519)

Terminal listing id_ed25519 as private and id_ed25519.pub as public, with personal details and fingerprint redacted

Step 8: Configure Git Defaults

Replace the placeholders with the identity that should appear in commits:

git config --global user.name "YOUR_FULL_NAME"
git config --global user.email "YOUR_EMAIL_ADDRESS"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"
git config --global alias.st status
git config --global alias.br branch
git config --global alias.co checkout
git config --global alias.last "log -1 --stat"

Expected output:

Git config commands produce no output when successful.

code --wait keeps Git open until you close the editor tab used for a commit or merge. Without --wait, VS Code returns at once and Git assumes you’re done. The aliases save keystrokes without hiding Git’s actions.

Inspect the non-secret settings:

git config --global --list

Representative output:

user.name=YOUR_FULL_NAME
user.email=YOUR_EMAIL_ADDRESS
init.defaultbranch=main
core.editor=code –wait
alias.st=status
alias.br=branch
alias.co=checkout
alias.last=log -1 –stat

Sanitized global Git configuration showing identity placeholders, main default branch, VS Code editor, and simple aliases

Identity, the default branch, the editor, and general aliases usually belong in ~/.gitconfig. Put project identity, signing rules, merge behavior, or hooks in the repository:

cd /absolute/path/to/repository
git config user.email "PROJECT_EMAIL_ADDRESS"

Expected output:

No output indicates that the repository-local value was saved.

Local settings override global values for that project. Use them when personal and work commits need different addresses. Fixing hundreds of commits later is avoidable work.

Step 9: Choose SSH or HTTPS Remotes

Use SSH for regular work on trusted PCs that allow key-based access. HTTPS often works better through strict proxies, temporary systems, and managed credential services. Both protocols are secure when configured correctly.

Inspect a repository remote:

git remote -v

Representative SSH output:

origin git@GIT_HOST:YOUR_USERNAME/YOUR_REPOSITORY.git (fetch)
origin git@GIT_HOST:YOUR_USERNAME/YOUR_REPOSITORY.git (push)

Change it when required:

git remote set-url origin git@GIT_HOST:YOUR_USERNAME/YOUR_REPOSITORY.git

Expected output:

No output indicates success.

For HTTPS, use Git Credential Manager when your distribution or employer provides a supported package. It reads and writes credentials through a secure OS store. Check the installed helper with:

git config --global credential.helper

Possible output:

manager

On Linux desktops without Git Credential Manager, libsecret is safer than plain text storage. The cache helper keeps credentials in memory for a set time:

git config --global credential.helper "cache --timeout=3600"

Expected output:

No output indicates that credentials will be cached in memory for 3,600 seconds.

The memory cache suits short-lived systems, but you’ll sign in again after one hour or a reboot. Avoid credential.helper store on shared systems because it writes credentials to a plain text file. Never put a token in a remote URL. URLs leak into shell history, logs, and screenshots.

Step 10: Test Source Control in a Disposable Repository

Create a small local repository before using the setup for real work:

mkdir -p "$HOME/dev/vscode-test"
cd "$HOME/dev/vscode-test"
git init
printf '%s\n' '# VS Code test' > README.md
git add README.md
git commit -m "Initial commit"
code .

Representative output:

Initialized empty Git repository in /home/your-user/dev/vscode-test/.git/
[main (root-commit) …] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md

Edit README.md, save it, and open VS Code’s Source Control view. The changed file should appear without a remote. These six commands test Git identity, the default branch, commits, VS Code discovery, and the working tree.

VS Code Source Control view in a disposable repository showing one harmless changed README file and no private remote information

Step 11: Add Optional Terminal Improvements

Install tmux when you run long remote sessions:

sudo apt install -y tmux
tmux -V

Representative output:

tmux 3.x

On Fedora or a RHEL-family system, replace apt install with dnf install. Tmux keeps a shell alive when SSH drops. Its prefix keys take a few sessions to become muscle memory.

Bash history can keep timestamps and remove duplicates. Add these lines to ~/.bashrc only after checking for existing values:

HISTCONTROL=ignoreboth:erasedups
HISTSIZE=10000
HISTFILESIZE=20000
HISTTIMEFORMAT='%F %T '
shopt -s histappend

These settings keep 10,000 commands in the current shell and 20,000 in the history file. histappend appends history as terminals close. This lowers the risk that the last shell will overwrite earlier entries.

Don’t type secrets into shell commands. Better history helps recall; it doesn’t protect credentials.

A fast prompt such as Starship can show useful Git details, but it adds another program and config layer. Use the distribution package when one exists. Avoid piping an unchecked remote installer into a shell. I’d skip prompt changes until the plain setup has worked for a week.

Step 12: Handle Multiple Language Runtime Versions

Version managers let Node.js, Python, Ruby, and similar runtimes coexist by user or project. They’re useful when one project needs Node.js 20 and another needs Node.js 22.

A version manager owns project runtimes. The system package manager still owns build dependencies, containers, security fixes, and OS runtimes. Keep the OS-managed Python or Ruby install. Package tools and desktop parts may depend on it.

Choose one manager per language and commit the project’s version file. Keep downloaded runtimes in your user account. Several managers editing PATH cause failures that seem random until you inspect the shell startup files.

Step 13: Windows, macOS, and Web Setup

Windows

Download VS Code from the official download page. Choose x64 or Arm64 to match the CPU, then run the installer. Install Git from Git for Windows, then open PowerShell:

code --version
git --version

Representative output:

1.xx.x
git version 2.xx.x.windows.x

Windows desktop with VS Code open and PowerShell showing successful VS Code and Git version checks

Use Git Credential Manager on Windows. It works with Windows credential storage and usually comes with Git for Windows. Check both version commands before importing settings or extensions from another PC.

macOS

Download the Universal, Apple silicon, or Intel VS Code build from the official page. Move the app into Applications, open it, and follow the current command-line setup instructions.

Check Git from Terminal:

git --version
code --version

Representative output:

git version 2.xx.x
1.xx.x

macOS Applications view with Visual Studio Code installed and Terminal showing successful version checks

Use the macOS Keychain helper for HTTPS remotes when available:

git config --global credential.helper osxkeychain

Expected output:

No output indicates success.

The Keychain helper avoids plain text credential files. It can still prompt after account, token, or Keychain changes. That’s expected behavior, rather than a Git fault.

Web

Open vscode.dev in a current browser. It works well for small file edits and supported repository tasks. The browser sandbox limits terminals, local runtimes, debuggers, and native tools. Use it as a light editor instead of a full Linux development PC.

Browser window displaying vscode.dev with the editor workbench visible and no authenticated repository data

Step 14: Verify the Complete Environment

Run the full check:

code --version
git --version
gcc --version
make --version
git config --global --get init.defaultBranch
git config --global --get core.editor
test -f "$HOME/.ssh/id_ed25519.pub" && echo "SSH public key: present" || echo "SSH public key: not configured"
command -v tmux >/dev/null && echo "tmux: installed (optional)" || echo "tmux: not installed (optional)"

Representative output:

1.xx.x
git version 2.xx.x
gcc (…distribution build…) …
GNU Make 4.x
main
code –wait
SSH public key: present
tmux: installed (optional)

A missing SSH key or tmux install may be valid because both are optional. Missing output for Git’s branch or editor means those settings didn’t stick.

Final sanitized verification run showing successful application, Git configuration, SSH public-key, compiler, Make, and optional tmux checks with variable versions labeled

Configuration

SettingRecommended scopePractical default
Commit identityGlobal, unless a project differsPersonal or approved work identity
Initial branchGlobalmain
Git editorGlobalcode --wait
Credential helperGlobal or organization-managedOS-backed helper; memory cache on temporary Linux systems
Remote protocolPer repositorySSH for trusted workstations; HTTPS for proxy-heavy or temporary systems
ExtensionsPer user or profileInstall only those required by active projects
Runtime versionPer projectVersion file managed by the chosen runtime manager

Check the VS Code updates page before using one extension or feature across a fleet. A monthly editor release is manageable on one PC. Across 200 systems, it needs a test group.

Official VS Code updates page showing the current stable release number, date, and update notice

Safely Repeatable Debian or Ubuntu Setup Script

This script installs the shared package base and official VS Code repository. It skips existing Git identity values. It never creates, reads, or overwrites SSH keys. Personal identity and access stay outside the shared script.

Save it as setup-dev-workstation.sh, review it, and run it as your normal user. It uses sudo only for system package changes. Read a script before giving it root access, even if you wrote it five minutes ago.

#!/usr/bin/env bash
set -euo pipefail

if ! command -v apt-get >/dev/null 2>&1; then
    echo "This script supports Debian and Ubuntu only."
    exit 1
fi

sudo install -d -m 0755 /etc/apt/keyrings
sudo apt-get update
sudo apt-get install -y git build-essential ca-certificates gnupg wget unzip zip tmux

if [ ! -f /etc/apt/keyrings/packages.microsoft.gpg ]; then
    wget -qO /tmp/packages.microsoft.asc https://packages.microsoft.com/keys/microsoft.asc
    gpg --dearmor < /tmp/packages.microsoft.asc | sudo tee /etc/apt/keyrings/packages.microsoft.gpg >/dev/null
    sudo chmod 0644 /etc/apt/keyrings/packages.microsoft.gpg
fi

if [ ! -f /etc/apt/sources.list.d/vscode.sources ]; then
    printf '%s\n' \
        'Types: deb' \
        'URIs: https://packages.microsoft.com/repos/code' \
        'Suites: stable' \
        'Components: main' \
        'Architectures: amd64 arm64 armhf' \
        'Signed-By: /etc/apt/keyrings/packages.microsoft.gpg' \
        | sudo tee /etc/apt/sources.list.d/vscode.sources >/dev/null
fi

sudo apt-get update
sudo apt-get install -y code

git config --global init.defaultBranch main
git config --global core.editor "code --wait"
git config --global alias.st status
git config --global alias.br branch
git config --global alias.co checkout
git config --global alias.last "log -1 --stat"

if ! git config --global --get user.name >/dev/null; then
    echo "Git user.name is unset. Configure it manually."
fi

if ! git config --global --get user.email >/dev/null; then
    echo "Git user.email is unset. Configure it manually."
fi

if [ -e "$HOME/.ssh/id_ed25519" ]; then
    echo "Existing Ed25519 private key detected; leaving it unchanged."
else
    echo "No default Ed25519 key found. Create one manually if required."
fi

echo "Setup complete."
code --version
git --version

Run it:

chmod 0755 ./setup-dev-workstation.sh
./setup-dev-workstation.sh

Representative output:

Git user.name is unset. Configure it manually.
Git user.email is unset. Configure it manually.
No default Ed25519 key found. Create one manually if required.
Setup complete.
1.xx.x
git version 2.xx.x

The script is safe to run again. Package installs are idempotent, repository files are made only when absent, and Git commands change known keys. Its weak spot is drift: it won’t replace an existing repository file when your approved version changes.

For a fleet, move this logic into configuration-management tasks. You’ll get central control of repository content, package state, and change reports. The first conversion takes longer than copying a shell script. By the tenth workstation, it usually pays for itself.

Tips and Troubleshooting

code: command not found

Cause: The launcher is missing from PATH, or the terminal was open before installation.

Fix: Close and reopen the terminal, then check:

command -v code

Expected output:

/usr/bin/code

If the command still returns nothing, check whether VS Code opens from the desktop. Then follow the current official command-line setup steps. Don’t add random directories to PATH before finding the installed launcher.

VS Code Cannot Find Git

Cause: Git is missing, or VS Code started before Git was installed.

Fix:

git --version

Representative output:

git version 2.xx.x

Install Git through the OS package manager if no version appears, then restart VS Code. The editor checks for Git at startup and may keep a failed result for that session.

APT or RPM Reports a Signature Error

Cause: The signing key or repository definition is missing, old, or malformed.

Fix: Compare the local repository definition with Microsoft’s current Linux documentation. Then import the official key again. Keep signature checks on. A bypass may install the package, but it removes proof that the expected signer supplied the repository data.

SSH Authentication Fails

Cause: You added the wrong public key, SSH chose another private key, or file permissions are too open.

Fix:

chmod 0700 "$HOME/.ssh"
chmod 0600 "$HOME/.ssh/id_ed25519"
chmod 0644 "$HOME/.ssh/id_ed25519.pub"
ssh-keygen -lf "$HOME/.ssh/id_ed25519.pub"

Representative output:

256 SHA256:REDACTED YOUR_EMAIL_ADDRESS (ED25519)

Confirm that the host account has the contents of the .pub file. Keep the private file local. If you have several keys, inspect SSH’s verbose output and set the intended identity for that host.

Git Repeatedly Requests HTTPS Credentials

Cause: No credential helper is set, or the saved credential expired.

Fix:

git config --show-origin --get credential.helper

Possible output:

file:/home/your-user/.gitconfig cache –timeout=3600

Use an OS-backed helper where possible. Sign in again with the Git host’s required token or browser flow. Keep credentials out of the remote URL. With this memory cache, another prompt after 3,600 seconds is normal.

A Runtime Manager Selects the Wrong Version

Cause: Its shell setup didn’t load, or the project has no version file.

Fix: Check the manager’s status and add a project version file with its documented command. Then open a new terminal. Keep the OS runtime unless you’ve checked every package that depends on it. Check PATH order too; the first matching program wins, regardless of your plans.

Wrapping Up

You now have a small base for editing, building, and tracking local projects without putting secrets in scripts. I prefer the official package repository, SSH on long-lived PCs, and a short extension list. It’s mildly boring, which is useful when you return to the machine a year later.

StepActionApplies To
1–5Select packages, install VS Code and Git, verify versionsLinux
6–10Limit extensions, configure SSH and Git, test a repositoryAll desktop systems
11–12Add terminal tools and runtime managers only when neededLinux and macOS
13Use platform-specific installation pathsWindows, macOS, web
14Run the final verification checksLinux