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