-
-
Notifications
You must be signed in to change notification settings - Fork 945
Add episode on branching #1083
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add episode on branching #1083
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,329 @@ | ||
--- | ||
title: Branches | ||
teaching: 20 | ||
exercises: 0 | ||
--- | ||
|
||
::::::::::::::::::::::::::::::::::::::: objectives | ||
|
||
- Understand why branches are useful for: | ||
- Working on separate tasks in the same repository concurrently | ||
- Trying multiple solutions to a problem | ||
- Check-pointing versions of code | ||
- Merge branches back into the main branch | ||
|
||
|
||
:::::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
||
:::::::::::::::::::::::::::::::::::::::: questions | ||
|
||
- What are branches? | ||
- How can I work in parallel using branches? | ||
|
||
:::::::::::::::::::::::::::::::::::::::::::::::::: | ||
|
||
So far we've always been working in a straight timeline. | ||
However, there are times when we might want to keep | ||
our main work safe from experimental changes we are working on. | ||
To do this we can use branches to work on separate tasks in parallel | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can branch our timeline to work on separate tasks in parallel |
||
without changing our current branch, `main`. | ||
|
||
We didn't see it before but the first branch made is called `main`. | ||
This is the default branch created when initializing a repository and | ||
is often considered to be the "clean" or "working" version of a | ||
repository's code. | ||
|
||
We can see what branches exist in a repository by typing | ||
|
||
```bash | ||
$ git branch | ||
``` | ||
|
||
```output | ||
* main | ||
``` | ||
|
||
|
||
The `*` indicates which branch we are currently on. | ||
|
||
In this lesson, Alfredo is trying to run an analysis | ||
and doesn't know if it will be faster in bash or python. | ||
To keep his main branch safe he will use separate branches | ||
for both bash and python analysis. | ||
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be good to keep the "flavour" of Alfredo as a chef keeping his recipes under version control. So perhaps we could say he's experimenting with a new version of his famous strawberry cream cake in which he uses mango and less sugar, or something of the kind? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it goes this way, then the whole content should be adapted accordingly. A possibility would be something like he wants to experiment on his current cake recipe, and change the type of flour and also the type of sweetening. So he creates only one branch of a variant of the cake. Where he removes the old ingredients and adds the new ones. And then he wants to compare the cake to his previous version so he switches to main branch and prepares the other cake (the students will see the changes in the recipe file immediately having effect inplace). Then he decides that the new recipe is better, so he merges the changes of the new branch to main. It's basic but it's also in the "flavour" you mention, and it's possible to see an advantage of branching. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's pretty much what I would suggest. But I think we need a good discussion on whether to do one branch or two branches, I'm not certain of my opinion. |
||
Then he will merge the branch with the faster script | ||
into his main branch. | ||
|
||
First let's make the python branch. | ||
We use the same `git branch` command but now add the | ||
name we want to give our new branch | ||
|
||
```bash | ||
$ git branch pythondev | ||
``` | ||
|
||
We can now check our work with the `git branch` command. | ||
|
||
```bash | ||
$ git branch | ||
``` | ||
|
||
```output | ||
* main | ||
pythondev | ||
``` | ||
|
||
We can see that we created the `pythondev` branch but we | ||
are still in the main branch. | ||
|
||
We can also see this in the output of the `git status` command. | ||
|
||
```bash | ||
$ git status | ||
``` | ||
|
||
```output | ||
On branch main | ||
nothing to commit, working directory clean | ||
``` | ||
|
||
To switch to our new branch we can use the `checkout` command | ||
we learned earlier and check our work with `git branch`. | ||
Comment on lines
+89
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has been changed, and we now try not to use |
||
|
||
```bash | ||
$ git checkout pythondev | ||
$ git branch | ||
``` | ||
|
||
```output | ||
main | ||
* pythondev | ||
``` | ||
|
||
Before we used the `checkout` command to checkout a file from a specific commit | ||
using commit hashes or `HEAD` and the filename (`git checkout HEAD <file>`). The | ||
`checkout` command can also be used to checkout an entire previous version of the | ||
repository, updating all files in the repository to match the state of a desired commit. | ||
Comment on lines
+102
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: |
||
|
||
Branches allow us to do this using a human-readable name rather than memorizing | ||
a commit hash. This name also typically gives purpose to the set of changes in | ||
that branch. When we use the command `git checkout <branch_name>`, we are using | ||
a nickname to checkout a version of the repository that matches the most recent | ||
commit in that branch (a.k.a. the HEAD of that branch). | ||
|
||
Here you can use `git log` and `ls` to see that the history and | ||
files are the same as our `main` branch. This will be true until | ||
some changes are committed to our new branch. | ||
|
||
Now lets make our python script. | ||
|
||
For simplicity, we will `touch` the script making an empty file | ||
but imagine we spent hours working on this python script for our analysis. | ||
|
||
```bash | ||
$ touch analysis.py | ||
``` | ||
Comment on lines
+119
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make an experimental edit to an existing recipe instead. |
||
|
||
Now we can add and commit the script to our branch. | ||
|
||
```bash | ||
$ git add analysis.py | ||
$ git commit -m "Wrote and tested python analysis script" | ||
``` | ||
|
||
```output | ||
[pythondev x792csa1] Wrote and tested python analysis script | ||
1 file changed, 1 insertion(+) | ||
create mode 100644 analysis.py | ||
``` | ||
|
||
Lets check our work! | ||
|
||
```bash | ||
$ ls | ||
$ git log --oneline | ||
``` | ||
|
||
As expected, we see our commit in the log. | ||
|
||
Now let's switch back to the `main` branch. | ||
|
||
```bash | ||
$ git checkout main | ||
$ git branch | ||
``` | ||
|
||
```output | ||
* main | ||
pythondev | ||
``` | ||
|
||
Let's explore the repository a bit. | ||
|
||
Now that we've confirmed we are on the `main` branch again. | ||
Let's confirm that `analysis.py` and our last commit aren't in `main`. | ||
|
||
```bash | ||
$ ls | ||
$ git log --oneline | ||
``` | ||
|
||
We no longer see the file `analysis.py` and our latest commit doesn't | ||
appear in this branch's history. But do not fear! All of our hard work | ||
remains in the `pythondev` branch. We can confirm this by moving back | ||
to that branch. | ||
|
||
```bash | ||
$ git checkout pythondev | ||
$ git branch | ||
``` | ||
|
||
```output | ||
main | ||
* pythondev | ||
``` | ||
|
||
```bash | ||
$ ls | ||
$ git log --oneline | ||
``` | ||
|
||
And we see that our `analysis.py` file and respective commit have been | ||
preserved in the `pythondev` branch. | ||
|
||
Now we can repeat the process for our bash script in a branch called | ||
`bashdev`. | ||
|
||
First we must checkout the `main` branch again. New branches will | ||
include the entire history up to the current commit, and we'd like | ||
to keep these two tasks separate. | ||
|
||
```bash | ||
$ git checkout main | ||
$ git branch | ||
``` | ||
|
||
```output | ||
* main | ||
pythondev | ||
``` | ||
|
||
This time let's create and switch two the `bashdev` branch | ||
in one command. | ||
|
||
We can do so by adding the `-b` flag to checkout. | ||
|
||
```bash | ||
$ git checkout -b bashdev | ||
$ git branch | ||
``` | ||
|
||
```output | ||
* bashdev | ||
main | ||
pythonndev | ||
``` | ||
|
||
|
||
We can use `ls` and `git log` to see that this branch is | ||
the same as our current `main` branch. | ||
|
||
Now we can make `analysis.sh` and add and commit it. | ||
Again imagine instead of `touch`ing the file we worked | ||
on it for many hours. | ||
|
||
```bash | ||
$ touch analysis.sh | ||
$ git add analysis.sh | ||
$ git commit -m "Wrote and tested bash analysis script" | ||
``` | ||
|
||
```output | ||
[bashdev 2n779ds] Wrote and tested bash analysis script | ||
1 file changed, 1 insertion(+) | ||
create mode 100644 analysis.sh | ||
``` | ||
|
||
Lets check our work again before we switch back to the main branch. | ||
|
||
```bash | ||
$ ls | ||
$ git log --oneline | ||
``` | ||
|
||
So it turns out the python `analysis.py` is much faster than `analysis.sh`. | ||
|
||
Let's merge this version into our `main` branch so we can use it for | ||
our work going forward. | ||
|
||
Merging brings the changes from a different branch into | ||
the current branch. | ||
|
||
First we must switch to the branch we're merging changes into, `main`. | ||
|
||
```bash | ||
$ git checkout main | ||
$ git branch | ||
``` | ||
|
||
```output | ||
bashdev | ||
* main | ||
pythonndev | ||
``` | ||
|
||
Now we can `merge` the `pythondev` branch into our current branch | ||
(`main`). In english, this command could be stated as "`git`, please | ||
`merge` the changes in the `pythondev` branch into the current branch | ||
I'm in". | ||
|
||
```bash | ||
$ git merge pythondev | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that one of the most complicated actions that a novice user of git needs to handle quite early is merge conflicts. In this case, everything works, but I thin it would make sense to make a merge conflict example where Alfredo needs to solve it, so that not only it is documented in the content on how to solve conflicts, but also the students understand the workflow of solving merge conflicts. What do you all think of adding this to the content? |
||
``` | ||
|
||
```output | ||
Updating 12687f6..x792csa1 | ||
Fast-forward | ||
analysis.py | 0 | ||
1 file changed, 0 insertions(+), 0 deletions(-) | ||
create mode 100644 analysis.py | ||
``` | ||
|
||
Now that we've merged the `pythondev` into `main`, these changes | ||
exist in both branches. This could be confusing in the future if we | ||
stumble upon the `pythondev` branch again. | ||
|
||
We can delete our old branches so as to avoid this confusion later. | ||
We can do so by adding the `-d` flag to the `git branch` command. | ||
|
||
```bash | ||
git branch -d pythondev | ||
``` | ||
|
||
```output | ||
Deleted branch pythondev (was x792csa1). | ||
``` | ||
|
||
And because we don't want to keep the changes in the `bashdev` branch, | ||
we can delete the `bashdev` branch as well | ||
|
||
```bash | ||
$ git branch -d bashdev | ||
``` | ||
|
||
```output | ||
error: The branch 'bashdev' is not fully merged. | ||
If you are sure you want to delete it, run 'git branch -D bashdev'. | ||
``` | ||
|
||
Since we've never merged the changes from the `bashdev` branch, | ||
git warns us about deleting them and tells us to use the `-D` flag instead. | ||
|
||
Since we really want to delete this branch we will go ahead and do so. | ||
|
||
```bash | ||
git branch -D bashdev | ||
``` | ||
|
||
```output | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's missing the ending (usually each episode has a summary at the end) |
||
Deleted branch bashdev (was 2n779ds). | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm quite sure this can take 25 to 30 minutes. Also, I believe it important to give them an exercise to try it out themselves, because it's something that can be confusing and just trying it allows to fully understand what one is doing. maybe 5 to 10 for exercises?