Blog Logo

14-Oct-2025 ~ 5 min read

Dotfiles Backup and Restore Script for GitHub (without links and without touching original files)


If you want to keep your dotfiles safe and easily accessible across machines, using GitHub is a great option. This guide will show you how to backup and restore your dotfiles (including directories) without using symlinks. All files and directories are copied directly to and from your GitHub repository based on a JSON configuration file.

Steps to Setup and Use Dotfiles Backup/Restore

  1. Create a GitHub Repository for Dotfiles

    • First, create a new repository on GitHub (e.g., dotfiles).
    • Clone this repository to your local machine:
git clone https://github.com/yourusername/dotfiles.git ~/dotfiles
cd ~/dotfiles
  1. Create the dotfiles.json Configuration File

    • This file will specify which files and directories you want to back up and restore.

    • Each entry will include:

      • source: The file or directory path to back up from.
      • destination: The path where it should be stored in your GitHub repository.

    Example dotfiles.json:

{
  "dotfiles": [
    {
      "source": "/Users/atd/.zshrc",
      "destination": "zshrc",
      "type": "file"
    }
  ]
}
  1. Create the Backup Script: backup.sh

    This script will read the dotfiles.json file, and back up the specified files and directories to your GitHub repository.

    backup.sh

#!/bin/bash

# Load the JSON file
BASE_DIR="$HOME/wk/dotfiles"
CONFIG_FILE="$BASE_DIR/dotfiles.json"
FILES_DIR="$BASE_DIR/backup_files"

echo "Backing up files to $FILES_DIR"
echo "Using config file $CONFIG_FILE"
echo "Using base dir $BASE_DIR"
mkdir -p "$FILES_DIR"

# Check if the repository exists
if [[ ! -d "$BASE_DIR" ]]; then
  echo "Dotfiles repository not found! Please clone your repository first."
  exit 1
fi

# Read the JSON and back up each file or folder
jq -c '.dotfiles[]' "$CONFIG_FILE" | while IFS= read -r item; do
  echo "Processing item: $item"

  # Extract the values from the JSON object
  source=$(echo "$item" | jq -r '.source')
  destination=$(echo "$item" | jq -r '.destination')
  type=$(echo "$item" | jq -r '.type')

  # Check if the source exists
  if [[ ! -e "$source" ]]; then
    echo "⚠️ Source $source not found. Skipping."
    continue
  fi

  # Handle based on type (file or dir)
  if [[ "$type" == "dir" ]]; then
    # If it's a directory, copy all files inside it
    dest_dir="$FILES_DIR/$destination"
    mkdir -p "$dest_dir"
    rsync -av --exclude='.git/' "$source/" "$dest_dir/"
    echo "✅ Backed up directory $source to $FILES_DIR/$destination"
  elif [[ "$type" == "file" ]]; then
    # If it's a file, ensure the directory for the destination exists, then copy the file
    dest_dir=$(dirname "$FILES_DIR/$destination")
    mkdir -p "$dest_dir"
    cp "$source" "$FILES_DIR/$destination"
    echo "✅ Backed up file $source to $FILES_DIR/$destination"
  fi
done
  1. Makefile
backup:
	./backup.sh

restore:
	./restore.sh

push:
	./push.sh
**How It Works:**

-   Reads the `dotfiles.json` file using `jq` to extract `source` and `destination`.

-   Copies files and directories using `rsync` (for directories) and `cp` (for individual files).

-   Pushes the changes to GitHub after backing up the files.

5. Create the Push Script: push.sh

#!/bin/bash
BASE_DIR="$HOME/wk/dotfiles"

# Commit and push the changes to GitHub
git -C "$BASE_DIR" add .
git -C "$BASE_DIR" commit -m "Backup dotfiles $(date)"
git -C "$BASE_DIR" push origin main
  1. Create the Restore Script: restore.sh

    This script will restore the backed-up dotfiles from your GitHub repository to the original paths on your system.

    restore.sh

#!/bin/bash

# Load the JSON file
BASE_DIR="$HOME/wk/dotfiles"
CONFIG_FILE="$BASE_DIR/dotfiles.json"
FILES_DIR="$BASE_DIR/backup_files"

# Check if the repository exists
if [[ ! -d "$BASE_DIR" ]]; then
  echo "Dotfiles repository not found! Please clone your repository first."
  exit 1
fi

# Pull the latest changes from GitHub
git -C "$BASE_DIR" pull origin main

# Read the JSON and restore each file or folder
jq -c '.dotfiles[]' "$CONFIG_FILE" | while IFS= read -r item; do
  source="$FILES_DIR/$(echo "$item" | jq -r '.destination')"
  destination=$(echo "$item" | jq -r '.source')
  type=$(echo "$item" | jq -r '.type')

  # Check if the source exists in the repository
  if [[ ! -e "$source" ]]; then
    echo "Source $source not found in repository. Skipping."
    continue
  fi

  # Handle based on type (file or dir)
  if [[ "$type" == "dir" ]]; then
    # If it's a directory, copy all files back
    rsync -av "$source/" "$destination/"
    echo "Restored directory $source to $destination"
  elif [[ "$type" == "file" ]]; then
    # If it's a file, just copy it directly
    cp "$source" "$destination"
    echo "Restored file $source to $destination"
  fi
done
**How It Works:**

-   Pulls the latest changes from GitHub.

-   Uses `rsync` to restore directories and `cp` to restore individual files to the correct locations.

5. Final Steps: Running the Backup and Restore

- **Backup Your Dotfiles:**
  Run the `backup.sh` script to back up your dotfiles to the GitHub repository:
make backup
make push
-   **Restore Your Dotfiles:**
    If you need to restore your dotfiles to a fresh machine or after changes, run the `restore.sh` script:
make restore

Conclusion:

This simple approach to backing up and restoring dotfiles allows you to keep your files in sync across different machines without worrying about symlinks. By using GitHub, you can easily manage your dotfiles, whether you’re working on a fresh setup or a new machine.

  • No Symlinks Needed: The files are copied directly to/from the repository.
  • Simple to Set Up: Just clone your repository, set up the dotfiles.json file, and you’re good to go!
  • Supports Both Files and Directories: The script handles files and entire directories, even those with nested files.

This setup is great for anyone who wants a clean, simple, and effective way to manage dotfiles. Happy coding!


Files Recap:

  1. backup.sh – Backs up your dotfiles to GitHub.
  2. restore.sh – Restores dotfiles from GitHub to your machine.
  3. dotfiles.json – Configuration file specifying which files and directories to back up/restore.

You can copy these scripts into your dotfiles directory, configure dotfiles.json, and use them on any machine to quickly back up or restore your essential dotfiles.