diff --git a/config.yaml b/config.yaml index 907bec5..3f334e0 100644 --- a/config.yaml +++ b/config.yaml @@ -59,11 +59,15 @@ contact: 'd.theodorakis@metoffice.gov.uk' # Order of episodes in your lesson episodes: -- 01-working-practices.md +- 01-issues.md - 02-branching.md - 03-feature-branch.md - 04-review.md - Break.md +- 05-forks.md +- 06-conflict.md +- 07-history.md +- 08-rebase.md - End.md diff --git a/episodes/01-collab.md b/episodes/01-collab.md deleted file mode 100644 index 12e3bf1..0000000 --- a/episodes/01-collab.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -title: Collaborating -teaching: 25 -exercises: 0 ---- - -::::::::::::::::::::::::::::::::::::::: objectives - -- Clone a remote repository. -- Add collaborators to your repository. - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -:::::::::::::::::::::::::::::::::::::::: questions - -- How can I use version control to collaborate with other people? - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -For the next step, get into pairs. One person will be the "Owner" and the other -will be the "Collaborator". The goal is that the Collaborator add changes into -the Owner's repository. We will switch roles at the end, so both persons will -play Owner and Collaborator. - -::::::::::::::::::::::::::::::::::::::::: callout - -## Practicing By Yourself - -If you're working through this lesson on your own, you can carry on by opening -a second terminal window. -This window will represent your partner, working on another computer. You -won't need to give anyone access on GitHub, because both 'partners' are you. - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -The Owner needs to give the Collaborator access. In your repository page on GitHub, click the "Settings" -button on the right, select "Collaborators", click "Add people", and -then enter your partner's username. - -![](fig/github-add-collaborators.png){alt='A screenshot of the GitHub Collaborators settings page, which is accessed by clicking "Settings" then "Collaborators"'} - -To accept access to the Owner's repo, the Collaborator -needs to go to [https://github.com/notifications](https://github.com/notifications) -or check for email notification. Once there they can accept access to the Owner's repo. - -Next, the Collaborator needs to download a copy of the Owner's repository to her -machine. This is called "cloning a repo". - -The Collaborator doesn't want to overwrite her own version of `climate`, so -needs to clone the Owner's repository to a different location than her own -repository with the same name. - -To clone the Owner's repo into her `Desktop` folder, the Collaborator enters: - -```bash -$ git clone git@github.com:mo-eormerod/weather.git ~/Desktop/mo-eormerod-weather -``` - -Replace 'mo-eormerod' with the Owner's username. - -If you choose to clone without the clone path -(`~/Desktop/mo-eormerod-weather`) specified at the end, -you will clone inside your own weather folder! -Make sure to navigate to the `Desktop` folder first. - -![](fig/github-collaboration.svg){alt='A diagram showing that "git clone" can create a copy of a remote GitHub repository, allowing a second person to create their own local repository that they can make changes to.'} - -The Collaborator can now make a change in her clone of the Owner's repository, -exactly the same way as we've been doing before: - -```bash -$ cd ~/Desktop/mo-eormerod-weather -$ nano shipping-forecast.md -$ cat shipping-forecast.md -``` - -```output -New high expected Dover 1028 by 0600 tomorrow. -Low Trafalgar 1013 losing its identity -``` - -```bash -$ git add shipping-forecast.md -$ git commit -m "Add in the shipping forecast" -``` - -```output - 1 file changed, 2 insertion(+) - create mode shipping-forecast.md -``` - -Then push the change to the *Owner's repository* on GitHub: - -```bash -$ git push origin main -``` - -```output -Enumerating objects: 4, done. -Counting objects: 4, done. -Delta compression using up to 4 threads. -Compressing objects: 100% (2/2), done. -Writing objects: 100% (3/3), 306 bytes, done. -Total 3 (delta 0), reused 0 (delta 0) -To https://github.com/mo-eormerod/weather.git - 9272da5..29aba7c main -> main -``` - -Note that we didn't have to create a remote called `origin`: Git uses this -name by default when we clone a repository. (This is why `origin` was a -sensible choice earlier when we were setting up remotes by hand.) - -Take a look at the Owner's repository on GitHub again, and you should be -able to see the new commit made by the Collaborator. You may need to refresh -your browser to see the new commit. - -::::::::::::::::::::::::::::::::::::::::: callout - -## Some more about remotes - -In this episode and the previous one, our local repository has had -a single "remote", called `origin`. A remote is a copy of the repository -that is hosted somewhere else, that we can push to and pull from, and -there's no reason that you have to work with only one. For example, -on some large projects you might have your own copy in your own GitHub -account (you'd probably call this `origin`) and also the main "upstream" -project repository (let's call this `upstream` for the sake of examples). -You would pull from `upstream` from time to -time to get the latest updates that other people have committed. - -Remember that the name you give to a remote only exists locally. It's -an alias that you choose - whether `origin`, or `upstream`, or `mo-eormerod` - -and not something intrinstic to the remote repository. - -The `git remote` family of commands is used to set up and alter the remotes -associated with a repository. Here are some of the most useful ones: - -- `git remote -v` lists all the remotes that are configured (we already used - this in the last episode) -- `git remote add [name] [url]` is used to add a new remote -- `git remote remove [name]` removes a remote. Note that it doesn't affect the - remote repository at all - it just removes the link to it from the local repo. -- `git remote set-url [name] [newurl]` changes the URL that is associated - with the remote. This is useful if it has moved, e.g. to a different GitHub - account, or from GitHub to a different hosting service. Or, if we made a typo when - adding it! -- `git remote rename [oldname] [newname]` changes the local alias by which a remote - is known - its name. For example, one could use this to change `upstream` to `mo-eormerod`. - - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -To download the Collaborator's changes from GitHub, the Owner now enters: - -```bash -$ git pull origin main -``` - -```output -remote: Enumerating objects: 4, done. -remote: Counting objects: 100% (4/4), done. -remote: Compressing objects: 100% (2/2), done. -remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 -Unpacking objects: 100% (3/3), done. -From https://github.com/mo-eormerod/weather - * branch main -> FETCH_HEAD - 9272da5..29aba7c main -> origin/main -Updating 9272da5..29aba7c -Fast-forward - shipping-forecast.md | 2 + - 1 file changed, 2 insertion(+) - create mode 100644 shipping-forecast.md -``` - -Now the three repositories (Owner's local, Collaborator's local, and Owner's on -GitHub) are back in sync. - -::::::::::::::::::::::::::::::::::::::::: callout - -## A Basic Collaborative Workflow - -In practice, it is good to be sure that you have an updated version of the -repository you are collaborating on, so you should `git pull` before making -our changes. The basic collaborative workflow would be: - -- update your local repo with `git pull origin main`, -- make your changes and stage them with `git add`, -- commit your changes with `git commit -m`, and -- upload the changes to GitHub with `git push origin main` - -It is better to make many commits with smaller changes rather than -of one commit with massive changes: small commits are easier to -read and review. - - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::::: challenge - -## Switch Roles and Repeat - -Switch roles and repeat the whole process. - - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::::: challenge - -## Review Changes - -The Owner putheyd commits to the repository without giving any information -to the Collaborator. How can the Collaborator find out what has changed with -command line? And on GitHub? - -::::::::::::::: solution - -## Solution - -On the command line, the Collaborator can use `git fetch origin main` -to get the remote changes into the local repository, but without merging -them. Then by running `git diff main origin/main` the Collaborator -will see the changes output in the terminal. - -On GitHub, the Collaborator can go to the repository and click on -"commits" to view the most recent commits putheyd to the repository. - - - -::::::::::::::::::::::::: - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::::: challenge - -## Comment Changes in GitHub - -The Collaborator has some questions about one line change made by the Owner and -has some suggestions to propose. - -With GitHub, it is possible to comment on the diff of a commit. Over the line of -code to comment, a blue comment icon appears to open a comment window. - -The Collaborator posts her comments and suggestions using the GitHub interface. - - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -::::::::::::::::::::::::::::::::::::::: challenge - -## Version History, Backup, and Version Control - -Some backup software can keep a history of the versions of your files. They also -allows you to recover specific versions. How is this functionality different from version control? -What are some of the benefits of using version control, Git and GitHub? - - -:::::::::::::::::::::::::::::::::::::::::::::::::: - -:::::::::::::::::::::::::::::::::::::::: keypoints - -- `git clone` copies a remote repository to create a local repository with a remote called `origin` automatically set up. - -:::::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/episodes/01-working-practices.md b/episodes/01-issues.md similarity index 58% rename from episodes/01-working-practices.md rename to episodes/01-issues.md index 25a46c3..e864b19 100644 --- a/episodes/01-working-practices.md +++ b/episodes/01-issues.md @@ -1,48 +1,36 @@ --- -title: Working Practices +title: Issues teaching: 10 exercises: 0 --- ::::::::::::::::::::::::::::::::::::::: objectives -- Describe a simple development flow using git and GitHub. +- Create an Issue with the correct labels. +- Assign yourself to an Issue. :::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::: questions -- What does using git and GitHub look like in practice? +- What information should go on an Issue? :::::::::::::::::::::::::::::::::::::::::::::::::: -Good working practices help us avoid mistakes, -keep our codebases secure, -and help us write sustainable code. -In this lesson we'll look at what good practice using -git and GitHub might look like. - -The process to develop new code with git and GitHub -looks like this: - -1. Open an Issue describing the feature or bug -2. Create a branch to develop your changes on -3. Make changes to your working copy -4. Write tests -5. Write documentation -6. Open a Pull Request -7. Review your changes -8. Merge the Pull Request and close the Issue -9. Tidy up your branches - -## Issues - GitHub Issues (tickets) are where you plan and track work. You can assign individuals to Issues and label them with a relevant tag such as `bug` or `enhancement`. Before opening a new Issue check whether there is already one open for the feature or bug by using GitHub's search. +Here's some advice for writing good Issues: + +- Be clear and concise, provide plenty of detail +- State the expected outcomes +- Tag relevant collaborators +- Break up large Issues into several small ones and or + use checklists to track tasks in the Issue + ![](fig/github-issue.png){alt='A screenshot of a GitHub Issue.'} ::::::::::::::::::::::::::::::::::::::: challenge @@ -52,6 +40,10 @@ one open for the feature or bug by using GitHub's search. Practice opening up an Issue on your `weather` repository. Your Issue will be a feature request for the shipping forecast. +1. Make sure you give the Issue an accurate title and description +2. Assign a label to the Issue +3. Assign yourself to the Issue + :::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::: keypoints diff --git a/episodes/03-feature-branch.md b/episodes/03-feature-branch.md index b154d3a..acda4bf 100644 --- a/episodes/03-feature-branch.md +++ b/episodes/03-feature-branch.md @@ -67,7 +67,7 @@ The Collaborator doesn't want to overwrite their own version of `climate`, so needs to clone the Owner's repository to a different location than their own repository with the same name. -To clone the Owner's repo into their `Desktop` folder, the Collaborator enters: +To clone the Owner's repository into their `Desktop` folder, the Collaborator enters: ```bash $ git clone git@github.com:mo-eormerod/weather.git ~/Desktop/mo-eormerod-weather @@ -205,14 +205,14 @@ If you don't see this notification click on the branches dropdown , the button showing `main`, and click on the `3_shipping-forecast` branch. -![](fig/feature-branch-1.png){alt='A screenshot of the GitHub weather repo showing the branch selection dropdown.'} +![](fig/feature-branch-1.png){alt='A screenshot of the GitHub weather repository showing the branch selection dropdown.'} You should now see the Code view for the `3_shipping-forecast` branch and a **Contribute** button. Click on the **Contribute** button and select the green **Open pull request** option. -![](fig/feature-branch-2.png){alt='A screenshot of the GitHub weather repo showing code view for the 3_shipping-forecast branch. The Contribute dropdown is expanded to show the Open pull request option.'} +![](fig/feature-branch-2.png){alt='A screenshot of the GitHub weather repository showing code view for the 3_shipping-forecast branch. The Contribute dropdown is expanded to show the Open pull request option.'} You may have noticed when running `git push` on the `3_shipping-forecast` branch for the first time @@ -251,8 +251,8 @@ are reviewed and merged back into `main` in more detail. :::::::::::::::::::::::::::::::::::::::: keypoints -- Add collaborators to your repo by going to the repository **Settings** then the **Collaborators** tab. -- Cloning a repo gives you a local copy of the repository: +- Add collaborators to your repository by going to the repository **Settings** then the **Collaborators** tab. +- Cloning a repository gives you a local copy of the repository: `git clone ` - Automatically close Issues when a PR is merged by adding a `Closes #` line to the first comment in the PR. diff --git a/episodes/05-forks.md b/episodes/05-forks.md new file mode 100644 index 0000000..03449f5 --- /dev/null +++ b/episodes/05-forks.md @@ -0,0 +1,303 @@ +--- +title: Forks +teaching: 30 +exercises: 0 +--- + +::::::::::::::::::::::::::::::::::::::: objectives + +- Create a fork of a repository. +- Contribute to the upstream repository using the fork. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- What is a fork? +- What are Issue and Pull Request templates? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +Most open source projects require new collaborators to +contribute via their personal **fork** of the repository. +A fork is simply a copy of the repository that you make +on the server, in our GitHub, side. +This avoids having to give repository permissions to +every single collaborator. + +In this episode we will create a fork and contribute +a change to the main GitHub repository using the +feature branch model we have been practising. + +Your instructor will give you a link to the `git-training-demo` +repository you will be forking. +This is the **upstream** repository for you fork. + +::::::::::::::::::::::::::::::::::::: instructor + +To create the conflict at the end of the episode +for all learners your co-instructor should +follow along making the same changes the learners +make. The co-instructors PR should be merged +just before the learners open their PRs. +If the co-instructor has the relevant permissions +they can do this themselves while the instructor +is still teaching. + +:::::::::::::::::::::::::::::::::::::::::::::::: + +## Open an Issue + +Remember we track our work with Issues. +Open an Issue on the `git-training-demo` repository +for adding yourself to the list of authors in the +`CITATION.cff` file. + +Navigate to the **Issues** tab: + +![](fig/github-fork-issue-open.png){alt='A screenshot of the git-training-demo repository showing the Issues view.'} + +This repositories Issue tab looks different. +It uses [Issue templates](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository) +to provide templates for bugs and feature requests. +Click on the green **Get started** button next to the +**Feature request** option: + +![](fig/github-fork-issue-1.jpeg){alt='A screenshot of the git-training-demo repository showing an Issue being opened. The template has automatically added text to the description and labelled the Issue as an enhancement.'} + +You can see the Issue has text in the description already. +This is from the template which provides a consistent +structure to the Issues on this repo. +The template has also added the `enhancement` label for you. + +Add in a clear title such as "Add Robert FitzRoy to the list +of authors in the CITATION file", +replace 'Robert FitzRoy' with your name. +Click **Submit new issue**. + +## Create a Fork + +On the repository Code tab click on the **Fork** dropdown arrow +and then the **+ Create a new fork** button: + +![](fig/github-fork.png){alt='A screenshot of the git-training-demo repository showing the fork dropdown with the Create a new fork button.'} + +GitHub will take you to the **Create a new fork** page. +There is no need to edit anything on this page. +Click on the green **Create fork** button: + +![](fig/github-fork-2.png){alt='A screenshot of the GitHub Create a new fork page.'} + +You should now see your repository fork. +The repository is marked as a fork by the fork symbol +next to the repository organisation and name in the top +navigation bar. +Under the main repository name you can see a link to the +repository we forked from. +The notification at the bottom of the screenshot shows +whether your forks `main` branch is up to date with the +upstream repository. +If you have commits on your fork not present upstream +you can **Contribute** your changes upstream via a PR. +If your fork is behind the upstream repository +you can **Sync fork** to pull in changes from the +upstream repository. + +![](fig/github-fork-3.png){alt='A screenshot of a fork of the git-training-demo repository. The repository is marked as a fork by the fork symbol next to the repository name and the link to the original repository under the repository name.'} + +## Make Changes + +You will be using this fork to make changes using +the feature branch model from the previous episodes. +Clone your fork, replace `mo-fitzroy` with your username: + +```bash +$ git clone git@github.com:mo-fitzroy/git-training-demo.git +``` + +```output +Cloning into 'git-training-demo'... +remote: Enumerating objects: 47, done. +remote: Counting objects: 100% (47/47), done. +remote: Compressing objects: 100% (44/44), done. +remote: Total 47 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0) +Receiving objects: 100% (47/47), 17.07 KiB | 1.07 MiB/s, done. +Resolving deltas: 100% (3/3), done. +``` + +Create your feature branch: + +```bash +$ cd git-training-demo +$ git switch -c add-citation-fitzroy +``` + +```output +Switched to a new branch 'add-citation-fitzroy' +``` + +Add your name to the `CITATION.cff` file, +underneath any existing author names: + +```bash +$ nano CITATION.cff +$ cat CITATION.cff +``` + +```output +cff-version: 1.2.0 +message: "Met Office Colleagues and Partners" +authors: +- family-names: "Theodorakis" + given-names: "Dimitrios" + orcid: "https://orcid.org/0000-0001-9288-1332" +- family-names: "FitzRoy" + given-names: "Robert" +title: "Met Office Git Training Demo" +version: 2.0.4 +doi: 10.4321/zenodo.1234 +date-released: 2024-09-23 +url: "https://github.com/MetOffice/git-training-demo" +``` + +Add and commit your changes: + +```bash +$ git add CITATION.cff +$ git commit -m "Adds Robert Fitzroy as an author" +``` +```output +[add-citation-fitzroy a3c5e13] "Adds Robert Fitzroy as an author" + 1 file changed, 2 insertions(+) +``` + +Push your changes to your GitHub fork: + +```bash +$ git push +``` + +```output +Enumerating objects: 5, done. +Counting objects: 100% (5/5), done. +Delta compression using up to 4 threads +Compressing objects: 100% (3/3), done. +Writing objects: 100% (3/3), 354 bytes | 354.00 KiB/s, done. +Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 +remote: Resolving deltas: 100% (2/2), completed with 2 local objects. +To github.com:mo-fitzroy/git-training-demo.git + f87bb5c..a3c5e13 add-citation-fitzroy -> add-citation-fitzroy +branch 'add-citation-fitzroy' set up to track 'origin/add-citation-fitzroy'. +``` + +## Open a Pull Request + +Head back to your fork on GitHub and open a PR to +contribute your changes upstream to the main +`git-training-demo` repository. + +![](fig/github-fork-pr-open.jpeg){alt='A screenshot of a user opening a pull request from their fork back to the upstream git-training-demo repository. The description has been autofilled with the pull request template contents.'} + +Notice the description has filled with a template. +Just like this repository used Issue templates it +also uses a [PR template](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository). + +Check the Issue you opened earlier for the Issue number. +`mo-fitzroy` checks theirs and it was Issue `#7`. +So he changes the line `Fixes <#ISSUE_NUMBER>` to `Fixes #7`. +This will automatically close Issue 7 when the PR is merged. +We use the keyword `Fixes` here instead of the `Closes` +keyword we used before because this PR comes from a fork[^link-issue-pr]. + +This template has a checklist that needs to be +completed before opening the PR[^pr-checklist]. +It also has checklists for science and code review. +In the description scroll down to the checklists +which look like this: + +```md +- [ ] I have read `CONTRIBUTING.md` and added my name as a Code Contributor. +``` + +Replace the space in the square checkbox brackets with an `x` +to mark the task as complete: + +```md +- [x] I have read `CONTRIBUTING.md` and added my name as a Code Contributor. +``` + +Now when you open the PR it should look something like this: + +![](fig/github-fork-pr-1.jpeg){alt='A screenshot of a users pull request from their fork back to the upstream git-training-demo repository.'} + +This PR number `#8` will close/fix Issue number `#7` (the top left arrow). +You can request a review on the top right. +Some repositories will be set up to automatically assign +a reviewer based on how many reviews each team member +currently has open[^auto-assign-pr-review]. +The middle arrow shows the checklist items we marked as complete. + +At the bottom of your PR you can see that a review is required +before merging. +All checks have passed, this repository has automatic checks +for trailing whitespace, accidentally adding large files etc. +More information can be found in the optional episode on +pre-commit hooks. +It also tells us **This branch has conflicts that must be resolved** and the conflicting file is `CITATION.cff`. + +Go to the main `git-training-demo` repositories code tab +and look at the contents of `CITATION.cff`: + +```output +cff-version: 1.2.0 +message: "Met Office Colleagues and Partners" +authors: +- family-names: "Theodorakis" + given-names: "Dimitrios" + orcid: "https://orcid.org/0000-0001-9288-1332" +- family-names: "Hogan" + given-names: "Emma" +title: "Met Office Git Training Demo" +version: 2.0.4 +doi: 10.4321/zenodo.1234 +date-released: 2024-09-23 +url: "https://github.com/MetOffice/git-training-demo" +``` + +Someone else has added their name +before our PR could be merged. +These changes now conflict with the one you made. +In the next episode you will learn how to deal with +conflicts. + +::::::::::::::::::::::::::::::::::::::::: spoiler + +## Practicing By Yourself + +If you're working through this lesson on your own, +you won't see a conflict. +You should still follow the materials through +the next episode on conflicts to learn +what to do when you do encounter a conflict. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- A fork is a server side (in our case GitHub) copy + of the repository. +- Forks allow collaborators to contribute to the main + repository without being given write permissions. +- Issue and Pull Request templates provide template text + for the first comment for new Issues of various types, + and Pull Requests. + They can auto-label Issues and encourage collaborators + to give plenty of detail. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +[^link-issue-pr]: The [GitHub Documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue) has more information +on linking PRs to Issues. +[^pr-checklist]: You can also open a draft PR and then edit the top +comment to mark the checklist tasks as completed. +[^auto-assign-pr-review]: The [GitHub Documentation](https://docs.github.com/en/organizations/organizing-members-into-teams/managing-code-review-settings-for-your-team) has more information on automatically assigning reviewers. diff --git a/episodes/06-conflict.md b/episodes/06-conflict.md new file mode 100644 index 0000000..8757cd0 --- /dev/null +++ b/episodes/06-conflict.md @@ -0,0 +1,490 @@ +--- +title: Conflicts +teaching: 15 +exercises: 0 +--- + +::::::::::::::::::::::::::::::::::::::: objectives + +- Explain what conflicts are and when they can occur. +- Resolve conflicts resulting from a merge. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- What do I do when my changes conflict with someone else's? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +As soon as people can work in parallel, they'll likely step on each other's +toes. This will even happen with a single person: if we are working on +a piece of software on both our laptop and a server in the lab, we could make +different changes to each copy. Version control helps us manage these +[conflicts](../learners/reference.md#conflict) by giving us tools to +[resolve](../learners/reference.md#resolve) overlapping changes. + +Good communication can help avoid conflicts. +In the last episode if we had communicated +that we each needed to edit the `CITATION.cff` file +we could have made our changes sequentially to +avoid the conflict we now have. + +## Updating a Fork + +Our fork is now behind the main upstream repository +by one commit. +We are going to update our fork. +First we need to set the correct upstream remote in git. + +Switch back to your forks `main` branch: + +```bash +$ git switch main +``` + +Now run: + +```bash +$ git remote -v +``` + +```output +origin git@github.com:mo-fitzroy/git-training-demo.git (fetch) +origin git@github.com:mo-fitzroy/git-training-demo.git (push) +``` + +This shows the GitHub remote links for our fork. +To set the upstream remote we can run: + +```bash +$ git remote add upstream git@github.com:MetOffice/git-training-demo.git +$ git remote -v +``` + +```output +origin git@github.com:mo-fitzroy/git-training-demo.git (fetch) +origin git@github.com:mo-fitzroy/git-training-demo.git (push) +upstream git@github.com:MetOffice/git-training-demo.git (fetch) +upstream git@github.com:MetOffice/git-training-demo.git (push) +``` + +Now git knows about the forks upstream repository. +We can fetch the changes to the upstream repository by running: + +```bash +$ git fetch upstream +``` + +```output +remote: Enumerating objects: 6, done. +remote: Counting objects: 100% (6/6), done. +remote: Compressing objects: 100% (2/2), done. +remote: Total 4 (delta 3), reused 2 (delta 2), pack-reused 0 (from 0) +Unpacking objects: 100% (4/4), 1.10 KiB | 41.00 KiB/s, done. +From github.com:MetOffice/git-training-demo + * [new branch] main -> upstream/main +``` + +We now have access to the `upstream/main` branch. +To merge in the changes on `upstream/main`: + +```bash +$ git merge upstream/main +``` + +```output +Updating f87bb5c..90808ab +Fast-forward + CITATION.cff | 2 ++ + 1 file changed, 2 insertions(+) +``` + +And push: + +```bash +$ git push +``` + +```output +Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 +To github.com:mo-fitzroy/git-training-demo.git + f87bb5c..90808ab main -> main +``` + +Your forks `main` branch is now up to date with the +main `git-training-demo` repositories `main` branch. + +## Resolving Conflicts + +We're going to resolve the conflict by merging +in our `main` branch into our feature branch +`add-citation-fitzroy`: + +```mermaid +gitGraph + accDescr {A git graph showing the main branch being merged + into the add-citation-fitzroy branch to resolve merge conflicts.} + commit id: 'cdb7fa6' + branch add-citation-fitzroy + commit id: 'a3c5e13 Adds Robert Fitzroy as an author' + checkout main + commit id: 's7dja9o' + checkout add-citation-fitzroy + merge main +``` + +Switch to the feature branch: + +```bash +$ git switch add-citation-fitzroy +``` + +```output +Switched to branch 'add-citation-fitzroy' +``` + +Merge in the `main` branch: + +```bash +$ git merge main +``` + +```output +Auto-merging CITATION.cff +CONFLICT (content): Merge conflict in CITATION.cff +Automatic merge failed; fix conflicts and then commit the result. +``` + +Git is warning us about the conflict. +We are still merging, if you run `git status` you will see: + +```bash +$ git status +``` + +```output +On branch add-citation-fitzroy +Your branch is up to date with 'origin/add-citation-fitzroy'. + +You have unmerged paths. + (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) + +Unmerged paths: + (use "git add ..." to mark resolution) + both modified: CITATION.cff + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +The message tells us **both modified** the `CITATION.cff` +file since both `main` and our feature branch modified +this file. + +If we look at the `CITATION.cff` file now: + +```bash +$ cat CITATION.cff +``` + +```output +cff-version: 1.2.0 +message: "Met Office Colleagues and Partners" +authors: +- family-names: "Theodorakis" + given-names: "Dimitrios" + orcid: "https://orcid.org/0000-0001-9288-1332" +<<<<<<< HEAD +- family-names: "FitzRoy" + given-names: "Robert" +======= +- family-names: "Hogan" + given-names: "Emma" +>>>>>>> dabb4c8c450e8475aee9b14b4383acc99f42af1d +title: "Met Office Git Training Demo" +version: 2.0.4 +doi: 10.4321/zenodo.1234 +date-released: 2024-09-23 +url: "https://github.com/MetOffice/git-training-demo" +``` + +Our change is preceded by `<<<<<<< HEAD`. +Git has then inserted `=======` as a separator between the conflicting changes +and marked the end of the content downloaded from GitHub with `>>>>>>>`. +(The string of letters and digits after that marker +identifies the commit we've just downloaded.) + +It is now up to us to edit this file to remove these markers +and reconcile the changes. +We can do anything we want: keep the change made in the local repository, keep +the change made in the remote repository, write something new to replace both, +or get rid of the change entirely. +Let's replace both so that the file looks like this: + +```bash +$ cat CITATION.cff +``` + +```output +cff-version: 1.2.0 +message: "Met Office Colleagues and Partners" +authors: +- family-names: "Theodorakis" + given-names: "Dimitrios" + orcid: "https://orcid.org/0000-0001-9288-1332" +- family-names: "Hogan" + given-names: "Emma" +- family-names: "FitzRoy" + given-names: "Robert" +title: "Met Office Git Training Demo" +version: 2.0.4 +doi: 10.4321/zenodo.1234 +date-released: 2024-09-23 +url: "https://github.com/MetOffice/git-training-demo" +``` + +To finish merging, +we add `CITATION.cff` to the changes being made by the merge +and then commit: + +```bash +$ git add CITATION.cff +$ git status +``` + +```output +On branch add-citation-fitzroy +All conflicts fixed but you are still merging. + (use "git commit" to conclude merge) + +Changes to be committed: + + modified: CITATION.cff +``` + +```bash +$ git commit +``` + +```output +[add-citation-fitzroy 312c561] Merge branch 'main' into add-citation-fitzroy +``` + +Now we can push our changes to GitHub: + +```bash +$ git push +``` + +```output +Enumerating objects: 7, done. +Counting objects: 100% (7/7), done. +Delta compression using up to 4 threads +Compressing objects: 100% (3/3), done. +Writing objects: 100% (3/3), 385 bytes | 128.00 KiB/s, done. +Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 +remote: Resolving deltas: 100% (2/2), completed with 2 local objects. +To github.com:mo-fitzroy/git-training-demo.git + a3c5e13..312c561 add-citation-fitzroy -> add-citation-fitzroy +``` + +Your PR on GitHub should now be ready to merge, +after review of course. + +## Avoiding Conflict + +Git's ability to resolve conflicts is very useful, but conflict resolution +costs time and effort, and can introduce errors if conflicts are not resolved +correctly. If you find yourself resolving a lot of conflicts in a project, +consider these technical approaches to reducing them: + +- Pull from upstream more frequently, especially before starting new work +- Use topic branches to segregate work, merging to main via a PR when complete +- Make smaller more atomic commits +- Push your work when it is done and encourage your team to do the same to reduce work in progress and, by extension, the chance of having conflicts +- Where logically appropriate, break large files into smaller ones so that it is + less likely that two authors will alter the same file simultaneously + +Conflicts can also be minimized with project management strategies: + +- Clarify who is responsible for what areas with your collaborators +- Discuss what order tasks should be carried out in with your collaborators so + that tasks expected to change the same lines won't be worked on simultaneously +- If the conflicts are stylistic churn (e.g. tabs vs. spaces), establish a + project convention that is governing and use code style tools (e.g. + `htmltidy`, `perltidy`, `rubocop`, etc.) to enforce, if necessary + +::::::::::::::::::::::::::::::::::::::: challenge + +## Conflicts on Non-textual files + +What does Git do +when there is a conflict in an image or some other non-textual file +that is stored in version control? + +::::::::::::::: solution + +## Solution + +Let's try it with your `weather` repository. +Suppose you take a picture of the television forecast and +call it `forecast.jpg`. Jimmy has already created a +feature branch to add the image in. + +```bash +$ git switch add_forecast_image +``` + +If you do not have an image file of forecast available, you can create +a dummy binary file like this: + +```bash +$ head --bytes 1024 /dev/urandom > forecast.jpg +$ ls -lh forecast.jpg +``` + +```output +-rw-r--r-- 1 mo-eormerod 57095 1.0K Mar 8 20:24 forecast.jpg +``` + +`ls` shows us that this created a 1-kilobyte file. It is full of +random bytes read from the special file, `/dev/urandom`. + +Now, suppose you add `forecast.jpg` to your repository: + +```bash +$ git add forecast.jpg +$ git commit -m "Add picture of forecast" +``` + +```output +[add_forecast_image 8e4115c] Add picture of forecast + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 forecast.jpg +``` + +Suppose that Jimmy has added a similar picture in the meantime. +His is a picture of a forecast from Chile, but it is *also* called `forecast.jpg`. +When you try to push, you get a familiar message: + +```bash +$ git push +``` + +```output +To https://github.com/mo-eormerod/weather.git + ! [rejected] add_forecast_image -> add_forecast_image (fetch first) +error: failed to push some refs to 'https://github.com/mo-eormerod/weather.git' +hint: Updates were rejected because the remote contains work that you do +hint: not have locally. This is usually caused by another repository pushing +hint: to the same ref. You may want to first integrate the remote changes +hint: (e.g., 'git pull ...') before pushing again. +hint: See the 'Note about fast-forwards' in 'git push --help' for details. +``` + +We've learned that we must pull first and resolve any conflicts: + +```bash +$ git pull +``` + +When there is a conflict on an image or other binary file, git prints +a message like this: + +```output +$ git pull +remote: Counting objects: 3, done. +remote: Compressing objects: 100% (3/3), done. +remote: Total 3 (delta 0), reused 0 (delta 0) +Unpacking objects: 100% (3/3), done. +From https://github.com/mo-eormerod/weather.git + * branch add_forecast_image -> FETCH_HEAD + 6a67967..439dc8c add_forecast_image -> origin/add_forecast_image +warning: Cannot merge binary files: forecast.jpg (HEAD vs. 439dc8c08869c342438f6dc4a2b615b05b93c76e) +Auto-merging forecast.jpg +CONFLICT (add/add): Merge conflict in forecast.jpg +Automatic merge failed; fix conflicts and then commit the result. +``` + +The conflict message here is mostly the same as it was for `forecast.md`, but +there is one key additional line: + +```output +warning: Cannot merge binary files: forecast.jpg (HEAD vs. 439dc8c08869c342438f6dc4a2b615b05b93c76e) +``` + +Git cannot automatically insert conflict markers into an image as it does +for text files. So, instead of editing the image file, we must check out +the version we want to keep. Then we can add and commit this version. + +On the key line above, Git has conveniently given us commit identifiers +for the two versions of `forecast.jpg`. Our version is `HEAD`, and Jimmy's +version is `439dc8c0...`. If we want to use our version, we can use +`git checkout`: + +```bash +$ git checkout HEAD forecast.jpg +$ git add forecast.jpg +$ git commit -m "Use image of just the local forecast" +``` + +```output +[add_forecast_image 21032c3] Use image of just the local forecast +``` + +If instead we want to use Jimmy's version, we can use `git checkout` with +Jimmy's commit identifier, `439dc8c0`: + +```bash +$ git checkout 439dc8c0 forecast.jpg +$ git add forecast.jpg +$ git commit -m "Use image of just the local forecast" +``` + +```output +[add_forecast_image da21b34] Use image of forecast with nachos instead of just forecast +``` + +We can also keep *both* images. The catch is that we cannot keep them +under the same name. But, we can check out each version in succession +and *rename* it, then add the renamed versions. First, check out each +image and rename it: + +```bash +$ git checkout HEAD forecast.jpg +$ git mv forecast.jpg forecast-only.jpg +$ git checkout 439dc8c0 forecast.jpg +$ mv forecast.jpg forecast-chile.jpg +``` + +Then, remove the old `forecast.jpg` and add the two new files: + +```bash +$ git rm forecast.jpg +$ git add forecast-only.jpg +$ git add forecast-chile.jpg +$ git commit -m "Use two images: local forecast and Chile forecast" +``` + +```output +[add_forecast_image 94ae08c] Use two images: local forecast and Chile forecast + 2 files changed, 0 insertions(+), 0 deletions(-) + create mode 100644 forecast-chile.jpg + rename forecast.jpg => forecast-only.jpg (100%) +``` + +Now both images of forecast are checked into the repository, and `forecast.jpg` +no longer exists. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Conflicts occur when two or more people change the same lines of the same file. +- The version control system does not allow people to overwrite each other's changes blindly, but highlights conflicts so that they can be resolved. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + \ No newline at end of file diff --git a/episodes/07-history.md b/episodes/07-history.md new file mode 100644 index 0000000..d5b26d7 --- /dev/null +++ b/episodes/07-history.md @@ -0,0 +1,284 @@ +--- +title: History +teaching: 15 +exercises: 0 +--- + +::::::::::::::::::::::::::::::::::::::: objectives + +- Visualise our git history. +- Learn the difference between merge, squash merge, and rebase. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- Why is a linear history useful? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +The history of your repository is simply +its commits. +A more linear history is easier to understand +and can be helpful when using certain git +commands to explore your history. + +## Viewing History + +You have already learnt that we can use the +`git log` command to output the commit history +of our repository. + +```bash +$ git log +``` + +```output +commit acce45c86ece7fd4823ddc6c1addb43edf4c0794 +Merge: e3fc783 ca8aca9 +Author: Robert FitzRoy +Date: Mon Sep 23 15:50:15 2024 +0100 + + Merge pull request #1 from MetOffice/mo-fitzroy-patch-1 + + Create CITATION.cff + +commit ca8aca9f2f43a4d799eb5c9ce9596b42360faa8b +Author: Robert FitzRoy +Date: Mon Sep 23 15:49:36 2024 +0100 + + Create CITATION.cff + +commit e3fc783648222d5eef0739922b06794b8d690341 +Author: Robert FitzRoy +Date: Fri Sep 20 13:01:05 2024 +0100 + + Initial commit +``` + +This shows the first 3 commits to the `git-training-demo` repository (the full output isn't shown here because it's very long). +We can use certain flags with `git log` to better +visualise the history in graph form: + +```bash +$ git log --decorate --oneline --graph +``` + +```output +* d800b46 (HEAD -> main, origin/main, origin/HEAD) Merge pull request #2 from MetOffice/mo-fitzroy-patch-2 +|\ +| * dbc944d Add pre-commit checks +|/ +* acce45c Merge pull request #1 from MetOffice/mo-fitzroy-patch-1 +|\ +| * ca8aca9 Create CITATION.cff +|/ +* e3fc783 Initial commit +``` + +The [GitHub Documentation for git log](https://git-scm.com/docs/git-log) has information on all the available flags. +The key here is `--graph` shows us the graphical +representation of our history on the left of the +terminal. +`*`'s are commits which are connected by lines. +The vertical lines represent links between commits. +The output above shows two feature branches each with +only one commit which were then merged back into +`main` via a pull request. + +You can either remember the flags using +the phrase "git dog", `d` for `--decorate`, +`o` for `--oneline`, `g` for `--graph` or +you can set an alias for the `git log` command: + +```bash +$ git config --global alias.dog "log --decorate --oneline --graph" +``` + +This alias makes these two commands equivalent: + +```bash +$ git dog +$ git log --decorate --oneline --graph +``` + +You can of course customise the log command +with other keywords and set more aliases for +different log views. +Some useful examples can be found on +[this Stackoverflow comment](https://stackoverflow.com/questions/1838873/visualizing-branch-topology-in-git/34467298#34467298). + +::: callout + +### IDE Git History Extensions + +Your IDE may have extensions which render your +git history as easy to read graphs. +If you use VSCode we recommend the [Git Graph extension](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph). + +::: + +## Merge Options + +When you opened your PRs you were given +three options for merging your feature +branch into `main`. +We will now explore how each merging method +affects the history of your repository. +In all the examples below we start with the same git history. + +### Merge + +Starting with: + +```mermaid +gitGraph + accDescr {A Git graph showing the main branch with a feature branch branching off at the second commit of main.} + commit id: '4631ebc' + commit id: 'ee406ac' + branch feature + checkout feature + commit id: '7cec787 Cool feature' + checkout main + commit id: '62440f8' + checkout feature + commit id: 'cd2db46 Cool feature docs' +``` + +Using merge creates a merge commit joining +the two branches: + +```mermaid +gitGraph + accDescr {A Git graph showing the result of merging a feature branch with the main branch. The history is non-linear in this case and difficult to read.} + commit id: '4631ebc' + commit id: 'ee406ac' + branch feature + checkout feature + commit id: '7cec787 Cool feature' + checkout main + commit id: '62440f8' + checkout feature + commit id: 'cd2db46 Cool feature docs' + checkout main + merge feature +``` + +This results in a non-linear history which +can be hard to navigate. +You can avoid this non-linear history by rebasing +your `feature` branch before you merge. +Rebasing a branch before you submit a PR for +review is covered in the next episode. + +Some teams choose to use Merge because it +keeps all the individual commits that made +up your change so more accurately represents +the history of your repository. + +### Squash and Merge + +Starting with: + +```mermaid +gitGraph + accDescr {A Git graph showing the main branch with a feature branch branching off at the second commit of main.} + commit id: '4631ebc' + commit id: 'ee406ac' + branch feature + checkout feature + commit id: '7cec787 Cool feature' + checkout main + commit id: '62440f8' + checkout feature + commit id: 'cd2db46 Cool feature docs' +``` + +Squashing before merging squashes all the +commits on the feature branch into one +commit which is then merged onto main: + +```mermaid +gitGraph + accDescr {A Git graph showing the result of squashing then merging a feature branch with the main branch.} + commit id: '4631ebc' + commit id: 'ee406ac' + commit id: '62440f8' + commit id: '5rtw8bq Squash & Merge Cool feature' +``` + +The last commit on main `5rtw8bq Squash & Merge Cool feature` +is the two feature branch commits squashed +together into a new one. + +Here the history is linear but all our commits +have been squashed into one. +If you have a very large branch with many commits +you might not want to squash them all into one commit. +Squashing in this case will make bug hunting harder. +Remember you should try and break work down into +small pieces so you avoid huge branches. + +### Rebase + +Starting with: + +```mermaid +gitGraph + accDescr {A Git graph showing the main branch with a feature branch branching off at the second commit of main.} + commit id: '4631ebc' + commit id: 'ee406ac' + branch feature + checkout feature + commit id: '7cec787 Cool feature' + checkout main + commit id: '62440f8' + checkout feature + commit id: 'cd2db46 Cool feature docs' +``` + +Rebase re-writes your git history removing +the `feature` branch commits from the `feature` +branch and adding them to `main`: + +```mermaid +gitGraph + accDescr {A Git graph showing the result of rebasing a feature branch with the main branch.} + commit id: '4631ebc' + commit id: 'ee406ac' + commit id: '62440f8' + commit id: '7cec787 Cool feature' + commit id: 'cd2db46 Cool feature docs' +``` + +::: caution + +### Rebase Re-Writes History + +Rebasing re-writes your git history. +Do **NOT** rebase shared branches such as `main`. + +::: + +Since rebase re-writes your history you have to force +push to the GitHub remote to override your remotes history. +The history in this case is linear and retains all +the commits which makes it easier to search for +a commit that introduced a bug. + +Your team will decide what approach is right +for your project. +If you choose to perform normal merge's on +your PRs we recommend rebasing your feature branch +before the PR is ready for review. + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- `git log --decorate --oneline --graph` lets you visualise your repository history in graph form. +- There are three options for merging your feature +branch into `main`. +- merge: creates a merge commit and results in a non-linear history unless you first rebase your feature branch +- squash and merge: squashes all your feature branch commits into one merge commit on `main`. Your history is linear. +- rebase: re-writes your git history so that all the feature branch commits are now on `main`. Your history is linear. + +:::::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/episodes/08-rebase.md b/episodes/08-rebase.md new file mode 100644 index 0000000..6234b59 --- /dev/null +++ b/episodes/08-rebase.md @@ -0,0 +1,531 @@ +--- +title: Rebasing +teaching: 15 +exercises: 0 +--- + +::::::::::::::::::::::::::::::::::::::: objectives + +- Rebase a feature branch. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- When should I rebase? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +Rebasing a branch re-writes your git history and +should be used with caution. +You might want to rebase if: + +- You need to tidy up your branches history before + performing a normal merge via a PR. + This will help keep the history of the `main` + branch linear. +- You need to update your branch with changes from the + `main` branch. + +## Tidying your Commit History + +Consider the following scenario. +You want to add a plotting script to the +`git-training-demo` repository. +You make a branch for the feature: + +```bash +$ git switch -c add_plot_script main +``` + +```output +Switched to branch 'add_plot_script' +``` + +And over the course of development you make +three commits to the file `plot_lfric.py`. +Use the commands in each tab make the same +commits to your repository: + +::: tab + +### Commit 1 + +```bash +$ nano plot_lfric.py +$ cat plot_lfric.py +``` + +```output +# pretnd there is code here! +``` + +```bash +$ git add plot_lfric.py +$ git commit -m "Adds in a Python script to plot LFRic data" +``` + +```output +[add_plot_script 64ac261] Adds in a Python script to plot LFRic data + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 plot_lfric.py +``` + +### Commit 2 + +```bash +$ nano plot_lfric.py +$ cat plot_lfric.py +``` + +```output +# pretnd there is code here! +# more Python +``` + +```bash +$ git commit -am "Extends the LFRic data plotting script to plot 2D fields" +``` + +```output +[add_plot_script 7053de7] Extends the LFRic data plotting script to plot 2D fields + 1 file changed, 1 insertion(+) +``` + +### Commit 3 + +```bash +$ nano plot_lfric.py +$ cat plot_lfric.py +``` + +```output +# pretend there is code here! +# more Python +``` + +```bash +$ git commit -am "Fixes the axis labels spelling in the LFRic data plotting script" +``` + +```output +[add_plot_script 0bb7871] Fixes the axis labels spelling in the LFRic data plotting script + 1 file changed, 1 insertion(+) +``` + +::: + +Before you push to the remote and open a PR +you check your git history. +The git history now looks something like this: + +```mermaid +gitGraph + accDescr {A Git graph showing the main branch with the add_plot_script branch branching off at the first commit of main.} + commit id: 'ed14d18' + branch add_plot_script + checkout add_plot_script + commit id: '64ac261' + commit id: '7053de7' + commit id: '0bb7871' +``` + +We can also visualise these changes with `git log`: + +```bash +$ git log --decorate --oneline --graph +``` + +```output +* 0bb7871 (HEAD -> add_plot_script) Fixes the axis labels spelling in the LFRic data plotting script +* 7053de7 Extends the LFRic data plotting script to plot 2D fields +* 64ac261 Adds in a Python script to plot LFRic data +* ed14d18 (origin/main) Adds Robert FitzRoy as an author (#8) +``` + +You realise that perhaps the spelling fix in the +third commit should have been a correction +to the first commit which added in the script. +We can use rebase to re-write our history and +combine these two commits. + +::: caution + +## Backup your Branch + +It is a good idea to create a backup of your +feature branch just in case something +goes wrong during the rebase: + +```bash +$ git branch add_plot_script.backup +``` + +::: + +We will rebase interactively using the `-i` flag. +To rebase our three commits we need to provide +the commit hash for the commit before our +three feature branch commits which is `ed14d18` +from the log above: + +```bash +git rebase -i ed14d18 +``` + +```output +pick 64ac261 Adds in a Python script to plot LFRic data +pick 7053de7 Extends the LFRic data plotting script to plot 2D fields +pick 0bb7871 Fixes the axis labels spelling in the LFRic data plotting script + +# Rebase ed14d18..0bb7871 onto ed14d18 (3 commands) +# +# Commands: +# p, pick = use commit +# r, reword = use commit, but edit the commit message +# e, edit = use commit, but stop for amending +# s, squash = use commit, but meld into previous commit +# f, fixup [-C | -c] = like "squash" but keep only the previous +# commit's log message, unless -C is used, in which case +# keep only this commit's message; -c is same as -C but +# opens the editor +# x, exec = run command (the rest of the line) using shell +# b, break = stop here (continue rebase later with 'git rebase --continue') +# d, drop = remove commit +# l, label