Skip to content

wsmr/Git

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 

Repository files navigation

Git Documentation: A Comprehensive Guide

Table of Contents

  1. Introduction
  2. Getting Started with Git
  3. Basic Git Commands
  4. Git Configuration
  5. Understanding Git History
  6. Managing Remote Repositories
  7. Managing Files with .gitignore
  8. Staging Area Management
  9. Git History Manipulation
  10. Git Tagging
  11. Troubleshooting Common Git Issues
  12. Advanced Topics
  13. Summary of Key Git Commands

1. Introduction

This document serves as a comprehensive guide to Git, a powerful distributed version control system. It covers fundamental Git commands, configuration, history management, and advanced topics such as handling sensitive data and troubleshooting common issues. This guide is designed for developers of all experience levels, providing clear explanations and practical examples to enhance your understanding and proficiency with Git.


2. Getting Started with Git

To begin working with Git, you can either initialize a new repository for a new project or clone an existing repository from a remote source.

What is version control and why is it important?

Version control (like Git) is a system that tracks changes in code over time. It lets multiple developers collaborate safely by merging changes, and it keeps a history of everything done. You can go back to previous versions if something breaks. This is important because it helps manage code, avoid conflicts, and keep a record of all work.

2.1 Initializing a New Repository

When starting a new project that you wish to track with Git, you will typically initialize a new Git repository in your project directory. This command creates a new .git subdirectory, which contains all the necessary Git metadata for the repository.

git init

After initialization, you might want to create a README.md file to describe your project and add it to your repository.

echo "# Your_Project_Name" >> README.md
git add README.md
git commit -m "first commit"

To connect your local repository to a remote repository (e.g., on GitHub), you need to add a remote origin. Replace your-remote-repository-url with the actual URL of your remote repository.

git remote add origin your-remote-repository-url

Finally, push your initial commit to the remote repository. The -u flag sets the upstream branch, so you can simply use git push in the future.

git push -u origin main

2.2 Cloning an Existing Repository

If you are joining an existing project or want to work on a project hosted remotely, you can clone the repository. Cloning downloads a complete copy of the repository, including all files, branches, and commit history, to your local machine.

There are two primary methods for cloning: HTTPS and SSH.

Cloning with HTTPS:

This method is generally simpler for read-only access and does not require SSH key setup. However, you will need to provide your username and password (or a personal access token) for write operations.

git clone https://github.com/your-username/your-repo.git

Cloning with SSH:

SSH provides a more secure way to interact with remote repositories, especially for frequent write operations, as it uses SSH keys for authentication. This requires prior setup of SSH keys on your system and adding them to your Git hosting service (e.g., GitHub).

git clone git@github.com:your-username/your-repo.git

After cloning, you can verify the remote origin to ensure it's correctly set up:

git remote -v

Cloning a Specific Branch:

Sometimes, you might want to clone a specific branch of a repository directly, rather than the default branch (usually main or master). This is particularly useful for projects that maintain different branches for active development and stable releases.

To clone a specific branch (e.g., stable):

git clone -b stable https://github.com/your-username/your-repo.git

The -b (or --branch) flag tells Git which branch to check out immediately after cloning. This avoids the need to manually switch branches after the initial clone.


3. Basic Git Commands

Understanding and utilizing basic Git commands is crucial for effective version control. These commands allow you to manage your project's history, collaborate with others, and maintain a clean and organized codebase.

3.1 Checking Repository Status

The git status command provides a summary of the current state of your working directory and the staging area. It shows which changes have been staged, which haven't, and which files aren't being tracked by Git.

git status

3.2 Branch Management

Branches are fundamental to Git, allowing you to work on different features or bug fixes in isolation from the main codebase. This section covers essential commands for managing branches.

To list all local branches:

git branch

To list all remote branches:

git branch -r

To list all local and remote branches:

git branch -a

To switch to the last branch you were on:

git checkout -

To switch to a specific existing branch:

git checkout your-branch-name

To create a new branch and immediately switch to it:

git checkout -b new-branch-name

If a branch exists on the remote but not locally, you can create and switch to it based on the remote branch:

git checkout -b your-branch-name origin/your-branch-name

To find the currently active Git branch:

git branch --show-current
# Alternatively:
git rev-parse --abbrev-ref HEAD

3.3 Staging and Committing Changes

After making changes to your files, you need to stage them and then commit them to your repository's history.

To stage all changes in the current directory (including new files, modifications, and deletions):

git add .

To stage specific files:

git add file1.js file2.py

To commit staged changes with a descriptive message:

git commit -m "Your descriptive commit message"

To stage all modified files and commit in one command (does not include new untracked files):

git commit -am "Your commit message"

3.4 Working with Remotes

Remote repositories are versions of your project that are hosted on the internet or network. They are essential for collaboration and backing up your work.

To verify the remote repositories configured for your project:

git remote -v

To fetch the latest changes from the remote repository and then switch to a specific branch (useful for updating your local branch with remote changes):

git fetch && git checkout your-branch-name

To push your local commits to the remote repository. The -u flag sets the upstream branch, which is useful for subsequent pushes.

git push -u origin main
# Or for a new remote and branch:
git push new_remote_name branch_name

For pushing to a specific GitHub repository using a Personal Access Token (PAT) for authentication (replace placeholders):

git push https://YOUR_GITHUB_USERNAME:YOUR_PERSONAL_ACCESS_TOKEN@github.com/your-username/your-repo.git

To pull changes from a specific remote and branch:

git pull origin main

To fetch all branches and their respective commits from the remote repository:

git fetch origin

4. Git Configuration

Git allows extensive configuration to tailor its behavior to your preferences and project needs. These configurations can be set at different levels: system, global (user), and local (repository).

4.1 Viewing Git Configuration

To view your Git configuration settings, you can use the git config command with various flags.

To display all Git configuration settings for your user account on the current system:

git config --list

To show only global settings (those applied to all your repositories):

git config --global --list

To show only local repository settings (those specific to the current repository):

git config --local --list

4.2 Changing User Information

It is essential to configure your Git username and email address, as this information is embedded in every commit you make. This helps identify who made which changes.

To change your global Git username:

git config --global user.name "Your Name"

To change your global Git email address:

git config --global user.email "your-email@example.com"

4.3 Handling Line Endings

Line ending inconsistencies between different operating systems (Windows uses CRLF, macOS/Linux use LF) can cause issues in collaborative projects. Git provides the core.autocrlf setting to manage this automatically.

To configure Git to convert CRLF to LF on commit (for macOS or Linux users), ensuring Unix-style line endings in the repository, but leaving line endings unchanged on checkout:

git config --global core.autocrlf input

To configure Git to convert LF to CRLF on checkout and CRLF to LF on commit (for Windows users):

git config --global core.autocrlf true

To disable automatic conversion and leave line endings unchanged:

git config --global core.autocrlf false

For most macOS and Linux users, setting core.autocrlf to input is recommended. This helps maintain consistent line endings across different development environments.


5. Understanding Git History

Git maintains a detailed history of all changes made to your repository, allowing you to track, review, and revert modifications. Understanding how to navigate and interpret this history is crucial for effective version control.

5.1 Viewing Commit History

The git log command is your primary tool for exploring the commit history. It displays a list of commits in reverse chronological order, showing the commit hash, author, date, and commit message.

To view the full commit history with detailed information:

git log

For a more compact view, displaying each commit on a single line with an abbreviated commit hash and message:

git log --oneline

To limit the display to a specific number of commits (e.g., last 10 commits):

git log --oneline -10

To visualize branches and their commit history graphically:

git log --graph --oneline --all

To see commits along with the patches or changes introduced by each commit:

git log -p

To see commits by a specific author:

git log --author="Your Author Name"

To see commits within a specific date range:

git log --since="YYYY-MM-DD" --until="YYYY-MM-DD"

To list all the files modified or added in a specific commit (replace commit-hash with the actual commit hash):

git diff-tree --no-commit-id --name-only -r commit-hash

To view recent Git operations (useful for finding lost commits):

git reflog

5.2 Amending Commit Messages

Sometimes you might need to modify the message of your most recent commit. The git commit --amend command allows you to do this.

To change the most recent commit message:

git commit --amend -m "Your new commit message"

This command replaces the last commit with a new one that includes the previous commit's contents and any newly staged changes. If you have already staged new changes with git add ., they will be included in the amended commit.

Important Consideration: If the commit has already been pushed to a remote repository, amending it will create a new commit that diverges from the remote history. You will need to force push to update the remote:

git push --force-with-lease origin main

If force-with-lease fails due to stale reference:

# Fetch latest remote references
git fetch origin

# Then force push
git push --force-with-lease origin main

5.3 Reverting Amended Commits

If you amend a commit and then decide you want to split it into two separate commits, you can do so by resetting the last commit and then re-committing your changes.

  1. Reset the last commit but keep changes staged:
git reset --soft HEAD~1

This command moves the HEAD pointer back one commit, but keeps the changes from that commit in your staging area.

  1. Make two new commits:

Now your changes will be staged again. You can selectively commit them.

git commit -m "First part of the commit message"

If some changes still remain staged after the first commit, unstage them:

git reset

Then, selectively add the remaining changes and commit them:

git add .  # or specific files
git commit -m "Second part of the commit message"

This process allows you to refine your commit history by breaking down a single amended commit into more granular, logically separated commits.


6. Managing Remote Repositories

Remote repositories are essential for collaboration and backup. This section covers how to manage and interact with remote repositories effectively.

6.1 Changing Remote URLs

If you need to change the remote URL after cloning, you can use the set-url command. This is useful if the repository's remote URL changes or if you initially cloned using HTTPS and now wish to switch to SSH, or vice-versa.

To update an existing remote URL:

git remote set-url origin your-new-remote-repository-url

To completely remove and re-add a remote:

# Remove the old remote
git remote remove origin

# Add the new remote
git remote add origin https://github.com/new-username/new-repo.git

Example: Switching from one repository to another:

If you're working on a forked repository and need to switch to a different one:

# Update remote URL to point to new repository
git remote set-url origin https://github.com/studiointeriorm/StudioM.git

# Verify the change
git remote -v

# Fetch from new remote
git fetch origin

6.2 Restoring Deleted Repositories

If a remote repository is accidentally deleted and you have a local copy with all commits intact, you can restore it to a newly created repository.

Steps to restore:

  1. Verify your local repository is intact:
# Check your commit history is still there
git log --oneline -10

# Check current remote
git remote -v
  1. Update the remote URL to point to the new repository:
git remote set-url origin https://github.com/your-username/new-repo.git
  1. Push everything including all commits:
# Push with full history
git push -u origin main --force

# If you have multiple branches
git push --all origin --force
git push --tags origin --force

This restores your entire project with complete commit history to the new repository.

6.3 Force Pushing Changes

Force pushing overwrites the remote branch with your local version. Use with extreme caution as it can delete other people's work.

Safer option - force push with lease:

git push --force-with-lease origin main

This will fail if someone else has pushed to the branch since your last fetch, protecting against accidentally overwriting others' work.

Regular force push (use only when absolutely necessary):

git push --force origin main

Understanding the consequences:

When you force push, you completely replace the remote branch history with your local history. Any commits that exist on the remote but not locally will be permanently deleted. Always:

  • Communicate with your team before force pushing
  • Use --force-with-lease instead of --force when possible
  • Consider if there's a safer alternative (like reverting commits)

7. Managing Files with .gitignore

Effective use of .gitignore is crucial for maintaining a clean and manageable Git repository. This file tells Git which files or folders to intentionally ignore, preventing them from being tracked or included in commits.

7.1 What is .gitignore?

A .gitignore file is a plain text file where each line contains a pattern for files or directories that Git should ignore. This is particularly useful for excluding temporary files, build artifacts, dependency directories (like node_modules), environment-specific configuration files, and operating system-generated files (like .DS_Store). By ignoring these files, you ensure that your repository only contains relevant source code and project assets, reducing repository size and avoiding unnecessary conflicts.

7.2 Setting Up .gitignore

To set up a .gitignore file, you typically create it in the root directory of your Git repository. Each line in the file specifies a pattern for files or directories to ignore.

  1. Create the .gitignore file:
touch .gitignore
  1. Add patterns to the file. Below is a suggested .gitignore template for projects that might involve both Node.js and Python components, along with common system and log files. You should adapt this to your specific project needs.
# Node.js specific ignores
node_modules/
npm-debug.log
# Optional: npm lock file if you prefer to not track it
package-lock.json

# Python specific ignores
__pycache__/
*.py[cod]
*.pyo
*.pyc

# Environment files
.env
.venv/
env/
venv/

# IDE specific files
.idea/
.vscode/
*.swp
*.swo

# Build directories
build/
dist/
*.egg-info/

# System Files (macOS, Windows)
.DS_Store
**/.DS_Store
Thumbs.db

# Log files
*.log
nohup.out
  1. Save and commit the .gitignore file:

After adding your desired patterns, save the file and commit it to your repository. This ensures that all collaborators will use the same ignore rules.

git add .gitignore
git commit -m "Add .gitignore"

GitHub maintains extensive .gitignore templates for various programming languages and frameworks at https://github.com/github/gitignore.

7.3 Untracking Already Added Files

A common scenario is that you might have mistakenly added and committed files (e.g., node_modules/, .DS_Store, .env) before setting up your .gitignore file. In such cases, Git will continue to track these files even after you add them to .gitignore.

To remove these files from Git's tracking (but keep them locally in your working directory), you need to use the git rm --cached command.

To untrack specific files or directories:

# Untrack a single file
git rm --cached .DS_Store

# Untrack a directory recursively
git rm -r --cached node_modules

# Untrack multiple items
git rm --cached .env
git rm -r --cached build/
git rm -r --cached .gradle/
git rm -r --cached .idea/

# Commit the changes
git commit -m "Remove unwanted tracked files and apply .gitignore"
git push

To untrack all ignored files at once:

# Untrack everything
git rm -r --cached .

# Re-add only files that should be tracked
git add .

# Commit
git commit -m "Clean up unwanted tracked files using .gitignore"

This sequence first untracks everything in your repository, then re-adds only the files that are not matched by any pattern in your .gitignore file.

7.4 Handling Tracked Files with .gitignore

Important: Adding a file to .gitignore ONLY prevents untracked files from being added. It does NOT stop tracking files that are already tracked by Git.

The Issue:

If a.txt is already tracked by Git, adding it to .gitignore will NOT prevent future changes from being committed. The file will continue to be tracked and any modifications will still show up in git status and be included in commits.

The Solution - Remove from Tracking:

# Add to .gitignore first
echo "a.txt" >> .gitignore

# Remove from Git tracking but keep local file
git rm --cached a.txt

# Commit the changes
git add .gitignore
git commit -m "Stop tracking a.txt and update .gitignore"
git push

What this does:

  • a.txt will be deleted from the GitHub repository
  • The file remains in your local directory
  • Future changes to a.txt will be ignored by Git

Note: There is no way to keep a file in the repository while preventing future updates to it. You must choose between:

  • Keep file in repo + accept future updates
  • Remove file from repo + ignore future changes

7.5 Common .gitignore Mistakes and Fixes

One common mistake is accidentally removing the .gitignore file from Git tracking. If you run git rm -r --cached .gitignore, the file will remain on your disk but Git will no longer track it.

To fix this, simply re-add the .gitignore file to Git:

git add .gitignore
git commit -m "Re-add .gitignore"

7.6 Best Practices for .gitignore

Adhering to these best practices will help you maintain a clean and efficient Git repository:

  • Create .gitignore early: Always create and configure your .gitignore file at the very beginning of your project. This prevents unwanted files from ever being tracked.
  • Never commit sensitive or unnecessary files: Ensure that directories like node_modules, .env files (containing sensitive environment variables), and OS-specific junk files are always ignored.
  • Use git rm --cached: If files are accidentally committed, use git rm --cached to stop tracking them without deleting them locally.
  • Leverage GitHub's .gitignore templates: Utilize the official .gitignore templates provided by GitHub for project-specific setups.

8. Staging Area Management

Understanding how to manage the staging area is crucial for controlling what gets included in your commits.

8.1 Removing Files from Staging

If you've staged files but want to unstage them before committing, use git restore --staged.

To unstage specific files:

git restore --staged filename.txt

To unstage multiple files:

git restore --staged file1.js file2.py file3.css

To unstage entire directories:

git restore --staged build/ .gradle/ .idea/

To unstage all staged files:

git restore --staged .

8.2 Staging Files from Parent Directories

When working in subdirectories, files in parent directories won't be staged by git add . because . refers to the current directory.

Problem scenario:

# You're in android/ subdirectory
cd android/
git add .
git status
# Shows: modified: ../package.json (not staged)

Solutions:

Option 1: Navigate to project root (recommended):

# Go to parent directory
cd ..

# Now stage all changes
git add .
git commit -m "Your message"

Option 2: Stage from current location using parent path:

# Stage specific parent directory files
git add ../package.json ../src/

# Or stage all changes from parent
git add ..

8.3 Removing Specific Files from Staging

If you've staged multiple files but want to remove some specific ones from the staging area:

# Check what's staged
git status

# Remove specific files from staging
git restore --staged gpg-wrapper.sh gradle.properties

# Verify
git status

9. Git History Manipulation

Git provides powerful tools for manipulating commit history. Use these carefully, especially on shared branches.

9.1 Resetting to Previous Commits

Resetting allows you to move your branch pointer to a different commit, optionally keeping or discarding changes.

To reset to a specific commit and discard all changes after it:

# Reset to commit hash (e.g., 547a7c7)
git reset --hard 547a7c7

# Force push to update remote
git push --force-with-lease origin main

To reset but keep changes staged:

git reset --soft HEAD~1

To reset but keep changes unstaged:

git reset HEAD~1

Creating a backup before resetting:

# Create backup branch first
git branch backup-before-reset

# Then reset
git reset --hard 547a7c7

# Force push
git push --force-with-lease origin main

9.2 Interactive Rebase

Interactive rebase allows you to modify, reorder, squash, or remove commits in your history.

To start interactive rebase:

# Rebase from the beginning of the repository
git rebase -i --root

# Rebase last N commits
git rebase -i HEAD~5

# Rebase from a specific commit
git rebase -i commit-hash

In the interactive rebase editor:

  • pick - Use commit as-is
  • drop - Remove commit entirely
  • reword - Change commit message
  • edit - Stop for amending
  • squash - Combine with previous commit
  • fixup - Like squash but discard commit message

Editor navigation (Vim):

  1. Press i to enter INSERT mode
  2. Edit the commands (change "pick" to "drop", etc.)
  3. Press Esc to exit INSERT mode
  4. Type :wq and press Enter to save and quit

9.3 Removing Commits from History

To remove specific commits (e.g., those containing sensitive data) from Git history:

Method 1: Interactive Rebase

# Start interactive rebase
git rebase -i --root

# In the editor, change "pick" to "drop" for commits to remove
# Example:
# drop 0697f23 first commit
# drop 04ea732 temp
# pick c558987 gradle build issue fixed

# Save and exit
# Then force push
git push --force-with-lease origin main

Method 2: Using git revert (safer for shared branches)

Instead of removing commits, create new commits that undo the changes:

# Revert a range of commits
git revert --no-edit commit-hash..HEAD

# Or revert specific commits
git revert --no-edit commit-hash1
git revert --no-edit commit-hash2

# Push normally (no force needed)
git push origin main

9.4 Reverting Changes

To undo a specific commit without removing it from history:

git revert commit-hash

To create a new commit with a specific old commit's content:

# Checkout files from an old commit
git checkout commit-hash -- .

# Commit as new state
git commit -m "Revert to working state from commit-hash"
git push origin main

To jump to a specific commit and make it the new HEAD:

# Option 1: Create new commit with old state
git checkout f4bde0e -- .
git commit -m "Revert to working state from f4bde0e"
git push origin main

# Option 2: Reset and force push (rewrites history)
git reset --hard f4bde0e
git push --force-with-lease origin main

10. Git Tagging

Tags are references to specific points in Git history, commonly used for marking release versions.

10.1 What are Git Tags?

Git tags are used to mark specific commits as important, typically for:

  • Version Releases: Mark release points (v1.0.0, v2.1.5, etc.)
  • GitHub Releases: Tags appear in the "Releases" section on GitHub
  • Reference Points: Easy way to checkout specific versions later

10.2 Creating Tags

Create an annotated tag (recommended):

git tag -a v1.0.0 -m "Initial release of PVM for macOS"

Create a lightweight tag:

git tag v1.0.0

Push a specific tag to remote:

git push origin v1.0.0

Push all tags to remote:

git push origin --tags

10.3 Managing Tags

List all tags:

git tag

View tag details:

git show v1.0.0

Delete a local tag:

git tag -d v1.0.0

Delete a remote tag:

git push origin --delete v1.0.0

Checkout a specific tag:

git checkout v1.0.0

Example versioning workflow:

# First stable release
git tag -a v1.0.0 -m "First stable release"
git push origin v1.0.0

# Bug fix release
git tag -a v1.0.1 -m "Bug fixes for login issue"
git push origin v1.0.1

# Major update
git tag -a v2.0.0 -m "Complete UI redesign"
git push origin v2.0.0

11. Troubleshooting Common Git Issues

Even with a good understanding of Git, you might encounter common issues. This section provides solutions and explanations for frequently faced problems.

11.1 Updates Rejected Due to Remote Changes

Error: Updates were rejected because the remote contains work that you do not have locally

This means the remote repository has commits that are not present in your local branch.

Solution 1: Merge Remote Changes (Recommended)

# Set upstream branch
git branch --set-upstream-to=origin/main main

# Pull and merge remote changes
git pull origin main --allow-unrelated-histories

# Push your changes
git push origin main

Solution 2: Force Push (⚠️ Use with caution)

This will delete everything in the remote and replace it with your local version:

git push origin main --force

11.2 Handling Diverged Branches During Pull

If your local and remote branches have diverged, Git needs to know how to combine them.

Fix Option 1: Merge (Safe and Common)

git config pull.rebase false
git pull

Fix Option 2: Rebase (Cleaner History)

git config pull.rebase true
git pull --rebase

Fix Option 3: One-time Override

# Merge for this pull only
git pull --no-rebase

# Rebase for this pull only
git pull --rebase

# Fast-forward only
git pull --ff-only

Set as Global Default:

# Merge (recommended for simplicity)
git config --global pull.rebase false

# Rebase (cleaner history)
git config --global pull.rebase true

# Fast-forward only
git config --global pull.ff only

11.3 GitHub File Not Showing

Problem: File doesn't appear after git add, git commit, and git push.

Common Causes:

  1. Incorrect file creation - Using mkdir instead of touch
  2. File ignored by .gitignore - A rule is blocking it

Step-by-Step Fix:

Step 1: Create the file correctly

# Create directory structure
mkdir -p .github/workflows

# Create the file (not directory)
touch .github/workflows/deploy.yml

# Add initial content
echo "# GitHub Actions workflow" > .github/workflows/deploy.yml

Step 2: Check which .gitignore rule is blocking it

git check-ignore -v .github/workflows/deploy.yml

Step 3: Fix the .gitignore rules

Option A - Refine the rule:

# Before (too broad):
.github/

# After (more specific):
.github/*
!.github/workflows/
!.github/workflows/deploy.yml

Option B - Force add the file:

git add -f .github/workflows/deploy.yml
git commit -m "Add GitHub Actions deploy workflow"
git push

Step 4: Verify the file was added

git status
git log --name-status

11.4 Resolving SSH Key Errors

Error: Permission denied (publickey) or no such identity: /Users/username/.ssh/id_ed25519

Solution 1: Use HTTPS Instead (Simpler)

git remote set-url origin https://github.com/your-username/your-repo.git

Solution 2: Fix SSH Key Setup

  1. Check for existing keys:
ls -la ~/.ssh/
  1. Generate new SSH key:
ssh-keygen -t ed25519 -C "your-email@example.com"
  1. Add key to SSH agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
  1. Add SSH key to GitHub:
# Copy public key
cat ~/.ssh/id_ed25519.pub

# Go to GitHub → Settings → SSH and GPG keys → New SSH key
# Paste the key
  1. Test connection:
ssh -T git@github.com

11.5 Resolving .DS_Store Issues

Problem: .DS_Store files (macOS system files) keep appearing in Git.

Solution:

Remove all .DS_Store files from staging:

git restore --staged **/.DS_Store

Delete actual .DS_Store files:

find . -name ".DS_Store" -type f -delete

Remove from Git tracking:

# Remove from Git but keep local
git rm --cached .DS_Store

# Or force remove if Git complains
git rm -f --cached .DS_Store

Prevent future tracking:

# Add to .gitignore
echo ".DS_Store" >> .gitignore
echo "**/.DS_Store" >> .gitignore

# Commit changes
git add .gitignore
git commit -m "Remove .DS_Store files and update .gitignore"
git push

11.6 Resolving .idea/ and Build Directory Issues

Problem: IDE configuration folders (.idea/) or build directories (build/, dist/) are being tracked.

Solution:

Remove from staging:

git restore --staged build/ .gradle/ .idea/

Remove from Git tracking:

# For directories, use -r flag
git rm -r --cached .idea/
git rm -r --cached build/
git rm -r --cached dist/

# Add to .gitignore
echo ".idea/" >> .gitignore
echo "build/" >> .gitignore
echo "dist/" >> .gitignore

# Commit
git add .gitignore
git commit -m "Remove IDE and build files from tracking"
git push

If Git complains about non-existent paths:

The directory might not be tracked. Just add it to .gitignore:

echo "dist/" >> .gitignore
git add .gitignore
git commit -m "Add dist/ to .gitignore"

11.7 Staged File Removal Issues

Problem: Git refuses to remove a staged file with error about "staged content different from both file and HEAD."

Solution:

Option 1: Unstage first, then remove (recommended):

# Unstage the file
git restore --staged .DS_Store

# Remove from tracking
git rm --cached .DS_Store

# Delete actual file
rm .DS_Store

Option 2: Force removal:

# Force remove (also deletes file)
git rm -f .DS_Store

11.8 Undoing Git Operations

Undo last commit but keep changes:

git reset --soft HEAD~1

Undo last commit and discard changes:

git reset --hard HEAD~1

Undo a git rm --cached operation:

# If not committed yet
git add filename.txt

# If already committed
git reset --soft HEAD~1
git add filename.txt

Undo force push / rebase disaster:

# View recent operations
git reflog

# Reset to before the operation (e.g., HEAD@{1})
git reset --hard HEAD@{1}

# Force push to restore
git push --force-with-lease origin main

Undo changes made by git revert:

# Find the commit hash before the revert in reflog
git reflog

# Reset to that commit
git reset --hard commit-hash-before-revert

# Force push
git push --force-with-lease origin main

12. Advanced Topics

This section delves into more advanced Git topics for power users.

12.1 Cleaning Git History (Removing Sensitive Data)

If sensitive credentials, API keys, or other confidential information are accidentally committed, you need to rewrite Git history to truly remove them.

⚠️ Warning: Rewriting Git history changes commit hashes. Communicate with your team before performing these operations.

Using git-filter-repo:

  1. Install git-filter-repo:
pip install git-filter-repo
  1. Remove sensitive file from all commits:
git filter-repo --path path/to/sensitive-file.txt --invert-paths --force
  1. Force push cleaned history:
git push --force-with-lease origin main

Alternative: Using BFG Repo-Cleaner

BFG Repo-Cleaner is another powerful tool for cleaning repositories. Refer to its official documentation for usage.

12.2 SSH Key Setup for GitHub

SSH keys provide secure authentication with GitHub without exposing passwords.

Complete SSH Setup:

  1. Check for existing keys:
ls -al ~/.ssh
  1. Generate new SSH key:
ssh-keygen -t ed25519 -C "your-email@example.com"

Or for older systems:

ssh-keygen -t rsa -b 4096 -C "your-email@example.com"
  1. Start SSH agent and add key:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
  1. Copy public key:
cat ~/.ssh/id_ed25519.pub
  1. Add to GitHub:

    • Go to GitHub → Settings → SSH and GPG keys → New SSH key
    • Paste the public key
    • Give it a descriptive title
  2. Test connection:

ssh -T git@github.com

12.3 Custom Git Aliases and Functions

Creating custom aliases and functions can significantly speed up your daily Git workflow by combining multiple frequently-used commands into a single shortcut.

Creating a Custom Pre-Commit Command

If you frequently run the same sequence of commands before committing (checking branch, repository URL, staging files, and viewing status), you can create a custom shell function to automate this workflow.

For macOS/Linux (zsh or bash):

  1. Open your shell configuration file:
# For zsh (default on macOS)
nano ~/.zshrc

# For bash
nano ~/.bashrc
  1. Add the following function:
ggg() {
    echo "Branch: $(git branch --show-current)"
    echo "Repo: $(git remote get-url origin)"
    git add .
    git status
    
    if [ -n "$*" ]; then
        git commit -m"$*"
    fi
}
  1. Save and reload your shell:
# For zsh
source ~/.zshrc

# For bash
source ~/.bashrc

Usage:

# Run pre-commit checks only (shows branch, repo, stages files, displays status)
ggg

# Run pre-commit checks AND commit with message
ggg Initial commit
ggg Fixed login bug
ggg Added user authentication feature

What this function does:

  1. Displays current branch name
  2. Shows remote repository URL
  3. Stages all changes with git add .
  4. Shows repository status
  5. If you provide a message, commits with that message
  6. If no message is provided, stops after showing status

Customization:

You can modify this function to fit your specific workflow:

# Example: Add automatic push after commit
ggg() {
    echo "Branch: $(git branch --show-current)"
    echo "Repo: $(git remote get-url origin)"
    git add .
    git status
    
    if [ -n "$*" ]; then
        git commit -m"$*"
        git push
    fi
}

# Example: Add confirmation before staging
ggg() {
    echo "Branch: $(git branch --show-current)"
    echo "Repo: $(git remote get-url origin)"
    
    read -p "Stage all changes? (y/n): " confirm
    if [ "$confirm" = "y" ]; then
        git add .
        git status
        
        if [ -n "$*" ]; then
            git commit -m"$*"
        fi
    fi
}

13. Summary of Key Git Commands

Command Description Example
git init Initialize new repository git init
git clone URL Clone existing repository git clone https://github.com/user/repo.git
git status Show repository status git status
git add . Stage all changes git add .
git add file Stage specific file git add README.md
git commit -m "msg" Commit staged changes git commit -m "Add feature"
git commit --amend Modify last commit git commit --amend -m "New message"
git push Push to remote git push origin main
git push --force-with-lease Safe force push git push --force-with-lease origin main
git pull Pull from remote git pull origin main
git fetch Fetch remote changes git fetch origin
git branch List branches git branch
git branch -r List remote branches git branch -r
git checkout branch Switch branch git checkout develop
git checkout -b branch Create and switch branch git checkout -b feature/new
git merge branch Merge branch git merge feature/new
git log View commit history git log --oneline -10
git reflog View reference log git reflog
git reset --soft HEAD~1 Undo commit keep changes git reset --soft HEAD~1
git reset --hard commit Reset to commit git reset --hard abc123
git revert commit Revert commit git revert abc123
git rebase -i --root Interactive rebase git rebase -i --root
git restore --staged file Unstage file git restore --staged app.js
git rm --cached file Untrack file git rm --cached .env
git rm -r --cached dir/ Untrack directory git rm -r --cached node_modules/
git remote -v List remotes git remote -v
git remote set-url origin URL Change remote URL git remote set-url origin https://...
git tag -a v1.0.0 -m "msg" Create annotated tag git tag -a v1.0.0 -m "Release"
git push origin v1.0.0 Push tag git push origin v1.0.0
git check-ignore -v file Check ignore rule git check-ignore -v app.log
git config --global user.name Set username git config --global user.name "John"
git config --global user.email Set email git config --global user.email "a@b.com"

End of Documentation

For more information, visit the official Git documentation at https://git-scm.com/doc.

About

Git Commends

Resources

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published