|
| 1 | +# Branching |
| 2 | + |
| 3 | +Each branch was deviated from certain commit of another branch, and could have its own `HEAD` when actual divergence was applied. |
| 4 | +So a branch besides the main branch is essentially a sequence of commits starting with a divergence from another branch. |
| 5 | + |
| 6 | +> [!IMPORTANT] |
| 7 | +> Branch is a concept upon commits, the branch is sometimes equivalent to the latest commit of that branch. |
| 8 | +> A branch is just a special commit points to latest commit of that branch and can trace back to the divergence. |
| 9 | +
|
| 10 | +## Branch Identifier |
| 11 | + |
| 12 | +1. **branch name**: generally refers to local branch |
| 13 | +2. `<remote>/<branch>`: refers to remote branch **copy fetched** in local |
| 14 | +3. `@{upstream}` or `@{u}`: see [Synchronization](./5.Synchronization.md#remote-branch-identifier) |
| 15 | + |
| 16 | +> [!NOTE] |
| 17 | +> Given the context that *upstream* is of a branch, `git rev-parse @{u}` should return the fetched latest commit hash of remote **in local**. |
| 18 | +
|
| 19 | +## Branch Inspection |
| 20 | + |
| 21 | +A branch has its dedicated text file containing its latest commit hash at `./.git/refs/heads/<branch>` |
| 22 | + |
| 23 | +```console |
| 24 | +$ cat ./.git/refs/heads/msbuid_ls |
| 25 | +4bfbc0c67e39f5615e0cdc4535611af1e71040d8 |
| 26 | +``` |
| 27 | + |
| 28 | +If the latest commit hash is the only thing the branch knows, how could it collect all of the commits when git requires to? |
| 29 | +The fact is, commits are chained with their parent and child, so git can track back along to the point where the branch was diverged. |
| 30 | + |
| 31 | +## Branch Manipulation |
| 32 | + |
| 33 | +> [!NOTE] |
| 34 | +> See `git help branch` and `tldr git-branch`. |
| 35 | +> Or `git help switch` and `tldr git-switch`. |
| 36 | +
|
| 37 | +- `git branch` |
| 38 | + - `-d|--delete`: delete branch |
| 39 | + - `-m|--move`: rename branch |
| 40 | + - `-c|--copy`: copy branch |
| 41 | + |
| 42 | +## Merging & Rebasing |
| 43 | + |
| 44 | +1. **General merge**: merges one branch history to another |
| 45 | + - this generates a **merge commit**, containing the information about all parents that were merged together, the merge commit is added to the branch merged into. |
| 46 | +2. **Fast forward merging**: when there' no actual divergence on graph between the parent branch and child branch, git can simply move the head pointer of current branch directly from the **merge-base** to the top commit of the branch to be merged from |
| 47 | + - generates no merge commit by default, but if do want to keep the history, use `git merge --no-ff` even when the history could be linear. |
| 48 | +3. **Rebasing**: move the **divergence point(aka the base)** to another commit. |
| 49 | + - generates no *merge commit* |
| 50 | + - alters your local commit history since its entire root of divergence has been changed. |
| 51 | + - **DO NOT** use `rebase` in public branch, use it only on your local branch. |
| 52 | + - If you're sure there's only you to work with the public branch(and its sub branches), feel free to `git push --force` to override the history on remote. |
| 53 | + |
| 54 | +> [!IMPORTANT] |
| 55 | +> Always *merge* on public branches, *rebase* on local branches. |
| 56 | +
|
| 57 | +### Merge |
| 58 | + |
| 59 | +A merging involves two branches, the subject of the operation is the branch to merge to. |
| 60 | + |
| 61 | +1. checkout to the branch to merge to. |
| 62 | +2. `git merge <another_branch>` |
| 63 | + - use `--no-ff` to always generate a merge commit. |
| 64 | + |
| 65 | +### Rebasing |
| 66 | + |
| 67 | +Differ from `merge` subcommand, `rebase` is the change on the branch itself, only one branch is involved in the whole operation. |
| 68 | + |
| 69 | +1. checkout to the branch you need to alter its merge-base |
| 70 | +2. `git rebase <commit_identifier>` |
0 commit comments