Introduction: The Problem Every Cross-Platform Developer Knows
Raise your hand if you've never found yourself in this situation: you work on a project on your Mac at the office, come home, open your Windows laptop, do a git pull
and... boom! Conflicts everywhere. Files that appear modified even though you've never touched them. Configurations that don't work. Paths that don't exist. Line endings gone crazy.
If you recognized yourself in this description, this article is for you. After months of work on my Smart Conda Terminal project β a VSCode extension that needs to work perfectly on both macOS and Windows β I learned (often the hard way) how to manage a truly multi-platform Git workflow.
In this article, I'll share everything I've learned: from initial configuration to best practices, from tricks to avoid conflicts to solutions for the most common problems. Not a theoretical guide, but a practical manual born from field experience.
Why is Multi-Platform Development So Complicated?
Before diving in, let's understand why Git makes our lives difficult when we work on different operating systems:
1. Paths are Different
// macOS
"python.defaultInterpreterPath": "/Users/tony/miniconda3/envs/sct-dev/bin/python"
// Windows
"python.defaultInterpreterPath": "C:\\Users\\Tony\\miniconda3\\envs\\sct-dev\\python.exe"
2. Line Endings are Different
- Unix/Mac use
LF
(Line Feed:\n
) - Windows uses
CRLF
(Carriage Return + Line Feed:\r\n
)
Result? Git sees every single file as modified, even if you haven't changed a comma.
3. Shell Scripts Don't Work on Windows
Bash scripts that run perfectly on Mac? On Windows you need PowerShell or WSL.
4. VSCode Configurations are Platform-Specific
Terminal profiles, conda paths, interpreter settings... all different.
The Strategy: One Repository, Two Platforms, Zero Conflicts
The solution I developed is based on three principles:
- Shared configurations for everything that is platform-agnostic
- Local files ignored by Git for platform-specific paths and settings
- Intelligent automation that detects the platform
Let's see how to implement it step by step.
Initial Setup: Preparing the Ground
1. Cross-Platform Git Configuration
First of all, let's configure Git correctly on both platforms:
# Name and email (same on both)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Line endings - CRUCIAL to avoid conflicts
# On Mac/Linux:
git config --global core.autocrlf input
# On Windows:
git config --global core.autocrlf true
# Editor and other useful settings
git config --global core.editor "code --wait"
git config --global push.default simple
git config --global color.ui auto
2. The .gitattributes File: The Line Endings Savior
Create this file in the project root and commit it:
text
# .gitattributes
* text=auto eol=lf
*.sh text eol=lf
*.js text eol=lf
*.json text eol=lf
*.md text eol=lf
*.py text eol=lf
# Binary files
*.png binary
*.jpg binary
*.ico binary
This file tells Git: "Whatever the operating system, always use LF internally, and let the local system decide how to save files."
3. The Intelligent .gitignore
A well-crafted .gitignore
is essential. Here's mine:
# Dependencies
node_modules/
.node_modules/
npm-debug.log*
package-lock.json
# Build outputs
out/
dist/
*.vsix
# OS files - Here's the trick!
.DS_Store # macOS
Thumbs.db # Windows
*.swp
*.swo
# IDE - Keep only shared configs
.vscode/settings.json.local
.vscode/*.local.json
# IMPORTANT: DO NOT ignore these
!.vscode/settings.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/tasks.json
# Logs and cache
*.log
.npm
.cache/
# Environment
.env
.env.local
# Conda specific
.smart-conda-terminal/
conda-meta/
The key is in the IDE section: we keep shared configurations (with !
) but ignore local ones.
Project Structure: What to Commit and What Not
project/
βββ .vscode/
β βββ settings.json β COMMITTED (general settings)
β βββ launch.json β COMMITTED (debug config)
β βββ extensions.json β COMMITTED (recommended extensions)
β βββ tasks.json β COMMITTED (common tasks)
βββ .gitattributes β COMMITTED
βββ .gitignore β COMMITTED
βββ package.json
βββ src/
βββ project.code-workspace β OPTIONAL, see below
The Secret: Two-Level Configurations
Level 1: Shared Settings (.vscode/settings.json
- committed)
{
"editor.formatOnSave": true,
"editor.insertSpaces": true,
"editor.tabSize": 2,
"files.trimTrailingWhitespace": true,
"files.exclude": {
"out": false,
"dist": true,
"node_modules": true,
"**/.DS_Store": true,
"**/Thumbs.db": true
}
}
Level 2: Workspace with Environment Variables (optional)
Instead of hard-coded paths, use variables:
{
"folders": [{"path": "."}],
"settings": {
"python.defaultInterpreterPath": "${env:CONDA_PREFIX}/bin/python",
"python.terminal.activateEnvironment": true
}
}
On Windows, ${env:CONDA_PREFIX}
will automatically resolve to the correct path.
Daily Workflow: The Four Commandments
1. Before Starting: PULL
cd your-project
git pull origin main
Simple but fundamental. Avoids 90% of conflicts.
2. During Work: Small and Frequent Commits
β Bad:
# After 3 days...
git commit -m "various changes"
β
Good:
git commit -m "feat: Add Windows terminal profile support"
git commit -m "fix: Python path resolution on Windows"
git commit -m "docs: Update cross-platform setup guide"
3. Before Finishing: Verify
# What did I modify?
git status
# See the differences in detail
git diff
# Everything ok? Add
git add .
# Commit with clear message
git commit -m "feat: Implement auto-platform detection"
4. When You Finish: PUSH
git push origin main
Conflict Management: Real Situations and How to Solve Them
Scenario 1: "Your local changes would be overwritten"
The problem: You have uncommitted local changes and do git pull
.
The solution (stash method):
# 1. Set aside your changes
git stash
# 2. Download updates
git pull origin main
# 3. Reapply your changes
git stash pop
# 4. If there are conflicts, resolve them manually
Scenario 2: Merge Conflicts
When Git can't merge automatically, you'll see this:
<<<<<<< HEAD
const version = "1.0.0"; // Your version
=======
const version = "2.0.0"; // Remote version
>>>>>>> origin/main
How I solve it:
- Open the file in VSCode
- Decide which version to keep (or merge both)
- Remove the markers
<<<<<<<
,=======
,>>>>>>>
- Save and commit:
git add conflicted-file.js
git commit -m "resolve: Merge conflict in version number"
git push origin main
Scenario 3: Crazy Line Endings
Symptoms: Git shows modified files even though you haven't touched them.
Diagnosis:
git diff file.js
# If you only see "^M" or invisible differences, it's line endings
Cure:
# 1. Add .gitattributes (if not already there)
# 2. Normalize all files
git add --renormalize .
git commit -m "fix: Normalize line endings"
git push origin main
Automation Scripts: Platform Detection
For scripts that need to work everywhere:
#!/bin/bash
# Detect platform
detect_platform() {
case "$(uname -s)" in
Darwin*) echo "mac" ;;
Linux*) echo "linux" ;;
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
*) echo "unknown" ;;
esac
}
# Get correct conda path
get_conda_path() {
PLATFORM=$(detect_platform)
case $PLATFORM in
mac|linux)
echo "$HOME/miniconda3"
;;
windows)
echo "$USERPROFILE/miniconda3"
;;
esac
}
# Use the function
CONDA_PATH=$(get_conda_path)
echo "Conda path: $CONDA_PATH"
Best Practices: The Golden Rules
1. Meaningful Commit Messages
I use the Conventional Commits format:
feat: Add new feature
fix: Fix bug
docs: Update documentation
style: Code formatting
refactor: Code restructuring
test: Add tests
chore: General maintenance
2. Pull Requests for Important Changes
# Create a branch for the feature
git checkout -b feature/new-feature
# Work on the branch
git add .
git commit -m "feat: Implement new feature"
# Push the branch
git push origin feature/new-feature
# On GitHub: create Pull Request
# After review: merge to main
3. Don't Commit Generated Files
Never ever commit:
node_modules/
- Build outputs (
dist/
,out/
) - Log files
- Local configurations
- Credentials
4. Test on Both Platforms Before Pushing
Personal checklist:
- Does the code work on Mac?
- Does the code work on Windows?
- Do tests pass on both?
- Is the documentation updated?
- Is the commit message clear?
Troubleshooting: The Most Common Problems
"Permission denied (publickey)"
Problem: Git can't connect to GitHub.
Solution:
# Generate SSH key
ssh-keygen -t ed25519 -C "your.email@example.com"
# Copy the key
# Mac:
pbcopy < ~/.ssh/id_ed25519.pub
# Windows:
cat ~/.ssh/id_ed25519.pub | clip
# Add it on GitHub: Settings β SSH Keys
# Test
ssh -T git@github.com
"Repository too large"
Problem: The repository has become huge.
Solution:
# Remove untracked files
git clean -fd
# Compress
git gc --aggressive --prune=now
"Detached HEAD state"
Problem: You checked out a specific commit.
Solution:
# Return to main branch
git checkout main
Tools That Simplify Life
1. GitHub Desktop
Simple and intuitive GUI, perfect for beginners.
2. GitKraken
Advanced graphical visualization of branches and history.
3. VSCode Built-in Git
My favorite. Perfect integration with the editor.
4. Git Aliases
Shortcuts for frequent commands:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
Now I can do git st
instead of git status
.
Conclusion: The Perfect Workflow Exists
After months of experimentation, my daily workflow has been reduced to this:
Morning (start work):
git pull origin main
Evening (end work):
git status
git add .
git commit -m "feat: Clear description"
git push origin main
In case of problems:
git stash
git pull origin main
git stash pop
Simple, right? The key is in the correct initial configuration. Once everything is set up properly, Git becomes an ally, not an enemy.
Final Checklist for Your Project
-
.gitattributes
configured for line endings - Complete and tested
.gitignore
- Multi-platform Git configuration (
core.autocrlf
) - Two-level VSCode settings (shared + local)
- Scripts with automatic platform detection
- SSH keys configured on both platforms
- Workflow documented for the team
- Tests on both operating systems
Useful Resources
- Pro Git Book - The Git bible, free
- Git Cheat Sheet - Essential commands
- Conventional Commits - Standard for commit messages
- GitHub Flow - Workflow with branches
Do you have questions or suggestions? Write to me in the comments! This workflow is constantly evolving and I'm always curious to discover how other developers handle the same problem.
If the article was useful to you, leave a clap π and share it with other developers who work on multiple platforms!
Final note: All the code and configurations shown in this article are taken from my real project Smart Conda Terminal, a VSCode extension for intelligent management of Conda environments. The repository is public and can serve as a practical example of what's described here.
Tags: #GitHub #VSCode #Python #NodeJS #DeveloperTools #Conda #ExtensionDevelopment #JavaScript #Productivity #OpenSource
Top comments (0)