An Advanced Guide to Git: Practical Tips and Best Practices

Even after using git for many years, it's common to encounter situations where certain operations are unclear or hard to remember. Sometimes, even if you know what to do, the infrequency of using certain features may cause hesitation, fearing that one wrong move could erase your existing changes. This article compiles some common but easily forgotten git operations to help you overcome these challenges.

⚠️ Note: This article is intended for readers who are already familiar with git. If you're new to git and need to learn the basics, please check out my "Git Beginner's Guide" first.

Table of Contents

Does Git Have a Undo Button? Can You Go Back After a Mistake?

Everyone makes mistakes, especially when using a powerful and flexible tool like git. A single misstep can lead to unintended consequences. Fortunately, git comes with a built-in "undo button," allowing us to revert errors and restore a previous state.

⚠️ Note: The following git reset --hard command will discard any uncommitted changes in your working directory. If you have any uncommitted modifications, make sure to stash them first using git stash, and then restore them afterward with git stash pop.

Steps:

# Show the complete git operation history (including reset, checkout, merge, etc.)
git reflog

# Find the commit before the mistake (using the commit hash from reflog) and reset
git reset --hard <commit-hash>

git reflog is a powerful command that keeps track of all HEAD movements in the repository, including deleted commits. This means that even if you mistakenly run git reset --hard or git rebase, which can overwrite history, you can often recover lost commits using reflog.

How to Delete All Commit History?

Deleting all commit history is not a common scenario, and it is not recommended for open-source projects with multiple collaborators. Even for personal projects, caution should be exercised. If your goal is to clean up part of your commit history, refer to this GitLab article: “How (and why!) to keep your Git commit history clean”.

⚠️ Note: Even after using this method to clear commit history, it is still theoretically possible to recover it. This is a deliberate design choice of git. If your goal is to permanently remove sensitive information that was accidentally committed, the best practice is to delete the repository and create a new one.

Steps:

# Create a new orphan branch
git checkout --orphan tmp_branch

# Add all files
git add -A

# Commit as the new initial commit
git commit -am "Initial commit"

# Delete the old master branch
git branch -D master

# Rename the current branch to master
git branch -m master

# Force push to the remote repository
git push -f origin master

After executing these steps, your repository will retain only a single fresh commit. It feels as refreshing as emptying the recycle bin! However, please proceed with caution.

How to Modify the Latest Commit?

Often, after making a commit, you may realize that some details need correction. Fortunately, git provides a convenient way to update the latest commit without adding a new commit entry.

Steps:

git add .  # Add changes
git commit --amend --no-edit  # Amend commit without changing the message

⚠️ Note: If this commit has already been pushed to a remote repository, using --amend will require a force push (git push --force), which could impact collaboration. Proceed with caution.

If you also want to modify the commit message, simply omit the --no-edit option:

git commit --amend

This will open the default text editor, allowing you to edit the commit message.

How to Reapply Your Commits After Significant Upstream Changes?

When contributing to open-source projects, you may encounter situations where the upstream repository has undergone significant changes, leaving your fork outdated. If your commits have not yet been pushed to a remote repository, instead of dealing with complex merge conflicts, you can simply reapply your commits on top of the latest upstream version.

Steps:

⚠️ Before proceeding, make a note of the commit hash you want to keep! If you forget, you can retrieve it using git reflog.

# Ensure you are on the branch where you want to retain commits
git checkout your-feature-branch

# Fetch the latest changes from upstream and reset your branch
# The upstream here is a remote we set up ourselves, and it can be replaced with any remote.
# Here, we assume that we want to update to the upstream master branch, but it can actually be any branch.
git fetch upstream
git reset --hard upstream/master

# Reapply your previous commit using its hash
git cherry-pick <your-modified-commit-hash>

# Force push the changes to your remote repository
git push --force

This method allows your commit to be neatly placed on top of the latest upstream commit without introducing unnecessary merge conflicts.

What to Do When You Need a Shared Repo?

One of the main use cases of git is collaborating with others on coding projects. People often rely on existing online services, but what if we want to create our own shared repo? In git, a bare repo is a repository without a working directory, typically used as a shared remote repo. For example, when a team needs a central repository to synchronize their changes, they can set up a bare repo to serve as the remote repo.

Steps:

# Create a bare repository
git init --bare my_project.git

After execution, the my_project.git directory will contain HEAD, objects/, refs/, and other git-related files, but it will not have an actual working directory, meaning code cannot be edited directly.

Using it is straightforward—just treat it as a remote repo, and developers can interact with it using git clone or git push. For example:

# Push a local repo to the bare repository
git remote add origin /path/to/my_project.git
git push -u origin master

Since a bare repo lacks a working directory, you cannot directly perform operations like git commit or git checkout within it. This is why it is best suited as a remote repo rather than for daily development.

In team collaborations or self-hosted git servers, bare repos are a common architecture choice, enabling development teams to share code and manage version control more efficiently.

I hope these git techniques help you manage version control more efficiently! In git, there are often multiple ways to achieve the same goal, and different situations may call for different approaches. By applying these techniques flexibly, understanding the underlying principles, and thinking critically, you can truly harness the power of git and make version control more efficient and seamless! (^u^)