]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-dev-guide/src/git.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / git.md
CommitLineData
6a06907d
XL
1# Using Git
2
3<!-- toc -->
4
5The Rust project uses [Git] to manage its source code. In order to
6contribute, you'll need some familiarity with its features so that your changes
7can be incorporated into the compiler.
8
9[Git]: https://git-scm.com
10
11The goal of this page is to cover some of the more common questions and
12problems new contributors face. Although some Git basics will be covered here,
13if you find that this is still a little too fast for you, it might make sense
14to first read some introductions to Git, such as the Beginner and Getting
15started sections of [this tutorial from Atlassian][atlassian-git]. GitHub also
16provides [documentation] and [guides] for beginners, or you can consult the
17more 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
923072b8 21[documentation]: https://docs.github.com/en/get-started/quickstart/set-up-git
6a06907d
XL
22[guides]: https://guides.github.com/introduction/git-handbook/
23
24## Prerequisites
25
26We'll assume that you've installed Git, forked [rust-lang/rust], and cloned the
27forked repo to your PC. We'll use the command line interface to interact
28with Git; there are also a number of GUIs and IDE integrations that can
29generally do the same things.
30
31[rust-lang/rust]: https://github.com/rust-lang/rust
32
33If you've cloned your fork, then you will be able to reference it with `origin`
34in your local repo. It may be helpful to also set up a remote for the official
35rust-lang/rust repo via
36
37```sh
38git remote add upstream https://github.com/rust-lang/rust.git
39```
40
41if you're using HTTPS, or
42
43```sh
44git remote add upstream git@github.com:rust-lang/rust.git
45```
46
47if you're using SSH.
48
136023e0
XL
49**NOTE:** This page is dedicated to workflows for `rust-lang/rust`, but will likely be
50useful when contributing to other repositories in the Rust project.
51
52
6a06907d
XL
53## Standard Process
54
55Below is the normal procedure that you're likely to use for most minor changes
56and PRs:
57
58 1. Ensure that you're making your changes on top of master:
59 `git checkout master`.
136023e0
XL
60 2. Get the latest changes from the Rust repo: `git pull upstream master --ff-only`.
61 (see [No-Merge Policy](#keeping-things-up-to-date) for more info about this).
6a06907d
XL
62 3. Make a new branch for your change: `git checkout -b issue-12345-fix`.
63 4. Make some changes to the repo and test them.
64 5. Stage your changes via `git add src/changed/file.rs src/another/change.rs`
65 and then commit them with `git commit`. Of course, making intermediate commits
66 may be a good idea as well. Avoid `git add .`, as it makes it too easy to
67 unintentionally commit changes that should not be committed, such as submodule
68 updates. You can use `git status` to check if there are any files you forgot
69 to stage.
136023e0
XL
70 6. Push your changes to your fork: `git push --set-upstream origin issue-12345-fix`
71 (After adding commits, you can use `git push` and after rebasing or
72pulling-and-rebasing, you can use `git push --force-with-lease`).
73 7. [Open a PR][ghpullrequest] from your fork to `rust-lang/rust`'s master branch.
6a06907d
XL
74
75[ghpullrequest]: https://guides.github.com/activities/forking/#making-a-pull-request
76
136023e0
XL
77If you end up needing to rebase and are hitting conflicts, see [Rebasing](#rebasing).
78If you want to track upstream while working on long-running feature/issue, see
79[Keeping things up to date](#keeping-things-up-to-date).
80
6a06907d
XL
81If your reviewer requests changes, the procedure for those changes looks much
82the same, with some steps skipped:
83
84 1. Ensure that you're making changes to the most recent version of your code:
85 `git checkout issue-12345-fix`.
86 2. Make, stage, and commit your additional changes just like before.
87 3. Push those changes to your fork: `git push`.
88
89## Troubleshooting git issues
90
91You don't need to clone `rust-lang/rust` from scratch if it's out of date!
92Even if you think you've messed it up beyond repair, there are ways to fix
93the git state that don't require downloading the whole repository again.
94Here are some common issues you might run into:
95
96### I deleted my fork on GitHub!
97
98This is not a problem from git's perspective. If you run `git remote -v`,
99it will say something like this:
100
101```
102$ git remote -v
103origin https://github.com//rust-lang/rust (fetch)
104origin https://github.com//rust-lang/rust (push)
105personal https://github.com/jyn514/rust (fetch)
106personal https://github.com/jyn514/rust (push)
107```
108
109If you renamed your fork, you can change the URL like this:
110
111```console
112git remote set-url personal <URL>
113```
114
115where the `<URL>` is your new fork.
116
117### I see 'Untracked Files: src/stdarch'?
118
119This is left over from the move to the `library/` directory.
120Unfortunately, `git rebase` does not follow renames for submodules, so you
121have to delete the directory yourself:
122
123```console
124rm -r src/stdarch
125```
126
127### I see `<<< HEAD`?
128
129You were probably in the middle of a rebase or merge conflict. See
130[Conflicts](#conflicts) for how to fix the conflict. If you don't care about the changes
131and just want to get a clean copy of the repository back, you can use `git reset`:
132
133```console
134# WARNING: this throws out any local changes you've made! Consider resolving the conflicts instead.
135git reset --hard master
136```
137
138### Quick note about submodules
139
140When updating your local repository with `git pull`, you may notice that sometimes
141Git says you have modified some files that you have never edited. For example,
142running `git status` gives you something like (note the `new commits` mention):
143
144```
145On branch master
146Your branch is up to date with 'origin/master'.
147
148Changes not staged for commit:
149 (use "git add <file>..." to update what will be committed)
150 (use "git restore <file>..." to discard changes in working directory)
151 modified: src/tools/cargo (new commits)
152 modified: src/tools/rls (new commits)
6a06907d
XL
153
154no changes added to commit (use "git add" and/or "git commit -a")
155```
156
157These changes are not changes to files: they are changes to submodules (more on
158this [later](#git-submodules)). To get rid of those, run `git submodule update`
159(or run any `x.py` command, which will automatically update the submodules).
5099ac24
FG
160Note that there is (as of <!-- date: 2022-02 --> February 2022) a [bug][#77620] if you use
161worktrees, submodules, and `x.py` in a commit hook. If you run into an error
6a06907d
XL
162like:
163
164```
165error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Cargo.toml`
166
167Caused by:
168 No such file or directory (os error 2)
169```
136023e0 170it's not anything you did wrong. There is a workaround in [the issue][#77620-workaround].
6a06907d 171
136023e0
XL
172[#77620]: https://github.com/rust-lang/rust/issues/77620
173[#77620-workaround]: https://github.com/rust-lang/rust/issues/77620#issuecomment-705228229
6a06907d 174
136023e0 175## Rebasing and Conflicts
6a06907d
XL
176
177When you edit your code locally, you are making changes to the version of
178rust-lang/rust that existed when you created your feature branch. As such, when
179you submit your PR it is possible that some of the changes that have been made
180to rust-lang/rust since then are in conflict with the changes you've made.
181
182When this happens, you need to resolve the conflicts before your changes can be
183merged. First, get a local copy of the conflicting changes: Checkout your local
184master branch with `git checkout master`, then `git pull upstream master` to
185update it with the most recent changes.
186
187### Rebasing
188
189You're now ready to start the rebasing process. Checkout the branch with your
190changes and execute `git rebase master`.
191
192When you rebase a branch on master, all the changes on your branch are
193reapplied to the most recent version of master. In other words, Git tries to
194pretend that the changes you made to the old version of master were instead
195made to the new version of master. During this process, you should expect to
196encounter at least one "rebase conflict." This happens when Git's attempt to
197reapply the changes fails because your changes conflicted with other changes
198that have been made. You can tell that this happened because you'll see
199lines in the output that look like
200
201```
202CONFLICT (content): Merge conflict in file.rs
203```
204
205When you open these files, you'll see sections of the form
206
207```
208<<<<<<< HEAD
209Original code
210=======
211Your code
212>>>>>>> 8fbf656... Commit fixes 12345
213```
214
215This represents the lines in the file that Git could not figure out how to
216rebase. The section between `<<<<<<< HEAD` and `=======` has the code from
217master, while the other side has your version of the code. You'll need to
218decide how to deal with the conflict. You may want to keep your changes,
219keep the changes on master, or combine the two.
220
221Generally, resolving the conflict consists of two steps: First, fix the
222particular conflict. Edit the file to make the changes you want and remove the
223`<<<<<<<`, `=======` and `>>>>>>>` lines in the process. Second, check the
224surrounding code. If there was a conflict, its likely there are some logical
225errors lying around too! It's a good idea to run `x.py check` here to make sure
226there are no glaring errors.
227
228Once you're all done fixing the conflicts, you need to stage the files that had
229conflicts in them via `git add`. Afterwards, run `git rebase --continue` to let
230Git know that you've resolved the conflicts and it should finish the rebase.
cdc7bbd5 231
6a06907d
XL
232Once the rebase has succeeded, you'll want to update the associated branch on
233your fork with `git push --force-with-lease`.
234
235Note that `git push` will not work properly and say something like this:
236
237```
238 ! [rejected] issue-xxxxx -> issue-xxxxx (non-fast-forward)
239error: failed to push some refs to 'https://github.com/username/rust.git'
240hint: Updates were rejected because the tip of your current branch is behind
241hint: its remote counterpart. Integrate the remote changes (e.g.
242hint: 'git pull ...') before pushing again.
243hint: See the 'Note about fast-forwards' in 'git push --help' for details.
244```
245
246The advice this gives is incorrect! Because of Rust's
247["no-merge" policy](#no-merge-policy) the merge commit created by `git pull`
248will not be allowed in the final PR, in addition to defeating the point of the
249rebase! Use `git push --force-with-lease` instead.
250
136023e0
XL
251### Keeping things up to date
252
253The above section on [Rebasing](#rebasing) is a specific
254guide on rebasing work and dealing with merge conflicts.
255Here is some general advice about how to keep your local repo
256up-to-date with upstream changes:
257
258Using `git pull upstream master` while on your local master branch regularly
259will keep it up-to-date. You will also want to rebase your feature branches
260up-to-date as well. After pulling, you can checkout the feature branches
261and rebase them:
262
263```
264git checkout master
265git pull upstream master --ff-only # to make certain there are no merge commits
266git checkout feature_branch
267git rebase master
268git push --force-with-lease (set origin to be the same as local)
269```
270
94222f64 271To avoid merges as per the [No-Merge Policy](#no-merge-policy), you may want to use
c295e0f8
XL
272`git config pull.ff only` (this will apply the config only to the local repo)
273to ensure that Git doesn't create merge commits when `git pull`ing, without
274needing to pass `--ff-only` or `--rebase` every time.
136023e0
XL
275
276You can also `git push --force-with-lease` from master to keep your origin's master in sync with
277upstream.
278
6a06907d
XL
279## Advanced Rebasing
280
281If your branch contains multiple consecutive rewrites of the same code, or if
282the rebase conflicts are extremely severe, you can use
283`git rebase --interactive master` to gain more control over the process. This
284allows you to choose to skip commits, edit the commits that you do not skip,
285change the order in which they are applied, or "squash" them into each other.
286
287Alternatively, you can sacrifice the commit history like this:
288
289```
290# squash all the changes into one commit so you only have to worry about conflicts once
291git rebase -i $(git merge-base master HEAD) # and squash all changes along the way
292git rebase master
293# fix all merge conflicts
294git rebase --continue
295```
296
297"Squashing" commits into each other causes them to be merged into a single
298commit. Both the upside and downside of this is that it simplifies the history.
299On the one hand, you lose track of the steps in which changes were made, but
300the history becomes easier to work with.
301
302You also may want to squash just the last few commits together, possibly
303because they only represent "fixups" and not real changes. For example,
304`git rebase --interactive HEAD~2` will allow you to edit the two commits only.
305
cdc7bbd5
XL
306### `git range-diff`
307
308After completing a rebase, and before pushing up your changes, you may want to
309review the changes between your old branch and your new one. You can do that
310with `git range-diff master @{upstream} HEAD`.
311
312The first argument to `range-diff`, `master` in this case, is the base revision
313that you're comparing your old and new branch against. The second argument is
314the old version of your branch; in this case, `@upstream` means the version that
315you've pushed to GitHub, which is the same as what people will see in your pull
316request. Finally, the third argument to `range-diff` is the *new* version of
317your branch; in this case, it is `HEAD`, which is the commit that is currently
318checked-out in your local repo.
319
320Note that you can also use the equivalent, abbreviated form `git range-diff
321master @{u} HEAD`.
322
323Unlike in regular Git diffs, you'll see a `-` or `+` next to another `-` or `+`
324in the range-diff output. The marker on the left indicates a change between the
325old branch and the new branch, and the marker on the right indicates a change
326you've committed. So, you can think of a range-diff as a "diff of diffs" since
327it shows you the differences between your old diff and your new diff.
328
329Here's an example of `git range-diff` output (taken from [Git's
330docs][range-diff-example-docs]):
331
332```
333-: ------- > 1: 0ddba11 Prepare for the inevitable!
3341: c0debee = 2: cab005e Add a helpful message at the start
3352: f00dbal ! 3: decafe1 Describe a bug
336 @@ -1,3 +1,3 @@
337 Author: A U Thor <author@example.com>
338
339 -TODO: Describe a bug
340 +Describe a bug
341 @@ -324,5 +324,6
342 This is expected.
343
344 -+What is unexpected is that it will also crash.
345 ++Unexpectedly, it also crashes. This is a bug, and the jury is
346 ++still out there how to fix it best. See ticket #314 for details.
347
348 Contact
3493: bedead < -: ------- TO-UNDO
350```
351
352(Note that `git range-diff` output in your terminal will probably be easier to
353read than in this example because it will have colors.)
354
355Another feature of `git range-diff` is that, unlike `git diff`, it will also
356diff commit messages. This feature can be useful when amending several commit
357messages so you can make sure you changed the right parts.
358
359`git range-diff` is a very useful command, but note that it can take some time
360to get used to its output format. You may also find Git's documentation on the
361command useful, especially their ["Examples" section][range-diff-example-docs].
362
363[range-diff-example-docs]: https://git-scm.com/docs/git-range-diff#_examples
364
6a06907d
XL
365## No-Merge Policy
366
367The rust-lang/rust repo uses what is known as a "rebase workflow." This means
368that merge commits in PRs are not accepted. As a result, if you are running
369`git merge` locally, chances are good that you should be rebasing instead. Of
370course, this is not always true; if your merge will just be a fast-forward,
371like the merges that `git pull` usually performs, then no merge commit is
372created and you have nothing to worry about. Running `git config merge.ff only`
136023e0 373(this will apply the config to the local repo).
6a06907d
XL
374once will ensure that all the merges you perform are of this type, so that you
375cannot make a mistake.
376
377There are a number of reasons for this decision and like all others, it is a
378tradeoff. The main advantage is the generally linear commit history. This
379greatly simplifies bisecting and makes the history and commit log much easier
380to follow and understand.
381
382## Git submodules
383
384**NOTE**: submodules are a nice thing to know about, but it *isn't* an absolute
385prerequisite to contribute to `rustc`. If you are using Git for the first time,
386you might want to get used to the main concepts of Git before reading this section.
387
388The `rust-lang/rust` repository uses [Git submodules] as a way to use other
389Rust projects from within the `rust` repo. Examples include Rust's fork of
17df50a5 390`llvm-project` and many devtools such as `cargo`, `rust-analyzer` and `rls`.
6a06907d 391
17df50a5 392Those projects are developed and maintained in an separate Git (and GitHub)
6a06907d
XL
393repository, and they have their own Git history/commits, issue tracker and PRs.
394Submodules allow us to create some sort of embedded sub-repository inside the
395`rust` repository and use them like they were directories in the `rust` repository.
396
397Take `miri` for example. `miri` is maintained in the [`rust-lang/miri`] repository,
398but it is used in `rust-lang/rust` by the compiler for const evaluation. We bring it
399in `rust` as a submodule, in the `src/tools/miri` folder.
400
401The contents of submodules are ignored by Git: submodules are in some sense isolated
402from the rest of the repository. However, if you try to `cd src/tools/miri` and then
403run `git status`:
404
405```
406HEAD detached at 3fafb835
407nothing to commit, working tree clean
408```
409
410As far as git is concerned, you are no longer in the `rust` repo, but in the `miri` repo.
3c0e092e 411You will notice that we are in "detached HEAD" state, i.e. not on a branch but on a
6a06907d
XL
412particular commit.
413
414This is because, like any dependency, we want to be able to control which version to use.
415Submodules allow us to do just that: every submodule is "pinned" to a certain
416commit, which doesn't change unless modified manually. If you use `git checkout <commit>`
417in the `miri` directory and go back to the `rust` directory, you can stage this
5099ac24
FG
418change like any other, e.g. by running `git add src/tools/miri`. (Note that if
419you *don't* stage the change to commit, then you run the risk that running
420`x.py` will just undo your change by switching back to the previous commit when
421it automatically "updates" the submodules.)
422
423This version selection is usually done by the maintainers of the project, and
424looks like [this][miri-update].
6a06907d
XL
425
426Git submodules take some time to get used to, so don't worry if it isn't perfectly
427clear yet. You will rarely have to use them directly and, again, you don't need
428to know everything about submodules to contribute to Rust. Just know that they
429exist and that they correspond to some sort of embedded subrepository dependency
430that Git can nicely and fairly conveniently handle for us.
431
432[Git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
433[`rust-toolstate`]: https://rust-lang-nursery.github.io/rust-toolstate/
434[`rust-lang/miri`]: https://github.com/rust-lang/miri
435[miri-update]: https://github.com/rust-lang/rust/pull/77500/files