provides [documentation] and [guides] for beginners, or you can consult the
more in depth [book from Git].
+This guide is incomplete. If you run into trouble with git that this page doesn't help with,
+please [open an issue] so we can document how to fix it.
+
+[open an issue]: https://github.com/rust-lang/rustc-dev-guide/issues/new
[book from Git]: https://git-scm.com/book/en/v2/
[atlassian-git]: https://www.atlassian.com/git/tutorials/what-is-version-control
[documentation]: https://docs.github.com/en/get-started/quickstart/set-up-git
1. Ensure that you're making your changes on top of master:
`git checkout master`.
2. Get the latest changes from the Rust repo: `git pull upstream master --ff-only`.
- (see [No-Merge Policy](#keeping-things-up-to-date) for more info about this).
+ (see [No-Merge Policy][no-merge-policy] for more info about this).
3. Make a new branch for your change: `git checkout -b issue-12345-fix`.
4. Make some changes to the repo and test them.
5. Stage your changes via `git add src/changed/file.rs src/another/change.rs`
If you end up needing to rebase and are hitting conflicts, see [Rebasing](#rebasing).
If you want to track upstream while working on long-running feature/issue, see
-[Keeping things up to date](#keeping-things-up-to-date).
+[Keeping things up to date][no-merge-policy].
If your reviewer requests changes, the procedure for those changes looks much
the same, with some steps skipped:
2. Make, stage, and commit your additional changes just like before.
3. Push those changes to your fork: `git push`.
+ [no-merge-policy]: #keeping-things-up-to-date
+
## Troubleshooting git issues
You don't need to clone `rust-lang/rust` from scratch if it's out of date!
the git state that don't require downloading the whole repository again.
Here are some common issues you might run into:
+### I made a merge commit by accident.
+
+Git has two ways to update your branch with the newest changes: merging and rebasing.
+Rust [uses rebasing][no-merge-policy]. If you make a merge commit, it's not too hard to fix:
+`git rebase -i upstream/master`.
+
+See [Rebasing](#rebasing) for more about rebasing.
+
### I deleted my fork on GitHub!
This is not a problem from git's perspective. If you run `git remote -v`,
```
$ git remote -v
-origin https://github.com//rust-lang/rust (fetch)
-origin https://github.com//rust-lang/rust (push)
-personal https://github.com/jyn514/rust (fetch)
-personal https://github.com/jyn514/rust (push)
+origin git@github.com:jyn514/rust.git (fetch)
+origin git@github.com:jyn514/rust.git (push)
+upstream https://github.com/rust-lang/rust (fetch)
+upstream https://github.com/rust-lang/rust (fetch)
```
If you renamed your fork, you can change the URL like this:
```console
-git remote set-url personal <URL>
+git remote set-url origin <URL>
```
where the `<URL>` is your new fork.
+### I changed a submodule by accident
+
+Usually people notice this when rustbot posts a comment on github that `cargo` has been modified:
+
+![rustbot submodule comment](./img/rustbot-submodules.png)
+
+You might also notice conflicts in the web UI:
+
+![conflict in src/tools/cargo](./img/submodule-conflicts.png)
+
+The most common cause is that you rebased after a change and ran `git add .` without first running
+`x.py` to update the submodules. Alternatively, you might have run `cargo fmt` instead of `x fmt`
+and modified files in a submodule, then committed the changes.
+
+To fix it, do the following things:
+
+1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo`
+2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~`
+ literally but replace `<my-commit>` with the output from step 1.
+3. Tell git to commit the changes: `git commit --fixup <my-commit>`
+4. Repeat steps 1-3 for all the submodules you modified.
+ - If you modified the submodule in several different commits, you will need to repeat steps 1-3
+ for each commit you modified. You'll know when to stop when the `git log` command shows a commit
+ that's not authored by you.
+5. Squash your changes into the existing commits: `git rebase --autosquash -i upstream/master`
+6. [Push your changes](#standard-process).
+
+### I see "error: cannot rebase" when I try to rebase
+
+These are two common errors to see when rebasing:
+```
+error: cannot rebase: Your index contains uncommitted changes.
+error: Please commit or stash them.
+```
+```
+error: cannot rebase: You have unstaged changes.
+error: Please commit or stash them.
+```
+
+(See https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F#_the_three_states for the difference between the two.)
+
+This means you have made changes since the last time you made a commit. To be able to rebase, either
+commit your changes, or make a temporary commit called a "stash" to have them still not be commited
+when you finish rebasing. You may want to configure git to make this "stash" automatically, which
+will prevent the "cannot rebase" error in nearly all cases:
+
+```
+git config --global rebase.autostash true
+```
+
+See https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning for more info about stashing.
+
### I see 'Untracked Files: src/stdarch'?
This is left over from the move to the `library/` directory.
git reset --hard master
```
+### Git is trying to rebase commits I didn't write?
+
+If you see many commits in your rebase list, or merge commits, or commits by other people that you
+didn't write, it likely means you're trying to rebase over the wrong branch. For example, you may
+have a `rust-lang/rust` remote `upstream`, but ran `git rebase origin/master` instead of `git rebase
+upstream/master`. The fix is to abort the rebase and use the correct branch instead:
+
+```
+git rebase --abort
+git rebase -i upstream/master
+```
+
+<details><summary>Click here to see an example of rebasing over the wrong branch</summary>
+
+![Interactive rebase over the wrong branch](img/other-peoples-commits.png)
+
+</details>
+
### Quick note about submodules
When updating your local repository with `git pull`, you may notice that sometimes
```
git checkout master
git pull upstream master --ff-only # to make certain there are no merge commits
-git checkout feature_branch
-git rebase master
-git push --force-with-lease (set origin to be the same as local)
+git rebase master feature_branch
+git push --force-with-lease # (set origin to be the same as local)
```
To avoid merges as per the [No-Merge Policy](#no-merge-policy), you may want to use
to ensure that Git doesn't create merge commits when `git pull`ing, without
needing to pass `--ff-only` or `--rebase` every time.
-You can also `git push --force-with-lease` from master to keep your origin's master in sync with
+You can also `git push --force-with-lease` from master to keep your fork's master in sync with
upstream.
## Advanced Rebasing
greatly simplifies bisecting and makes the history and commit log much easier
to follow and understand.
+## Tips for reviewing
+
+**NOTE**: This section is for *reviewing* PRs, not authoring them.
+
+### Hiding whitespace
+
+Github has a button for disabling whitespace changes that may be useful.
+You can also use `git diff -w origin/master` to view changes locally.
+
+![hide whitespace](./img/github-whitespace-changes.png)
+
+### Fetching PRs
+
+To checkout PRs locally, you can use `git fetch upstream pull/NNNNN/head && git checkout
+FETCH_HEAD`.
+
+You can also use github's cli tool. Github shows a button on PRs where you can copy-paste the
+command to check it out locally. See <https://cli.github.com/> for more info.
+
+![`gh` suggestion](./img/github-cli.png)
+
+### Moving large sections of code
+
+Git and Github's default diff view for large moves *within* a file is quite poor; it will show each
+line as deleted and each line as added, forcing you to compare each line yourself. Git has an option
+to show moved lines in a different color:
+
+```
+git log -p --color-moved=dimmed-zebra --color-moved-ws=allow-indentation-change
+```
+
+See [the docs for `--color-moved`](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---color-movedltmodegt) for more info.
+
+### range-diff
+
+See [the relevant section for PR authors](#git-range-diff). This can be useful for comparing code
+that was force-pushed to make sure there are no unexpected changes.
+
## Git submodules
**NOTE**: submodules are a nice thing to know about, but it *isn't* an absolute