<style>
.reveal {
font-size: 26px;
}
</style>
## Git: Branches, merging, rebasing
Wojciech Hardy
link: https://hackmd.io/@WHardy/RR-git3
---
## Branches
Part of the typical workflow

Source: [Harness](https://www.harness.io/blog/git-branching)
---
## Branches -- advantages
Main branch keeping a clean history of releases
Room for experimentation without breaking anything
Simultaneous work for many people
Easy to reverse work on a feature and continue with main
---
## Branches can have branches

(Source: [Git Better](https://gitbetter.substack.com/p/how-to-work-in-multiple-git-branches))
---
## Branches - how do they work?
Recall `master` or `main` branch is an indicator
You create a new branch using `git branch <branch-name>`
The new branch is a new indicator with its own `staging area` and `working directory`
Scroll down to see what happens step-by-step
----
## We start with one branch: `main`

Recall: `HEAD` points to 'where we currently are'
`main` points to the latest commit on branch
----
## We create a new branch that we name "feature" with `git branch feature`

This creates a new indicator pointing to where we are.
But `HEAD` still points to the `main` branch.
----
## We use `git checkout feature` to get to the new "feature" branch

The `HEAD` indicator goes to the `feature` branch.
---
## Ok, let's do it, setup:
1) In folder RR_git3 create bare central repository and two cloned ones.
`mkdir RR_git3`
`cd RR_git3`
`git init CentralRepo --bare`
`git clone CentralRepo Dev1`
`git clone CentralRepo Dev2`
----
2) As `dev1` create a short history of commits (minimum two) and push it
`cd dev1`
`echo "a first file" > file1.txt`
`git add .`
`git commit -m "Added a first file"`
`echo "a second file" > file2.txt`
`git add .`
`git commit -m "Added a second file"`
`git push`
----
3) As `dev2` pull the information
`cd ../dev2`
`git pull`
---
## Let's practice branching
1) As Dev1, create a new branch named `feature1`
`cd ../dev1`
`git branch feature1`
----
2) List branches (try to find the appropriate `git branch` option to do that)
`git branch -l`
----
3) Switch to the new branch (use `git checkout <branch-name>`)
`git checkout feature1`
---
## What's the new workflow?
You can add commits only to one of the branches at a time.
When you switch between branches, Git 'refreshes' your staging area and working directories to match `HEAD`.
---
## Let's start with a simple commit history:

----
## New commits affect only the current branch

----
## New commits affect only the current branch

In a big project, e.g. if you're the one working on the `feature`, changes to `main` might not be yours (other people push their features/fixes, etc. in the meantime).
----
## Let's switch to the `feature` branch with `git checkout feature`

----
## And add some commits while in there

----
## One more

----
## At any point you can return to the `main` with `git checkout main`

---
## Let's try working with branches
1) As Dev1, while in the `feature1` branch, add a file, stage and commit it. Then do a `push`.
`echo "some text" > file_on_feature1.txt`
`git add .`
`git commit -m "First file on feature1 branch"`
`git push`
Read the message and follow the hints.
`git push --set-upstream origin feature1`
----
2) Switch back to the `main` branch and notice what's going on in your working directory.
`ls`
`git checkout main`
`ls`
(or look at it in Explorer/Finder)
----
3) Add a file (do not commit it) and try changing branches.
`echo "some other text" > some_file.txt`
`git checkout feature1`
What happens? (put it somewhere as part of a new commit and push it)
`git add .`
`git commit -m "New file added to history"`
----
4) As Dev2 execute `git pull` and check `git branch -l`
`cd ../Dev2`
`git pull`
`git branch -l`
----
5) Execute `git checkout feature1` and check `git branch -l` again
`git checkout feature1`
`git branch -l`
---
## Let Dev2 do some work
1) Create a new commit on the `main` branch
`git checkout main`
`echo "another text" > file_dev2main.txt`
`git add .`
`git commit -m "A file added to main by dev2"`
----
2) Create a new commit on the `feature1` branch
`git checkout feature1`
`echo "another text" > file_dev2feature.txt`
`git add .`
`git commit -m "A file added to feature1 by dev2"`
----
3) Run `git status` on the `main` branch, push the changes
`git checkout main`
`git status`
`git push`
`git status`
----
4) Run `git status` on the `feature1` branch, push the changes
`git checkout feature1`
`git status`
`git push`
`git status`
---
## There are two main ways of putting the results back together
You might recall `merge` from how we united `main` with `origin/main`.

----
## While in `main` do `git merge feature`

Recall: `merge` creates a new commit.
----
## You can still work on your `feature` branch
It doesn't include the merge (unless you also do `git merge main` while on the branch `feature`).

----
## Now that we know the basics, let's look again
Can you trace what's been going on in this project?

(Source: [Git Better](https://gitbetter.substack.com/p/how-to-work-in-multiple-git-branches))
---
## Let's go back to the terminal
1) As Dev1 get all the newest updates for both branches.
`cd ../dev1`
`git pull`
`git checkout main`
`git pull`
----
2) Merge the `feature1` branch to the `main` branch using `git merge <branch-name>`. Push.
`git checkout main`
`git merge feature1`
Conflict resolution is the same as in the last week's case.
`git push`
---
## The second approach is rebasing
Rebasing is making your branch start from a different point

----
## Let's first move to the branch we want to move (`git checkout feature`)

----
## Then `git rebase main`

Important: `rebase` destroys original commits and creates new ones! Probably not a good thing if the original ones were shared with others or in a remote repository!
---
## Also, you don't need to rebase only within the same branch
Assume you start with this:

----
## Possible troublesome situations:
- `feature1` branch proved a dead end, but `feature2` is promising
- `feature2` is actually unrelated to `feature1`
- `main` branch introduced something relevant to `feature2`
----
## The solution is to rebase `feature2` to `main`
`git checkout feature2`
`git rebase --onto main feature1 feature2`
`git rebase --onto <new-base> <old-base> <moved-branch>

----
## Let's go back to the large graph
Can you see how `rebase` could come in handy for the lower `feature` branch?

(Source: [Git Better](https://gitbetter.substack.com/p/how-to-work-in-multiple-git-branches))
---
## Helpful links
[For more on rebasing](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase).
Read [Merging vs rebasing on Atlassian](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) for a nice description of both approaches (also their individual pages).
Also, take a look at [`git bisect`](https://git-scm.com/docs/git-bisect), to understand when rebasing might be helpful.
---
{"metaMigratedAt":"2023-06-17T23:18:23.078Z","metaMigratedFrom":"YAML","title":"Reproducible Research 4 - Git 3","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"1c10bb23-6c4c-4c1b-8586-5f8d56305139\",\"add\":23141,\"del\":15099}]","description":"Wojciech Hardy"}