## Branches
### Jan Kozubowski
---
## Git architecture
### Commits
1. Commits history forms a [Directed Acyclic Graph (DAG)](https://journal.hexmos.com/git-uses-dag/)
2. Each commit contains:
- a snapshot of the repository
- metadata (author, timestamp, message)
- a pointer to its parent commit
- unique hash id
---

[Source](https://pavolkutaj.medium.com/explaining-dag-directec-acyclic-graphs-as-utilized-in-git-a7acccf2a6c6)
---
<div style="transform: scale(0.55); transform-origin: top;">
### Branches
1. Branch is simply a pointer to a specific commit
2. No files are copied while creating a new branch
3. After merging two branches node (commit) has two parents in DAG
- check `git log` after the merge

[Source](https://www.graphapp.ai/engineering-glossary/git/dag-directed-acyclic-graph#:~:text=Branches%20and%20Merging&text=In%20the%20context%20of%20the,node%20with%20two%20parent%20commits.)
</div>
---
## HEAD
Your current position in the repository (or the checkout commit that is the basis for your work)
Special pointer to track the current location.
1. HEAD usually points to a branch name
2. Branch name points to the last commit
When you make a commit:
1. Git moves the branch forward
2. HEAD moves with it
----
<!-- .slide: style="font-size: 0.87em;" -->
## Investigate .git folder
```
# Show all the files in the directory (including hidden folder)
ls -la
# Access .git folder
cd .git
ls
# Show HEAD
cat HEAD
# Switch branch
cd ..
git switch -c new_branch
# Add some sample file and commit
touch text.txt
git add .
git commit -m "Add text txt file"
# Check HEAD after the change
cat .git/HEAD
```
Check refs/heads in .git folder and open a file for specific branch. What is inside?
---
## Detached HEAD
When HEAD point to the specific commit not to the branch
Effect: you are not on a specific branch
```
# Moves HEAD to a different state in a repository history:
git checkout <commit-hash>
# or
git switch --detach <commit-hash>
```
---

[Source](https://blog.git-init.com/what-is-head-in-git/)
---

Created with [visualizing-git](https://github.com/git-school/visualizing-git)
---
## Why do we use detached HEAD?
1. Temporarily experimenting
2. Testing old code (investigate a bug in old version)
3. Creating new branch starting from old commit
---
<!-- .slide: style="font-size: 0.95em;" -->
## Risk associated with detached HEAD
1. You can lose work
2. Commits in detached state can become unreachable
- you won't see them after switching branch and triggering `git log` (try: `git reflog`)
4. Finally they will be removed by git (garbage collection)
5. Easy to accidentally discard work (switch branch)
```
Warning: you are leaving commits behind
```
---
## Example workflow

---

---
<!-- .slide: style="font-size: 0.85em;" -->

You can also do these three steps using one command:
```
# Modern way:
git switch -c <new-branch-name> <commit-hash>
# Old way:
git checkout -b <new-branch-name> <commit-hash>
```
---
## Switching branches with uncommited changes
Scenarios:
1. If there is no conflict between changes git will bring the them to the new branch (they will still be in working directory)
2. If there are conflicting changes git will show error message. You need to commit changes first and then change branch
```
error: Your local changes to the following
files would be overwritten by checkout
```
---
## Exercise: detached HEAD and braches
1. Initialize a repository: `git init branch-demo`
2. `cd branch-demo`
3. You can open VSC: `code .` Open terminal in VSC and continue
4. Create a history of three commits (you can create and change sample txt files)
```
# repeat 3 times
git add .
git commit -m "Message"
```
3. Check hitory: `git log --oneline`
---
5. Checkout a specific commit (you are now in detached HEAD):
```
git switch --detach HEAD~1
# Check git status:
git status
# See "future" commits:
git log HEAD..master
# See all history:
git log --all --graph --oneline
```
---
5. Change something in txt files. Stage and commit changes.
6. Show all the branches: `git branch`
7. Create a new branch starting from a new commit:
```
git switch -c branch_based_on_old_commit
```
8. Check all the branches and logs:
```
git branch
git log --all --graph --oneline
```
Our work is preserved on a new branch.
---
## Exercise: lost commits
1. In branch-demo repo go back to master branch:
```
git switch master
```
2. Add two commits to the history
3. Run `git log` and copy hash id of some old commit
4. Use detached HEAD (paste hash id)
```
git switch --detach <commit-hash-id>
```
---
5. Add two sample commits and check logs (`git log`)
6. Switch branch back to master
```
git switch master
```
What warning is git showing? Run `git log` and try to find these commits. Try `git reflog`!
---
## Merging and rebasing
---
## Fast-forward merge

[Source](https://lukemerrett.com/different-merge-types-in-git/)
---
## Merge commit

[Source](https://lukemerrett.com/different-merge-types-in-git/)
---
<!-- .slide: style="font-size: 0.87em;" -->
## Exercise: merge
```
# 1. Create a git repo
mkdir merge-demo && cd merge-demo
git init
# 2. Add commit history
echo "commit 1 master" > commit_log.txt
# Stage and commit.
# 3. Add new line to the file
echo "commit 2 master" >> commit_log.txt
# Stage and commit.
# Print the file:
cat commit_log.txt
# 4. Create a new branch feature:
git switch -c feature #or git checkout -b feature
```
---
<!-- .slide: style="font-size: 0.87em;" -->
```
# 5. Make a divergent history on feature and master
echo "commit 1 feature" >> commit_log.txt
# Stage and commit.
# 6. Switch to master and make commits
git switch master
echo "commit 3 master" > new_file.txt
# Stage and commit.
# Check the graph
git log --oneline --graph --decorate --all
```
<div style="transform: scale(0.55); transform-origin: top;">

</div>
---
```
# 7. Merge
git switch master
cat commit_log.txt
git merge feature
cat commit_log.txt
git log --oneline --graph --decorate --all
# Show parents:
git show
```
<div style="transform: scale(0.55); transform-origin: top;">

</div>
---
## Squash and merge

[Source](https://lukemerrett.com/different-merge-types-in-git/)
---
## Rebase and merge

[Source](https://lukemerrett.com/different-merge-types-in-git/)
---
## Exercise: rebase
```
# 1. Go back to our merge-demo repo
cd merge-demo
# 2. We want to delete a merge commit from previous exercise. Check where the HEAD was:
git reflog
# Copy the commit shash just before the merge commit
git reset --hard <copied-hash-id>
# Show file
cat commit_log.txt
```
<div style="transform: scale(0.55); transform-origin: top;">

</div>
---
```
3. Switch to feature branch
git switch feature
# Show log
git log --oneline --graph --decorate --all
# 4. Rebase: feature commits will be replayed on top of master
git rebase master
# Show log
git log --oneline --graph --decorate --all
```
<div style="transform: scale(0.55); transform-origin: top;">

</div>
---
```
# 5. Merge branches
git switch master
git merge feature
# 6. Show history
git log --oneline --graph --decorate --all
```
What kind of merge is that? What are we missing in the history compared to the previous exercise?
<div style="transform: scale(0.45); transform-origin: top;">

</div>
---
Git merge mess

[Source](https://www.edureka.co/blog/git-rebase-vs-merge/)
---
## When to use rebase?
1. With `git merge` history gets messy with merge commits
2. Rebase often makes fast-forward merge possible (without commit)
3. Clean, linear history
4. Easy to review
Don't use rebase in shared/remote branches! Rebase rewrites history to make it cleaner.
---
## Exercise: merge conflict
```
# In merge-demo repo switch to master and create file
git switch master
echo "Hello world" > file.txt
# Stage and commit
# Switch to feature
git switch feature
echo "Hello world from feature branch" > file.txt
# Stage and commit
```
---
```
# Switch to master and merge
git switch master
git merge feature
# Open the conflicted file and resolve the conflict
# Check changed files
git status
# Stage and commit:
git add file.txt
git commit -m "Resolve merge conflict"
# Show log:
git log --oneline --graph --decorate --all
```
{"description":"Commits history forms a Directed Acyclic Graph (DAG)","title":"Branches","contributors":"[{\"id\":\"9b02b446-e66a-4b87-ad0b-21574e73f20f\",\"add\":12219,\"del\":2891,\"latestUpdatedAt\":1774289815705}]"}