⚙️

Git

13 notes  •  DevOps & CI/CD

Add an Existing Project to GitHub

Push a local project directory to a new GitHub repository using SSH or HTTPS.

Step 1 – Create a new repository on GitHub

On GitHub, click New repository. Do not initialise it with a README, .gitignore, or licence — these will conflict when you push.

Step 2 – Initialise Git in your local project

cd /path/to/your/project
git init
git add .
git commit -m "Initial commit"

Step 3 – Connect to the remote and push

# Using SSH (recommended)
git remote add origin git@github.com:USERNAME/REPO.git

# Using HTTPS
git remote add origin https://github.com/USERNAME/REPO.git

git branch -M main
git push -u origin main

Verify

git remote -v

Git Pre-commit Hook with Bash

A pre-commit hook runs automatically before each commit. Use it to enforce code formatting, run tests, or compile assets so developers can't accidentally skip the step.

Create the hook

nano .git/hooks/pre-commit

Add the following example (adjust for your project's build command):

#!/bin/bash
echo "Running pre-commit checks..."

# Example: run a linter
npm run lint
if [ $? -ne 0 ]; then
    echo "Linting failed. Commit aborted."
    exit 1
fi

# Example: run tests
npm test
if [ $? -ne 0 ]; then
    echo "Tests failed. Commit aborted."
    exit 1
fi

echo "All checks passed."
exit 0
chmod +x .git/hooks/pre-commit

Share hooks with the team

Git hooks in .git/hooks/ are not tracked by Git. To share them, store scripts in a hooks/ folder in the repo and configure Git to use it:

git config core.hooksPath hooks/

Or use Husky for a more robust cross-platform solution.

Change the Git Remote URL

Use git remote set-url to update the URL of an existing remote (typically origin) when moving repositories or switching between HTTPS and SSH.

Switch to SSH

git remote set-url origin git@github.com:USERNAME/REPO.git

Switch to HTTPS

git remote set-url origin https://github.com/USERNAME/REPO.git

Verify the change

git remote -v

Add a new remote (if none exists)

git remote add origin git@github.com:USERNAME/REPO.git

Common scenario – rename origin to upstream

git remote rename origin upstream
git remote add origin git@github.com:USERNAME/NEW_REPO.git

Generate and Add SSH Keys for GitHub / GitLab

SSH keys provide passwordless, secure authentication to GitHub, GitLab, and Bitbucket. Always specify the key type explicitly when generating.

Step 1 – Generate an SSH key pair

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

When prompted:

  • Save to the default location (~/.ssh/id_rsa) or a custom path.
  • Set a passphrase for extra security (recommended).

Step 2 – Start the SSH agent and add the key

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa

Step 3 – Copy the public key

cat ~/.ssh/id_rsa.pub

Copy the entire output (starts with ssh-rsa AAAA...).

Step 4 – Add the key to GitHub

  1. Go to GitHub → Settings → SSH and GPG keys → New SSH key.
  2. Paste the public key and save.

Step 5 – Test the connection

ssh -T git@github.com

You should see: Hi USERNAME! You've successfully authenticated...

Git Commands Reference

Frequently used Git commands for configuration, branch management, and common fixes.

Configuration

# List all config settings
git config --list

# Check a specific setting
git config user.name
git config user.email

# Set global identity
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Increase HTTP post buffer (fixes "The remote end hung up unexpectedly")
git config http.postBuffer 524288000

# Allow long file paths (Windows)
git config --system core.longpaths true
git config --global core.longpaths true

Branch operations

# Set upstream tracking branch
git branch --set-upstream-to=origin/master master

# List all branches (local and remote)
git branch -a

# Delete a local branch
git branch -d branch-name

# Delete a remote branch
git push origin --delete branch-name

Status and history

git status
git log --oneline --graph --decorate --all
git diff HEAD~1

Undo changes

# Unstage a file
git reset HEAD filename

# Discard local changes to a file
git checkout -- filename

# Undo last commit (keep changes staged)
git reset --soft HEAD~1

# Undo last commit (discard changes)
git reset --hard HEAD~1

Remove Large Files from Git History

If a large file was accidentally committed and pushed, it remains in Git history even after deletion. Use git filter-repo (recommended) or BFG Repo Cleaner to purge it from all commits.

Warning: This rewrites history. All collaborators must re-clone or rebase after the rewrite. Back up your repository first.

Method 1 – git filter-repo (recommended)

# Install
pip install git-filter-repo

# Remove a specific file from all history
git filter-repo --path path/to/largefile.zip --invert-paths --force

# Remove all files over 50MB
git filter-repo --strip-blobs-bigger-than 50M --force

# Push the rewritten history (force required)
git push origin --force --all
git push origin --force --tags

Method 2 – BFG Repo Cleaner (faster for large repos)

# Download BFG
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar

# Remove a specific file
java -jar bfg-1.14.0.jar --delete-files largefile.zip

# Remove files bigger than 50MB
java -jar bfg-1.14.0.jar --strip-blobs-bigger-than 50M

# Clean up and push
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push origin --force --all

After the rewrite

  • Add the file to .gitignore to prevent it being committed again.
  • All collaborators must run git fetch --all and then re-clone or use git reset --hard origin/main.
  • Consider Git LFS for legitimately large binary files that need to be versioned.

Revert a File to a Previous Git Version

To restore a single file to how it looked in a previous commit without rolling back the entire branch.

Step 1 – Find the right commit

# Show commits that touched a specific file
git log --oneline path/to/file.txt

# Show the diff introduced in each commit
git log -p path/to/file.txt

# Use gitk for a graphical view
gitk path/to/file.txt

Step 2 – Restore the file from that commit

# Replace the working copy with the version from a specific commit
git checkout <commit-hash> -- path/to/file.txt

# Then stage and commit the revert
git add path/to/file.txt
git commit -m "Revert file.txt to version from <commit-hash>"

Alternative – use git restore (Git 2.23+)

git restore --source=<commit-hash> path/to/file.txt

Discard all local changes to a file (restore to last commit)

git checkout -- path/to/file.txt
# or
git restore path/to/file.txt

Use a Specific SSH Key for Git Commands

When you have multiple SSH keys (e.g., personal and work GitHub accounts), you need to tell Git which key to use for a particular remote.

Method 1 – SSH config file (recommended)

Edit ~/.ssh/config:

Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/work_rsa

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/personal_rsa

Then use the alias in remote URLs:

git remote add origin git@github-work:company/repo.git

Method 2 – GIT_SSH_COMMAND environment variable

GIT_SSH_COMMAND="ssh -i ~/.ssh/specific_key -F /dev/null" git clone git@github.com:org/repo.git

Method 3 – GIT_SSH wrapper script

Create ~/gitwrap.sh:

#!/bin/bash
ssh -i ~/.ssh/gitkey_rsa "$@"
chmod +x ~/gitwrap.sh

Add to ~/.bashrc:

export GIT_SSH=~/gitwrap.sh

Git Hooks: Automate Development and Deployment Tasks

Git hooks are scripts that run automatically at specific points in the Git workflow — before/after commits, pushes, merges, and more. They're stored in .git/hooks/.

Common hook types

HookTriggersCommon use
pre-commitBefore commit is createdLinting, tests, formatting
commit-msgAfter commit message is writtenEnforce message format
post-commitAfter commit is createdNotifications
pre-pushBefore git pushRun full test suite
post-receiveOn the server after pushAuto-deploy, CI trigger

Example: post-receive auto-deploy hook

On the server, in the bare repository's hooks/post-receive:

#!/bin/bash
GIT_WORK_TREE=/var/www/html git checkout -f main
echo "Deployed to /var/www/html"
sudo systemctl reload nginx
chmod +x hooks/post-receive

Example: pre-commit linting hook

#!/bin/bash
# Run PHP syntax check on staged files
git diff --cached --name-only --diff-filter=ACM | grep '\.php$' | while read file; do
    php -l "$file" || exit 1
done

Bypass a hook for one commit (use sparingly)

git commit --no-verify -m "Emergency fix"

Git Hooks: Automatic Code Quality Checks

Automating code quality checks via Git hooks ensures every commit meets standards without relying on developers to remember to run them manually.

Setup: pre-commit hook for Python (flake8 + pytest)

#!/bin/bash
echo "Running code quality checks..."

# Check Python style
flake8 . --count --select=E9,F63,F7,F82 --show-source
if [ $? -ne 0 ]; then
    echo "Flake8 style errors found. Commit aborted."
    exit 1
fi

# Run tests
pytest tests/
if [ $? -ne 0 ]; then
    echo "Tests failed. Commit aborted."
    exit 1
fi

exit 0
chmod +x .git/hooks/pre-commit

Using the pre-commit framework (cross-language, team-friendly)

# Install
pip install pre-commit

# Create .pre-commit-config.yaml in project root
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

# Install the hooks into .git/hooks/
pre-commit install

Run checks on all files manually

pre-commit run --all-files

Remove a Large File Accidentally Committed to Git

If you accidentally committed a large file (e.g., a 100MB binary), GitHub will reject the push if it exceeds the file size limit. You must rewrite history to remove it before you can push.

Step 1 – Undo the commit (if not yet pushed)

# Undo last commit, keep changes staged
git reset --soft HEAD~1

# Add the file to .gitignore
echo "largefile.zip" >> .gitignore
git rm --cached largefile.zip

# Recommit without the large file
git add .gitignore
git commit -m "Remove large file, add to .gitignore"

Step 2 – Remove from history (if already pushed)

# Using git filter-repo (install first: pip install git-filter-repo)
git filter-repo --path largefile.zip --invert-paths --force

# Force push the rewritten history
git push origin --force --all

Step 3 – Prevent it happening again

Add large file patterns to .gitignore:

# .gitignore
*.zip
*.tar.gz
*.mp4
*.sql

Alternative: Use Git LFS for legitimately large files

# Install Git LFS
git lfs install

# Track large file types
git lfs track "*.psd"
git add .gitattributes
git add design.psd
git commit -m "Add design file via LFS"

Rename a Local and Remote Branch in Git

Renaming a Git branch requires renaming it locally, pushing the new name, and deleting the old remote branch.

If you are currently on the branch to rename

git branch -m new-name

If you are on a different branch

git branch -m old-name new-name

Push the renamed branch and delete the old remote branch

# Push new branch name
git push origin -u new-name

# Delete the old remote branch
git push origin --delete old-name

Update tracking reference (if needed)

git branch --unset-upstream
git branch --set-upstream-to=origin/new-name new-name

Notify collaborators

Anyone who had the old branch checked out must run:

git fetch --all --prune
git checkout new-name
git branch --set-upstream-to=origin/new-name new-name

Use Multiple SSH Keys for Different GitHub Accounts

If you have both a personal and a work GitHub account on the same machine, you need separate SSH keys and an SSH config to route connections to the right key.

Step 1 – Generate separate SSH keys

# Personal key
ssh-keygen -t rsa -b 4096 -C "personal@email.com" -f ~/.ssh/id_rsa_personal

# Work key
ssh-keygen -t rsa -b 4096 -C "work@company.com" -f ~/.ssh/id_rsa_work

Step 2 – Add public keys to GitHub accounts

For each account, copy the .pub key and add it under GitHub → Settings → SSH keys:

cat ~/.ssh/id_rsa_personal.pub
cat ~/.ssh/id_rsa_work.pub

Step 3 – Configure SSH aliases in ~/.ssh/config

# Personal GitHub account
Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_personal

# Work GitHub account
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_work

Step 4 – Use the alias in remote URLs

# Clone using personal account
git clone git@github-personal:personal-username/repo.git

# Clone using work account
git clone git@github-work:company-org/repo.git

# Update an existing remote
git remote set-url origin git@github-work:company-org/repo.git

Test each key

ssh -T git@github-personal
ssh -T git@github-work