Contributing to OSS Projects With Git Practices, Part 1

Overview
I'm a big fan of contributing back to the OSS community while learning and/or engaging OSS projects, which can be Concourse, MinIO, Kubernetes and more.
And Git will always play a big part of it, as a collaboration platform for issues and pull requests (PRs).
Here are some of the typical practices while learning and/or engaging OSS projects. And I may be continuously adding more and more such practices along the way, consolidating some of my learned/tried ones too.
So this can be a series, and this is just the part 1.
Note: The majority of the contents is originated from my gist: https://gist.github.com/brightzheng100/6993117dda82437ce1b31ba531a87daf
Adding upstream remote to our forked Git repos
Forking is always the first step before contributing.
And adding the upstream remote to our forked Git repos helps us keep in synced with upstream before any contribution.
Assuming we have forked the repo.
Now we clone our forked repo, with git
protocol:
1$ git clone git@github.com:YOUR-USERNAME/THE-REPO.git
See what remotes we have:
1$ git remote -vv
2origin git@github.com:YOUR-USERNAME/THE-REPO.git (fetch)
3origin git@github.com:YOUR-USERNAME/THE-REPO.git (push)
To add the upstream remote, with https
protocol:
1$ git remote add upstream https://github.com/UPSTREAM-NAMESPACE/THE-REPO.git
2$ git remote -vv
3origin git@github.com:YOUR-USERNAME/THE-REPO.git (fetch)
4origin git@github.com:YOUR-USERNAME/THE-REPO.git (push)
5upstream https://github.com/UPSTREAM-NAMESPACE/THE-REPO.git (fetch)
6upstream https://github.com/UPSTREAM-NAMESPACE/THE-REPO.git (push)
Syncing a fork with its upstream
- Fetch the branches and their respective commits from the upstream repository to Git's local database:
1$ git fetch upstream
- Check out your fork's local
master
branch:
1$ git checkout master
- Merge the updates from
upstream/master
into your localorigin/master
branch:
This syncs up your fork's local master
branch with the upstream repository upstream/master
, without losing your local changes.
1$ git merge upstream/master
- Push it to your fork:
1$ git push
Checking what's going to be pushed?
For a list of files to be pushed, run:
1$ git diff --stat --cached [remote/branch]
Contributing to a PR
It's ALWAYS recommended to start the contribution, a potential PR, with a dedicated new branch.
1# Start from synced origin/master
2$ git checkout master
3
4# Create a new local branch
5$ git checkout -b my-awesome-feature
6
7# ...work, work, work...
8
9# Add the work
10$ git add xxx
11
12# Commit it
13$ git commit -m "add my awesome feature" my-files
14
15# Push it as a remote branch
16$ git push origin my-awesome-feature
Then we can send it as a PR, through GitHub UI, between such a branch to desired upstream branch, which typically master
.
Contributing to multiple PRs
Multiple PRs are of course possible, simply with different branches.
Let's say we start our feature 1:
1$ git checkout master
2$ git checkout -b my-awesome-feature-1
3...work, work, work
4$ git add xxx
5$ git commit -am "add my-awesome-feature-1"
6$ git push origin my-awesome-feature-1
Then we can send it as a PR through GitHub UI.
While pending for further discussions and merging, you can start another feature 2 too:
1$ git checkout master
2$ git checkout -b my-awesome-feature-2
3...work, work, work
4$ git add xxx
5$ git commit -am "add my-awesome-feature-2"
6$ git push origin my-awesome-feature-2
So two features are relatively independent.
How to "rollback" some specific files?
You may have messed up some files and you want to "rollback" to the original:
1# To simply rollback that file
2$ git checkout that-file.ext
3
4# Or to rollback to some specific version
5$ git checkout master~2 that-file.ext
Resetting things if PR is not accepted?
It's also common if a PR is not accepted as there might be many reasons:
- There is already another ongoing PR which has covered what you're trying to achieve;
- Your PR is simply not good enough;
- The author / maintainer has different opinion compared to yours;
- etc.
This is okay and you may want to reset it in your fork after the PR has been closed.
If you've adopted PR-as-a-new-branch approach, you can simply remove the local and remote branch if you don't want to keep it -- or you simply do nothing and leave it there, for your future reference.
Let's say you want to remove it completely:
1# Delete the local branch
2$ git branch -d <branch_name>
3
4# Delete the remote branch
5$ git push --delete origin <branch_name>
Worse case might be: you were using master
, instead of a dedicated branch, while working on the new feature.
Do this in this case:
1# Fetch the upstream/master
2$ git fetch upstream
3
4# Check out to the origin/master
5$ git checkout master
6
7# Hard reset the origin/master to upstream/master
8$ git reset --hard upstream/master
9
10# Double check the logs
11$ git log --oneline
12
13# Force push to origin/master
14git push --force-with-lease origin master
Updating commit messages after pushing
If the message to be changed is for the latest commit to the repository, then the following commands are to be executed:
1git commit --amend -m "Updated message"
2
3# using --force is not recommended unless you are absolutely sure that no one else has cloned your repository after the latest commit.
4#git push --force repository-name branch-name
5# A safer alternative is to use:
6git push --force-with-lease repository-name branch-name
If the message needs to be amended is an older commit:
1# Use the git rebase -i HEAD~n command to display a list of the last n commits in your default text editor.
2git rebase -i HEAD~3
The list would be similiar to this:
1pick e499d83 c message
2pick 0c39032 b message
3pick f7fde41 a message
4
5# Rebase 9fdb3bd..f7fde4a onto 9fdb3bd
6#
7# Commands:
8# p, pick = use commit
9# r, reword = use commit, but edit the commit message
10# e, edit = use commit, but stop for amending
11# s, squash = use commit, but meld into previous commit
12# f, fixup = like "squash", but discard this commit's log message
13# x, exec = run command (the rest of the line) using shell
14#
15# These lines can be re- ordered; they are executed from top to
16bottom.
17...
Replace pick
with reword
before each commit message that needs to be changed:
1pick e499d83 updated c message
2reword 0c39032 updated b message
3reword f7fde41 updated a message
Save and close the commit list file.
Force push the amended commits:
1git push --force