CODE FARM
Galaxy background

"Do not go where the path may lead, go instead where there is no path and leave a trail."

- Ralph Waldo Emerson

Git Bash, Cygwin, and WSL

1. Git Bash on Windows

To enhance the command-line experience on Windows, Git Bash can be integrated directly into Windows Terminal by creating a dedicated profile that correctly launches the Bash shell and ensures full support for Unicode characters.

1.1. Windows Terminal

A new profile for Git Bash can be added within the Windows Terminal settings, which are accessible via the Ctrl + , shortcut, or navigate to the "Add a new profile" section and select "New empty profile".

  • Name: Git Bash

  • Command Line: C:\Program Files\Git\bin\bash.exe -i -l

  • Starting Directory: %USERPROFILE%

  • Icon: C:\Program Files\Git\git-bash.exe

The -i -l (or --interactive --login) flags in the command line instruct the shell to start as an interactive login shell, which properly loads configuration files and enables features like correct handling of non-ASCII text.

For example, without these flags, Unicode filenames may appear garbled:

$ ls -l /tmp/hello/
total 0
-rw-r--r-- 1 ousia 197121 0 Aug 29 16:46 '''□□'''$'''\226''''''□'''$'''\225\214'''

With the flags, the same command correctly displays the filename:

$ ls -l /tmp/hello/
total 0
-rw-r--r-- 1 ousia 197121 0 Aug 29 16:46 世界

1.2. Unicode Filenames

By default, Git may escape non-ASCII characters in filenames when using commands like git status, which can make it difficult to read the output.

$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        "Hello \344\270\226\347\225\214.txt"

$ git -c core.quotePath=false status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        Hello 世界.txt

To disable this behavior and display filenames literally, the core.quotePath configuration option should be set to false.

$ git config core.quotePath false # git config --global core.quotePath false
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        Hello 世界.txt

1.3. Bell

The Bash shell may produce an audible or visual bell for certain events, such as when a tab-completion search finds no results, controlled by the Readline library, which can be disabled by creating or editing the .inputrc file located in the user’s home directory (%USERPROFILE% or ~).

# ~/.inputrc

# Disable bell
set bell-style none

1.4. SSH

Managing SSH keys and configurations is a common task when working with Git repositories on multiple platforms or with multiple accounts.

The ssh-keygen command is used for generating a new SSH key pair: a private key that stays on the local machine and a public key to be uploaded to services like GitHub. It is best practice to use the modern and secure Ed25519 algorithm.

# The -t flag specifies the key type, and -f specifies the output filename
ssh-keygen -t ed25519 -f ~/.ssh/<your-private-key-filename>

To ensure Git uses the correct SSH key for the right repository, the SSH client can be configured to present a specific key based on the host at ~/.ssh/config.

# ~/.ssh/config

Match host github.com (1)
  IdentitiesOnly yes (2)
  IdentityFile ~/.ssh/<your-private-key-filename> (3)
1 Match host github.com: Applies the following settings only when connecting to github.com.
2 IdentitiesOnly yes: A security measure that prevents the SSH client from trying every available key. It will only use the key specified by IdentityFile.
3 IdentityFile: Specifies the exact path to the private key to be used for this host.

When managing multiple accounts for the same host (e.g., a personal and a work account on GitHub), it is necessary to use host aliases in the SSH configuration to allow for differentiating between connections to the same real host.

# Example for a personal GitHub account
Host github.com-personal (1)
  HostName github.com (2)
  User git
  IdentityFile ~/.ssh/id_ed25519_personal
  IdentitiesOnly yes

# Example for a work GitHub account
Host github.com-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes
1 Host github.com-personal: a named arbitrarily custom alias.
2 HostName github.com: specifies the real server address that SSH will connect to.

When cloning a repository, the real hostname (github.com) in the clone URL must be replaced with the appropriate alias.

The first time a connection is made to a new host, its public key is stored in the ~/.ssh/known_hosts file to prevent man-in-the-middle attacks. If a server’s host key changes (e.g., because the server was rebuilt), connection attempts will fail with a security warning.

To remove the old host key from the known_hosts file, the ssh-keygen -R command is used.

# Remove all keys belonging to github.com from the known_hosts file
ssh-keygen -R github.com

After removing the old key, the new key will be automatically added on the next connection attempt.

1.5. Proxy

In environments behind a corporate firewall or when using a SOCKS proxy, Git operations (like clone, fetch, push) may require proxy configuration. Git can be configured to use HTTP/HTTPS or SOCKS5 proxies.

Git configurations can be set at three levels:

  • Local (per repository): Applies only to the current Git repository (git config).

  • Global (per user): Applies to all repositories for the current user (git config --global).

  • System (all users): Applies to all repositories for all users on the system (git config --system).

To configure Git to use a standard HTTP or HTTPS proxy, the http.proxy and https.proxy configurations can be set:

# For HTTP traffic
git config --global http.proxy http://proxy.example.com:8080

# For HTTPS traffic
git config --global https://proxy.example.com:8080

For SOCKS5 proxies, the configuration uses the socks5:// protocol prefix:

# For HTTP traffic over SOCKS5
git config --global http.proxy socks5://127.0.0.1:1080

# For HTTPS traffic over SOCKS5
git config --global https.proxy socks5://127.0.0.1:1080

For more advanced scenarios, or when a SOCKS proxy needs to be used for SSH connections, netcat (or nc) can be configured as a proxy command, typically in the ~/.ssh/config file for, but can also be used with http.proxy for HTTP/S traffic if netcat is set up to tunnel.

# Example for SSH over SOCKS5 using netcat (in ~/.ssh/config)
Host github.com
  ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p

2. Cygwin on Windows

Cygwin provides a large collection of GNU and Open Source tools which provide functionality similar to a Linux distribution on Windows. It offers a powerful command-line environment with access to many standard Unix utilities.

The entire Cygwin environment is managed through a single executable, setup-x86_64.exe, which handles the initial installation and is used subsequently for updating the core system or installing, updating, and removing individual packages.

By default, the setup program attempts to run with administrative privileges to perform a system-wide installation. For a portable or user-specific installation that does not require administrator rights, the --no-admin flag can be used:

./setup-x86_64.exe --no-admin

To manage packages after the initial setup, the same setup-x86_64.exe file is run again. After proceeding to the "Select Packages" screen, the interface provides several options. Packages are grouped by category, and a search bar is available to find specific tools. To change a package’s status, click on the "New" column next to its name, which cycles through the following states:

  • To install a package: Select a specific version number (instead of "Skip").

  • To update a package: Select the latest version number. The setup tool will often highlight upgradable packages automatically.

  • To remove a package: Cycle through the options until "Uninstall" is displayed.

Once all desired changes have been made, proceeding with the installation will apply the selected actions.

A key advantage of installing Cygwin is the ability to use its powerful command-line utilities from other shells. To make tools like grep, sed, and awk available within Git Bash, PowerShell, or the standard Command Prompt, the bin subdirectory of the Cygwin installation must be added to the Windows PATH environment variable. For a standard installation, this directory is typically located at C:\cygwin64\bin.

3. WSL

The Windows Subsystem for Linux (WSL) allows for running native Linux distributions directly on Windows, providing a tightly integrated and high-performance environment for development and system administration.

3.1. Installation

To install WSL along with its default distribution (Ubuntu), the following command is used:

wsl --install

To install only the required WSL components without installing a Linux distribution, the --no-distribution flag can be used. This is useful for preparing a system where distributions will be imported manually later.

wsl --install --no-distribution

A list of available Linux distributions can be viewed with wsl --list --online. A specific distribution can then be installed using the -d flag as wsl --install -d Debian.

Here are some of the most common commands for managing distributions:

  • List installed distributions: shows the state and WSL version of all installed distributions.

    wsl --list --verbose
  • Shutdown all running distributions: immediately terminates all running distributions and the WSL 2 virtual machine.

    wsl --shutdown
  • Export a distribution: creates a .tar archive of a distribution, which is useful for backups or for sharing a configured environment.

    wsl --export <DistroName> <FileName.tar>
  • Import a distribution: imports a .tar archive as a new distribution.

    wsl --import <NewDistroName> <InstallLocation> <FileName.tar>
  • Unregister a distribution: deletes a distribution, including its entire file system.

    wsl --unregister <DistroName>
  • Get primary IP address: retrieves the primary IP address of the WSL distribution.

    wsl [-d <DistroName>] hostname -i
  • Get all IP addresses: retrieves all IP addresses assigned to the WSL distribution.

    wsl [-d <DistroName>] hostname -I
  • Get Windows host IP from within WSL: from inside a WSL2 Linux distribution, retrieves the Windows host’s IP address by querying the default gateway.

    ip route show | grep -i default | awk '{ print $3}'

3.2. Networking

WSL’s networking architecture dictates how distributions connect to the internet, Windows host, and local network.

  • By default, WSL uses a Network Address Translation (NAT) based architecture, where the Linux environment receives an IP address on a separate, private virtual network.

    • Windows to Linux: Windows can communicate with Linux applications via localhost. For example, a web server running in Linux on port 8000 is accessible from Windows at http://localhost:8000.

    • Linux to Windows: Linux must use the Windows host’s IP address to communicate with Windows services, whereas the localhost address inside Linux refers only to the Linux environment itself, not the Windows host.

    • Limitations: This virtualized networking can create challenges for some VPN configurations and does not provide direct access to WSL services from other devices on the local network.

  • Mirrored mode: mirrors Windows network interfaces into Linux (i.e., share the same network stack), enabled via networkingMode=mirrored in .wslconfig.

    • IPv6 support: IPv6 connectivity within the Linux virtual network

    • Localhost forwarding: Windows and Linux can communicate with each other via 127.0.0.1 (IPv6 ::1 not supported)

    • VPN compatibility: WSL can access resources through Windows VPN connections

    • Multicast support: Multicast network traffic for service discovery protocols

    • LAN accessibility: WSL services are directly reachable from other devices on the local network

3.3. Configuration

  • The .wslconfig file in the Windows user profile directory (%USERPROFILE%) configures global WSL 2 settings for all distributions, primarily controlling hardware resources and networking.

    # Settings apply across all WSL 2 distros
    [wsl2]
    
    # Limit VM memory to 10GB
    memory=10GB
    
    # Disable the swap file for the WSL VM
    swap=0
    
    # Use the mirrored networking mode for simpler network access
    networkingMode=mirrored
    
    # Automatically configure proxy settings from Windows
    autoProxy=true
    Changes to .wslconfig only take effect after running wsl --shutdown.
  • The /etc/wsl.conf file inside each distribution configures distribution-specific settings for boot behavior, networking, and user settings.

    # /etc/wsl.conf
    
    [boot]
    # Enable systemd to run services like Docker
    systemd=true
    
    [network]
    # Set the hostname for this distribution
    hostname=<your-hostname>
    
    [user]
    # Set the default user to log in with
    default=<your-username>
    After modifying /etc/wsl.conf, the specific distribution must be terminated (e.g., wsl --terminate <DistroName>) and restarted for the changes to apply.

3.4. Git

Specific configurations for Git within WSL enhance interoperability, particularly for repositories accessed from both Windows and the Linux environment, such as line ending and credential management.

3.4.1. Line Endings

The difference in default line endings between Windows (CRLF) and Linux (LF) can cause Git to report files as modified, which is addressed by configuring line ending handling, for example, with a .gitattributes file.

A .gitattributes file in the root of the project with the following content instructs Git to automatically manage consistent line endings:

* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf

An .editorconfig file can define the expected line endings for each file type to align editor behavior with these Git settings:

root = true

[*]
end_of_line = lf
insert_final_newline = true

[*.{cmd,bat}]
end_of_line = crlf

3.4.2. Shared Credentials

Use one credential helper per URL scope. Windows and WSL share credentials only when both use the same helper or credential store.

The current ~/.gitconfig represents the credential configuration with URL-scoped sections:

[credential "https://github.com"]
    helper = (1)
    helper = !/usr/bin/gh auth git-credential (2)

[credential "https://github.com/<organization>"]
    helper =
    helper = !/home/<user>/.local/bin/git-credential-gh-user <account-name>

[credential "https://gist.github.com"]
    helper =
    helper = !/usr/bin/gh auth git-credential

[credential "https://dev.azure.com"]
    useHttpPath = true
    helper = /mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe
1 Clears inherited credential helpers.
2 Invokes the GitHub CLI credential helper.

These URL-scoped entries authenticate GitHub and Gist through gh and delegate the organization-specific GitHub URL scope to git-credential-gh-user; they do not use the Windows credential store.

The https://dev.azure.com entry uses Git Credential Manager (GCM) from WSL. Install Git for Windows with GCM enabled and replace the executable path when necessary. useHttpPath = true keeps credentials separate for different Azure DevOps paths. Do not configure the obsolete wincred helper.

To use GCM for GitHub instead, replace the relevant gh helper under the corresponding [credential] section. Do not retain overlapping helpers unless their precedence is intentional.

Inspect the effective credential configuration without displaying stored tokens:

git config --global --get-regexp '^credential'