]>
Commit | Line | Data |
---|---|---|
6a06907d XL |
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 | ||
9c376795 FG |
19 | This guide is incomplete. If you run into trouble with git that this page doesn't help with, |
20 | please [open an issue] so we can document how to fix it. | |
21 | ||
22 | [open an issue]: https://github.com/rust-lang/rustc-dev-guide/issues/new | |
6a06907d XL |
23 | [book from Git]: https://git-scm.com/book/en/v2/ |
24 | [atlassian-git]: https://www.atlassian.com/git/tutorials/what-is-version-control | |
923072b8 | 25 | [documentation]: https://docs.github.com/en/get-started/quickstart/set-up-git |
6a06907d XL |
26 | [guides]: https://guides.github.com/introduction/git-handbook/ |
27 | ||
28 | ## Prerequisites | |
29 | ||
30 | We'll assume that you've installed Git, forked [rust-lang/rust], and cloned the | |
31 | forked repo to your PC. We'll use the command line interface to interact | |
32 | with Git; there are also a number of GUIs and IDE integrations that can | |
33 | generally do the same things. | |
34 | ||
35 | [rust-lang/rust]: https://github.com/rust-lang/rust | |
36 | ||
37 | If you've cloned your fork, then you will be able to reference it with `origin` | |
38 | in your local repo. It may be helpful to also set up a remote for the official | |
39 | rust-lang/rust repo via | |
40 | ||
41 | ```sh | |
42 | git remote add upstream https://github.com/rust-lang/rust.git | |
43 | ``` | |
44 | ||
45 | if you're using HTTPS, or | |
46 | ||
47 | ```sh | |
48 | git remote add upstream git@github.com:rust-lang/rust.git | |
49 | ``` | |
50 | ||
51 | if you're using SSH. | |
52 | ||
136023e0 XL |
53 | **NOTE:** This page is dedicated to workflows for `rust-lang/rust`, but will likely be |
54 | useful when contributing to other repositories in the Rust project. | |
55 | ||
56 | ||
6a06907d XL |
57 | ## Standard Process |
58 | ||
59 | Below is the normal procedure that you're likely to use for most minor changes | |
60 | and PRs: | |
61 | ||
62 | 1. Ensure that you're making your changes on top of master: | |
63 | `git checkout master`. | |
136023e0 | 64 | 2. Get the latest changes from the Rust repo: `git pull upstream master --ff-only`. |
9c376795 | 65 | (see [No-Merge Policy][no-merge-policy] for more info about this). |
6a06907d XL |
66 | 3. Make a new branch for your change: `git checkout -b issue-12345-fix`. |
67 | 4. Make some changes to the repo and test them. | |
68 | 5. Stage your changes via `git add src/changed/file.rs src/another/change.rs` | |
69 | and then commit them with `git commit`. Of course, making intermediate commits | |
70 | may be a good idea as well. Avoid `git add .`, as it makes it too easy to | |
71 | unintentionally commit changes that should not be committed, such as submodule | |
72 | updates. You can use `git status` to check if there are any files you forgot | |
73 | to stage. | |
136023e0 XL |
74 | 6. Push your changes to your fork: `git push --set-upstream origin issue-12345-fix` |
75 | (After adding commits, you can use `git push` and after rebasing or | |
76 | pulling-and-rebasing, you can use `git push --force-with-lease`). | |
77 | 7. [Open a PR][ghpullrequest] from your fork to `rust-lang/rust`'s master branch. | |
6a06907d XL |
78 | |
79 | [ghpullrequest]: https://guides.github.com/activities/forking/#making-a-pull-request | |
80 | ||
136023e0 XL |
81 | If you end up needing to rebase and are hitting conflicts, see [Rebasing](#rebasing). |
82 | If you want to track upstream while working on long-running feature/issue, see | |
9c376795 | 83 | [Keeping things up to date][no-merge-policy]. |
136023e0 | 84 | |
6a06907d XL |
85 | If your reviewer requests changes, the procedure for those changes looks much |
86 | the same, with some steps skipped: | |
87 | ||
88 | 1. Ensure that you're making changes to the most recent version of your code: | |
89 | `git checkout issue-12345-fix`. | |
90 | 2. Make, stage, and commit your additional changes just like before. | |
91 | 3. Push those changes to your fork: `git push`. | |
92 | ||
9c376795 FG |
93 | [no-merge-policy]: #keeping-things-up-to-date |
94 | ||
6a06907d XL |
95 | ## Troubleshooting git issues |
96 | ||
97 | You don't need to clone `rust-lang/rust` from scratch if it's out of date! | |
98 | Even if you think you've messed it up beyond repair, there are ways to fix | |
99 | the git state that don't require downloading the whole repository again. | |
100 | Here are some common issues you might run into: | |
101 | ||
9c376795 FG |
102 | ### I made a merge commit by accident. |
103 | ||
104 | Git has two ways to update your branch with the newest changes: merging and rebasing. | |
105 | Rust [uses rebasing][no-merge-policy]. If you make a merge commit, it's not too hard to fix: | |
106 | `git rebase -i upstream/master`. | |
107 | ||
108 | See [Rebasing](#rebasing) for more about rebasing. | |
109 | ||
6a06907d XL |
110 | ### I deleted my fork on GitHub! |
111 | ||
112 | This is not a problem from git's perspective. If you run `git remote -v`, | |
113 | it will say something like this: | |
114 | ||
115 | ``` | |
116 | $ git remote -v | |
9c376795 FG |
117 | origin git@github.com:jyn514/rust.git (fetch) |
118 | origin git@github.com:jyn514/rust.git (push) | |
119 | upstream https://github.com/rust-lang/rust (fetch) | |
120 | upstream https://github.com/rust-lang/rust (fetch) | |
6a06907d XL |
121 | ``` |
122 | ||
123 | If you renamed your fork, you can change the URL like this: | |
124 | ||
125 | ```console | |
9c376795 | 126 | git remote set-url origin <URL> |
6a06907d XL |
127 | ``` |
128 | ||
129 | where the `<URL>` is your new fork. | |
130 | ||
9c376795 FG |
131 | ### I changed a submodule by accident |
132 | ||
133 | Usually people notice this when rustbot posts a comment on github that `cargo` has been modified: | |
134 | ||
135 | ![rustbot submodule comment](./img/rustbot-submodules.png) | |
136 | ||
137 | You might also notice conflicts in the web UI: | |
138 | ||
139 | ![conflict in src/tools/cargo](./img/submodule-conflicts.png) | |
140 | ||
141 | The most common cause is that you rebased after a change and ran `git add .` without first running | |
142 | `x.py` to update the submodules. Alternatively, you might have run `cargo fmt` instead of `x fmt` | |
143 | and modified files in a submodule, then committed the changes. | |
144 | ||
145 | To fix it, do the following things: | |
146 | ||
147 | 1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo` | |
148 | 2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~` | |
149 | literally but replace `<my-commit>` with the output from step 1. | |
150 | 3. Tell git to commit the changes: `git commit --fixup <my-commit>` | |
151 | 4. Repeat steps 1-3 for all the submodules you modified. | |
152 | - If you modified the submodule in several different commits, you will need to repeat steps 1-3 | |
153 | for each commit you modified. You'll know when to stop when the `git log` command shows a commit | |
154 | that's not authored by you. | |
155 | 5. Squash your changes into the existing commits: `git rebase --autosquash -i upstream/master` | |
156 | 6. [Push your changes](#standard-process). | |
157 | ||
158 | ### I see "error: cannot rebase" when I try to rebase | |
159 | ||
160 | These are two common errors to see when rebasing: | |
161 | ``` | |
162 | error: cannot rebase: Your index contains uncommitted changes. | |
163 | error: Please commit or stash them. | |
164 | ``` | |
165 | ``` | |
166 | error: cannot rebase: You have unstaged changes. | |
167 | error: Please commit or stash them. | |
168 | ``` | |
169 | ||
170 | (See https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F#_the_three_states for the difference between the two.) | |
171 | ||
172 | This means you have made changes since the last time you made a commit. To be able to rebase, either | |
173 | commit your changes, or make a temporary commit called a "stash" to have them still not be commited | |
174 | when you finish rebasing. You may want to configure git to make this "stash" automatically, which | |
175 | will prevent the "cannot rebase" error in nearly all cases: | |
176 | ||
177 | ``` | |
178 | git config --global rebase.autostash true | |
179 | ``` | |
180 | ||
181 | See https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning for more info about stashing. | |
182 | ||
6a06907d XL |
183 | ### I see 'Untracked Files: src/stdarch'? |
184 | ||
185 | This is left over from the move to the `library/` directory. | |
186 | Unfortunately, `git rebase` does not follow renames for submodules, so you | |
187 | have to delete the directory yourself: | |
188 | ||
189 | ```console | |
190 | rm -r src/stdarch | |
191 | ``` | |
192 | ||
193 | ### I see `<<< HEAD`? | |
194 | ||
195 | You were probably in the middle of a rebase or merge conflict. See | |
196 | [Conflicts](#conflicts) for how to fix the conflict. If you don't care about the changes | |
197 | and just want to get a clean copy of the repository back, you can use `git reset`: | |
198 | ||
199 | ```console | |
200 | # WARNING: this throws out any local changes you've made! Consider resolving the conflicts instead. | |
201 | git reset --hard master | |
202 | ``` | |
203 | ||
9c376795 FG |
204 | ### Git is trying to rebase commits I didn't write? |
205 | ||
206 | If you see many commits in your rebase list, or merge commits, or commits by other people that you | |
207 | didn't write, it likely means you're trying to rebase over the wrong branch. For example, you may | |
208 | have a `rust-lang/rust` remote `upstream`, but ran `git rebase origin/master` instead of `git rebase | |
209 | upstream/master`. The fix is to abort the rebase and use the correct branch instead: | |
210 | ||
211 | ``` | |
212 | git rebase --abort | |
213 | git rebase -i upstream/master | |
214 | ``` | |
215 | ||
216 | <details><summary>Click here to see an example of rebasing over the wrong branch</summary> | |
217 | ||
218 | ![Interactive rebase over the wrong branch](img/other-peoples-commits.png) | |
219 | ||
220 | </details> | |
221 | ||
6a06907d XL |
222 | ### Quick note about submodules |
223 | ||
224 | When updating your local repository with `git pull`, you may notice that sometimes | |
225 | Git says you have modified some files that you have never edited. For example, | |
226 | running `git status` gives you something like (note the `new commits` mention): | |
227 | ||
228 | ``` | |
229 | On branch master | |
230 | Your branch is up to date with 'origin/master'. | |
231 | ||
232 | Changes not staged for commit: | |
233 | (use "git add <file>..." to update what will be committed) | |
234 | (use "git restore <file>..." to discard changes in working directory) | |
2b03887a | 235 | modified: src/llvm-project (new commits) |
6a06907d | 236 | modified: src/tools/cargo (new commits) |
6a06907d XL |
237 | |
238 | no changes added to commit (use "git add" and/or "git commit -a") | |
239 | ``` | |
240 | ||
9ffffee4 FG |
241 | These changes are not changes to files: they are changes to submodules (more on this |
242 | [later](#git-submodules)). To get rid of those, run `./x.py --help`, which will automatically update | |
243 | the submodules. | |
244 | ||
245 | Some submodules are not actually needed; for example, `src/llvm-project` doesn't need to be checked | |
246 | out if you're using `download-ci-llvm`. To avoid having to keep fetching its history, you can use | |
247 | `git submodule deinit -f src/llvm-project`, which will also avoid it showing as modified again. | |
248 | ||
249 | Note that, as of <!-- date-check --> Aug 2022, | |
f2b60f7d FG |
250 | there is a [bug][#77620] if you use worktrees, |
251 | submodules, and `x.py` in a commit hook. | |
252 | If you run into an error like the following, | |
253 | it's not anything you did wrong: | |
6a06907d XL |
254 | |
255 | ``` | |
9ffffee4 | 256 | error: failed to read `/home/jyn/rustc-worktree/src/tools/cargo/Cargo.toml` |
6a06907d XL |
257 | |
258 | Caused by: | |
259 | No such file or directory (os error 2) | |
260 | ``` | |
f2b60f7d FG |
261 | |
262 | There is a workaround in [the issue][#77620-workaround]. | |
6a06907d | 263 | |
136023e0 XL |
264 | [#77620]: https://github.com/rust-lang/rust/issues/77620 |
265 | [#77620-workaround]: https://github.com/rust-lang/rust/issues/77620#issuecomment-705228229 | |
6a06907d | 266 | |
136023e0 | 267 | ## Rebasing and Conflicts |
6a06907d XL |
268 | |
269 | When you edit your code locally, you are making changes to the version of | |
270 | rust-lang/rust that existed when you created your feature branch. As such, when | |
271 | you submit your PR it is possible that some of the changes that have been made | |
272 | to rust-lang/rust since then are in conflict with the changes you've made. | |
273 | ||
274 | When this happens, you need to resolve the conflicts before your changes can be | |
275 | merged. First, get a local copy of the conflicting changes: Checkout your local | |
276 | master branch with `git checkout master`, then `git pull upstream master` to | |
277 | update it with the most recent changes. | |
278 | ||
279 | ### Rebasing | |
280 | ||
281 | You're now ready to start the rebasing process. Checkout the branch with your | |
282 | changes and execute `git rebase master`. | |
283 | ||
284 | When you rebase a branch on master, all the changes on your branch are | |
285 | reapplied to the most recent version of master. In other words, Git tries to | |
286 | pretend that the changes you made to the old version of master were instead | |
287 | made to the new version of master. During this process, you should expect to | |
288 | encounter at least one "rebase conflict." This happens when Git's attempt to | |
289 | reapply the changes fails because your changes conflicted with other changes | |
290 | that have been made. You can tell that this happened because you'll see | |
291 | lines in the output that look like | |
292 | ||
293 | ``` | |
294 | CONFLICT (content): Merge conflict in file.rs | |
295 | ``` | |
296 | ||
297 | When you open these files, you'll see sections of the form | |
298 | ||
299 | ``` | |
300 | <<<<<<< HEAD | |
301 | Original code | |
302 | ======= | |
303 | Your code | |
304 | >>>>>>> 8fbf656... Commit fixes 12345 | |
305 | ``` | |
306 | ||
307 | This represents the lines in the file that Git could not figure out how to | |
308 | rebase. The section between `<<<<<<< HEAD` and `=======` has the code from | |
309 | master, while the other side has your version of the code. You'll need to | |
310 | decide how to deal with the conflict. You may want to keep your changes, | |
311 | keep the changes on master, or combine the two. | |
312 | ||
313 | Generally, resolving the conflict consists of two steps: First, fix the | |
314 | particular conflict. Edit the file to make the changes you want and remove the | |
315 | `<<<<<<<`, `=======` and `>>>>>>>` lines in the process. Second, check the | |
316 | surrounding code. If there was a conflict, its likely there are some logical | |
317 | errors lying around too! It's a good idea to run `x.py check` here to make sure | |
318 | there are no glaring errors. | |
319 | ||
320 | Once you're all done fixing the conflicts, you need to stage the files that had | |
321 | conflicts in them via `git add`. Afterwards, run `git rebase --continue` to let | |
322 | Git know that you've resolved the conflicts and it should finish the rebase. | |
cdc7bbd5 | 323 | |
6a06907d XL |
324 | Once the rebase has succeeded, you'll want to update the associated branch on |
325 | your fork with `git push --force-with-lease`. | |
326 | ||
327 | Note that `git push` will not work properly and say something like this: | |
328 | ||
329 | ``` | |
330 | ! [rejected] issue-xxxxx -> issue-xxxxx (non-fast-forward) | |
331 | error: failed to push some refs to 'https://github.com/username/rust.git' | |
332 | hint: Updates were rejected because the tip of your current branch is behind | |
333 | hint: its remote counterpart. Integrate the remote changes (e.g. | |
334 | hint: 'git pull ...') before pushing again. | |
335 | hint: See the 'Note about fast-forwards' in 'git push --help' for details. | |
336 | ``` | |
337 | ||
338 | The advice this gives is incorrect! Because of Rust's | |
339 | ["no-merge" policy](#no-merge-policy) the merge commit created by `git pull` | |
340 | will not be allowed in the final PR, in addition to defeating the point of the | |
341 | rebase! Use `git push --force-with-lease` instead. | |
342 | ||
136023e0 XL |
343 | ### Keeping things up to date |
344 | ||
345 | The above section on [Rebasing](#rebasing) is a specific | |
346 | guide on rebasing work and dealing with merge conflicts. | |
347 | Here is some general advice about how to keep your local repo | |
348 | up-to-date with upstream changes: | |
349 | ||
350 | Using `git pull upstream master` while on your local master branch regularly | |
351 | will keep it up-to-date. You will also want to rebase your feature branches | |
352 | up-to-date as well. After pulling, you can checkout the feature branches | |
353 | and rebase them: | |
354 | ||
355 | ``` | |
356 | git checkout master | |
357 | git pull upstream master --ff-only # to make certain there are no merge commits | |
9c376795 FG |
358 | git rebase master feature_branch |
359 | git push --force-with-lease # (set origin to be the same as local) | |
136023e0 XL |
360 | ``` |
361 | ||
94222f64 | 362 | To avoid merges as per the [No-Merge Policy](#no-merge-policy), you may want to use |
c295e0f8 XL |
363 | `git config pull.ff only` (this will apply the config only to the local repo) |
364 | to ensure that Git doesn't create merge commits when `git pull`ing, without | |
365 | needing to pass `--ff-only` or `--rebase` every time. | |
136023e0 | 366 | |
9c376795 | 367 | You can also `git push --force-with-lease` from master to keep your fork's master in sync with |
136023e0 XL |
368 | upstream. |
369 | ||
6a06907d XL |
370 | ## Advanced Rebasing |
371 | ||
372 | If your branch contains multiple consecutive rewrites of the same code, or if | |
373 | the rebase conflicts are extremely severe, you can use | |
374 | `git rebase --interactive master` to gain more control over the process. This | |
375 | allows you to choose to skip commits, edit the commits that you do not skip, | |
376 | change the order in which they are applied, or "squash" them into each other. | |
377 | ||
378 | Alternatively, you can sacrifice the commit history like this: | |
379 | ||
380 | ``` | |
381 | # squash all the changes into one commit so you only have to worry about conflicts once | |
382 | git rebase -i $(git merge-base master HEAD) # and squash all changes along the way | |
383 | git rebase master | |
384 | # fix all merge conflicts | |
385 | git rebase --continue | |
386 | ``` | |
387 | ||
388 | "Squashing" commits into each other causes them to be merged into a single | |
389 | commit. Both the upside and downside of this is that it simplifies the history. | |
390 | On the one hand, you lose track of the steps in which changes were made, but | |
391 | the history becomes easier to work with. | |
392 | ||
393 | You also may want to squash just the last few commits together, possibly | |
394 | because they only represent "fixups" and not real changes. For example, | |
395 | `git rebase --interactive HEAD~2` will allow you to edit the two commits only. | |
396 | ||
cdc7bbd5 XL |
397 | ### `git range-diff` |
398 | ||
399 | After completing a rebase, and before pushing up your changes, you may want to | |
400 | review the changes between your old branch and your new one. You can do that | |
401 | with `git range-diff master @{upstream} HEAD`. | |
402 | ||
403 | The first argument to `range-diff`, `master` in this case, is the base revision | |
404 | that you're comparing your old and new branch against. The second argument is | |
405 | the old version of your branch; in this case, `@upstream` means the version that | |
406 | you've pushed to GitHub, which is the same as what people will see in your pull | |
407 | request. Finally, the third argument to `range-diff` is the *new* version of | |
408 | your branch; in this case, it is `HEAD`, which is the commit that is currently | |
409 | checked-out in your local repo. | |
410 | ||
411 | Note that you can also use the equivalent, abbreviated form `git range-diff | |
412 | master @{u} HEAD`. | |
413 | ||
414 | Unlike in regular Git diffs, you'll see a `-` or `+` next to another `-` or `+` | |
415 | in the range-diff output. The marker on the left indicates a change between the | |
416 | old branch and the new branch, and the marker on the right indicates a change | |
417 | you've committed. So, you can think of a range-diff as a "diff of diffs" since | |
418 | it shows you the differences between your old diff and your new diff. | |
419 | ||
420 | Here's an example of `git range-diff` output (taken from [Git's | |
421 | docs][range-diff-example-docs]): | |
422 | ||
423 | ``` | |
424 | -: ------- > 1: 0ddba11 Prepare for the inevitable! | |
425 | 1: c0debee = 2: cab005e Add a helpful message at the start | |
426 | 2: f00dbal ! 3: decafe1 Describe a bug | |
427 | @@ -1,3 +1,3 @@ | |
428 | Author: A U Thor <author@example.com> | |
429 | ||
430 | -TODO: Describe a bug | |
431 | +Describe a bug | |
432 | @@ -324,5 +324,6 | |
433 | This is expected. | |
434 | ||
435 | -+What is unexpected is that it will also crash. | |
436 | ++Unexpectedly, it also crashes. This is a bug, and the jury is | |
437 | ++still out there how to fix it best. See ticket #314 for details. | |
438 | ||
439 | Contact | |
440 | 3: bedead < -: ------- TO-UNDO | |
441 | ``` | |
442 | ||
443 | (Note that `git range-diff` output in your terminal will probably be easier to | |
444 | read than in this example because it will have colors.) | |
445 | ||
446 | Another feature of `git range-diff` is that, unlike `git diff`, it will also | |
447 | diff commit messages. This feature can be useful when amending several commit | |
448 | messages so you can make sure you changed the right parts. | |
449 | ||
450 | `git range-diff` is a very useful command, but note that it can take some time | |
451 | to get used to its output format. You may also find Git's documentation on the | |
452 | command useful, especially their ["Examples" section][range-diff-example-docs]. | |
453 | ||
454 | [range-diff-example-docs]: https://git-scm.com/docs/git-range-diff#_examples | |
455 | ||
6a06907d XL |
456 | ## No-Merge Policy |
457 | ||
458 | The rust-lang/rust repo uses what is known as a "rebase workflow." This means | |
459 | that merge commits in PRs are not accepted. As a result, if you are running | |
460 | `git merge` locally, chances are good that you should be rebasing instead. Of | |
461 | course, this is not always true; if your merge will just be a fast-forward, | |
462 | like the merges that `git pull` usually performs, then no merge commit is | |
463 | created and you have nothing to worry about. Running `git config merge.ff only` | |
136023e0 | 464 | (this will apply the config to the local repo). |
6a06907d XL |
465 | once will ensure that all the merges you perform are of this type, so that you |
466 | cannot make a mistake. | |
467 | ||
468 | There are a number of reasons for this decision and like all others, it is a | |
469 | tradeoff. The main advantage is the generally linear commit history. This | |
470 | greatly simplifies bisecting and makes the history and commit log much easier | |
471 | to follow and understand. | |
472 | ||
9c376795 FG |
473 | ## Tips for reviewing |
474 | ||
475 | **NOTE**: This section is for *reviewing* PRs, not authoring them. | |
476 | ||
477 | ### Hiding whitespace | |
478 | ||
479 | Github has a button for disabling whitespace changes that may be useful. | |
480 | You can also use `git diff -w origin/master` to view changes locally. | |
481 | ||
482 | ![hide whitespace](./img/github-whitespace-changes.png) | |
483 | ||
484 | ### Fetching PRs | |
485 | ||
486 | To checkout PRs locally, you can use `git fetch upstream pull/NNNNN/head && git checkout | |
487 | FETCH_HEAD`. | |
488 | ||
489 | You can also use github's cli tool. Github shows a button on PRs where you can copy-paste the | |
490 | command to check it out locally. See <https://cli.github.com/> for more info. | |
491 | ||
492 | ![`gh` suggestion](./img/github-cli.png) | |
493 | ||
494 | ### Moving large sections of code | |
495 | ||
496 | Git and Github's default diff view for large moves *within* a file is quite poor; it will show each | |
497 | line as deleted and each line as added, forcing you to compare each line yourself. Git has an option | |
498 | to show moved lines in a different color: | |
499 | ||
500 | ``` | |
501 | git log -p --color-moved=dimmed-zebra --color-moved-ws=allow-indentation-change | |
502 | ``` | |
503 | ||
504 | See [the docs for `--color-moved`](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---color-movedltmodegt) for more info. | |
505 | ||
506 | ### range-diff | |
507 | ||
508 | See [the relevant section for PR authors](#git-range-diff). This can be useful for comparing code | |
509 | that was force-pushed to make sure there are no unexpected changes. | |
510 | ||
6a06907d XL |
511 | ## Git submodules |
512 | ||
513 | **NOTE**: submodules are a nice thing to know about, but it *isn't* an absolute | |
514 | prerequisite to contribute to `rustc`. If you are using Git for the first time, | |
515 | you might want to get used to the main concepts of Git before reading this section. | |
516 | ||
517 | The `rust-lang/rust` repository uses [Git submodules] as a way to use other | |
518 | Rust projects from within the `rust` repo. Examples include Rust's fork of | |
2b03887a | 519 | `llvm-project`, `cargo` and libraries like `stdarch` and `backtrace`. |
6a06907d | 520 | |
17df50a5 | 521 | Those projects are developed and maintained in an separate Git (and GitHub) |
6a06907d XL |
522 | repository, and they have their own Git history/commits, issue tracker and PRs. |
523 | Submodules allow us to create some sort of embedded sub-repository inside the | |
524 | `rust` repository and use them like they were directories in the `rust` repository. | |
525 | ||
2b03887a FG |
526 | Take `llvm-project` for example. `llvm-project` is maintained in the [`rust-lang/llvm-project`] |
527 | repository, but it is used in `rust-lang/rust` by the compiler for code generation and | |
528 | optimization. We bring it in `rust` as a submodule, in the `src/llvm-project` folder. | |
6a06907d XL |
529 | |
530 | The contents of submodules are ignored by Git: submodules are in some sense isolated | |
2b03887a | 531 | from the rest of the repository. However, if you try to `cd src/llvm-project` and then |
6a06907d XL |
532 | run `git status`: |
533 | ||
534 | ``` | |
2b03887a | 535 | HEAD detached at 9567f08afc943 |
6a06907d XL |
536 | nothing to commit, working tree clean |
537 | ``` | |
538 | ||
2b03887a | 539 | As far as git is concerned, you are no longer in the `rust` repo, but in the `llvm-project` repo. |
3c0e092e | 540 | You will notice that we are in "detached HEAD" state, i.e. not on a branch but on a |
6a06907d XL |
541 | particular commit. |
542 | ||
543 | This is because, like any dependency, we want to be able to control which version to use. | |
544 | Submodules allow us to do just that: every submodule is "pinned" to a certain | |
545 | commit, which doesn't change unless modified manually. If you use `git checkout <commit>` | |
2b03887a FG |
546 | in the `llvm-project` directory and go back to the `rust` directory, you can stage this |
547 | change like any other, e.g. by running `git add src/llvm-project`. (Note that if | |
5099ac24 FG |
548 | you *don't* stage the change to commit, then you run the risk that running |
549 | `x.py` will just undo your change by switching back to the previous commit when | |
550 | it automatically "updates" the submodules.) | |
551 | ||
552 | This version selection is usually done by the maintainers of the project, and | |
2b03887a | 553 | looks like [this][llvm-update]. |
6a06907d XL |
554 | |
555 | Git submodules take some time to get used to, so don't worry if it isn't perfectly | |
556 | clear yet. You will rarely have to use them directly and, again, you don't need | |
557 | to know everything about submodules to contribute to Rust. Just know that they | |
558 | exist and that they correspond to some sort of embedded subrepository dependency | |
559 | that Git can nicely and fairly conveniently handle for us. | |
560 | ||
561 | [Git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules | |
2b03887a FG |
562 | [`rust-lang/llvm-project`]: https://github.com/rust-lang/llvm-project |
563 | [llvm-update]: https://github.com/rust-lang/rust/pull/99464/files |