Git is an essential tool for modern software development, enabling efficient tracking of code changes and facilitating collaboration. This guide will introduce the fundamental concepts of Git, cover essential commands for managing local repositories, explore branch management strategies, and explain how to interact with remote repositories and manage tags.
Understanding Git Concepts
What is Version Control?
Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. This is crucial for tracking modifications, reverting to previous states, and understanding the evolution of a project.
Centralized vs. Distributed Version Control
Traditional centralized systems store all versions on a single server. If this server fails, all historical data is lost. Git, on the other hand, is a distributed system. Each developer has a complete copy of the repository locally, meaning that even if the central server goes down, work can continue and data can be recovered from local copies.
Setting Up a Local Git Repository
To begin, navigate to your project directory and initialize a new Git repository:
git init
It's important to configure your identity for commit history. This includes your name and email address:
git config user.name "Your Name"
git config user.email "your.email@example.com"
You can verify your configuration:
git config -l
To unset a configuration, use:
git config --unset user.name
git config --unset user.email
To apply these configurations globally for all your Git repositories on this machine, use the --global flag:
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
git config --global --unset user.name
The Git Workflow: Working Directory, Staging Area, and Repository
Understanding Git's three main areas is key to its operation:
- Working Directory: This is your project folder where you create, modify, and delete files.
- Staging Area (Index): This is an intermediate area where you prepare changes to be committed. You add modified files from the working directory to the staging area.
- Repository (.git directory): This is where Git permanently stores your project's history and metadata. Commits are saved here.
When you make changes in the working directory, Git tracks these as objects. The staging area holds a snapshot of these changes, and a commit permanently saves this snapshot to the repository.
Core Git Operations
Adding Files
To stage changes for a commit:
# Stage all changes in the current directory
git add .
# Stage a specific file
git add specific_file.txt
After staging, commit the changes to the repository:
git commit -m "Descriptive commit message"
Viewing Status and Changes
Check the status of your working directory and staging area:
git status
To see the differences between your working directory and the staging area:
git diff filename.txt
To see the differences between the staging area and the last commit:
git diff --cached filename.txt
Undoing Changes
Git provides several ways to revert changes:
Discarding Changes in the Working Directory
To discard changes in your working directory for a specific file (since the last commit and not yet staged):
git checkout -- filename.txt
Unstaging Files and Revising Commits
To unstage a file (move it back to the working directory):
git reset HEAD filename.txt
To revert a commit and keep changes in the staging area (soft reset):
git reset --soft HEAD~1
To revert a commit and keep changes in the working directory (mixed reset, the default):
git reset HEAD~1
To completely discard a commit and all subsequent changes (hard reset - use with caution!):
git reset --hard HEAD~1
HEAD~1 refers to the previous commit. You can use HEAD~2 for two commits back, or specify a commit hash.
Deleting Files
To remove a file from both the working directory and the staging area, then commit the deletion:
git rm filename.txt
git commit -m "Remove filename.txt"
Configuring Command Aliases
You can create shortcuts for frequently used Git commands:
git config --global alias.co checkout
git config --global alias.st status
Now you can use git co branch_name instead of git checkout branch_name.
Branch Management
Understanding Branches
Branches allow you to diverge from the main line of development and continue to do new work without messing with the main line. The master branch is typically the main produciton branch. HEAD is a pointer to the currently active branch.
Viewing Branches
List all local branches:
git branch
An asterisk (*) indicates the currently active branch.
Creating and Switching Branches
To create a new branch:
git branch new-feature
To switch to a different branch:
git checkout new-feature
A shortcut to create and switch to a new branch:
git checkout -b new-feature-branch
Merging Branches
To integrate changes from one branch into another, first switch to the branch you want to merge into, then run the merge command:
git checkout master
git merge new-feature
Merge Conflicts
Conflicts occur when Git cannot automaticlaly resolve differences between branches. You'll need to manually edit the conflicting files to choose which changes to keep, then stage and commit the resolved files.
Merge Strategies (Fast-Forward vs. No-Fast-Forward)
Fast-Forward (ff): If the target branch hasn't diverged since the feature branch was created, Git simply moves the target branch pointer forward. Branch history might not clearly show when a merge occurred.
No-Fast-Forward (no-ff): Git creates a new merge commit even if a fast-forward is possible. This preserves branch history and clearly indicates when merges happened.
git merge --no-ff -m "Merge branch 'new-feature' into master" new-feature
Deleting Branches
Once a branch's changes have been merged, you can delete it:
git branch -d merged-branch
To forcefully delete a branch (even if unmerged, use with caution):
git branch -D unmerged-branch
Branching Strategies
A common strategy is to keep the master branch stable for releases. Development occurs on a develop branch, and individual features or bug fixes are developed on their own short-lived branches, which are then merged back into develop.
Fixing Bugs with Branches
When a bug is found in production (e.g., on master), create a hotfix branch from master, fix the bug, merge it back to master, and then merge master back into develop.
Stashing Changes
If you need to switch branches but have uncommitted changes you don't want to commit yet, you can stash them:
git stash
To reapply stashed changes later:
git stash pop
Remote Repository Operations
Setting Up a Remote Repository
Platforms like GitHub, GitLab, and Gitee provide hosting for remote Git repositories. You'll typically create a new repository on one of these platforms.
Cloning a Remote Repository
To download a repository from a remote server:
# Using HTTPS
git clone https://github.com/user/repo.git
# Using SSH (requires SSH key setup)
git clone git@github.com:user/repo.git
git remote -v shows your configured remote repositories.
Pushing to a Remote Repository
Send your local commits to a remote repository:
git push origin main
This pushes your local main branch to the remote repository named origin.
Pulling from a Remote Repository
Fetch changes from a remote repository and merge them into your current local branch:
git pull origin main
Ignoring Specific Files
Create a .gitignore file in your project's root directory to specify files or patterns that Git should ignore (e.g., compiled code, log files, sensitive credentials).
# Example .gitignore content
*.log
build/
secrets.json
To check why a file is being ignored:
git check-ignore -v filename.txt
Tag Management
Tags are used to mark specific points in the repository's history as important, typically for releases (e.g., v1.0, v2.1).
Creating and Deleting Tags
List all tags:
git tag
Create an annotated tag (recommended):
git tag -a v1.0 -m "Version 1.0 release"
Create a lightweight tag:
git tag v1.0-light
View tag details:
git show v1.0
Delete a local tag:
git tag -d v1.0
Pushing Tags to Remote
Tags are not pushed by default. To push a specific tag:
git push origin v1.0
To push all local tags:
git push origin --tags
To delete a remote tag:
git push origin --delete v1.0
# or
git push origin :refs/tags/v1.0