Skip to content

Commit 7885733

Browse files
committed
Add a section on using git.
This section addresses the biggest issues that new contributors, especially those with limited familiarity with git, are likely to face. This is still a WIP. Thanks to jyn for the recommended improvements!
1 parent 4470641 commit 7885733

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed

src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
- [About the compiler team](./compiler-team.md)
3434
- [Mastering @rustbot](./rustbot.md)
3535
- [Walkthrough: a typical contribution](./walkthrough.md)
36+
- [Using git](./git.md)
3637
- [Bug Fix Procedure](./bug-fix-procedure.md)
3738
- [Implementing new features](./implementing_new_features.md)
3839
- [Stability attributes](./stability.md)

src/git.md

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Using git
2+
3+
The Rust project uses [git] to manage its source code. In order to
4+
contribute, you'll need some familiarity with its features so that your changes
5+
can be incorporated into the compiler.
6+
7+
[git]: https://git-scm.com
8+
9+
The goal of this page is to cover some of the more common questions and
10+
problems new contributors face. Although some git basics will be covered here,
11+
if you have never used git or GitHub before you may find that this is still a
12+
little too fast for you. In that case, it would make sense to first read some
13+
introductions to git, such as the Beginner and Getting started sections of
14+
[this tutorial from Atlassian][atlassian-git]. GitHub also provides
15+
[documentation] and [guides] for beginners.
16+
17+
[atlassian-git]: https://www.atlassian.com/git/tutorials/what-is-version-control
18+
[documentation]: https://docs.github.com/en/github/getting-started-with-github/set-up-git
19+
[guides]: https://guides.github.com/introduction/git-handbook/
20+
21+
Although this page should get you to a point where you can start contributing,
22+
learning more git is almost certainly a good use of your time if you want to
23+
keep contributing. There are many tutorials online for those folks that are
24+
newer which combine excellently with man pages and official documentation.
25+
26+
## Prequisites
27+
28+
We'll assume that you've installed git, forked [rust-lang/rust], and cloned the
29+
forked repo to your PC. We'll also use the command line interface to interact
30+
with git; there are also a number of GUIs and IDE integrations that can
31+
generally do the same things.
32+
33+
[rust-lang/rust]: https://github.com/rust-lang/rust
34+
35+
If you've cloned your fork, then you will be able to reference it with `origin`
36+
in your local repo. It may be helpful to also set up a remote for the official
37+
rust-lang/rust repo via
38+
39+
```sh
40+
git remote add rust https://github.com/rust-lang/rust.git
41+
```
42+
43+
if you're using HTTPS, or
44+
45+
```sh
46+
git remote add rust [email protected]:rust-lang/rust.git
47+
```
48+
49+
if you're using SSH.
50+
51+
## Standard Process
52+
53+
Below is the normal procedure that you're likely to use for most minor changes
54+
and PRs:
55+
56+
1. Ensure that you're making your changes on top of master:
57+
`git checkout master`.
58+
2. Get the latest changes from the Rust repo: `git pull rust master`.
59+
3. Make a new branch for your change: `git checkout -b issue-12345-fix`.
60+
4. Make some changes to the repo and test them.
61+
5. Stage your changes via `git add src/changed/file.rs src/another/change.rs`
62+
and then commit them with `git commit`. Of course, making intermediate commits
63+
may be a good idea as well. Avoid `git add .`, as it makes it too easy to
64+
unintentionally commit changes that should not be committed, such as submodule
65+
updates. You can use `git status` to check if there are any files you forgot
66+
to stage.
67+
6. Push your changes to your fork: `git push -u origin issue-12345-fix`.
68+
7. [Open a PR][ghpullrequest] from your fork to rust-lang/rust's master branch.
69+
70+
[ghpullrequest]: https://guides.github.com/activities/forking/#making-a-pull-request
71+
72+
If your reviewer requests changes, the procedure for those changes looks much
73+
the same, with some steps skipped:
74+
75+
1. Ensure that you're making changes to the most recent version of your code:
76+
`git checkout issue-12345-fix`.
77+
2. Make, stage, and commit your additional changes just like before.
78+
3. Push those changes to your fork: `git push`.
79+
80+
## Conflicts
81+
82+
When you edit your code locally, you are making changes to the version of
83+
rust-lang/rust that existed the last time you ran `git pull rust master` on
84+
your master branch. As such, when you submit your PR it is possible that some
85+
of the changes that have been made to rust-lang/rust since then are in conflict
86+
with the changes you've made; maybe someone else changed the same lines of
87+
code, or git cannot figure out how to merge your changes with the others for
88+
another reason.
89+
90+
When this happens, you need to resolve the conflicts before your changes can be
91+
merged. First, get a local copy of the conflicting changes. Checkout your local
92+
master branch with `git checkout master`. Then, `git pull rust master` to
93+
update it with the most recent changes.
94+
95+
### Rebasing
96+
97+
You're now ready to start the rebasing process. Check out the branch with your
98+
changes, and then execute `git rebase master`.
99+
100+
First, a little background: In git, commits are stored as "diffs" which are a
101+
record of all the changes that a commit made to its parent. When you rebase a
102+
branch, all the changes in the commits on that branch are reapplied on the
103+
branch you are rebasing on top of (in this case master). In other words, git
104+
tries to pretend that the changes you made to the old version of master were
105+
instead made to the new version of master.
106+
107+
During rebasing, you should expect to encounter at least one "rebase conflict."
108+
This happens when git's attempt to reapply the changes onto the more recent
109+
version of master fails because your changes conflicted with other changes that
110+
have been made since then. You can tell that this happened because you'll see
111+
lines in the output that look like
112+
113+
```
114+
CONFLICT (content): Merge conflict in file.rs
115+
```
116+
117+
When you open these files, you'll see sections of the form
118+
119+
```
120+
<<<<<<< HEAD
121+
Original code
122+
=======
123+
Your code
124+
>>>>>>> 8fbf656... Commit fixes 12345
125+
```
126+
127+
This represents the lines in the file that git could not figure out how to
128+
rebase. The section between `<<<<<<< HEAD` and `=======` has the code from
129+
master, while the other side has your version of the code. You'll need to
130+
decide how to deal with the conflict. You may want to keep your changes,
131+
keep the changes on master, or combine the two.
132+
133+
Generally, resovling the conflict consists of two steps: First, fix the
134+
particular conflict. Edit the file to make the changes you want and remove the
135+
`<<<<<<<`, `=======` and `>>>>>>>` lines in the process. Second, check the
136+
surrounding code. If there was a conflict, its because someone else changed the
137+
same code you did. That means its likely there are some logical errors lying
138+
around too!
139+
140+
Once you're all done fixing the conflicts, you need to stage the files that had
141+
conflicts in them via `git add`. Afterwards, run `git rebase --continue` to let
142+
git know that you've resolved the conflicts and it should finish the rebase.
143+
Finally, once the rebase has succeeded, you'll want to update the associated
144+
branch on your fork with `git push -f`.
145+
146+
Note that `git push` will not work properly and say something like this:
147+
148+
```
149+
! [rejected] issue-xxxxx -> issue-xxxxx (non-fast-forward)
150+
error: failed to push some refs to 'https://github.com/username/rust.git'
151+
hint: Updates were rejected because the tip of your current branch is behind
152+
hint: its remote counterpart. Integrate the remote changes (e.g.
153+
hint: 'git pull ...') before pushing again.
154+
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
155+
```
156+
157+
The advice this gives is incorrect! Because of the "no-merge" policy, running
158+
`git pull` will create a merge commit, defeating the point of your rebase. Use
159+
`git push -f` instead.
160+
161+
## Advanced Rebasing
162+
163+
Sometimes, you may want to perform a more complicated rebase. There are two
164+
common scenarios that might call for this.
165+
166+
If your branch contains multiple consecutive rewrites of the same code, or if
167+
the rebase conflicts are extremely severe, it is possible that just trying to
168+
reapply the changes you made on top of the updated code will be too much of a
169+
headache. In this case, you can use the interactive rebase feature via
170+
`git rebase -i master` to gain more control over the process. This allows you
171+
to choose to skip commits because they represent changes you no longer need,
172+
edit the commits that you do not skip, or change the order in which they are
173+
applied.
174+
175+
The other common scenario is if you are asked to or want to "squash" multiple
176+
commits into each other. The most common example of this is likely if you
177+
forgot to run `x.py tidy` before committing. Your PR will need to be revised,
178+
but a single commit at the end with message "fixup tidy issue" is usually
179+
unhelpful, and it is easier for everyone else if you combine that commit with
180+
another that has a more meaningful commit message. In this case, you'll want to
181+
run `git rebase -i HEAD~2` to edit the last two commits and merge them
182+
together. Essentially, this reapplies the last two commits on top of your
183+
current branch; this is of course a no-op, since that is where they are
184+
already. However, by selecting the `-i` option, you give yourself the
185+
opportunity to edit the rebase first, just like before. This way you can
186+
request to have the most recent commit squashed into its parent.
187+
188+
## No-Merge Policy
189+
190+
The rust-lang/rust repo uses what is known as a "rebase workflow." This means
191+
that merge commits in PRs are not accepted. As a result, if you are running
192+
`git merge` locally, chances are good that you should be rebasing instead. Of
193+
course, this is not always true; if your merge will just be a fast-forward,
194+
like the merges that `git pull` usually performs, then no merge commit is
195+
created and you have nothing to worry about. Running `git config merge.ff only`
196+
once will prevent the creation of merge commits will help ensure you don't make
197+
a mistake here.
198+
199+
There are a number of reasons for this decision and like all others, it is a
200+
tradeoff. The main advantage is the (mostly) linear commit history. This
201+
greatly simplifies bisecting. TODO: There are other advantages to a rebase
202+
workflow, but I would like to focus on the ones that people in the Rust project
203+
consider most relevant, so I'm going to leave this unfinished for now.

0 commit comments

Comments
 (0)