]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc-dev-guide/src/git.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / git.md
1 # Using Git
2
3 <!-- toc -->
4
5 The Rust project uses [Git] to manage its source code. In order to
6 contribute, you'll need some familiarity with its features so that your changes
7 can be incorporated into the compiler.
8
9 [Git]: https://git-scm.com
10
11 The goal of this page is to cover some of the more common questions and
12 problems new contributors face. Although some Git basics will be covered here,
13 if you find that this is still a little too fast for you, it might make sense
14 to first read some introductions to Git, such as the Beginner and Getting
15 started sections of [this tutorial from Atlassian][atlassian-git]. GitHub also
16 provides [documentation] and [guides] for beginners, or you can consult the
17 more in depth [book from Git].
18
19 [book from Git]: https://git-scm.com/book/en/v2/
20 [atlassian-git]: https://www.atlassian.com/git/tutorials/what-is-version-control
21 [documentation]: https://docs.github.com/en/github/getting-started-with-github/set-up-git
22 [guides]: https://guides.github.com/introduction/git-handbook/
23
24 ## Prerequisites
25
26 We'll assume that you've installed Git, forked [rust-lang/rust], and cloned the
27 forked repo to your PC. We'll use the command line interface to interact
28 with Git; there are also a number of GUIs and IDE integrations that can
29 generally do the same things.
30
31 [rust-lang/rust]: https://github.com/rust-lang/rust
32
33 If you've cloned your fork, then you will be able to reference it with `origin`
34 in your local repo. It may be helpful to also set up a remote for the official
35 rust-lang/rust repo via
36
37 ```sh
38 git remote add upstream https://github.com/rust-lang/rust.git
39 ```
40
41 if you're using HTTPS, or
42
43 ```sh
44 git remote add upstream git@github.com:rust-lang/rust.git
45 ```
46
47 if you're using SSH.
48
49 ## Standard Process
50
51 Below is the normal procedure that you're likely to use for most minor changes
52 and PRs:
53
54 1. Ensure that you're making your changes on top of master:
55 `git checkout master`.
56 2. Get the latest changes from the Rust repo: `git pull upstream master`.
57 3. Make a new branch for your change: `git checkout -b issue-12345-fix`.
58 4. Make some changes to the repo and test them.
59 5. Stage your changes via `git add src/changed/file.rs src/another/change.rs`
60 and then commit them with `git commit`. Of course, making intermediate commits
61 may be a good idea as well. Avoid `git add .`, as it makes it too easy to
62 unintentionally commit changes that should not be committed, such as submodule
63 updates. You can use `git status` to check if there are any files you forgot
64 to stage.
65 6. Push your changes to your fork: `git push --set-upstream origin issue-12345-fix`.
66 7. [Open a PR][ghpullrequest] from your fork to rust-lang/rust's master branch.
67
68 [ghpullrequest]: https://guides.github.com/activities/forking/#making-a-pull-request
69
70 If your reviewer requests changes, the procedure for those changes looks much
71 the same, with some steps skipped:
72
73 1. Ensure that you're making changes to the most recent version of your code:
74 `git checkout issue-12345-fix`.
75 2. Make, stage, and commit your additional changes just like before.
76 3. Push those changes to your fork: `git push`.
77
78 ## Troubleshooting git issues
79
80 You don't need to clone `rust-lang/rust` from scratch if it's out of date!
81 Even if you think you've messed it up beyond repair, there are ways to fix
82 the git state that don't require downloading the whole repository again.
83 Here are some common issues you might run into:
84
85 ### I deleted my fork on GitHub!
86
87 This is not a problem from git's perspective. If you run `git remote -v`,
88 it will say something like this:
89
90 ```
91 $ git remote -v
92 origin https://github.com//rust-lang/rust (fetch)
93 origin https://github.com//rust-lang/rust (push)
94 personal https://github.com/jyn514/rust (fetch)
95 personal https://github.com/jyn514/rust (push)
96 ```
97
98 If you renamed your fork, you can change the URL like this:
99
100 ```console
101 git remote set-url personal <URL>
102 ```
103
104 where the `<URL>` is your new fork.
105
106 ### I see 'Untracked Files: src/stdarch'?
107
108 This is left over from the move to the `library/` directory.
109 Unfortunately, `git rebase` does not follow renames for submodules, so you
110 have to delete the directory yourself:
111
112 ```console
113 rm -r src/stdarch
114 ```
115
116 ### I see `<<< HEAD`?
117
118 You were probably in the middle of a rebase or merge conflict. See
119 [Conflicts](#conflicts) for how to fix the conflict. If you don't care about the changes
120 and just want to get a clean copy of the repository back, you can use `git reset`:
121
122 ```console
123 # WARNING: this throws out any local changes you've made! Consider resolving the conflicts instead.
124 git reset --hard master
125 ```
126
127 ### Quick note about submodules
128
129 When updating your local repository with `git pull`, you may notice that sometimes
130 Git says you have modified some files that you have never edited. For example,
131 running `git status` gives you something like (note the `new commits` mention):
132
133 ```
134 On branch master
135 Your branch is up to date with 'origin/master'.
136
137 Changes not staged for commit:
138 (use "git add <file>..." to update what will be committed)
139 (use "git restore <file>..." to discard changes in working directory)
140 modified: src/tools/cargo (new commits)
141 modified: src/tools/rls (new commits)
142 modified: src/tools/rustfmt (new commits)
143
144 no changes added to commit (use "git add" and/or "git commit -a")
145 ```
146
147 These changes are not changes to files: they are changes to submodules (more on
148 this [later](#git-submodules)). To get rid of those, run `git submodule update`
149 (or run any `x.py` command, which will automatically update the submodules).
150 Note that there is (as of <!-- date: 2021-01 --> January 2021) a bug if you use
151 worktrees, submodules, and x.py in a commit hook. If you run into an error
152 like:
153
154 ```
155 error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Cargo.toml`
156
157 Caused by:
158 No such file or directory (os error 2)
159 ```
160 it's not anything you did wrong. There is a workaround at [#77620].
161
162 [#77620]: https://github.com/rust-lang/rust/issues/77620#issuecomment-705228229
163
164 ## Conflicts
165
166 When you edit your code locally, you are making changes to the version of
167 rust-lang/rust that existed when you created your feature branch. As such, when
168 you submit your PR it is possible that some of the changes that have been made
169 to rust-lang/rust since then are in conflict with the changes you've made.
170
171 When this happens, you need to resolve the conflicts before your changes can be
172 merged. First, get a local copy of the conflicting changes: Checkout your local
173 master branch with `git checkout master`, then `git pull upstream master` to
174 update it with the most recent changes.
175
176 ### Rebasing
177
178 You're now ready to start the rebasing process. Checkout the branch with your
179 changes and execute `git rebase master`.
180
181 When you rebase a branch on master, all the changes on your branch are
182 reapplied to the most recent version of master. In other words, Git tries to
183 pretend that the changes you made to the old version of master were instead
184 made to the new version of master. During this process, you should expect to
185 encounter at least one "rebase conflict." This happens when Git's attempt to
186 reapply the changes fails because your changes conflicted with other changes
187 that have been made. You can tell that this happened because you'll see
188 lines in the output that look like
189
190 ```
191 CONFLICT (content): Merge conflict in file.rs
192 ```
193
194 When you open these files, you'll see sections of the form
195
196 ```
197 <<<<<<< HEAD
198 Original code
199 =======
200 Your code
201 >>>>>>> 8fbf656... Commit fixes 12345
202 ```
203
204 This represents the lines in the file that Git could not figure out how to
205 rebase. The section between `<<<<<<< HEAD` and `=======` has the code from
206 master, while the other side has your version of the code. You'll need to
207 decide how to deal with the conflict. You may want to keep your changes,
208 keep the changes on master, or combine the two.
209
210 Generally, resolving the conflict consists of two steps: First, fix the
211 particular conflict. Edit the file to make the changes you want and remove the
212 `<<<<<<<`, `=======` and `>>>>>>>` lines in the process. Second, check the
213 surrounding code. If there was a conflict, its likely there are some logical
214 errors lying around too! It's a good idea to run `x.py check` here to make sure
215 there are no glaring errors.
216
217 Once you're all done fixing the conflicts, you need to stage the files that had
218 conflicts in them via `git add`. Afterwards, run `git rebase --continue` to let
219 Git know that you've resolved the conflicts and it should finish the rebase.
220 Once the rebase has succeeded, you'll want to update the associated branch on
221 your fork with `git push --force-with-lease`.
222
223 Note that `git push` will not work properly and say something like this:
224
225 ```
226 ! [rejected] issue-xxxxx -> issue-xxxxx (non-fast-forward)
227 error: failed to push some refs to 'https://github.com/username/rust.git'
228 hint: Updates were rejected because the tip of your current branch is behind
229 hint: its remote counterpart. Integrate the remote changes (e.g.
230 hint: 'git pull ...') before pushing again.
231 hint: See the 'Note about fast-forwards' in 'git push --help' for details.
232 ```
233
234 The advice this gives is incorrect! Because of Rust's
235 ["no-merge" policy](#no-merge-policy) the merge commit created by `git pull`
236 will not be allowed in the final PR, in addition to defeating the point of the
237 rebase! Use `git push --force-with-lease` instead.
238
239 ## Advanced Rebasing
240
241 If your branch contains multiple consecutive rewrites of the same code, or if
242 the rebase conflicts are extremely severe, you can use
243 `git rebase --interactive master` to gain more control over the process. This
244 allows you to choose to skip commits, edit the commits that you do not skip,
245 change the order in which they are applied, or "squash" them into each other.
246
247 Alternatively, you can sacrifice the commit history like this:
248
249 ```
250 # squash all the changes into one commit so you only have to worry about conflicts once
251 git rebase -i $(git merge-base master HEAD) # and squash all changes along the way
252 git rebase master
253 # fix all merge conflicts
254 git rebase --continue
255 ```
256
257 "Squashing" commits into each other causes them to be merged into a single
258 commit. Both the upside and downside of this is that it simplifies the history.
259 On the one hand, you lose track of the steps in which changes were made, but
260 the history becomes easier to work with.
261
262 You also may want to squash just the last few commits together, possibly
263 because they only represent "fixups" and not real changes. For example,
264 `git rebase --interactive HEAD~2` will allow you to edit the two commits only.
265
266 ## No-Merge Policy
267
268 The rust-lang/rust repo uses what is known as a "rebase workflow." This means
269 that merge commits in PRs are not accepted. As a result, if you are running
270 `git merge` locally, chances are good that you should be rebasing instead. Of
271 course, this is not always true; if your merge will just be a fast-forward,
272 like the merges that `git pull` usually performs, then no merge commit is
273 created and you have nothing to worry about. Running `git config merge.ff only`
274 once will ensure that all the merges you perform are of this type, so that you
275 cannot make a mistake.
276
277 There are a number of reasons for this decision and like all others, it is a
278 tradeoff. The main advantage is the generally linear commit history. This
279 greatly simplifies bisecting and makes the history and commit log much easier
280 to follow and understand.
281
282 ## Git submodules
283
284 **NOTE**: submodules are a nice thing to know about, but it *isn't* an absolute
285 prerequisite to contribute to `rustc`. If you are using Git for the first time,
286 you might want to get used to the main concepts of Git before reading this section.
287
288 The `rust-lang/rust` repository uses [Git submodules] as a way to use other
289 Rust projects from within the `rust` repo. Examples include Rust's fork of
290 `llvm-project` and many devtools such as `cargo`, `rust-analyzer` and `rustfmt`.
291
292 Those projects are developped and maintained in an separate Git (and GitHub)
293 repository, and they have their own Git history/commits, issue tracker and PRs.
294 Submodules allow us to create some sort of embedded sub-repository inside the
295 `rust` repository and use them like they were directories in the `rust` repository.
296
297 Take `miri` for example. `miri` is maintained in the [`rust-lang/miri`] repository,
298 but it is used in `rust-lang/rust` by the compiler for const evaluation. We bring it
299 in `rust` as a submodule, in the `src/tools/miri` folder.
300
301 The contents of submodules are ignored by Git: submodules are in some sense isolated
302 from the rest of the repository. However, if you try to `cd src/tools/miri` and then
303 run `git status`:
304
305 ```
306 HEAD detached at 3fafb835
307 nothing to commit, working tree clean
308 ```
309
310 As far as git is concerned, you are no longer in the `rust` repo, but in the `miri` repo.
311 You will notice that we are in "detatched HEAD" state, i.e. not on a branch but on a
312 particular commit.
313
314 This is because, like any dependency, we want to be able to control which version to use.
315 Submodules allow us to do just that: every submodule is "pinned" to a certain
316 commit, which doesn't change unless modified manually. If you use `git checkout <commit>`
317 in the `miri` directory and go back to the `rust` directory, you can stage this
318 change like any other. This is usually done by the maintainers of the
319 project, and looks like [this][miri-update].
320
321 Git submodules take some time to get used to, so don't worry if it isn't perfectly
322 clear yet. You will rarely have to use them directly and, again, you don't need
323 to know everything about submodules to contribute to Rust. Just know that they
324 exist and that they correspond to some sort of embedded subrepository dependency
325 that Git can nicely and fairly conveniently handle for us.
326
327 [Git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
328 [`rust-toolstate`]: https://rust-lang-nursery.github.io/rust-toolstate/
329 [`rust-lang/miri`]: https://github.com/rust-lang/miri
330 [miri-update]: https://github.com/rust-lang/rust/pull/77500/files