-
Notifications
You must be signed in to change notification settings - Fork 529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add section on using git #890
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
# Using Git | ||
|
||
The Rust project uses [Git] to manage its source code. In order to | ||
contribute, you'll need some familiarity with its features so that your changes | ||
can be incorporated into the compiler. | ||
|
||
[Git]: https://git-scm.com | ||
|
||
The goal of this page is to cover some of the more common questions and | ||
problems new contributors face. Although some Git basics will be covered here, | ||
if you find that this is still a little too fast for you, it might make sense | ||
to first read some introductions to Git, such as the Beginner and Getting | ||
started sections of [this tutorial from Atlassian][atlassian-git]. GitHub also | ||
provides [documentation] and [guides] for beginners, or you can consult the | ||
more in depth [book from Git]. | ||
|
||
[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/github/getting-started-with-github/set-up-git | ||
[guides]: https://guides.github.com/introduction/git-handbook/ | ||
|
||
## Prequisites | ||
|
||
We'll assume that you've installed Git, forked [rust-lang/rust], and cloned the | ||
forked repo to your PC. We'll use the command line interface to interact | ||
with Git; there are also a number of GUIs and IDE integrations that can | ||
generally do the same things. | ||
|
||
[rust-lang/rust]: https://github.com/rust-lang/rust | ||
|
||
If you've cloned your fork, then you will be able to reference it with `origin` | ||
in your local repo. It may be helpful to also set up a remote for the official | ||
rust-lang/rust repo via | ||
|
||
```sh | ||
git remote add upstream https://github.com/rust-lang/rust.git | ||
``` | ||
|
||
if you're using HTTPS, or | ||
|
||
```sh | ||
git remote add upstream [email protected]:rust-lang/rust.git | ||
``` | ||
|
||
if you're using SSH. | ||
|
||
## Standard Process | ||
|
||
Below is the normal procedure that you're likely to use for most minor changes | ||
and PRs: | ||
|
||
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`. | ||
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` | ||
and then commit them with `git commit`. Of course, making intermediate commits | ||
may be a good idea as well. Avoid `git add .`, as it makes it too easy to | ||
unintentionally commit changes that should not be committed, such as submodule | ||
updates. You can use `git status` to check if there are any files you forgot | ||
to stage. | ||
6. Push your changes to your fork: `git push --set-upstream origin issue-12345-fix`. | ||
7. [Open a PR][ghpullrequest] from your fork to rust-lang/rust's master branch. | ||
|
||
[ghpullrequest]: https://guides.github.com/activities/forking/#making-a-pull-request | ||
|
||
If your reviewer requests changes, the procedure for those changes looks much | ||
the same, with some steps skipped: | ||
|
||
1. Ensure that you're making changes to the most recent version of your code: | ||
`git checkout issue-12345-fix`. | ||
2. Make, stage, and commit your additional changes just like before. | ||
3. Push those changes to your fork: `git push`. | ||
|
||
## Conflicts | ||
|
||
When you edit your code locally, you are making changes to the version of | ||
rust-lang/rust that existed when you created your feature branch. As such, when | ||
you submit your PR it is possible that some of the changes that have been made | ||
to rust-lang/rust since then are in conflict with the changes you've made. | ||
|
||
When this happens, you need to resolve the conflicts before your changes can be | ||
merged. First, get a local copy of the conflicting changes: Checkout your local | ||
master branch with `git checkout master`, then `git pull upstream master` to | ||
update it with the most recent changes. | ||
|
||
### Rebasing | ||
|
||
You're now ready to start the rebasing process. Checkout the branch with your | ||
changes and execute `git rebase master`. | ||
|
||
When you rebase a branch on master, all the changes on your branch are | ||
reapplied to the most recent version of master. In other words, Git tries to | ||
pretend that the changes you made to the old version of master were instead | ||
made to the new version of master. During this process, you should expect to | ||
encounter at least one "rebase conflict." This happens when Git's attempt to | ||
reapply the changes fails because your changes conflicted with other changes | ||
that have been made. You can tell that this happened because you'll see | ||
lines in the output that look like | ||
|
||
``` | ||
CONFLICT (content): Merge conflict in file.rs | ||
``` | ||
|
||
When you open these files, you'll see sections of the form | ||
|
||
``` | ||
<<<<<<< HEAD | ||
Original code | ||
======= | ||
Your code | ||
>>>>>>> 8fbf656... Commit fixes 12345 | ||
``` | ||
|
||
This represents the lines in the file that Git could not figure out how to | ||
rebase. The section between `<<<<<<< HEAD` and `=======` has the code from | ||
master, while the other side has your version of the code. You'll need to | ||
decide how to deal with the conflict. You may want to keep your changes, | ||
keep the changes on master, or combine the two. | ||
|
||
Generally, resolving the conflict consists of two steps: First, fix the | ||
particular conflict. Edit the file to make the changes you want and remove the | ||
`<<<<<<<`, `=======` and `>>>>>>>` lines in the process. Second, check the | ||
surrounding code. If there was a conflict, its likely there are some logical | ||
errors lying around too! It's a good idea to run `x.py check` here to make sure | ||
there are no glaring errors. | ||
|
||
Once you're all done fixing the conflicts, you need to stage the files that had | ||
conflicts in them via `git add`. Afterwards, run `git rebase --continue` to let | ||
Git know that you've resolved the conflicts and it should finish the rebase. | ||
Once the rebase has succeeded, you'll want to update the associated branch on | ||
your fork with `git push --force-with-lease`. | ||
|
||
Note that `git push` will not work properly and say something like this: | ||
|
||
``` | ||
! [rejected] issue-xxxxx -> issue-xxxxx (non-fast-forward) | ||
error: failed to push some refs to 'https://github.com/username/rust.git' | ||
hint: Updates were rejected because the tip of your current branch is behind | ||
hint: its remote counterpart. Integrate the remote changes (e.g. | ||
hint: 'git pull ...') before pushing again. | ||
hint: See the 'Note about fast-forwards' in 'git push --help' for details. | ||
``` | ||
|
||
The advice this gives is incorrect! Because of Rust's | ||
["no-merge" policy](#no-merge-policy) the merge commit created by `git pull` | ||
will not be allowed in the final PR, in addition to defeating the point of the | ||
rebase! Use `git push --force-with-lease` instead. | ||
|
||
## Advanced Rebasing | ||
|
||
If your branch contains multiple consecutive rewrites of the same code, or if | ||
the rebase conflicts are extremely severe, you can use | ||
`git rebase --interactive master` to gain more control over the process. This | ||
allows you to choose to skip commits, edit the commits that you do not skip, | ||
change the order in which they are applied, or "squash" them into each other. | ||
|
||
Alternatively, you can sacrifice the commit history like this: | ||
|
||
``` | ||
# squash all the changes into one commit so you only have to worry about conflicts once | ||
git rebase -i $(git merge-base master) # and squash all changes along the way | ||
git rebase master | ||
# fix all merge conflicts | ||
git rebase --continue | ||
``` | ||
|
||
"Squashing" commits into each other causes them to be merged into a single | ||
commit. Both the upside and downside of this is that it simplifies the history. | ||
On the one hand, you lose track of the steps in which changes were made, but | ||
the history becomes easier to work with. | ||
|
||
You also may want to squash just the last few commits together, possibly | ||
because they only represent "fixups" and not real changes. For example, | ||
`git rebase --interactive HEAD~2` will allow you to edit the two commits only. | ||
|
||
## No-Merge Policy | ||
|
||
The rust-lang/rust repo uses what is known as a "rebase workflow." This means | ||
that merge commits in PRs are not accepted. As a result, if you are running | ||
`git merge` locally, chances are good that you should be rebasing instead. Of | ||
course, this is not always true; if your merge will just be a fast-forward, | ||
like the merges that `git pull` usually performs, then no merge commit is | ||
created and you have nothing to worry about. Running `git config merge.ff only` | ||
once will ensure that all the merges you perform are of this type, so that you | ||
cannot make a mistake. | ||
|
||
There are a number of reasons for this decision and like all others, it is a | ||
tradeoff. The main advantage is the generally linear commit history. This | ||
greatly simplifies bisecting and makes the history and commit log much easier | ||
to follow and understand. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.