tl;dr: Branch off upstream/master. Don't commit to your local master.
If your branch has local changes and you just merge with upstream you'll still have those local changes. When you submit a PR based on this merged master it will contain those local changes.
Let's demonstrate. Here's what you look like after merging with local changes.
# Your situation after merging with local changes.
# D - E - F are new changes from upstream.
# 1 - 2 - 3 is your local changes.
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
Now you make a branch off master and add some commits.
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
\
4 - 5 - 6 [feature]
If you submit feature as a PR with upstream/master as the base, it will drag in 1 - 2 - 3 as well as 4 - 5 - 6, because those all contain differences from upstream/master.
This is why one avoids committing directly to master, you no longer have a common base for new branches. Instead, do all your work in branches and submit them as PRs.
The simplest and safest thing is to branch your work off upstream/master instead of master. Then it doesn't matter what state your fork is in.
$ git checkout -b feature upstream/master
# then make a few commits
4 - 5 - 6 [feature]
/
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
If you have an existing branch off master, rebase it onto upstream/master. This will rewrite each commit as if you'd written it on top of upstream/master. There may be conflicts, fix them as needed.
# Before with feature based on master.
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
\
4 - 5 - 6 [feature]
# Rebase onto upstream/master the commits from master to feature.
$ git rebase --onto upstream/master master feature
4A - 5A - 6A [feature]
/
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
\
4 - 5 - 6
The original 4 - 5 - 6 will eventually be deleted.
To restore your fork's master, return your master to your upstream's master.
First, make a new branch at your existing master to preserve any local changes.
$ git checkout master
$ git branch dev # or whatever you want to call it
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [master]
[dev]
Now any local changes you made to master will be preserved in your dev branch. You can call it anything you like, but avoid a branch name that already exists upstream.
Then move your local master to your upstream's master.
$ git checkout master
$ git reset --hard upstream/master
[master]
A - B - C - D - E - F [upstream/master]
\ \
1 - 2 - 3 - M [dev]
Branches in Git are just labels that point at commits. git reset is how you move them around as you like. This is moving your local master to where upstream/master is pointing. --hard refers to what to do about the staging area and checked out files (working copy). --hard says to also reset them to upstream/master.
Now your master is their upstream/master. dev has your local changes to master.
Finally, push your new local master up to origin. Since it moved it will have to be forced. Do not use --force use the safer git push --force-with-lease.
If you want to update your local master, simply git pull. A git pull is just a git fetch plus a git merge. We'll do a git pull as two separate steps to demonstrate.
# Fetch new commits, that's G and H.
$ git fetch upstream
G - H [upstream/master]
/
A - B - C - D - E - F [master]
\ \
1 - 2 - 3 - M [dev]
$ git checkout master
$ git merge upstream/master
[master]
G - H [upstream/master]
/
A - B - C - D - E - F
\ \
1 - 2 - 3 - M [dev]
Since master is a direct ancestor of upstream/master no merge commit is necessary. Git will "fast-forward" master to upstream/master.