Git Workflows
This post documents the common git workflows when working in open source projects. Although it is still simplified, it is better than using "add-commit-push" workflow.
# Basic Concepts
There are 3 different regions in git:
- Remote: this is the remote repository
- Local: this is the local repository (stored in .git folder)
- Staging: this is a temporary region for uncommitted changes.
- Disk: this is the file system (physical files)
# Git Workflow
# Start from remote repository
Use git clone
to make a copy of the remote repository to your local.
git clone remote-main.git
Don't directly make changes to the main branch on the local. Instead, create a new branch.
git checkout -b 'my-feature'
Now all changes will be made to the "my-feature" branch.
# Make changes on local
After making changes to the local files. It is recommended to use git diff
to see what changes were made.
After that, use git add <my-change>
to add the changes to the staging area.
So far, all changes happened in the "Disk" region. My local git knows nothing about the changes.
To inform the local git about the change, use git commit
# Push changes to remote
Use git push
to add the new feature branch to the remote repository.
git push origin my-feature
What usually happens is that after you push the new branch, there are new updates to the main branch (on remote). To test to see if my-feature still works after the new update. First on the local repository, switch to the main branch:
git checkout main
At this time, the local main branch still knows nothing about the remote update. To sync the local main to remote main, use git pull origin main
Because we don't make any changes on our local mian, it shouldn't be problem to pull all updates
Now we go back to my-feature branch, we can use git rebase
to merge updates from main.
git rebase main
There will be a possibility that there is a rebase conflict. In such case, you will need to resolve the conflict manually.
After rebase, the "my-feature" branch on the local git has both the new added feature and the remote update. It's ready to update the remote "my-feature" again
Since I'm the only one working on the "my-feature" branch, I can use --force
push the new changes to remote my-feature
.
git push -f origin my-feature
# Pull feature branch to main branch
Pull request means ask the owner of the main branch to merge changes from "my-feature" to main. It is recommended to use "squash and merge". Lastly, we can clean up the feature branch. The feature branch will be deleted from the remote repository.
On the local git, we will first switch to the main branch
git checkout main
Now delete the local "my-feature" branch too:
git branch -D my-feature
Lastly, update the local main branch
git pull origin master
# Undo changes in Git
# Undo changes on disk
If a change hasn't been added to the staging area, (showing as red when git status
). Both of the following will undo the changed files.
git checkout <changed-file>
# or equivalently in newer version of git
git restore <changed-file>
# Undo changes in staging region
After git add
, the changed file will show as green. Use the following to undo the changes:
# only remove file out of staging
git reset <changed_file>
# or equivalently
git restore --staged <changed_file>
# to remove file out of staging AND undo changes
# HEAD represents the latest commit
git checkout HEAD <changed_file
# Undo changes after committing in local git
To retain the changes in the staging region, but undo the latest commit (also known as soft reset):
# ~1 means the previous commit
git reset --soft HEAD~1
To undo the previous commit, and remove the changed file out of staging region (also known as mixed reset):
git reset HEAD~1
To undo the previous commit and changes (also known as hard reset):
git reset --hard HEAD~1
The other way of undoing one or more commits is git revert
. Unlike git reset
, git revert
will add a new commit to revert the changes
The benefit of git revert
is it can revert any commit in the middle. And more importantly, git revert
can be used in a public branch.