Skip to content

Instantly share code, notes, and snippets.

@brightzheng100
Last active March 1, 2021 02:34
Show Gist options
  • Save brightzheng100/f69e32438e7be4d2206400eccc44c0dd to your computer and use it in GitHub Desktop.
Save brightzheng100/f69e32438e7be4d2206400eccc44c0dd to your computer and use it in GitHub Desktop.
Git Tips

It's common that we use business email to commit for work while using personal email to commit for OSS.

You can configure an individual repo to use a specific user / email address which overrides the global configuration.

Let say we want to make the OSS commits as default, do this:

From the root of the repo, run

git config user.name "Your biz name here"
git config user.email your@bizemail.com

Note: this will update the project's .git/config with above config

whereas the default user / email is configured in your ~/.gitconfig

git config --global user.name "Your default name Here"
git config --global user.email your@personalemail.com

Another way is to use includeIf:

For example:

$ cat > ~/.gitconfig.biz <<EOF
[user]
	name = BIZ NAME
	email = your@bizemail.com
EOF

$ cat > ~/.gitconfig.personal <<EOF
[user]
	name = PERSONAL NAME
	email = your@personalemail.com
EOF

$ cat > ~/.gitconfig <<EOF
[includeIf "gitdir:~/path-to-personal-projects"]
        path = ~/.gitconfig.personal
[includeIf "gitdir:~/path-to-biz-projects"]
        path = ~/.gitconfig.biz
[credential]
	helper = osxkeychain
EOF

Typical GitHub PR Workflow

Contributor: from forking to submitting PRs

Fork it to our own namespace

First of all, fork the upstream repo that you want to collaborate with, through GitHub UI.

Let's assume the upstream is: https://github.com/the-org/the-repo.git.

And let's assume I'm the one who forks it so this repo will be forked into my namespace, which is brightzheng100, as:

# Let's export some variables to make later commands generic
export NAMESPACE_UPSTREAM=the-org
export NAMESPACE_MINE=brightzheng100
export REPO_NAME=the-repo

Clone it back to our local workspace

Remember to clone it back by using git protocol, instead of https, so that it's updatable.

$ git clone git@github.com:$NAMESPACE_MINE/$REPO_NAME.git

Keep your fork up to date

It's recommended to add a "remote" pointing to the original "upstream":

$ git remote add upstream https://github.com/$NAMESPACE_UPSTREAM/$REPO_NAME.git

# Verify the remotes
$ git remote -v
origin	git@github.com:$NAMESPACE_MINE/$REPO_NAME.git (fetch)
origin	git@github.com:$NAMESPACE_MINE/$REPO_NAME.git (push)
upstream	https://github.com/$NAMESPACE_UPSTREAM/$REPO_NAME.git (fetch)
upstream	https://github.com/$NAMESPACE_UPSTREAM/$REPO_NAME.git (push)

Sync up upstream changes

Whenever you want to update your fork with the latest upstream changes:

# Fetch from upstream
git fetch upstream

# View all branches, including those from upstream
git branch -va

# Checkout your master branch and merge upstream
git checkout master
git merge upstream/master

Working on it

Create a branch when trying to contribute

Whenever you begin work on a new feature or bugfix, it's important that you create a new branch.

Not only is it proper git workflow, but it also keeps your changes organized and separated from the master branch so that you can easily submit and manage multiple pull requests for every task you complete.

To create a new branch and start working on it:

# Checkout the master branch - you want your new branch to come from master
git checkout master

# Create a new branch named say add-xxx-feature -- please be informative enough, and check out to it
git branch -b add-xxx-feature

Now start hacking away and making whatever changes you want to in this branch

Rebase before submitting a Pull Request

Always rebase your development branch so that merging it will be a simple fast-forward that won't require any conflict resolution work.

# Fetch upstream master
git fetch upstream

# Merge with your repo's master branch
git checkout master
git merge upstream/master

# Rebase your development branch
git checkout add-xxx-feature
git rebase master

Squash your commits if required

It may be desirable to squash some of your smaller commits down into a small number of larger more cohesive commits.

You can do this with an interactive rebase process:

# Rebase all commits on your development branch
git checkout add-xxx-feature
git rebase -i master

This will open up a text editor where you can specify which commits to squash.

Tips: to perform an interactive rebase of only the last 3 commits: git rebase -i HEAD~3

There are a couple of options that we can perform, but please remember some important ones:

  • pick is to continue to pick the commit as is
  • reword is to use the commit but change the commit message
  • squash is to squash the commit so the content will be merged into previous one but the commit will be deleted
  • fixup is like squash but discard the commit's log message

For example:

  1. Squash two commits:

Change:

pick 1234 Add something
pick 5678 Edit something

To:

pick 1234 Add something
squash 5678 Edit something
  1. Once we save it, it will prompt up for new commit message:
Add something
Edit something

We now have the chance to enhance it with one message.

And do consider to use git push -f to force replace as they're diverged:

# Check out the logs
git log --grash --oneline --all -4
* r73943 (HEAD -> add-xxx-feature) Add something interesting
| * 47343r (origin -> add-xxx-feature) Edit something
| * 4r9384 Add something
|/
43794d (origin/master origin/HEAD, master) add other stuff

# Force push
git push -f

Submit the work as a Pull Request

Once you've committed and pushed all of your changes to your GitHub repo, go to the page for your fork on GitHub, select your development branch, and click the pull request button.

If you need to make any adjustments to your pull request, just push the updates to GitHub: Your pull request will automatically track the changes on your development branch and update.

Continue to Squash your commits if required step if you want to further squash the commits.

Upstream Owner: accepting and merging a Pull Request

Check out and test the PRs

Open the .git/config file and add a new line under [remote "origin"], like this:

[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://github.com/$NAMESPACE_UPSTREAM/$REPO_NAME.git
	fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/pull/origin/*                   # <-- newly added
[branch "main"]
	remote = origin
	merge = refs/heads/main

Now you can fetch and checkout any pull request so that you can test them:

# Fetch all pull request branches
git fetch origin

# Checkout out a given pull request branch based on its PR number
git checkout -b pr-123 pull/origin/123

Keep in mind that these branches will be read only and you won't be able to push any changes.

Automatically merge a Pull Request

In cases where the merge would be a simple fast-forward, you can automatically do the merge by just clicking the button on the pull request page on GitHub.

Manually merge a Pull Request

To do the merge manually, you'll need to checkout the target branch in the source repo, pull directly from the fork, and then merge and push.

# Checkout the branch you're merging to in the target/upstream repo
git checkout master

# Pull the development branch from the fork repo where the pull request development was done
git pull https://github.com/$NAMESPACE_MINE/$REPO_NAME.git add-xxx-feature

# Merge the development branch
git merge add-xxx-feature

Do take care of the conflicts if there are any

Push it to upstream repo

# Push master with the new feature merged into it
git push origin master

Clean up

Now that you're done with the development branch, you're free to delete it.

git branch -d add-xxx-feature

References

Chaser324/GitHub-Forking.md

Google's training series: Introduction to Git and GitHub

Merging vs. Rebasing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment