
Using Git like a Pro
- Published on
- Authors
- Author
- Ram Simran G
- twitter @rgarimella0124
Git has become the cornerstone of modern software development, enabling teams to collaborate efficiently, track changes, and manage complex projects with ease. This comprehensive guide will take you through essential Git commands and best practices that will elevate your version control skills to a professional level.
Setting Up a New Project
Properly initializing a Git repository sets the foundation for your entire project. Here’s how to start on the right foot:
git init
- Initializes a new Git repository in the current directory
- Creates a hidden
.git
folder to store all Git-related information - Best practice: Run this in the root folder of your project
Example:
mkdir my-new-project cd my-new-project git init
git remote add origin <url>
- Connects your local repository to a remote server
- Replace
<url>
with the URL of your remote repository (e.g., from GitHub, GitLab, etc.) - Best practice: Use HTTPS URLs for easier authentication, or SSH if you have it set up
Example:
git remote add origin https://github.com/username/repo.git
git commit -am "Initial commit"
- Stages and commits all tracked files with a commit message in one step
- The
-a
flag stages all modified files, and-m
allows you to provide a commit message - Best practice: Make your initial commit message descriptive of the project’s starting point
Example:
git commit -am "Initial commit: Project structure and README"
git push -u origin main
- Pushes the main branch to the remote and sets upstream tracking
- This establishes a link between your local and remote branches for future pushes
- Note: Some repositories use
master
instead ofmain
. Adjust accordingly.
Example:
git push -u origin main
Pro tip: After this, you can simply use
git push
for subsequent pushes to this branch.
Working with Branches
Effective branching strategies are crucial for organized development and smooth collaboration:
git branch -a
- Lists all branches, including remote branches
- Helps you keep track of existing branches in your project
- The current branch is usually highlighted or marked with an asterisk
Example output:
* main feature/user-authentication remotes/origin/main remotes/origin/feature/payment-gateway
git checkout -b feature/new-feature
- Creates and switches to a new branch for your feature
- Combines
git branch
andgit checkout
into one command - Best practice: Use descriptive branch names, prefixed with the type of change (e.g., feature/, bugfix/, hotfix/)
Example:
git checkout -b feature/user-profile
git push -u origin feature/new-feature
- Pushes the new branch to the remote and sets upstream for future pushes
- Ensures your feature branch is backed up and accessible to collaborators
- The
-u
flag sets up tracking, allowing you to usegit pull
without arguments in the future
Example:
git push -u origin feature/user-profile
git branch -d feature/old-feature
- Deletes a local branch after merging it
- Use
-D
instead of-d
to force delete an unmerged branch - Best practice: Clean up old branches regularly to keep your repository tidy
Example:
git branch -d feature/completed-feature
Pro tip: To delete a remote branch, use:
git push origin --delete feature/old-feature
Handling Changes
Efficiently managing your changes is crucial for maintaining a clean project history:
git add -p
- Stages changes interactively, allowing selection of specific hunks
- Useful for creating more granular, focused commits
- Responds to prompts:
y
(yes),n
(no),s
(split),e
(edit), etc.
Example workflow:
git add -p # Review each change and decide whether to stage it git commit -m "Update user model and fix validation bug"
git commit --amend
- Modifies the most recent commit, updating the message or adding changes
- Helpful for fixing small mistakes or improving commit messages
- Caution: Don’t amend commits that have been pushed to a shared repository
Example:
git commit --amend -m "Refactor user authentication and add unit tests"
git reset --hard HEAD~2
- Rolls back the last two commits, discarding changes locally
- Use with caution as this operation is destructive and cannot be undone
- Best used for local cleanup before pushing
Example:
git reset --hard HEAD~2 # This will discard the last two commits and all changes
git stash push -m "Work in progress"
- Stashes current changes with a custom description
- Useful for quickly switching contexts without committing incomplete work
Example:
git stash push -m "Half-implemented payment feature" git checkout main # Do some other work git checkout feature/payments git stash pop
Collaboration
Smooth collaboration is essential in team environments:
git fetch origin
- Fetches changes from the remote without merging them
- Allows you to see what’s changed before integrating updates
- Best practice: Fetch regularly to stay updated with remote changes
Example:
git fetch origin git log --oneline main..origin/main # This shows commits that exist in origin/main but not in your local main
git merge origin/main
- Merges changes from the remote’s main branch into the current branch
- Typically used after
git fetch
to integrate upstream changes
Example workflow:
git checkout feature/my-feature git fetch origin git merge origin/main # Resolve any merge conflicts if they occur
git rebase -i HEAD~3
- Interactively rebases the last 3 commits for a clean history
- Useful for squashing commits or reordering them before pushing
- Opens an editor where you can mark commits to squash, reword, edit, etc.
Example:
git rebase -i HEAD~3 # In the opened editor, change 'pick' to 'squash' for commits you want to combine
git cherry-pick <commit-hash>
- Applies a specific commit from another branch
- Helpful when you want to bring in isolated changes without merging entire branches
Example:
git cherry-pick 5f83c68 # This applies the changes from commit 5f83c68 to your current branch
History and Tracking
Understanding your project’s history is crucial for debugging and code review:
git log --oneline --graph --decorate --all
- Displays commit history as a compact, visual graph
- Gives a clear overview of branch structure and merge history
Example output:
* 5f83c68 (HEAD -> main, origin/main) Merge pull request #123 || * 2e3d4f5 Add new payment gateway | * 1a2b3c4 Update user model |/ * 6789abc Refactor authentication system
git diff HEAD^ HEAD
- Shows the changes introduced by the last commit
- Useful for quick code reviews or verifying recent changes
Example:
git diff HEAD^ HEAD # This will show the diff of the last commit
git blame <file> -L 10,20
- Shows who last changed lines 10 to 20 in a file
- Helpful for understanding code evolution and identifying experts for specific code sections
Example:
git blame app/models/user.rb -L 10,20 # This will show who last modified lines 10-20 in the user.rb file
Managing Tags
Tags are essential for marking release points:
git tag -a v1.0.0 -m "Version 1.0 release"
- Creates an annotated tag for release with a description
- Use semantic versioning for clear communication of release significance
Example:
git tag -a v1.0.0 -m "First stable release with core features implemented"
git push origin v1.0.0
- Pushes the tag to the remote repository
- Ensures release points are shared with the team and available for deployment
Example:
git push origin v1.0.0 # To push all tags at once: git push origin --tags
Handling Remotes
Managing connections to remote repositories is important for collaboration:
git remote -v
- Lists all configured remote repositories with their URLs
- Useful for verifying your remote connections
Example output:
origin https://github.com/username/repo.git (fetch) origin https://github.com/username/repo.git (push) upstream https://github.com/original-owner/repo.git (fetch) upstream https://github.com/original-owner/repo.git (push)
git fetch --all --prune
- Fetches changes from all remotes and prunes stale branches
- Keeps your local repository up-to-date with all remote changes
Example:
git fetch --all --prune # This will update all remote branches and remove any that no longer exist on the remote
Undoing Changes
Sometimes you need to revert changes or go back to a previous state:
git reset --soft HEAD~1
- Reverts the last commit but keeps changes staged for re-commit
- Useful when you want to restructure your last commit
Example:
git reset --soft HEAD~1 # Make changes, stage them git commit -m "Restructured previous commit with additional changes"
git checkout -- <file>
- Reverts local changes in a file to the last commit
- Helpful for discarding unwanted modifications in a specific file
Example:
git checkout -- app/models/user.rb # This will discard all uncommitted changes in user.rb
Advanced Git Techniques
To truly use Git like a pro, consider these advanced techniques:
Git Hooks
- Scripts that run automatically on certain Git events
- Useful for enforcing coding standards, running tests, etc.
- Example: Create a pre-commit hook to run linters
Git Submodules
- Allow you to keep a Git repository as a subdirectory of another Git repository
- Useful for including external libraries or shared components
- Example:
git submodule add https://github.com/example/library.git external/library
Git Worktrees
- Manage multiple working trees attached to the same repository
- Useful for working on different branches simultaneously without switching
- Example:
git worktree add -b hotfix/critical-bug ../hotfix main
Git Bisect
- Binary search through your commit history to find the commit that introduced a bug
- Example:
git bisect start git bisect bad # Current version is bad git bisect good v1.0.0 # Last known good version # Git will checkout commits for you to test git bisect good # or git bisect bad, depending on your test # Repeat until the culprit is found git bisect reset # to end the bisect session
By mastering these Git commands and techniques, you’ll be able to manage your projects more efficiently, collaborate more effectively with your team, and maintain a clean, organized codebase. Remember, practice is key to becoming proficient with Git, so don’t hesitate to experiment in a safe environment as you learn.
Pro tip: Consider setting up aliases for commonly used Git commands to speed up your workflow. For example, you could add these to your .gitconfig
file:
[alias]
co = checkout
br = branch
ci = commit
st = status
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk
This allows you to use shortcuts like git co
instead of git checkout
, saving time and keystrokes.
Remember, Git is a powerful tool, and with great power comes great responsibility. Always think before you push, especially when working with shared branches. Happy coding!
Cheers,
Sim