Files
mapas-mentales/mindmap/Git Branching.md

28 KiB
Raw Blame History

# Git Branching

## Why branching matters (and why Git is different)
- Branching (general VCS concept)
  - Meaning: diverge from the main line of development
  - Goal: keep working without disturbing the main line
- Traditional VCS branching (typical tradeoff)
  - Often “expensive”
  - May require creating a full new copy of the source directory
  - Large projects → branching can take a long time
- Git branching “killer feature”
  - Incredibly lightweight model
  - Branch operations are (nearly) instantaneous
  - Switching branches is typically just as fast
  - Encourages frequent branching + merging (even multiple times per day)
  - Mastering branching can significantly change how you develop

## Branches in a Nutshell (how Gits model works)
- Why you must understand Gits storage model
  - Branching is “just pointers” in Git, but that only makes sense once you know what commits are
  - Reference: earlier concept “What is Git?” (snapshots, SHA-1, objects)

### Git stores snapshots, not diffs/changesets
- Gits core model
  - Instead of storing a sequence of diffs, Git stores a sequence of snapshots
  - Each commit represents the state of the project at that point

### Commit objects: what a commit contains
- Commit object includes
  - Pointer to the snapshot you committed (via a tree object)
  - Metadata
    - author name + email
    - commit message
  - Parent commit pointer(s)
    - 0 parents → initial commit
    - 1 parent → normal commit
    - 2+ parents → merge commit (merging 2+ branches)

### Example: first commit with 3 files (blobs + tree + commit)
- Scenario
  - Working directory contains 3 files
  - You stage all and commit
- Staging step (`git add …`)
  - Example:
    - `git add README test.rb LICENSE`
  - Git computes a checksum (SHA-1) for each file version
  - Git stores each file version as a **blob** object
  - The staging area (index) records the blob checksums for whats staged
- Commit step (`git commit …`)
  - Example:
    - `git commit -m "Initial commit"`
  - Git checksums each directory (here: project root) and stores a **tree** object
    - Tree object
      - Lists directory contents
      - Maps filenames → blob IDs
      - (And subdirectories → subtree IDs)
  - Git creates a **commit** object
    - Contains metadata + pointer to the root tree
- Object count after this commit (in this example)
  - 3 blobs (file contents)
  - 1 tree (directory listing + blob references)
  - 1 commit (metadata + pointer to root tree)

### Commit history: parents create a graph
- Each new commit typically
  - Points to a new snapshot (tree)
  - Points to its direct parent commit (previous tip)
- Merge commits
  - Have multiple parents
  - Represent snapshots produced by merges

### What a branch is (Git definition)
- Branch = lightweight movable pointer to a commit (the tip)
- Default starting branch name
  - `master` (historical default name)
  - Moves forward automatically as you commit on it

#### Note: “master” is not special
- Its identical to any other branch
- Its common because
  - `git init` creates it by default
  - many repos never rename it

### Creating a new branch (pointer creation only)
- Command
  - `git branch testing`
- Effect
  - Creates a new pointer named `testing`
  - Points to the same commit youre currently on
  - Does **not** switch your working branch

### HEAD: how Git tracks “current branch”
- HEAD in Git
  - Special pointer to the local branch you currently have checked out
- Difference from other VCSs (conceptual)
  - In Git, HEAD is a pointer to the current local branch (not just “latest revision” in a repo)

### Seeing branch pointers in `git log`
- Useful visualization option
  - `git log --oneline --decorate`
- What `--decorate` shows
  - Labels like `HEAD -> master`
  - Other branch pointers (e.g., `testing`) attached to commits

### Switching branches (checkout)
- Switch to an existing branch
  - `git checkout testing`
- Effect
  - Moves HEAD to point to `testing`
  - Your next commit will advance `testing` (because HEAD points to it)

### Committing advances only the checked-out branch pointer
- If you commit while on `testing`
  - `testing` pointer moves forward
  - `master` pointer stays behind (unchanged)

### Switching back updates pointers and your working directory
- Switch back
  - `git checkout master`
- Checkout does two major things
  - Moves HEAD to `master`
  - Resets working directory to match the snapshot at `master`s tip
- Result
  - Your future work on `master` diverges from the commit you left behind on `testing`

#### Note: `git log` doesnt show all branches by default
- Default behavior
  - `git log` shows the history reachable from the currently checked-out branch
- To see another branchs history explicitly
  - `git log testing`
- To see all branches
  - `git log --all` (often paired with `--graph` and `--decorate`)

#### Note: switching branches changes working directory files
- On branch switch, Git may
  - add files
  - remove files
  - modify files
- Safety rule
  - If Git cant switch cleanly (because it would overwrite conflicting uncommitted changes), it will block the checkout

### Divergent history and visualization
- When both branches get new commits after diverging
  - History becomes a DAG with multiple “tips”
- View divergence clearly
  - `git log --oneline --decorate --graph --all`

### Why Git branches are cheap
- A branch is stored as a simple reference (a file) containing
  - the 40-character SHA-1 of the commit it points to
  - plus a newline → ~41 bytes written
- Consequences
  - Create/delete branches instantly
  - Switching is fast because its mostly pointer movement + updating working directory snapshot
- Contrast: older VCS branching
  - Often implemented by copying the entire project directory
  - Can take seconds/minutes depending on repo size
- Merge support benefit
  - Git records parent pointers in commits
  - Merge-base detection for merges is typically automatic and easy

### Creating a branch and switching immediately
- Common pattern
  - `git checkout -b <newbranch>`
- Git ≥ 2.23 alternative: `git switch`
  - switch to existing: `git switch <branch>`
  - create + switch: `git switch -c <newbranch>` (or `--create`)
  - return to previous branch: `git switch -`

## Basic Branching and Merging (realistic workflow)
- Example workflow goal: develop features while handling urgent production fixes
- High-level steps (website scenario)
  - Work on site
  - Create branch for a user story
  - Work on that branch
  - Urgent hotfix appears
    - switch to production branch
    - create hotfix branch
    - test hotfix
    - merge hotfix and deploy
    - return to user story branch

### Basic Branching example (issue branch + hotfix branch)
- Starting assumption
  - You already have a few commits on `master`

#### Create and work on a topic branch (issue #53)
- Create + switch
  - `git checkout -b iss53`
  - Shorthand for
    - `git branch iss53`
    - `git checkout iss53`
- Do work and commit
  - edit `index.html`
  - `git commit -a -m "Create new footer [issue 53]"`
- Result
  - `iss53` advances (HEAD points to it)

#### Interrupt with urgent hotfix (without mixing in feature work)
- Key rule before switching branches
  - If working directory or staging area has uncommitted changes that would conflict, Git blocks switching
  - Best practice: keep a clean working state when switching
  - Mentioned workarounds (covered later): stashing, commit amending
- Switch back to production/stable branch
  - `git checkout master`
- What you gain
  - working directory restored to `master` snapshot (pre-issue work)
  - you can focus on hotfix cleanly

#### Create and finish the hotfix
- Create + switch to hotfix branch
  - `git checkout -b hotfix`
- Fix and commit
  - edit `index.html`
  - `git commit -a -m "Fix broken email address"`

#### Merge hotfix into master (fast-forward)
- Merge steps
  - `git checkout master`
  - `git merge hotfix`
- Why its a “fast-forward” merge
  - hotfix tip commit is directly ahead of master tip commit
  - No divergence to reconcile
  - Git simply moves the `master` pointer forward
- Deployment outcome
  - master now points to a commit whose snapshot includes the hotfix
  - you can deploy production fix

#### Delete completed hotfix branch
- Delete (safe when merged)
  - `git branch -d hotfix`
- Rationale
  - master already contains the hotfix work

#### Return to feature branch (iss53) and continue
- Switch back
  - `git checkout iss53`
- Continue work and commit
  - `git commit -a -m "Finish the new footer [issue 53]"`
- Important note: hotfix isnt in `iss53` automatically
  - Options if needed
    - merge master into iss53: `git merge master`
    - or wait until iss53 is merged back into master

### Basic Merging (merge feature branch into master)
- When issue #53 is done
  - `git checkout master`
  - `git merge iss53`
- Why this merge differs from the hotfix merge
  - histories diverged earlier
  - master tip is not an ancestor of iss53 tip
- Git performs a three-way merge
  - Inputs
    - snapshot at master tip
    - snapshot at iss53 tip
    - snapshot at their common ancestor
- Output
  - a new merged snapshot
  - a new merge commit
    - “special” because it has more than one parent
- Merge strategy note (as shown in output)
  - merge made by the `recursive` strategy (typical default for two heads)

#### Clean up merged branch
- Delete iss53 after merge
  - `git branch -d iss53`

### Basic Merge Conflicts (when Git cannot auto-merge)
- When conflicts occur
  - both branches changed the same part of the same file differently
- What `git merge` does on conflict
  - stops and reports conflict(s)
  - does NOT create the merge commit yet
  - requires manual resolution

#### Identify unmerged paths
- Use
  - `git status`
- Status shows
  - you are in a merging state
  - list of “unmerged paths”
  - hints to:
    - fix conflicts
    - `git add` files to mark resolution
    - then `git commit` to conclude merge

#### Conflict markers inserted into files
- Git writes markers like
  - `<<<<<<<` (start of conflict block)
  - `=======` (separator)
  - `>>>>>>>` (end of block)
- Meaning
  - Top section = HEAD version (current branch at merge time, e.g., master)
  - Bottom section = incoming branch version (e.g., iss53)

#### Resolve and mark as resolved
- Manual resolution workflow
  - edit file(s)
  - choose one side or combine them
  - remove all markers
- Mark resolution
  - `git add <file>` for each conflicted file
  - staging indicates conflict resolved in Git

#### Using a merge tool (optional)
- Run
  - `git mergetool`
- Behavior
  - opens a visual merge tool
  - helps walk through conflict resolution
- If not configured
  - Git warns `merge.tool` isnt configured
  - offers possible tool choices (platform dependent)
  - you can specify an alternative tool name

#### Finalize the merge
- Verify state
  - `git status`
  - typically indicates “all conflicts fixed” but merge still in progress
- Conclude
  - `git commit`
- Merge commit message details
  - default message mentions merged branch
  - often lists conflicts
  - note in message references merge metadata (e.g., `.git/MERGE_HEAD`)
  - you may edit message to explain how/why conflicts were resolved
- Reference for deeper conflict handling
  - “Advanced Merging” (mentioned as later coverage)

## Branch Management (everyday utilities)
- `git branch` does more than create/delete
  - provides multiple views and filters of branch state

### Listing branches
- `git branch`
  - lists local branches
  - `*` shows current branch (HEAD points here)

### See last commit on each branch
- `git branch -v`
  - shows branch tip commit SHA + message summary

### Filter by merge status
- `git branch --merged`
  - branches already merged into current branch
  - usually safe to delete those (except the current `*` branch)
- `git branch --no-merged`
  - branches not merged into current branch
  - deletion safety
    - `git branch -d <branch>` fails if not fully merged
    - `git branch -D <branch>` forces deletion (discarding unmerged work)

#### Note: merge-status filters are relative to a base
- Default base
  - current branch (if no argument given)
- You can compare relative to a different branch without checking it out
  - `git branch --no-merged master`

## Changing a branch name (rename)
- Safety warning
  - do not rename branches still used by other collaborators
  - do not rename default branches (master/main/etc.) without reading next section

### Rename locally
- `git branch --move bad-branch-name corrected-branch-name`
- Effect
  - preserves history
  - changes only your local ref name initially

### Publish the renamed branch and set upstream
- `git push --set-upstream origin corrected-branch-name`
- Effect
  - creates the new remote branch name
  - configures tracking

### Remove the old remote branch name
- `git push origin --delete bad-branch-name`
- Effect
  - fully replaces the bad remote name with the corrected one

### Verification
- `git branch --all`
  - shows local branches and `remotes/origin/...` remote-tracking refs

## Changing the master branch name (e.g., `master` → `main`)
- High-impact warning
  - renaming default branch can break
    - integrations/services
    - helper utilities
    - build/release scripts
    - any references in code, configs, docs
  - consult collaborators
  - search/update all references to the old name

### Local rename
- `git branch --move master main`
- Result
  - local `master` ref no longer exists
  - local `main` points to the same commit tip

### Push and set upstream
- `git push --set-upstream origin main`
- Result
  - remote now has `main`
  - remote may still have `master`
  - remote HEAD may still point to `origin/master` until host settings change

### Migration checklist (must update external references)
- Dependent projects
  - update code/config referencing old branch
- Test runner configs
  - update any branch-name assumptions
- Build/release scripts
  - update target branch names
- Repo host settings
  - default branch
  - merge rules / protections
  - other branch-name-based settings
- Documentation
  - update old references
- Pull requests
  - close/merge/retarget PRs aimed at old branch

### Delete old remote branch after transition
- `git push origin --delete master`

## Branching Workflows (patterns enabled by lightweight branches)
- Goal
  - choose a branching strategy that matches team/release needs
- Key enabler
  - easy repeated three-way merges over time

### Long-Running Branches (progressive stability)
- Concept
  - keep multiple always-open branches for different stability levels
  - merge “upwards” as code becomes stable
- Common pattern
  - `master`: only stable/released (or release-candidate) code
  - `develop` / `next`: integration/testing branch; can be unstable
  - topic branches merged into develop/next for testing before master
- How to think about “stability”
  - linear commit history view
    - stable branches are “behind” (older, tested commits)
    - bleeding-edge branches are “ahead” (newer, less proven commits)
  - “silo” view
    - commits graduate to more stable silos once fully tested
- Multi-level stability in large projects
  - additional branches like `proposed` / `pu` (proposed updates)
  - idea: not everything is ready for `next` or `master` immediately
- Note
  - not required, but often helpful for large/complex projects

### Topic Branches (short-lived branches)
- Definition
  - branch created for a single feature/bugfix/experiment
  - typically merged and deleted after completion
- Why Git makes this common
  - branch creation/merging is cheap → can do it many times a day
- Benefits
  - clean context switching (work isolated by topic)
  - easier code review (topics commits grouped)
  - flexible integration timing (minutes, days, months later)
  - can merge in any order regardless of creation order
- Example topology from the chapter
  - work on `master`
  - branch `iss91` (issue work)
  - branch `iss91v2` off `iss91` (alternate approach)
  - return to `master` and continue other work
  - branch `dumbidea` off `master` (experimental idea)
  - outcome
    - discard `iss91` if inferior
    - merge `iss91v2` and `dumbidea` if chosen
- Reminder: local operations
  - branching/merging is local-only until you fetch/push/pull
- Reference mention
  - more workflow discussion later in “Distributed Git”

## Remote Branches (remote references + remote-tracking branches)
### Remote references overview
- Remote repos contain references (pointers) to
  - branches
  - tags
  - other refs
- Ways to inspect
  - `git ls-remote <remote>` (full list of remote refs)
  - `git remote show <remote>` (focus on remote branches + info)

### Remote-tracking branches
- Definition
  - local references that record the state of remote branches
  - you cant move them yourself
  - Git updates them during network communication
- Naming
  - `<remote>/<branch>`
  - Examples
    - `origin/master`
    - `origin/iss53`
- Mental model
  - bookmarks showing where a remote branch was last time you connected

### Clone example (how origin/master appears)
- When cloning from a server
  - Git names the remote `origin` by default
  - downloads data
  - creates `origin/master` (remote-tracking)
  - creates your local `master` starting at same commit as origins master

#### Note: “origin” is not special
- Its just the default name created by `git clone`
- You can rename the default remote at clone time
  - `git clone -o booyah ...` → remote-tracking branch becomes `booyah/master`

### Divergence between local and remote
- If you commit locally and someone else pushes to the remote
  - histories diverge
  - `origin/master` does not move until you communicate

### Fetching updates remote-tracking branches
- `git fetch origin`
  - contacts remote
  - downloads objects you dont have
  - updates pointers like `origin/master` to newer commits

### Multiple remotes
- Add another remote
  - `git remote add teamone <url>`
- Fetch it
  - `git fetch teamone`
- Possible outcome
  - if teamone has only a subset of commits you already have from origin:
    - fetch downloads no new objects
    - still updates `teamone/master` pointer to match teamones master tip

## Pushing (sharing branches)
### Why pushing is explicit
- Local branches do not automatically sync to remotes
- Benefit
  - you can keep private local branches
  - push only branches you intend to share/collaborate on

### Push a branch
- Pattern
  - `git push <remote> <branch>`
- Example
  - `git push origin serverfix`
- What Git expands it to (conceptual)
  - `refs/heads/serverfix:refs/heads/serverfix`
- Push local branch to a different remote branch name
  - `git push origin serverfix:awesomebranch`

### Authentication convenience (HTTPS)
- HTTPS push commonly prompts for username/password
- To avoid typing credentials repeatedly
  - credential cache example:
    - `git config --global credential.helper cache`
  - reference mentioned: “Credential Storage” (for other options)

### After someone else fetches
- Fetching a pushed branch
  - `git fetch origin`
- Result
  - creates/updates a remote-tracking ref (e.g., `origin/serverfix`)
  - does NOT create a local editable branch automatically

### Using fetched remote-tracking branch work
- Merge directly into current branch
  - `git merge origin/serverfix`
- Create a local branch based on it (editable) and track it
  - `git checkout -b serverfix origin/serverfix`

## Tracking Branches (local branches that track upstream)
### Definitions
- Tracking branch
  - local branch tied to a remote-tracking branch
- Upstream branch
  - remote-tracking branch the local branch tracks

### Why tracking matters
- On a tracking branch, `git pull` can automatically
  - fetch from the right remote
  - merge the right branch

### How tracking branches are created
- Common creation form
  - `git checkout -b <branch> <remote>/<branch>`
- Shorthand
  - `git checkout --track origin/serverfix`
- Extra shortcut
  - `git checkout serverfix`
  - works if
    - local `serverfix` doesnt exist, and
    - exactly one remote has `serverfix`
- Different local name than remote branch
  - `git checkout -b sf origin/serverfix`
  - local `sf` tracks `origin/serverfix`

### Set or change upstream later
- `git branch -u origin/serverfix`
  - also available as `--set-upstream-to`

### Upstream shorthand in commands
- `@{upstream}` or `@{u}`
  - references the upstream branch of the current branch
- Example
  - `git merge @{u}` instead of `git merge origin/master` (when master tracks origin/master)

### Inspect tracking status and ahead/behind
- `git branch -vv`
  - shows local branches
  - indicates upstream tracking target
  - shows ahead/behind counts
- Interpreting counts
  - ahead N → N local commits not pushed
  - behind N → N remote commits not merged locally
- Cache caveat
  - ahead/behind shown is from last fetch; command doesnt contact server
- To refresh counts
  - `git fetch --all; git branch -vv`

## Pulling (fetch + merge convenience)
- `git fetch`
  - downloads new data
  - does not modify working directory
  - leaves integration to you (merge/rebase)
- `git pull`
  - in most cases = `fetch` immediately followed by `merge`
  - uses tracking (upstream) info to pick remote + branch
- Guidance from the chapter
  - explicit `fetch` + `merge` is often clearer than the “magic” of `pull`

## Deleting Remote Branches
- When a remote branch is no longer needed
  - merged into mainline/stable branch on the server
- Delete remote branch pointer
  - `git push origin --delete serverfix`
- Effect
  - removes the branch pointer on the server
  - server may keep underlying objects until garbage collection
  - accidental deletions can often be recovered before GC runs

## Rebasing (the other integration strategy)
- Two main ways to integrate changes between branches
  - `merge`
  - `rebase`

### The Basic Rebase (replaying commits)
- Starting situation
  - branches diverged; each has unique commits
- Merge recap (already covered earlier)
  - three-way merge of:
    - tip snapshot A
    - tip snapshot B
    - common ancestor snapshot
  - creates a new snapshot + merge commit
- Rebase concept
  - take the patch introduced by commits on one branch
  - reapply them on top of another branchs tip
- Example commands
  - `git checkout experiment`
  - `git rebase master`
- Internal steps (conceptual)
  - find common ancestor between current branch and target branch
  - compute diffs for each commit on current branch since ancestor
  - save diffs temporarily
  - reset current branch to target tip
  - apply diffs sequentially (creating new commits with new SHAs)
- After rebase
  - integrate by fast-forward merge
    - `git checkout master`
    - `git merge experiment`
- Result comparison
  - final snapshot content is the same as with merge
  - history is different
    - rebase → linear-looking history
    - merge → preserves the true parallel shape
- Common use case (contributing workflow)
  - rebase your work onto `origin/master` before submitting patches
  - maintainer can integrate via fast-forward / clean apply
- Core conceptual distinction
  - rebase: replay changes in order introduced
  - merge: combine endpoints and record a merge

### More Interesting Rebases (rebasing a branch off another topic branch)
- Scenario
  - topic branch `server` created from master; commits added
  - topic branch `client` created from `server`; commits added
  - later additional commits added to `server`
- Goal
  - ship client changes now (merge into master)
  - delay server changes until tested
- Use `--onto`
  - `git rebase --onto master server client`
  - Meaning
    - take commits on `client` that are not on `server`
    - replay them as if `client` started from `master`
- Integrate client quickly
  - `git checkout master`
  - `git merge client` (fast-forward)
- Integrate server later without manual checkout
  - `git rebase master server`
    - checks out `server` and replays onto master
  - `git checkout master`
  - `git merge server` (fast-forward)
- Cleanup
  - delete topic branches once integrated
    - `git branch -d client`
    - `git branch -d server`

### The Perils of Rebasing (rewriting published history)
- The one-line rule
  - Do not rebase commits that exist outside your repository and that people may have based work on
- Why rebasing public commits is dangerous
  - rebase abandons existing commits and creates new ones
  - new commits have different SHAs
  - collaborators who based work on old SHAs must reconcile mismatched history
- Example failure pattern (from the chapter)
  - you clone and do work
  - someone else pushes a merge to the central server
  - later they rebase their work and `push --force` (rewriting server history)
  - you fetch new commits
  - if you `git pull` normally, you may create a merge combining old + new lines
    - can lead to duplicate-looking commits (same message/author/date) with different IDs
    - pushing that back can reintroduce commits the other dev tried to eliminate
- Social consequence emphasized
  - if you rewrite shared history, teammates will have to re-merge and untangle confusion

### Rebase When You Rebase (recovering after a force-push)
- Problem after force-push
  - determine which commits are uniquely yours vs rewritten copies
- Patch-id concept
  - besides commit SHA-1, Git can compute a checksum based on the patch content (“patch-id”)
- How rebase helps
  - rebasing onto the updated target can let Git:
    - identify which commits are already represented (same patch)
    - replay only the unique commits
- Example approach
  - `git rebase teamone/master`
- What Git may compute during this recovery rebase (as described)
  - determine commits unique to your branch
  - exclude merge commits from replay
  - detect commits that were rewritten but represent the same patch in the target
  - apply remaining unique commits on top of the updated branch
- Limitation noted
  - works best if rewritten commits are almost the same patch
  - otherwise Git may not detect duplication and may reapply a similar patch (possibly failing)
- Convenience options
  - `git pull --rebase` instead of normal pull
  - or manual: `git fetch` then `git rebase <remote>/<branch>`
  - configure default:
    - `git config --global pull.rebase true`
- Safety guideline recap
  - safe: rebase commits that never left your machine
  - generally ok: rebase pushed commits if nobody based work on them
  - risky: rebase publicly shared commits → coordinate + warn others to use `pull --rebase`

### Rebase vs. Merge (choosing based on what “history” means)
- Two viewpoints on commit history
  - History as a factual record
    - commit history documents what actually happened
    - rewriting is “lying” about events
    - merge commits reflect real parallel work
  - History as a curated story
    - raw development includes missteps and dead ends
    - before mainline, rewrite history to tell a clearer story
    - tools mentioned: `rebase`, `filter-branch`
- Conclusion
  - no universal best choice; depends on team/project
- Practical “best of both worlds” guideline
  - rebase local changes before pushing (clean up)
  - never rebase anything youve pushed somewhere shared/public

## Summary (skills this chapter expects you to have now)
- Branch creation and switching
  - create branches, move between them
  - understand HEAD as “current branch pointer”
- Merging
  - fast-forward merges
  - three-way merges and merge commits (multiple parents)
  - resolve conflicts (markers, `status`, `add`, `mergetool`, final `commit`)
- Branch management
  - list branches and identify current branch
  - inspect branch tips (`-v`)
  - find merged/unmerged branches (`--merged`, `--no-merged`)
  - delete safely (`-d`) or forcibly (`-D`)
  - rename branches (local + remote cleanup)
  - rename default branch (master/main) with ecosystem updates
- Collaboration with remotes
  - remote-tracking branches, fetch/push/pull behaviors
  - create tracking branches and set upstream
  - delete remote branches
- Rebasing
  - what rebase does and why it can make history linear
  - advanced rebase (`--onto`)
  - when rebasing is dangerous and how to mitigate with `pull --rebase`
- Next topic preview (mentioned)
  - how to run your own Git repository-hosting server