Add comprehensive GitHub guide covering account setup, collaboration, and API usage
This commit is contained in:
495
mindmap/Appendix A_ Git in Other Environments.md
Normal file
495
mindmap/Appendix A_ Git in Other Environments.md
Normal file
@@ -0,0 +1,495 @@
|
||||
```markmap
|
||||
# Appendix A: Git in Other Environments
|
||||
|
||||
## Purpose / framing
|
||||
- You’ve learned Git at the command line
|
||||
- Work with local files
|
||||
- Connect repositories over a network
|
||||
- Collaborate effectively
|
||||
- Git is often part of a larger ecosystem
|
||||
- Terminal isn’t always the best interface
|
||||
- Goal of this appendix
|
||||
- Survey other environments where Git is useful
|
||||
- Show how other applications work alongside Git
|
||||
|
||||
## Graphical Interfaces (GUIs)
|
||||
- Git’s native environment: the terminal
|
||||
- New features appear there first
|
||||
- Full power is available at the command line
|
||||
- Why GUIs exist / when they help
|
||||
- Plain text isn’t best for all tasks
|
||||
- Visual representations can be essential
|
||||
- Some users prefer point-and-click workflows
|
||||
- Tools differ by intended workflow
|
||||
- Some clients expose only a curated subset of Git
|
||||
- To support a specific way of working the author considers effective
|
||||
- “Better” is workflow-dependent
|
||||
- Tools are more/less fit for purpose, not universally better
|
||||
- Key constraint
|
||||
- GUIs can’t do anything the command line client can’t
|
||||
- Command line = most power and control
|
||||
|
||||
## gitk and git-gui (bundled with Git)
|
||||
|
||||
### gitk (graphical history viewer)
|
||||
- What it is
|
||||
- GUI history viewer
|
||||
- Think: powerful GUI shell over
|
||||
- `git log`
|
||||
- `git grep`
|
||||
- Best used for
|
||||
- Finding something that happened in the past
|
||||
- Visualizing project history
|
||||
- How to start
|
||||
- In a Git repo directory
|
||||
- `cd <repo>`
|
||||
- Run:
|
||||
- `gitk [git log options]`
|
||||
- Options
|
||||
- Accepts many command-line options
|
||||
- Most are passed through to underlying `git log`
|
||||
- Especially useful:
|
||||
- `--all`
|
||||
- Show commits reachable from any ref (not just `HEAD`)
|
||||
- Interface overview (Figure 151: The gitk history viewer)
|
||||
- Top area (graph; similar to `git log --graph`)
|
||||
- Dot = commit
|
||||
- Lines = parent relationships
|
||||
- Refs = colored boxes
|
||||
- Yellow dot = `HEAD`
|
||||
- Red dot = changes not yet a commit
|
||||
- Bottom area (selected commit)
|
||||
- Left = comments + patch
|
||||
- Right = summary view
|
||||
- Middle controls
|
||||
- Searching history controls
|
||||
|
||||
### git-gui (commit crafting tool)
|
||||
- What it is
|
||||
- Primarily a tool for crafting commits
|
||||
- How to start
|
||||
- Run:
|
||||
- `git gui`
|
||||
- Interface overview (Figure 152: The git-gui commit tool)
|
||||
- Left: index (staging area)
|
||||
- Unstaged changes: top
|
||||
- Staged changes: bottom
|
||||
- Move entire files between states
|
||||
- Click file icons
|
||||
- Select a file for viewing
|
||||
- Click file name
|
||||
- Top right: diff view
|
||||
- Shows changes for the selected file
|
||||
- Stage granular changes
|
||||
- Stage individual hunks (or lines) by right-clicking
|
||||
- Bottom right: message + action area
|
||||
- Enter commit message
|
||||
- Click “Commit”
|
||||
- Similar to `git commit`
|
||||
- Amend last commit workflow
|
||||
- Select “Amend” radio button
|
||||
- Updates “Staged Changes” with contents of last commit
|
||||
- Then
|
||||
- Stage/unstage changes
|
||||
- Alter commit message
|
||||
- Click “Commit” again
|
||||
- Replaces old commit with a new one
|
||||
|
||||
### Tool style classification
|
||||
- `gitk` and `git-gui` are **task-oriented tools**
|
||||
- Tailored to one purpose each
|
||||
- `gitk`: viewing/searching history
|
||||
- `git-gui`: creating/amending commits
|
||||
- Omit features not needed for that task
|
||||
|
||||
## GitHub for macOS and Windows
|
||||
- What these clients are
|
||||
- Two **workflow-oriented** Git clients
|
||||
- One for Windows
|
||||
- One for macOS
|
||||
- Workflow-oriented meaning
|
||||
- Focus on a curated set of commonly used features
|
||||
- Avoid exposing all of Git’s functionality
|
||||
- Similarity across platforms
|
||||
- Designed to look and work very much alike
|
||||
- Treated as a single product here
|
||||
- Not a full product rundown
|
||||
- They have their own documentation
|
||||
- Focus here: “changes” view tour (main work area)
|
||||
|
||||
### “Changes” view: main areas
|
||||
- Left: repositories list (tracked by client)
|
||||
- Add repo via “+” icon
|
||||
- Clone
|
||||
- Attach local repository
|
||||
- Center: commit-input area
|
||||
- Enter commit message
|
||||
- Select which files to include
|
||||
- Commit history placement differs
|
||||
- Windows: directly below
|
||||
- macOS: separate tab
|
||||
- Right: diff view
|
||||
- Shows working directory changes
|
||||
- Or changes included in selected commit
|
||||
- Top-right: “Sync” button
|
||||
- Primary network interaction method
|
||||
- Important note
|
||||
- No GitHub account required
|
||||
- Designed to highlight GitHub service/workflow
|
||||
- Still works with
|
||||
- Any repository
|
||||
- Any Git host (network operations)
|
||||
|
||||
### Installation
|
||||
- Download locations
|
||||
- GitHub for Windows: <https://windows.github.com>
|
||||
- GitHub for macOS: <https://mac.github.com>
|
||||
- First run behavior
|
||||
- Walks through first-time Git setup
|
||||
- Configure name
|
||||
- Configure email address
|
||||
- Sets sane defaults for common config options
|
||||
- Credential caches
|
||||
- CRLF behavior
|
||||
- Update model
|
||||
- “Evergreen”
|
||||
- Updates downloaded/installed in background while app is open
|
||||
- Bundled Git
|
||||
- Likely no need to manually update Git separately
|
||||
- Windows addition
|
||||
- Includes shortcut to launch PowerShell with Posh-git (covered later)
|
||||
- Add repositories
|
||||
- Shows list of GitHub repos you have access to
|
||||
- Clone in one step
|
||||
- Add existing local repo
|
||||
- Drag directory from
|
||||
- Finder (macOS)
|
||||
- Windows Explorer (Windows)
|
||||
- Added to repository list on the left
|
||||
|
||||
### Recommended Workflow (“GitHub Flow”)
|
||||
- Covered elsewhere in more detail (“The GitHub Flow”), gist here
|
||||
- (a) Commit to a branch
|
||||
- (b) Sync with a remote repository fairly regularly
|
||||
- Branch management differences
|
||||
- macOS
|
||||
- “Create Branch” button at top of window (Figure 155)
|
||||
- Windows
|
||||
- Type new branch name in branch-switching widget (Figure 156)
|
||||
- Making commits
|
||||
- Make changes in working directory
|
||||
- Client shows changed files
|
||||
- Enter commit message
|
||||
- Select files to include
|
||||
- Click “Commit”
|
||||
- Shortcut: `Ctrl-Enter` (Windows) or `⌘-Enter` (macOS)
|
||||
- Network interaction via “Sync”
|
||||
- Git internally separates
|
||||
- push / fetch / merge / rebase
|
||||
- GitHub clients collapse these into one multi-step feature
|
||||
- Clicking “Sync” does
|
||||
1. `git pull --rebase`
|
||||
- If fails due to merge conflict
|
||||
- Fall back to `git pull --no-rebase`
|
||||
2. `git push`
|
||||
- Rationale
|
||||
- Common network sequence in this style
|
||||
- Squashing into one command saves time
|
||||
|
||||
### GitHub client summary (fit and tradeoffs)
|
||||
- Strengths
|
||||
- Well-suited to intended workflow
|
||||
- Developers and non-developers can collaborate within minutes
|
||||
- Best practices baked into the tools
|
||||
- When to choose something else
|
||||
- Workflow differs
|
||||
- Want more control over
|
||||
- How network operations are done
|
||||
- When network operations are done
|
||||
- Recommendation
|
||||
- Use another client or the command line
|
||||
|
||||
## Other GUIs (general landscape)
|
||||
- Many graphical Git clients exist
|
||||
- From specialized single-purpose tools
|
||||
- To apps that try to expose everything Git can do
|
||||
- Where to find them
|
||||
- Official Git site curated list: <https://git-scm.com/downloads/guis>
|
||||
- More comprehensive list (Git wiki):
|
||||
- <https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Graphical_Interfaces>
|
||||
|
||||
## Git in Visual Studio
|
||||
- Built-in Git tooling
|
||||
- Starting Visual Studio 2019 version 16.8
|
||||
- Supported Git functionality
|
||||
- Create or clone a repository
|
||||
- Open and browse repository history
|
||||
- Create and checkout branches and tags
|
||||
- Stash, stage, and commit changes
|
||||
- Fetch, pull, push, or sync commits
|
||||
- Merge and rebase branches
|
||||
- Resolve merge conflicts
|
||||
- View diffs
|
||||
- “…and more!”
|
||||
- Next step
|
||||
- Read official documentation
|
||||
|
||||
## Git in Visual Studio Code
|
||||
- Built-in Git support
|
||||
- Requirement
|
||||
- Git version 2.0.0 (or newer) installed
|
||||
- Main features
|
||||
- Diff in the gutter for the file you are editing
|
||||
- Git Status Bar (lower left)
|
||||
- Current branch
|
||||
- Dirty indicators
|
||||
- Incoming commits
|
||||
- Outgoing commits
|
||||
- Common operations inside the editor
|
||||
- Initialize a repository
|
||||
- Clone a repository
|
||||
- Create branches and tags
|
||||
- Stage and commit changes
|
||||
- Push/pull/sync with a remote branch
|
||||
- Resolve merge conflicts
|
||||
- View diffs
|
||||
- GitHub Pull Requests support (extension)
|
||||
- <https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github>
|
||||
- Official documentation
|
||||
- <https://code.visualstudio.com/Docs/editor/versioncontrol>
|
||||
|
||||
## Git in JetBrains IDEs (IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine / others)
|
||||
- Git Integration plugin
|
||||
- Ships with JetBrains IDEs
|
||||
- Provides
|
||||
- Dedicated IDE view for Git
|
||||
- Dedicated IDE view for GitHub Pull Requests
|
||||
- Example: Version Control ToolWindow (Figure 157)
|
||||
- Dependency
|
||||
- Relies on command-line `git`
|
||||
- Requires `git` to be installed
|
||||
- Official documentation
|
||||
- <https://www.jetbrains.com/help/idea/using-git-integration.html>
|
||||
|
||||
## Git in Sublime Text
|
||||
- Availability
|
||||
- From version 3.2 onwards
|
||||
- Features
|
||||
- Sidebar shows git status with a badge/icon
|
||||
- `.gitignore`-listed files/folders are faded in sidebar
|
||||
- Status bar shows
|
||||
- Current git branch
|
||||
- How many modifications you have made
|
||||
- Gutter markers show all changes to a file
|
||||
- Partial integration with Sublime Merge
|
||||
- Use some Sublime Merge git client functionality from within Sublime Text
|
||||
- Requires Sublime Merge installed
|
||||
- Sublime Merge: <https://www.sublimemerge.com/>
|
||||
- Official documentation
|
||||
- <https://www.sublimetext.com/docs/3/git_integration.html>
|
||||
|
||||
## Git in Bash
|
||||
- Motivation
|
||||
- Use shell features to make Git friendlier in Bash
|
||||
- Note
|
||||
- Git ships with plugins for several shells
|
||||
- Not enabled by default
|
||||
|
||||
### Enable tab completion (`git-completion.bash`)
|
||||
- Get completion script matching your Git version
|
||||
- Check version: `git version`
|
||||
- In Git source for that release
|
||||
- `git checkout tags/vX.Y.Z` (match your installed version)
|
||||
- Copy file:
|
||||
- `contrib/completion/git-completion.bash`
|
||||
- Place somewhere handy (example)
|
||||
- Home directory
|
||||
- Enable in `~/.bashrc`
|
||||
- Add:
|
||||
- `. ~/git-completion.bash`
|
||||
- Use completion
|
||||
- Inside a Git repository, type
|
||||
- `git chec<tab>`
|
||||
- Auto-completes to `git checkout`
|
||||
- Completion coverage
|
||||
- Git subcommands
|
||||
- Command-line parameters
|
||||
- Remotes and ref names (where appropriate)
|
||||
|
||||
### Customize prompt (`git-prompt.sh`)
|
||||
- Motivation
|
||||
- Show Git info in prompt
|
||||
- Current branch
|
||||
- Working directory status
|
||||
- Setup
|
||||
- Copy file from Git source:
|
||||
- `contrib/completion/git-prompt.sh`
|
||||
- Place in home directory
|
||||
- Add to `~/.bashrc`
|
||||
- `. ~/git-prompt.sh`
|
||||
- `export GIT_PS1_SHOWDIRTYSTATE=1`
|
||||
- `export PS1='\w$(__git_ps1 " (%s)")\$ '`
|
||||
- Meaning of prompt pieces
|
||||
- `\w`
|
||||
- Print current working directory
|
||||
- `\$`
|
||||
- Print `$` part of the prompt
|
||||
- `__git_ps1 " (%s)"`
|
||||
- Calls function provided by `git-prompt.sh`
|
||||
- Uses formatting argument `" (%s)"`
|
||||
- Result
|
||||
- Prompt shows Git context inside Git-controlled projects (Figure 158)
|
||||
- Further info
|
||||
- Both scripts have documentation
|
||||
- Inspect `git-completion.bash`
|
||||
- Inspect `git-prompt.sh`
|
||||
|
||||
## Git in Zsh
|
||||
|
||||
### Tab completion
|
||||
- Enable
|
||||
- Add to `~/.zshrc`
|
||||
- `autoload -Uz compinit && compinit`
|
||||
- Interface (more powerful than Bash)
|
||||
- Example: `git che<tab>`
|
||||
- Shows options with descriptions, e.g.
|
||||
- `check-attr` — display gitattributes information
|
||||
- `check-ref-format` — ensure a reference name is well formed
|
||||
- `checkout` — checkout branch or paths to working tree
|
||||
- `checkout-index` — copy files from index to working directory
|
||||
- `cherry` — find commits not merged upstream
|
||||
- `cherry-pick` — apply changes introduced by an existing commit
|
||||
- Ambiguous completions
|
||||
- Not just listed; include helpful descriptions
|
||||
- Navigate list by repeatedly hitting tab
|
||||
- Completion scope
|
||||
- Git commands and arguments
|
||||
- Refs/remotes and other repo-internal names
|
||||
- Filenames and standard Zsh completions
|
||||
|
||||
### Prompt integration with `vcs_info`
|
||||
- Built-in framework
|
||||
- `vcs_info` provides VCS information for prompts
|
||||
- Configure branch name in right prompt
|
||||
- Add to `~/.zshrc`
|
||||
- `autoload -Uz vcs_info`
|
||||
- `precmd_vcs_info() { vcs_info }`
|
||||
- `precmd_functions+=( precmd_vcs_info )`
|
||||
- `setopt prompt_subst`
|
||||
- `RPROMPT='${vcs_info_msg_0_}'`
|
||||
- `# PROMPT='${vcs_info_msg_0_}%# '`
|
||||
- `zstyle ':vcs_info:git:*' formats '%b'`
|
||||
- Result
|
||||
- Branch shown on right side inside Git repos (Figure 159)
|
||||
- Left-side prompt also possible
|
||||
- Uncomment the `PROMPT=...` line
|
||||
- Documentation
|
||||
- `vcs_info` docs in `zshcontrib(1)`
|
||||
- Online:
|
||||
- <http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Version-Control-Information>
|
||||
|
||||
### Alternative: Git’s `git-prompt.sh`
|
||||
- Option
|
||||
- Use Git’s `git-prompt.sh` instead of `vcs_info`
|
||||
- Compatibility
|
||||
- Works with Bash and Zsh
|
||||
- Reference
|
||||
- <https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh>
|
||||
|
||||
### Zsh framework: oh-my-zsh
|
||||
- What it is
|
||||
- A framework to enhance Zsh
|
||||
- Location
|
||||
- <https://github.com/robbyrussell/oh-my-zsh>
|
||||
- Git-related value
|
||||
- Powerful git tab completion via plugin system
|
||||
- Many prompt “themes” showing version-control data
|
||||
- Example theme shown (Figure 160)
|
||||
|
||||
## Git in PowerShell
|
||||
|
||||
### Why / what
|
||||
- Limitation
|
||||
- `cmd.exe` isn’t really capable of a customized Git experience
|
||||
- If using PowerShell
|
||||
- `posh-git` provides
|
||||
- Powerful tab completion
|
||||
- Enhanced prompt (repository status awareness)
|
||||
- Works with PowerShell Core on Linux/macOS too
|
||||
- Project: <https://github.com/dahlbyk/posh-git>
|
||||
- Example shown (Figure 161)
|
||||
|
||||
### Installation
|
||||
|
||||
#### Prerequisites (Windows only): ExecutionPolicy
|
||||
- Requirement
|
||||
- Set local `ExecutionPolicy` to `RemoteSigned`
|
||||
- Anything except `Undefined` and `Restricted`
|
||||
- `AllSigned` vs `RemoteSigned`
|
||||
- `AllSigned`
|
||||
- Local scripts (your own) also need digital signatures
|
||||
- `RemoteSigned`
|
||||
- Only scripts with `ZoneIdentifier` = Internet (downloaded from web) need signatures
|
||||
- Others do not
|
||||
- Scope guidance
|
||||
- Admin / all users
|
||||
- `-Scope LocalMachine`
|
||||
- Normal user / no admin rights
|
||||
- `-Scope CurrentUser`
|
||||
- References
|
||||
- Scopes: <https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes>
|
||||
- ExecutionPolicy: <https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy>
|
||||
- Set `RemoteSigned` for all users
|
||||
- `Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned -Force`
|
||||
|
||||
#### Install via PowerShell Gallery
|
||||
- When available
|
||||
- PowerShell 5+, or PowerShell 4 with PackageManagement installed
|
||||
- Reference
|
||||
- <https://docs.microsoft.com/en-us/powershell/scripting/gallery/overview>
|
||||
- Install commands (CurrentUser)
|
||||
- `Install-Module posh-git -Scope CurrentUser -Force`
|
||||
- `Install-Module posh-git -Scope CurrentUser -AllowPrerelease -Force`
|
||||
- Newer beta with PowerShell Core support
|
||||
- Install for all users
|
||||
- Use `-Scope AllUsers`
|
||||
- Run from elevated PowerShell console
|
||||
- If install fails due to `PowerShellGet` error
|
||||
- Run first:
|
||||
- `Install-Module PowerShellGet -Force -SkipPublisherCheck`
|
||||
- Then retry
|
||||
- Reason given
|
||||
- Built-in Windows PowerShell modules are signed with a different publishment certificate
|
||||
|
||||
#### Update PowerShell prompt (load automatically)
|
||||
- Import now
|
||||
- `Import-Module posh-git`
|
||||
- Auto-import every time PowerShell starts
|
||||
- `Add-PoshGitToProfile -AllHosts`
|
||||
- Adds import statement to `$profile` script
|
||||
- Note
|
||||
- Multiple `$profile` scripts exist
|
||||
- e.g., console profile vs ISE profile
|
||||
|
||||
#### Install from source
|
||||
- Download a release
|
||||
- <https://github.com/dahlbyk/posh-git/releases>
|
||||
- Uncompress
|
||||
- Import module via full path to `posh-git.psd1`
|
||||
- `Import-Module <path-to-uncompress-folder>\src\posh-git.psd1`
|
||||
- Add to profile
|
||||
- `Add-PoshGitToProfile -AllHosts`
|
||||
- Effect
|
||||
- Adds proper line to `profile.ps1`
|
||||
- Active next time PowerShell opens
|
||||
|
||||
#### Further references (prompt meaning & customization)
|
||||
- Git status summary information
|
||||
- <https://github.com/dahlbyk/posh-git/blob/master/README.md#git-status-summary-information>
|
||||
- Prompt customization variables
|
||||
- <https://github.com/dahlbyk/posh-git/blob/master/README.md#customization-variables>
|
||||
|
||||
## Appendix summary
|
||||
- You can harness Git from within everyday tools (GUIs, IDEs, editors, shells)
|
||||
- You can also access Git repositories from your own programs
|
||||
```
|
||||
695
mindmap/Appendix B_ Embedding Git in your Applications.md
Normal file
695
mindmap/Appendix B_ Embedding Git in your Applications.md
Normal file
@@ -0,0 +1,695 @@
|
||||
# Appendix B: Embedding Git in your Applications
|
||||
|
||||
## Why embed / integrate Git
|
||||
- Target audience for integration
|
||||
- Developer-focused applications
|
||||
- likely benefit from integration with source control
|
||||
- Non-developer applications
|
||||
- example: document editors
|
||||
- can benefit from version-control features
|
||||
- Why Git specifically
|
||||
- Git’s model works very well for many different scenarios
|
||||
|
||||
## Two main integration options
|
||||
- Option A: spawn a shell and call the `git` command-line program
|
||||
- Option B: embed a Git library into your application
|
||||
- This appendix covers
|
||||
- command-line integration
|
||||
- several of the most popular embeddable Git libraries
|
||||
|
||||
## Command-line Git (calling the `git` CLI)
|
||||
- What it is
|
||||
- spawn a shell process
|
||||
- use the Git command-line tool to do the work
|
||||
- Benefits
|
||||
- canonical behavior
|
||||
- all of Git’s features are supported
|
||||
- fairly easy to implement
|
||||
- most runtime environments can invoke a process with command-line arguments
|
||||
- Downsides
|
||||
- Output is plain text
|
||||
- you must parse Git’s output to read progress/results
|
||||
- Git’s output format can change occasionally
|
||||
- parsing can be inefficient and error-prone
|
||||
- Lack of error recovery
|
||||
- if repository is corrupted
|
||||
- or user has malformed configuration value
|
||||
- Git may refuse to perform many operations
|
||||
- Process management complexity
|
||||
- must maintain a shell environment in a separate process
|
||||
- coordinating many processes can be challenging
|
||||
- especially if multiple processes may access the same repository
|
||||
|
||||
## Libgit2
|
||||
- What it is
|
||||
- dependency-free implementation of Git
|
||||
- focus: a nice API for use within other programs
|
||||
- website: https://libgit2.org
|
||||
|
||||
### Libgit2 C API (whirlwind tour)
|
||||
- Example flow shown
|
||||
- Open a repository
|
||||
- `git_repository *repo;`
|
||||
- `int error = git_repository_open(&repo, "/path/to/repository");`
|
||||
- Dereference `HEAD` to a commit
|
||||
- `git_object *head_commit;`
|
||||
- `error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");`
|
||||
- `git_commit *commit = (git_commit*)head_commit;`
|
||||
- Print commit properties
|
||||
- `printf("%s", git_commit_message(commit));`
|
||||
- `const git_signature *author = git_commit_author(commit);`
|
||||
- `printf("%s <%s>\n", author->name, author->email);`
|
||||
- `const git_oid *tree_id = git_commit_tree_id(commit);`
|
||||
- Cleanup
|
||||
- `git_commit_free(commit);`
|
||||
- `git_repository_free(repo);`
|
||||
|
||||
- Repository opening details
|
||||
- `git_repository` type
|
||||
- handle to a repository with an in-memory cache
|
||||
- `git_repository_open`
|
||||
- simplest method when you know exact path to working directory or `.git` folder
|
||||
- other APIs mentioned
|
||||
- `git_repository_open_ext`
|
||||
- includes options for searching
|
||||
- `git_clone` (and friends)
|
||||
- make a local clone of a remote repository
|
||||
- `git_repository_init`
|
||||
- create an entirely new repository
|
||||
|
||||
- Dereferencing `HEAD` details
|
||||
- rev-parse usage
|
||||
- uses rev-parse syntax
|
||||
- reference: “see Branch References for more on this”
|
||||
- return type
|
||||
- `git_revparse_single` returns a `git_object*`
|
||||
- represents something that exists in the repository’s Git object database
|
||||
- `git_object` is a “parent” type for several object kinds
|
||||
- child types share the same memory layout as `git_object`
|
||||
- safe to cast to the correct “child” type when appropriate
|
||||
- cast safety note in this example
|
||||
- `git_object_type(commit)` would return `GIT_OBJ_COMMIT`
|
||||
- therefore it’s safe to cast to `git_commit*`
|
||||
|
||||
- Commit property access details
|
||||
- message
|
||||
- `git_commit_message(commit)`
|
||||
- author signature
|
||||
- `git_commit_author(commit)` returns `const git_signature *`
|
||||
- fields shown
|
||||
- `author->name`
|
||||
- `author->email`
|
||||
- tree id
|
||||
- `git_commit_tree_id(commit)` returns a `git_oid`
|
||||
- `git_oid`
|
||||
- Libgit2 representation for a SHA-1 hash
|
||||
|
||||
### Patterns illustrated by the Libgit2 C sample
|
||||
- Error-code style
|
||||
- pattern: declare pointer, pass its address into a Libgit2 call
|
||||
- return value: integer error code
|
||||
- `0` = success
|
||||
- `< 0` = error
|
||||
- Memory / ownership rules
|
||||
- if Libgit2 populates a pointer for you
|
||||
- you must free it
|
||||
- if Libgit2 returns a `const` pointer
|
||||
- you don’t free it
|
||||
- it becomes invalid when the owning object is freed
|
||||
- Practical note
|
||||
- “Writing C is a bit painful.”
|
||||
|
||||
### Language bindings (Libgit2 ecosystem)
|
||||
- Implication of “writing C is painful”
|
||||
- you’re unlikely to write C when using Libgit2
|
||||
- there are language-specific bindings that make integration easier
|
||||
|
||||
#### Ruby bindings: Rugged
|
||||
- Name: Rugged
|
||||
- URL: https://github.com/libgit2/rugged
|
||||
- Example equivalent to the C code
|
||||
- `repo = Rugged::Repository.new('path/to/repository')`
|
||||
- `commit = repo.head.target`
|
||||
- `puts commit.message`
|
||||
- `puts "#{commit.author[:name]} <#{commit.author[:email]}>" `
|
||||
- `tree = commit.tree`
|
||||
- Why it’s “less cluttered”
|
||||
- error handling
|
||||
- Rugged uses exceptions
|
||||
- examples mentioned: `ConfigError`, `ObjectError`
|
||||
- resource management
|
||||
- no explicit freeing
|
||||
- Ruby is garbage-collected
|
||||
|
||||
- Example: crafting a commit from scratch (Rugged)
|
||||
- Code sequence shown (with numbered markers)
|
||||
- ① create a new blob
|
||||
- `blob_id = repo.write("Blob contents", :blob) ①`
|
||||
- work with index
|
||||
- `index = repo.index`
|
||||
- `index.read_tree(repo.head.target.tree)`
|
||||
- ② add a new file entry
|
||||
- `index.add(:path => 'newfile.txt', :oid => blob_id) ②`
|
||||
- build a signature hash
|
||||
- `sig = {`
|
||||
- ` :email => "bob@example.com",`
|
||||
- ` :name => "Bob User",`
|
||||
- ` :time => Time.now,`
|
||||
- `}`
|
||||
- create the commit (with parameters)
|
||||
- `commit_id = Rugged::Commit.create(repo,`
|
||||
- ` :tree => index.write_tree(repo), ③`
|
||||
- ` :author => sig,`
|
||||
- ` :committer => sig, ④`
|
||||
- ` :message => "Add newfile.txt", ⑤`
|
||||
- ` :parents => repo.empty? ? [] : [ repo.head.target ].compact, ⑥`
|
||||
- ` :update_ref => 'HEAD', ⑦`
|
||||
- `)`
|
||||
- ⑧ look up the created commit object
|
||||
- `commit = repo.lookup(commit_id) ⑧`
|
||||
|
||||
- Meaning of each numbered step (①–⑧)
|
||||
- ① Create a new blob
|
||||
- contains the contents of a new file
|
||||
- ② Populate index and add file
|
||||
- populate index with head commit’s tree
|
||||
- add the new file at path `newfile.txt`
|
||||
- ③ Create a new tree in the ODB
|
||||
- uses it for the new commit
|
||||
- ④ Author and committer fields
|
||||
- same signature used for both
|
||||
- ⑤ Commit message
|
||||
- `"Add newfile.txt"`
|
||||
- ⑥ Parents
|
||||
- when creating a commit, you must specify parents
|
||||
- uses the tip of `HEAD` for the single parent
|
||||
- handles empty repository case
|
||||
- ⑦ Update a ref (optional)
|
||||
- Rugged (and Libgit2) can optionally update a reference when making a commit
|
||||
- here it updates `HEAD`
|
||||
- ⑧ Return value / lookup
|
||||
- the return value is the SHA-1 hash of the new commit object
|
||||
- you can use it to get a `Commit` object
|
||||
|
||||
- Performance note
|
||||
- Ruby code is clean
|
||||
- Libgit2 does heavy lifting → runs pretty fast
|
||||
- Pointer to later section
|
||||
- “If you’re not a rubyist, we touch on some other bindings in Other Bindings.”
|
||||
|
||||
## Advanced Functionality (Libgit2)
|
||||
- Out-of-core-Git capabilities
|
||||
- Libgit2 has capabilities outside the scope of core Git
|
||||
- Example capability: pluggability
|
||||
- can provide custom “backends” for several operation types
|
||||
- enables storage in a different way than stock Git
|
||||
- backend types mentioned
|
||||
- configuration
|
||||
- ref storage
|
||||
- object database
|
||||
- “among other things”
|
||||
|
||||
### Custom backend example: object database (ODB)
|
||||
- Example source
|
||||
- from Libgit2 backend examples
|
||||
- URL: https://github.com/libgit2/libgit2-backends
|
||||
- Setup shown (with numbered markers)
|
||||
- ① create ODB “frontend”
|
||||
- `git_odb *odb;`
|
||||
- `int error = git_odb_new(&odb); ①`
|
||||
- meaning: initialize empty ODB frontend container for backends
|
||||
- ② initialize custom backend
|
||||
- `git_odb_backend *my_backend;`
|
||||
- `error = git_odb_backend_mine(&my_backend, /*…*/); ②`
|
||||
- ③ add backend to frontend
|
||||
- `error = git_odb_add_backend(odb, my_backend, 1); ③`
|
||||
- open a repository
|
||||
- `git_repository *repo;`
|
||||
- `error = git_repository_open(&repo, "some-path");`
|
||||
- ④ set repository to use custom ODB
|
||||
- `error = git_repository_set_odb(repo, odb); ④`
|
||||
- meaning: repo uses this ODB to look up objects
|
||||
- Note about the example’s error handling
|
||||
- errors are captured but not handled
|
||||
- “We hope your code is better than ours.”
|
||||
|
||||
### Implementing `git_odb_backend_mine`
|
||||
- What it is
|
||||
- constructor for your own ODB implementation
|
||||
- Requirement
|
||||
- fill in the `git_odb_backend` structure properly
|
||||
- Example struct layout shown
|
||||
- `typedef struct {`
|
||||
- ` git_odb_backend parent;`
|
||||
- ` // Some other stuff`
|
||||
- ` void *custom_context;`
|
||||
- `} my_backend_struct;`
|
||||
- Subtle memory-layout constraint
|
||||
- `my_backend_struct`’s first member must be a `git_odb_backend` structure
|
||||
- ensures Libgit2 sees the memory layout it expects
|
||||
- Flexibility
|
||||
- the rest of the struct is arbitrary
|
||||
- can be as large or small as needed
|
||||
- Example initialization function responsibilities shown
|
||||
- allocate
|
||||
- `backend = calloc(1, sizeof (my_backend_struct));`
|
||||
- set custom context
|
||||
- `backend->custom_context = …;`
|
||||
- fill supported function pointers in `parent`
|
||||
- `backend->parent.read = &my_backend__read;`
|
||||
- `backend->parent.read_prefix = &my_backend__read_prefix;`
|
||||
- `backend->parent.read_header = &my_backend__read_header;`
|
||||
- `// …`
|
||||
- return it through output parameter
|
||||
- `*backend_out = (git_odb_backend *) backend;`
|
||||
- return success constant
|
||||
- `return GIT_SUCCESS;`
|
||||
- Where to find full signatures
|
||||
- Libgit2 source file:
|
||||
- `include/git2/sys/odb_backend.h`
|
||||
- which signatures to implement depends on use case
|
||||
|
||||
## Other Bindings (Libgit2)
|
||||
- Breadth
|
||||
- bindings exist for many languages
|
||||
- Section purpose
|
||||
- show small examples using a few more complete bindings packages (as of writing)
|
||||
- Other languages mentioned as having libraries (various maturity)
|
||||
- C++
|
||||
- Go
|
||||
- Node.js
|
||||
- Erlang
|
||||
- JVM
|
||||
- Official collection of bindings
|
||||
- browse repos: https://github.com/libgit2
|
||||
- Common goal for the code in this section
|
||||
- return the commit message from the commit eventually pointed to by `HEAD`
|
||||
- “sort of like `git log -1`”
|
||||
|
||||
### LibGit2Sharp
|
||||
- For
|
||||
- .NET or Mono applications
|
||||
- URL
|
||||
- https://github.com/libgit2/libgit2sharp
|
||||
- Characteristics
|
||||
- bindings written in C#
|
||||
- wraps raw Libgit2 calls with native-feeling CLR APIs
|
||||
- Example program (single expression)
|
||||
- `new Repository(@"C:\path\to\repo").Head.Tip.Message;`
|
||||
- Desktop Windows note
|
||||
- NuGet package available to get started quickly
|
||||
|
||||
### objective-git
|
||||
- Platform context
|
||||
- Apple platform
|
||||
- likely using Objective-C as implementation language
|
||||
- URL
|
||||
- https://github.com/libgit2/objective-git
|
||||
- Example program outline
|
||||
- initialize repo
|
||||
- `GTRepository *repo =`
|
||||
- ` [[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"]`
|
||||
- `error:NULL];`
|
||||
- retrieve commit message
|
||||
- `NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message];`
|
||||
- Swift note
|
||||
- objective-git is fully interoperable with Swift
|
||||
|
||||
### pygit2
|
||||
- What it is
|
||||
- Python bindings for Libgit2
|
||||
- URL
|
||||
- https://www.pygit2.org
|
||||
- Example program (chained calls)
|
||||
- `pygit2.Repository("/path/to/repo") # open repository`
|
||||
- `.head # get the current branch`
|
||||
- `.peel(pygit2.Commit) # walk down to the commit`
|
||||
- `.message # read the message`
|
||||
|
||||
## Further Reading (Libgit2)
|
||||
- Scope note
|
||||
- full treatment of Libgit2 capabilities is outside the scope of the book
|
||||
- Libgit2 resources
|
||||
- API documentation: https://libgit2.github.com/libgit2
|
||||
- guides: https://libgit2.github.com/docs
|
||||
- Other bindings
|
||||
- check bundled README and tests
|
||||
- often have small tutorials and pointers to further reading
|
||||
|
||||
## JGit
|
||||
- Purpose
|
||||
- use Git from within a Java program
|
||||
- What it is
|
||||
- fully featured Git library called JGit
|
||||
- relatively full-featured implementation of Git written natively in Java
|
||||
- widely used in the Java community
|
||||
- under the Eclipse umbrella
|
||||
- Home
|
||||
- https://www.eclipse.org/jgit/
|
||||
|
||||
### Getting Set Up (JGit)
|
||||
- Multiple ways to connect project to JGit
|
||||
- Easiest path: Maven
|
||||
- add dependency snippet to `<dependencies>` in `pom.xml`
|
||||
- `<dependency>`
|
||||
- ` <groupId>org.eclipse.jgit</groupId>`
|
||||
- ` <artifactId>org.eclipse.jgit</artifactId>`
|
||||
- ` <version>3.5.0.201409260305-r</version>`
|
||||
- `</dependency>`
|
||||
- version note
|
||||
- likely advanced by the time you read this
|
||||
- check updates:
|
||||
- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit
|
||||
- result
|
||||
- Maven automatically acquires and uses the JGit libraries you need
|
||||
- Manual dependency management
|
||||
- pre-built binaries
|
||||
- https://www.eclipse.org/jgit/download
|
||||
- compile/run examples
|
||||
- `javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java`
|
||||
- `java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App`
|
||||
|
||||
### Plumbing (JGit)
|
||||
- Two levels of API
|
||||
- plumbing
|
||||
- porcelain
|
||||
- Terminology source: Git itself
|
||||
- porcelain APIs
|
||||
- friendly front-end for common user-level actions
|
||||
- like what a normal user would use the Git command-line tool for
|
||||
- plumbing APIs
|
||||
- interact with low-level repository objects directly
|
||||
|
||||
#### Starting point: `Repository`
|
||||
- Starting point for most JGit sessions
|
||||
- class: `Repository`
|
||||
- Creating/opening a filesystem-based repository
|
||||
- note: JGit also allows other storage models
|
||||
- Create new repository
|
||||
- `Repository newlyCreatedRepo = FileRepositoryBuilder.create(new File("/tmp/new_repo/.git"));`
|
||||
- `newlyCreatedRepo.create();`
|
||||
- Open existing repository
|
||||
- `Repository existingRepo = new FileRepositoryBuilder()`
|
||||
- `.setGitDir(new File("my_repo/.git"))`
|
||||
- `.build();`
|
||||
|
||||
#### `FileRepositoryBuilder` (finding repositories)
|
||||
- Builder style
|
||||
- fluent API
|
||||
- Helps locate a Git repository
|
||||
- whether or not your program knows exactly where it’s located
|
||||
- Methods/strategies mentioned
|
||||
- environment variables
|
||||
- `.readEnvironment()`
|
||||
- search starting from working directory
|
||||
- `.setWorkTree(…).findGitDir()`
|
||||
- open known `.git` directory
|
||||
- `.setGitDir(...)` (as in example)
|
||||
|
||||
#### Plumbing API: quick sampling + explanations
|
||||
- Sampling actions shown (code outline)
|
||||
- Get a reference
|
||||
- `Ref master = repo.getRef("master");`
|
||||
- Get object ID pointed to by reference
|
||||
- `ObjectId masterTip = master.getObjectId();`
|
||||
- Rev-parse
|
||||
- `ObjectId obj = repo.resolve("HEAD^{tree}");`
|
||||
- Load raw object contents
|
||||
- `ObjectLoader loader = repo.open(masterTip);`
|
||||
- `loader.copyTo(System.out);`
|
||||
- Create a branch
|
||||
- `RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");`
|
||||
- `createBranch1.setNewObjectId(masterTip);`
|
||||
- `createBranch1.update();`
|
||||
- Delete a branch
|
||||
- `RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");`
|
||||
- `deleteBranch1.setForceUpdate(true);`
|
||||
- `deleteBranch1.delete();`
|
||||
- Config
|
||||
- `Config cfg = repo.getConfig();`
|
||||
- `String name = cfg.getString("user", null, "name");`
|
||||
|
||||
- Explanation: references (`Ref`)
|
||||
- `repo.getRef("master")`
|
||||
- JGit automatically grabs the actual master ref at `refs/heads/master`
|
||||
- returns a `Ref` object for reading information about the reference
|
||||
- `Ref` info available
|
||||
- name: `.getName()`
|
||||
- direct reference target object: `.getObjectId()`
|
||||
- symbolic reference target reference: `.getTarget()`
|
||||
- `Ref` objects also used for
|
||||
- tag refs
|
||||
- tag objects
|
||||
- Tag “peeled” concept
|
||||
- peeled = points to final target of a (potentially long) string of tag objects
|
||||
|
||||
- Explanation: object IDs (`ObjectId`)
|
||||
- represents SHA-1 hash of an object
|
||||
- object might or might not exist in the object database
|
||||
|
||||
- Explanation: rev-parse (`repo.resolve(...)`)
|
||||
- accepts any object specifier Git understands
|
||||
- returns
|
||||
- a valid `ObjectId`, or
|
||||
- `null`
|
||||
- reference: “see Branch References”
|
||||
|
||||
- Explanation: raw object access (`ObjectLoader`)
|
||||
- can stream contents
|
||||
- `ObjectLoader.copyTo(...)`
|
||||
- other capabilities mentioned
|
||||
- read type and size of object
|
||||
- return contents as a byte array
|
||||
- large object handling
|
||||
- when `.isLarge()` is `true`
|
||||
- `.openStream()` returns an InputStream-like object
|
||||
- reads raw data without pulling everything into memory at once
|
||||
|
||||
- Explanation: creating a branch (`RefUpdate`)
|
||||
- create `RefUpdate`
|
||||
- set new object ID
|
||||
- call `.update()` to trigger change
|
||||
|
||||
- Explanation: deleting a branch
|
||||
- requires `.setForceUpdate(true)`
|
||||
- otherwise `.delete()` returns `REJECTED`
|
||||
- and nothing happens
|
||||
|
||||
- Explanation: config (`Config`)
|
||||
- get via `repo.getConfig()`
|
||||
- example value read
|
||||
- `user.name` via `cfg.getString("user", null, "name")`
|
||||
- config resolution behavior
|
||||
- uses repository for local configuration
|
||||
- automatically detects global and system config files
|
||||
- reads values from them as well
|
||||
|
||||
- Error handling in JGit (not shown in code sample)
|
||||
- handled via exceptions
|
||||
- may throw standard Java exceptions
|
||||
- example: `IOException`
|
||||
- also has JGit-specific exceptions (examples)
|
||||
- `NoRemoteRepositoryException`
|
||||
- `CorruptObjectException`
|
||||
- `NoMergeBaseException`
|
||||
|
||||
- Scope note
|
||||
- this is only a small sampling of the full plumbing API
|
||||
- many more methods/classes exist
|
||||
|
||||
### Porcelain (JGit)
|
||||
- Why porcelain exists
|
||||
- plumbing APIs are rather complete
|
||||
- but can be cumbersome to string together for common goals
|
||||
- adding a file to the index
|
||||
- making a new commit
|
||||
- Entry point class
|
||||
- `Git`
|
||||
- construction shown
|
||||
- `Repository repo;`
|
||||
- `// construct repo...`
|
||||
- `Git git = new Git(repo);`
|
||||
|
||||
#### Porcelain command pattern (Git class)
|
||||
- Pattern
|
||||
- `Git` methods return a command object
|
||||
- chain method calls to set parameters
|
||||
- execute via `.call()`
|
||||
|
||||
#### Example: like `git ls-remote`
|
||||
- Credentials
|
||||
- `CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");`
|
||||
- Command chain
|
||||
- `Collection<Ref> remoteRefs = git.lsRemote()`
|
||||
- `.setCredentialsProvider(cp)`
|
||||
- `.setRemote("origin")`
|
||||
- `.setTags(true)`
|
||||
- `.setHeads(false)`
|
||||
- `.call();`
|
||||
- Output loop
|
||||
- `for (Ref ref : remoteRefs) {`
|
||||
- ` System.out.println(ref.getName() + " -> " + ref.getObjectId().name());`
|
||||
- `}`
|
||||
- What it requests
|
||||
- tags from `origin`
|
||||
- not heads
|
||||
- Authentication note
|
||||
- uses a `CredentialsProvider`
|
||||
|
||||
#### Other commands available through `Git` (examples listed)
|
||||
- add
|
||||
- blame
|
||||
- commit
|
||||
- clean
|
||||
- push
|
||||
- rebase
|
||||
- revert
|
||||
- reset
|
||||
|
||||
### Further Reading (JGit)
|
||||
- Official JGit API documentation
|
||||
- https://www.eclipse.org/jgit/documentation
|
||||
- standard Javadoc
|
||||
- JVM IDEs can install locally as well
|
||||
- JGit Cookbook
|
||||
- https://github.com/centic9/jgit-cookbook
|
||||
- many examples of specific tasks
|
||||
|
||||
## go-git
|
||||
- When to use
|
||||
- integrate Git into a service written in Golang
|
||||
- What it is
|
||||
- pure Go library implementation
|
||||
- no native dependencies
|
||||
- not prone to manual memory management errors
|
||||
- transparent to standard Golang performance analysis tooling
|
||||
- CPU profilers
|
||||
- memory profilers
|
||||
- race detector
|
||||
- etc.
|
||||
- Focus
|
||||
- extensibility
|
||||
- compatibility
|
||||
- Compatibility / API coverage note
|
||||
- supports most plumbing APIs
|
||||
- compatibility documented at:
|
||||
- https://github.com/go-git/go-git/blob/master/COMPATIBILITY.md
|
||||
|
||||
### Basic go-git example
|
||||
- Import
|
||||
- `import "github.com/go-git/go-git/v5"`
|
||||
- Clone
|
||||
- `r, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{`
|
||||
- ` URL: "https://github.com/go-git/go-git",`
|
||||
- ` Progress: os.Stdout,`
|
||||
- `})`
|
||||
|
||||
### After you have a `Repository` instance
|
||||
- “Access information and perform mutations”
|
||||
- Example operations shown
|
||||
- Get branch pointed by `HEAD`
|
||||
- `ref, err := r.Head()`
|
||||
- Get commit object pointed by `ref`
|
||||
- `commit, err := r.CommitObject(ref.Hash())`
|
||||
- Get commit history
|
||||
- `history, err := commit.History()`
|
||||
- Iterate commits and print each
|
||||
- `for _, c := range history {`
|
||||
- ` fmt.Println(c)`
|
||||
- `}`
|
||||
|
||||
### Advanced Functionality (go-git)
|
||||
- Feature: pluggable storage system
|
||||
- similar to Libgit2 backends
|
||||
- default implementation: in-memory storage
|
||||
- “very fast”
|
||||
- example: clone into memory storage
|
||||
- `r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{`
|
||||
- ` URL: "https://github.com/go-git/go-git",`
|
||||
- `})`
|
||||
- Storage options example
|
||||
- store references, objects, and configuration in Aerospike
|
||||
- example location:
|
||||
- https://github.com/go-git/go-git/tree/master/_examples/storage
|
||||
- Feature: flexible filesystem abstraction
|
||||
- uses go-billy `Filesystem`
|
||||
- https://pkg.go.dev/github.com/go-git/go-billy/v5?tab=doc#Filesystem
|
||||
- makes it easy to store files differently
|
||||
- pack all files into a single archive on disk
|
||||
- keep all files in-memory
|
||||
- Advanced use-case: fine-tunable HTTP client
|
||||
- example referenced:
|
||||
- https://github.com/go-git/go-git/blob/master/_examples/custom_http/main.go
|
||||
- custom client shown
|
||||
- `customClient := &http.Client{`
|
||||
- ` Transport: &http.Transport{ // accept any certificate (might be useful for testing)`
|
||||
- ` TLSClientConfig: &tls.Config{InsecureSkipVerify: true},`
|
||||
- ` },`
|
||||
- ` Timeout: 15 * time.Second, // 15 second timeout`
|
||||
- ` CheckRedirect: func(req *http.Request, via []*http.Request) error {`
|
||||
- ` return http.ErrUseLastResponse // don't follow redirect`
|
||||
- ` },`
|
||||
- `}`
|
||||
- override protocol handling
|
||||
- `client.InstallProtocol("https", githttp.NewClient(customClient))`
|
||||
- purpose: override http(s) default protocol to use custom client
|
||||
- clone using new client (for `https://`)
|
||||
- `r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{URL: url})`
|
||||
|
||||
### Further Reading (go-git)
|
||||
- Scope note
|
||||
- full treatment outside scope of the book
|
||||
- API documentation
|
||||
- https://pkg.go.dev/github.com/go-git/go-git/v5
|
||||
- Usage examples
|
||||
- https://github.com/go-git/go-git/tree/master/_examples
|
||||
|
||||
## Dulwich
|
||||
- What it is
|
||||
- pure-Python Git implementation: Dulwich
|
||||
- Project hosting / site
|
||||
- https://www.dulwich.io/
|
||||
- Goal
|
||||
- interface to Git repositories (local and remote)
|
||||
- does not call out to `git` directly
|
||||
- uses pure Python instead
|
||||
- Performance note
|
||||
- optional C extensions
|
||||
- significantly improve performance
|
||||
- API design
|
||||
- follows Git design
|
||||
- separates two API levels
|
||||
- plumbing
|
||||
- porcelain
|
||||
|
||||
### Dulwich plumbing example (lower-level API)
|
||||
- Goal
|
||||
- access the commit message of the last commit
|
||||
- Code and shown outputs
|
||||
- `from dulwich.repo import Repo`
|
||||
- `r = Repo('.')`
|
||||
- `r.head()`
|
||||
- `# '57fbe010446356833a6ad1600059d80b1e731e15'`
|
||||
- `c = r[r.head()]`
|
||||
- `c`
|
||||
- `# <Commit 015fc1267258458901a94d228e39f0a378370466>`
|
||||
- `c.message`
|
||||
- `# 'Add note about encoding.\n'`
|
||||
|
||||
### Dulwich porcelain example (high-level API)
|
||||
- Goal
|
||||
- print a commit log using porcelain API
|
||||
- Code and shown outputs
|
||||
- `from dulwich import porcelain`
|
||||
- `porcelain.log('.', max_entries=1)`
|
||||
- `#commit: 57fbe010446356833a6ad1600059d80b1e731e15`
|
||||
- `#Author: Jelmer Vernooij <jelmer@jelmer.uk>`
|
||||
- `#Date: Sat Apr 29 2017 23:57:34 +0000`
|
||||
|
||||
### Further Reading (Dulwich)
|
||||
- Available on official website
|
||||
- API documentation
|
||||
- tutorial
|
||||
- many task-focused examples
|
||||
- URL
|
||||
- https://www.dulwich.io/
|
||||
85
mindmap/Appendix C_ Git Commands.md
Normal file
85
mindmap/Appendix C_ Git Commands.md
Normal file
@@ -0,0 +1,85 @@
|
||||
```markmap
|
||||
# Appendix C: Git Commands
|
||||
## Context / Why this appendix exists
|
||||
- The book introduces “dozens” of Git commands
|
||||
- Commands were introduced inside a narrative
|
||||
- Added “slowly” as the story progressed
|
||||
- Result of narrative approach
|
||||
- Examples/usage of commands are “somewhat scattered” throughout the book
|
||||
- Goal of this appendix
|
||||
- Go through **all Git commands addressed throughout the book**
|
||||
- Group them “roughly by what they’re used for”
|
||||
- For each command
|
||||
- Explain **very generally** what it does
|
||||
- Point out **where in the book** it was used
|
||||
|
||||
## Tip / Note: Abbreviating long options
|
||||
- You can abbreviate long options (when unambiguous)
|
||||
- Example
|
||||
- `git commit --a` behaves like `git commit --amend`
|
||||
- Constraint
|
||||
- Abbreviation works **only** when the letters after `--` are **unique** among options
|
||||
- Guidance for scripting
|
||||
- Use the **full option** when writing scripts
|
||||
|
||||
## Setup and Config
|
||||
- Two commands used “quite a lot”
|
||||
- From the **first invocations** of Git
|
||||
- Through **common every day** tweaking and referencing
|
||||
- The two commands
|
||||
- `git config`
|
||||
- `git help`
|
||||
|
||||
### `git config`
|
||||
- Core idea
|
||||
- Git has a **default way** of doing “hundreds of things”
|
||||
- `git config` lets you change those defaults and set preferences
|
||||
- What configuration can include (examples given)
|
||||
- Your **name**
|
||||
- Your **email address**
|
||||
- Your **editor** preference
|
||||
- Specific **terminal color** preferences
|
||||
- (More generally) “hundreds of things” Git can be told to do differently
|
||||
- How configuration is stored/applied
|
||||
- Multiple files are involved
|
||||
- The command can **read from** and **write to** several files
|
||||
- Scope flexibility
|
||||
- Set values **globally**
|
||||
- Or down to **specific repositories**
|
||||
|
||||
#### How often it appears in the book
|
||||
- “Used in nearly every chapter of the book”
|
||||
|
||||
#### Where the book used `git config` (as listed)
|
||||
- **First-Time Git Setup**
|
||||
- Used to specify
|
||||
- Name
|
||||
- Email address
|
||||
- Editor preference
|
||||
- Noted as happening “before we even got started using Git”
|
||||
- **Git Aliases**
|
||||
- Used to create shorthand commands (aliases)
|
||||
- Aliases expand to long option sequences
|
||||
- Purpose: avoid typing long sequences every time
|
||||
- **Rebasing**
|
||||
- Used to make `--rebase` the default behavior when running `git pull`
|
||||
- **Credential Storage**
|
||||
- Used to set up a default store for HTTP passwords
|
||||
- **Keyword Expansion**
|
||||
- Used to set up
|
||||
- “smudge” filters
|
||||
- “clean” filters
|
||||
- Purpose: manage content coming **into** and going **out of** Git
|
||||
- **Git Configuration**
|
||||
- “Basically the entirety” of that section/chapter is dedicated to `git config`
|
||||
|
||||
### `git config core.editor` (editor configuration)
|
||||
- Mentioned as a specific configuration focus
|
||||
- “git config core.editor commands”
|
||||
- Linked context
|
||||
- Accompanies the configuration instructions in **Your Editor**
|
||||
- What is stated
|
||||
- Many editors can be set using `core.editor`
|
||||
- Boundary of provided material
|
||||
- The excerpt ends just before listing the specific editor command examples
|
||||
```
|
||||
665
mindmap/Customizing Git.md
Normal file
665
mindmap/Customizing Git.md
Normal file
@@ -0,0 +1,665 @@
|
||||
# Customizing Git
|
||||
## Purpose & scope
|
||||
- Goal: make Git operate in a more customized fashion (personal/team/company needs)
|
||||
- Main customization mechanisms covered
|
||||
- Configuration settings (`git config`)
|
||||
- Attributes (path-specific behavior via `.gitattributes` / `.git/info/attributes`)
|
||||
- Hooks (event-driven scripts: client-side + server-side)
|
||||
|
||||
## Git Configuration
|
||||
### `git config` basics
|
||||
- Used to read/write configuration values
|
||||
- Common initial setup (examples)
|
||||
- `git config --global user.name "John Doe"`
|
||||
- `git config --global user.email johndoe@example.com`
|
||||
|
||||
### Configuration files (“levels”) & precedence
|
||||
- System level
|
||||
- File: `[path]/etc/gitconfig`
|
||||
- Applies to: every user + all repositories on the system
|
||||
- `git config --system …` reads/writes here
|
||||
- Global level (user)
|
||||
- File: `~/.gitconfig` or `~/.config/git/config`
|
||||
- Applies to: a specific user across repositories
|
||||
- `git config --global …` reads/writes here
|
||||
- Local level (repo)
|
||||
- File: `.git/config` (inside current repository)
|
||||
- Applies to: current repository only
|
||||
- `git config --local …` reads/writes here
|
||||
- Default level if you don’t specify `--system/--global/--local`
|
||||
- Override rule
|
||||
- `local` overrides `global` overrides `system`
|
||||
- Editing note
|
||||
- Config files are plain text; manual edits work
|
||||
- Generally easier/safer to use `git config`
|
||||
|
||||
### Client-side vs server-side options
|
||||
- Options fall into two categories
|
||||
- Client-side (most options): personal working preferences
|
||||
- Server-side (fewer): repository receiving/policy behaviors
|
||||
- Discover all supported options
|
||||
- `man git-config`
|
||||
- Reference: `https://git-scm.com/docs/git-config`
|
||||
|
||||
### Basic client configuration (common & useful)
|
||||
#### `core.editor`
|
||||
- Purpose: editor used for commit/tag messages
|
||||
- Default selection order
|
||||
- `$VISUAL` or `$EDITOR` environment variables
|
||||
- fallback: `vi`
|
||||
- Set example
|
||||
- `git config --global core.editor emacs`
|
||||
|
||||
#### `commit.template`
|
||||
- Purpose: provide an initial commit message template
|
||||
- Use cases
|
||||
- Remind yourself/team of message structure and policy
|
||||
- Encourage consistent subject length + body + ticket references
|
||||
- Example template content (concepts)
|
||||
- Subject line guidance (e.g., keep under ~50 chars for `git log --oneline`)
|
||||
- Multi-line description
|
||||
- Optional ticket marker (e.g., `[Ticket: X]`)
|
||||
- Set + behavior
|
||||
- `git config --global commit.template ~/.gitmessage.txt`
|
||||
- `git commit` opens editor pre-filled with the template + comment lines
|
||||
|
||||
#### `core.pager`
|
||||
- Purpose: pager for long output (e.g., `log`, `diff`)
|
||||
- Default: usually `less`
|
||||
- Disable paging
|
||||
- `git config --global core.pager ''`
|
||||
- Effect: output is printed directly (no pager), regardless of length
|
||||
|
||||
#### `user.signingkey`
|
||||
- Purpose: simplify signing annotated tags (GPG)
|
||||
- Set
|
||||
- `git config --global user.signingkey <gpg-key-id>`
|
||||
- Use afterward
|
||||
- `git tag -s <tag-name>` (no need to specify key each time)
|
||||
|
||||
#### `core.excludesfile`
|
||||
- Purpose: global ignore patterns (applies to all repositories for that user)
|
||||
- Use cases (examples)
|
||||
- macOS: `.DS_Store`
|
||||
- editors: Emacs backups `*~`, Vim swap files `.*.swp`
|
||||
- Example workflow
|
||||
- Create `~/.gitignore_global` with patterns like
|
||||
- `*~`
|
||||
- `.*.swp`
|
||||
- `.DS_Store`
|
||||
- Configure
|
||||
- `git config --global core.excludesfile ~/.gitignore_global`
|
||||
|
||||
#### `help.autocorrect`
|
||||
- Problem: mistyped commands are suggested but not run
|
||||
- Set behavior: auto-run a likely intended command after a delay
|
||||
- Setting semantics
|
||||
- Integer in tenths of a second
|
||||
- `1` → 0.1s delay
|
||||
- `50` → 5s delay
|
||||
- Example
|
||||
- `git config --global help.autocorrect 1`
|
||||
- Runtime behavior
|
||||
- Shows warning + countdown-like delay, then runs corrected command
|
||||
|
||||
## Colors in Git
|
||||
### `color.ui` (master switch)
|
||||
- Purpose: enable/disable default colored terminal output
|
||||
- Values
|
||||
- `false` → no color
|
||||
- `auto` (default) → color only when writing to a terminal; no color codes when piped/redirected
|
||||
- `always` → always emit color codes (rarely desired)
|
||||
- Per-command override
|
||||
- Use `--color` flag on specific Git commands if you want forced coloring in redirected output
|
||||
|
||||
### `color.*` (command-specific control)
|
||||
- Per-area switches (each: `true`, `false`, or `always`)
|
||||
- `color.branch`
|
||||
- `color.diff`
|
||||
- `color.interactive`
|
||||
- `color.status`
|
||||
- Fine-grained subsettings (override specific parts)
|
||||
- Example: diff “meta” styling
|
||||
- `git config --global color.diff.meta "blue black bold"`
|
||||
- Supported colors
|
||||
- `normal`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`
|
||||
- Supported attributes
|
||||
- `bold`, `dim`, `ul` (underline), `blink`, `reverse`
|
||||
|
||||
## External Merge and Diff Tools
|
||||
### Why use external tools
|
||||
- Git has built-in diff/merge, but you can:
|
||||
- Use external diff viewers
|
||||
- Use GUI merge tools for conflict resolution
|
||||
- Example tool used in chapter
|
||||
- P4Merge (Perforce Visual Merge Tool): graphical + free + cross-platform
|
||||
|
||||
### Wrapper-script approach (example: P4Merge)
|
||||
- Platform note
|
||||
- Example paths are macOS/Linux-style
|
||||
- On Windows, replace `/usr/local/bin` with an executable path in your environment
|
||||
|
||||
#### `extMerge` wrapper
|
||||
- Purpose: call the GUI merge tool with all passed arguments
|
||||
- Example content (conceptual)
|
||||
- Shell script that runs: `p4merge $*`
|
||||
- macOS example path to binary:
|
||||
- `/Applications/p4merge.app/Contents/MacOS/p4merge $*`
|
||||
|
||||
#### `extDiff` wrapper
|
||||
- Purpose: adapt Git’s diff-program arguments to what your merge viewer needs
|
||||
- Git passes 7 arguments to external diff programs (concept)
|
||||
- `path old-file old-hex old-mode new-file new-hex new-mode`
|
||||
- Wrapper logic
|
||||
- Ensure 7 args exist
|
||||
- Invoke merge tool on the *old file* and *new file* only
|
||||
- Uses `$2` (old-file) and `$5` (new-file)
|
||||
|
||||
#### Make wrappers executable
|
||||
- `sudo chmod +x /usr/local/bin/extMerge`
|
||||
- `sudo chmod +x /usr/local/bin/extDiff`
|
||||
|
||||
### Configure Git to use wrappers
|
||||
- Key settings involved
|
||||
- `merge.tool` → selects merge tool name
|
||||
- `mergetool.<tool>.cmd` → how to invoke tool (with `$BASE`, `$LOCAL`, `$REMOTE`, `$MERGED`)
|
||||
- `mergetool.<tool>.trustExitCode` → whether tool’s exit code indicates success
|
||||
- `diff.external` → command for external diffs
|
||||
- Example config commands
|
||||
- `git config --global merge.tool extMerge`
|
||||
- `git config --global mergetool.extMerge.cmd 'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'`
|
||||
- `git config --global mergetool.extMerge.trustExitCode false`
|
||||
- `git config --global diff.external extDiff`
|
||||
- Equivalent `.gitconfig` blocks (concept)
|
||||
- `[merge] tool = extMerge`
|
||||
- `[mergetool "extMerge"] cmd = … ; trustExitCode = false`
|
||||
- `[diff] external = extDiff`
|
||||
|
||||
### Using the configured tools
|
||||
- External diff example
|
||||
- `git diff <rev1> <rev2>` opens GUI instead of printing to terminal
|
||||
- (Figure reference in chapter: P4Merge screenshot)
|
||||
- Merge conflicts
|
||||
- `git mergetool` launches GUI tool to resolve conflicts
|
||||
|
||||
### Switching tools easily
|
||||
- Benefit of wrapper design
|
||||
- Change the underlying tool by editing `extMerge`
|
||||
- `extDiff` continues calling `extMerge`
|
||||
- Example: switch to KDiff3 by changing the binary invoked by `extMerge`
|
||||
|
||||
### Built-in mergetool presets
|
||||
- Git supports many merge tools without custom `cmd`
|
||||
- List supported tools
|
||||
- `git mergetool --tool-help`
|
||||
- Environment caveat
|
||||
- Windowed tools require a GUI; terminal-only sessions may fail
|
||||
|
||||
### Using a tool only for merges (not diffs)
|
||||
- If tool command is in `PATH` (example: `kdiff3`)
|
||||
- `git config --global merge.tool kdiff3`
|
||||
- Result
|
||||
- Merge resolution uses KDiff3
|
||||
- Diffs remain Git’s normal diff output
|
||||
|
||||
## Formatting and Whitespace
|
||||
### Problems addressed
|
||||
- Cross-platform line endings (Windows vs macOS/Linux)
|
||||
- Subtle whitespace edits introduced by editors/tools
|
||||
|
||||
### `core.autocrlf` (line ending normalization)
|
||||
- Background
|
||||
- Windows newline: CRLF (`\r\n`)
|
||||
- macOS/Linux newline: LF (`\n`)
|
||||
- Behavior: auto-convert at boundaries
|
||||
- On add/commit: convert as configured into repository-friendly form
|
||||
- On checkout: convert as configured into working-tree-friendly form
|
||||
- Recommended settings by environment
|
||||
- Windows + cross-platform collaboration
|
||||
- `git config --global core.autocrlf true`
|
||||
- Checkout uses CRLF; repo stores LF
|
||||
- macOS/Linux (LF) but want to “clean up” accidental CRLF commits
|
||||
- `git config --global core.autocrlf input`
|
||||
- Convert CRLF→LF on commit; do not convert on checkout
|
||||
- Windows-only project, want CRLF stored as-is
|
||||
- `git config --global core.autocrlf false`
|
||||
|
||||
### `core.whitespace` (detect/fix whitespace issues)
|
||||
- Six primary whitespace issues
|
||||
- Enabled by default (can be disabled)
|
||||
- `blank-at-eol` (spaces at end of line)
|
||||
- `blank-at-eof` (blank lines at end of file)
|
||||
- `space-before-tab` (spaces before tabs in indentation)
|
||||
- Disabled by default (can be enabled)
|
||||
- `indent-with-non-tab` (indent begins with spaces; uses `tabwidth`)
|
||||
- `tab-in-indent` (tabs in indentation portion)
|
||||
- `cr-at-eol` (treat CR at EOL as acceptable)
|
||||
- How to set
|
||||
- Comma-separated list
|
||||
- Disable an option by prefixing with `-`
|
||||
- Omit options to keep defaults
|
||||
- Shorthand
|
||||
- `trailing-space` = `blank-at-eol` + `blank-at-eof`
|
||||
- Example intent from chapter
|
||||
- Enable most checks, disable `space-before-tab`, and enable the three disabled-by-default checks
|
||||
- Where it’s used
|
||||
- `git diff` highlights whitespace problems
|
||||
- `git apply` uses it for patch application
|
||||
- Warn: `git apply --whitespace=warn <patch>`
|
||||
- Fix: `git apply --whitespace=fix <patch>`
|
||||
- `git rebase` can also fix while rewriting patches
|
||||
- `git rebase --whitespace=fix`
|
||||
|
||||
## Server Configuration
|
||||
### General note
|
||||
- Fewer server-side config options, but some are important for integrity and policy
|
||||
|
||||
### `receive.fsckObjects`
|
||||
- Purpose: validate object integrity during push reception
|
||||
- Check SHA-1 checksums
|
||||
- Ensure objects point to valid objects
|
||||
- Tradeoff: expensive; can slow pushes (especially large repos/pushes)
|
||||
- Enable
|
||||
- `git config --system receive.fsckObjects true`
|
||||
- Benefit
|
||||
- Helps prevent corrupt or malicious objects being introduced
|
||||
|
||||
### `receive.denyNonFastForwards`
|
||||
- Purpose: refuse non-fast-forward updates (blocks most force-pushes)
|
||||
- Typical scenario
|
||||
- Rebase already-pushed commits, then attempt to push rewritten history
|
||||
- Enable
|
||||
- `git config --system receive.denyNonFastForwards true`
|
||||
- Alternative/enhancement
|
||||
- Server-side hooks can enforce this with per-user/per-ref logic
|
||||
|
||||
### `receive.denyDeletes`
|
||||
- Purpose: prevent deletion of branches/tags on the server
|
||||
- Stops the “delete and recreate” workaround to bypass non-FF restrictions
|
||||
- Enable
|
||||
- `git config --system receive.denyDeletes true`
|
||||
- Effect
|
||||
- No user can delete branches/tags via push
|
||||
- Must remove ref files manually on server (or via ACLs/policy hooks)
|
||||
|
||||
## Git Attributes
|
||||
### What attributes are
|
||||
- Path-specific settings controlling Git behavior for subsets of files
|
||||
- Where to define them
|
||||
- `.gitattributes` (committed, shared with the project)
|
||||
- `.git/info/attributes` (local-only, not committed)
|
||||
- Typical uses
|
||||
- Choose merge strategies per file/directory
|
||||
- Teach Git how to diff “non-text” formats
|
||||
- Filter content on check-in/check-out (clean/smudge filters)
|
||||
|
||||
### Binary Files
|
||||
#### Identifying binary-like files
|
||||
- Motivation: some “text” is effectively binary for Git operations (diff/merge not meaningful)
|
||||
- Example from chapter
|
||||
- Xcode `*.pbxproj` (UTF-8 text, but acts like machine-managed DB)
|
||||
- Diffs/merges are not helpful; conflicts are not realistically resolvable by humans
|
||||
- Attribute
|
||||
- In `.gitattributes`: `*.pbxproj binary`
|
||||
- Effects
|
||||
- Avoid CRLF conversions/fixes for those paths
|
||||
- Avoid computing/printing diffs for those files
|
||||
|
||||
#### Diffing binary files via text conversion (`textconv`)
|
||||
- Core idea
|
||||
- Convert binary content to a text representation, then use normal diff on that representation
|
||||
|
||||
##### Microsoft Word (`.docx`) diffing
|
||||
- Attribute mapping
|
||||
- `.gitattributes`: `*.docx diff=word`
|
||||
- Define the `word` diff “driver” with `textconv`
|
||||
- Install `docx2txt` (chapter references SourceForge project + INSTALL instructions)
|
||||
- Create wrapper script named `docx2txt` in `PATH` (concept)
|
||||
- Calls `docx2txt.pl "$1" -` to emit text to stdout
|
||||
- Make executable (`chmod a+x docx2txt`)
|
||||
- Configure Git
|
||||
- `git config diff.word.textconv docx2txt`
|
||||
- Result
|
||||
- `git diff` shows added/removed text instead of “Binary files differ”
|
||||
- Limitation noted
|
||||
- Formatting-only changes may not be represented perfectly
|
||||
|
||||
##### Image metadata diffing (EXIF)
|
||||
- Attribute mapping
|
||||
- `.gitattributes`: `*.png diff=exif`
|
||||
- Tool
|
||||
- Install `exiftool`
|
||||
- Configure Git
|
||||
- `git config diff.exif.textconv exiftool`
|
||||
- Result
|
||||
- `git diff` shows textual metadata differences (e.g., file size, width/height)
|
||||
|
||||
### Keyword Expansion (CVS/SVN-style substitutions)
|
||||
#### Why it’s tricky in Git
|
||||
- Git hashes file content (blobs); modifying file contents “after commit” would change the hash
|
||||
- Solution pattern
|
||||
- Inject content on checkout
|
||||
- Remove/normalize before staging/commit
|
||||
|
||||
#### Built-in `ident` attribute (`$Id$`)
|
||||
- Attribute
|
||||
- `.gitattributes`: `*.txt ident`
|
||||
- Behavior
|
||||
- On checkout, replaces `$Id$` with `$Id: <blob-sha1> $`
|
||||
- Note: uses blob SHA-1 (not commit SHA-1)
|
||||
- Limitation
|
||||
- Blob SHA-1 isn’t a human-friendly timestamp/ordering signal
|
||||
|
||||
#### Custom clean/smudge filters
|
||||
- Terminology
|
||||
- **smudge**: runs on checkout (into working directory)
|
||||
- **clean**: runs when staging (into index)
|
||||
- (Figure references in chapter: smudge-on-checkout and clean-on-stage diagrams)
|
||||
|
||||
##### Example: auto-format C code using `indent`
|
||||
- `.gitattributes`
|
||||
- `*.c filter=indent`
|
||||
- Config filter behavior
|
||||
- Clean (before staging): `git config --global filter.indent.clean indent`
|
||||
- Smudge (on checkout): `git config --global filter.indent.smudge cat` (no-op)
|
||||
- Effect
|
||||
- Code is run through `indent` before being committed
|
||||
|
||||
##### Example: `$Date$` expansion (RCS-like)
|
||||
- Smudge script (concept)
|
||||
- Reads stdin
|
||||
- Computes last commit date: `git log --pretty=format:"%ad" -1`
|
||||
- Replaces `$Date$` → `$Date: <last_date>$`
|
||||
- Script name in chapter: `expand_date` (Ruby), placed in `PATH`
|
||||
- Configure the filter “driver” (named `dater`)
|
||||
- Smudge: `git config filter.dater.smudge expand_date`
|
||||
- Clean: `git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'`
|
||||
- Strips expanded date back to literal `$Date$` before storing
|
||||
- Apply to files
|
||||
- `.gitattributes`: `date*.txt filter=dater`
|
||||
- Demonstrated workflow
|
||||
- Create file containing `$Date$`
|
||||
- Commit
|
||||
- Remove + checkout again
|
||||
- Observe expanded date in working directory
|
||||
- Portability caveat
|
||||
- `.gitattributes` is shared with the repo
|
||||
- Filter scripts/config are not automatically shared
|
||||
- Filters should fail gracefully so project still works without them
|
||||
|
||||
### Exporting Your Repository (archives)
|
||||
#### `export-ignore`
|
||||
- Purpose: exclude files/dirs from `git archive` output while still tracking them in Git
|
||||
- Example
|
||||
- `.gitattributes`: `test/ export-ignore`
|
||||
- Result
|
||||
- `git archive` tarball omits `test/`
|
||||
|
||||
#### `export-subst`
|
||||
- Purpose: apply `git log` formatting/keyword-style substitutions during `git archive`
|
||||
- Mark file(s)
|
||||
- `.gitattributes`: `LAST_COMMIT export-subst`
|
||||
- Embed placeholders in file content (concept)
|
||||
- Example pattern: `$Format:%cd by %aN$`
|
||||
- Behavior on archive
|
||||
- `git archive` injects metadata (date/author/etc.) into exported file
|
||||
- Can include commit message, git notes, and word-wrapped formatting (chapter shows `%+w(...)` usage)
|
||||
- Important limitation
|
||||
- Exported archive is suitable for deployment
|
||||
- Not suitable for continued development like a full Git checkout
|
||||
|
||||
### Merge Strategies (per-path)
|
||||
- Goal: apply special merge behavior for specific files
|
||||
- Example: keep “our” version of a config-like file
|
||||
- `.gitattributes`: `database.xml merge=ours`
|
||||
- Configure merge driver
|
||||
- `git config --global merge.ours.driver true` (dummy driver; always “succeeds” taking ours)
|
||||
- Result when merging
|
||||
- Git uses current branch version for that path, avoiding manual conflict resolution for that file
|
||||
|
||||
## Git Hooks
|
||||
### What hooks are
|
||||
- Custom scripts triggered by Git events
|
||||
- Two groups
|
||||
- Client-side: local operations (commit, rebase, merge, checkout, push initiation, etc.)
|
||||
- Server-side: network operations (receiving pushes)
|
||||
|
||||
### Installing a hook
|
||||
- Location
|
||||
- `.git/hooks` in a repository
|
||||
- Defaults
|
||||
- `git init` creates example hook scripts (typically `*.sample`)
|
||||
- Enabling a hook
|
||||
- Create/rename a file with the proper hook name (no extension)
|
||||
- Make it executable
|
||||
- Implementation language
|
||||
- Any executable script works (shell, Perl, Ruby, Python, …)
|
||||
|
||||
### Client-side hooks
|
||||
- Critical distribution note
|
||||
- Client-side hooks are **not** transferred when cloning
|
||||
- To **enforce** policy, prefer server-side hooks (client-side can only assist)
|
||||
|
||||
#### Committing-workflow hooks
|
||||
- `pre-commit`
|
||||
- Runs: before commit message entry
|
||||
- Use: inspect staged snapshot, run tests/lint, detect trailing whitespace, verify docs, etc.
|
||||
- Abort rule: non-zero exit cancels commit
|
||||
- Bypass: `git commit --no-verify`
|
||||
- `prepare-commit-msg`
|
||||
- Runs: after default message is created, before editor opens
|
||||
- Inputs (parameters)
|
||||
- Commit message file path
|
||||
- Commit type
|
||||
- Commit SHA-1 (for amended commits)
|
||||
- Use: adjust auto-generated messages (merge commits, squashes, amended commits, template-based flows)
|
||||
- `commit-msg`
|
||||
- Runs: after message is written, before commit is finalized
|
||||
- Input: commit message file path
|
||||
- Use: validate message format / required patterns
|
||||
- `post-commit`
|
||||
- Runs: after commit completes
|
||||
- No parameters
|
||||
- Use: notifications; can identify last commit via `git log -1 HEAD`
|
||||
|
||||
#### Email workflow hooks (for `git am`)
|
||||
- Scope note
|
||||
- Only relevant if using email patch workflows (`git format-patch` → `git am`)
|
||||
- `applypatch-msg`
|
||||
- Runs: first
|
||||
- Input: temp file with proposed commit message
|
||||
- Abort rule: non-zero cancels patch application
|
||||
- Use: validate/normalize commit messages (can edit file in place)
|
||||
- `pre-applypatch`
|
||||
- Runs: after patch applied, before commit is made
|
||||
- Use: inspect snapshot; run tests; abort `git am` if failures occur
|
||||
- `post-applypatch`
|
||||
- Runs: after commit is made
|
||||
- Use: notify author/team that patch was applied
|
||||
- Cannot stop the patching process
|
||||
|
||||
#### Other client hooks
|
||||
- `pre-rebase`
|
||||
- Runs: before rebase
|
||||
- Abort rule: non-zero cancels rebase
|
||||
- Use: prevent rebasing commits that have already been pushed (sample hook attempts this)
|
||||
- `post-rewrite`
|
||||
- Triggered by: commands that replace commits (`git commit --amend`, `git rebase`; not `git filter-branch`)
|
||||
- Input: argument naming the triggering command; rewrite list on stdin
|
||||
- Use: similar to post-checkout/post-merge automation/notifications
|
||||
- `post-checkout`
|
||||
- Runs: after successful `git checkout`
|
||||
- Use: project environment setup (populate large binaries not tracked, generate docs, etc.)
|
||||
- `post-merge`
|
||||
- Runs: after successful merge
|
||||
- Use: restore non-tracked working-tree data (e.g., permissions), validate external dependencies
|
||||
- `pre-push`
|
||||
- Runs: during `git push` after remote refs updated but before objects transferred
|
||||
- Inputs
|
||||
- Parameters: remote name + remote location
|
||||
- stdin: refs to be updated
|
||||
- Abort rule: non-zero cancels push
|
||||
- Use: validate ref updates before transferring objects
|
||||
- `pre-auto-gc`
|
||||
- Runs: before automatic garbage collection (`git gc --auto`)
|
||||
- Use: notify user or abort GC if inconvenient
|
||||
|
||||
### Server-side hooks
|
||||
- Admin-focused: enforce policies on pushes
|
||||
- Pre hooks can reject pushes
|
||||
- Exit non-zero to reject
|
||||
- Print message to stdout to show error to client
|
||||
|
||||
#### `pre-receive`
|
||||
- Runs: first during push handling
|
||||
- Input: list of refs on stdin
|
||||
- Reject behavior
|
||||
- Non-zero exit rejects **all** refs in the push
|
||||
- Use cases
|
||||
- Block non-fast-forward updates globally
|
||||
- Access control across refs and paths being modified
|
||||
|
||||
#### `update`
|
||||
- Similar role to `pre-receive`, but:
|
||||
- Runs **once per branch/ref** being updated
|
||||
- Inputs (arguments)
|
||||
- Ref name
|
||||
- Old SHA-1
|
||||
- New SHA-1
|
||||
- Reject behavior
|
||||
- Non-zero exit rejects **only that ref**; other refs can still update
|
||||
|
||||
#### `post-receive`
|
||||
- Runs: after push process completes
|
||||
- Input: same stdin data as `pre-receive`
|
||||
- Use cases
|
||||
- Notify services/users (email lists, CI, ticket trackers)
|
||||
- Parse commit messages for automation
|
||||
- Performance note
|
||||
- Cannot stop push; client waits until hook finishes
|
||||
- Avoid long-running tasks or offload them
|
||||
|
||||
#### Hook scripting tip (from chapter)
|
||||
- Prefer long-form command-line flags in scripts for readability/maintainability
|
||||
|
||||
## An Example Git-Enforced Policy
|
||||
### Goals
|
||||
- Enforce commit message format (must include a ticket/reference token)
|
||||
- Enforce user-based access control (who can change which directories/files)
|
||||
- Provide client-side hooks to warn users early (reduce rejected pushes)
|
||||
|
||||
### Implementation language in chapter
|
||||
- Ruby (chosen for readability), but any scripting language works
|
||||
|
||||
### Server-side enforcement (in `hooks/update`)
|
||||
#### Update hook inputs & environment
|
||||
- Runs once per branch being pushed
|
||||
- Arguments
|
||||
- `refname` (ref being updated)
|
||||
- `oldrev` (old SHA-1)
|
||||
- `newrev` (new SHA-1)
|
||||
- User identification assumption
|
||||
- User available in `$USER`
|
||||
- SSH single-user setups may need a wrapper to map public keys to a user and set env var
|
||||
- Hook prints an “Enforcing Policies…” banner
|
||||
- Anything printed to stdout is relayed to the pushing client
|
||||
|
||||
#### Policy 1: Enforce commit message format
|
||||
- Requirement: each commit message must contain something like `[ref: 1234]`
|
||||
- Identify commits included in the push
|
||||
- `git rev-list oldrev..newrev` (lists new commits by SHA-1)
|
||||
- Extract commit message for each commit
|
||||
- `git cat-file commit <sha>` gives raw commit object
|
||||
- Message content begins after first blank line
|
||||
- Use `sed '1,/^$/d'` to print message portion
|
||||
- Validate messages
|
||||
- Regex (concept): `/\[ref: (\d+)\]/`
|
||||
- If any commit lacks the pattern
|
||||
- Print policy message
|
||||
- `exit 1` → reject push
|
||||
|
||||
#### Policy 2: Enforce directory/file ACL (user-based permissions)
|
||||
- ACL file location (server-side)
|
||||
- `acl` file stored in the bare repository
|
||||
- ACL format (CVS-like)
|
||||
- Lines: `avail|user1,user2|path`
|
||||
- Pipe `|` delimits fields
|
||||
- Blank `path` means access to everything
|
||||
- (Example also mentions `unavail`, but the sample enforcement only handles `avail`)
|
||||
- Example intent
|
||||
- Admin users: full access
|
||||
- Doc writers: only `doc/`
|
||||
- Limited dev: only `lib/` and `tests/`
|
||||
- Parse ACL into structure
|
||||
- Map: `user -> [allowed_paths]`
|
||||
- `nil` path denotes “allowed everywhere”
|
||||
- Determine what files are modified by pushed commits
|
||||
- For each new commit: `git log -1 --name-only --pretty=format:'' <rev>`
|
||||
- Validate each changed path against user’s allowed paths
|
||||
- Allowed if
|
||||
- user has a `nil` access path (full access), or
|
||||
- file path starts with an allowed directory prefix
|
||||
- On violation
|
||||
- Print `[POLICY] You do not have access to push to <path>`
|
||||
- `exit 1` to reject
|
||||
|
||||
#### Testing behavior (server-side)
|
||||
- Enable hook: `chmod u+x .git/hooks/update`
|
||||
- Pushing with a bad commit message
|
||||
- Hook prints policy banner + error
|
||||
- Git reports hook failure and rejects the ref update
|
||||
- Pushing unauthorized file edits
|
||||
- Similar rejection, specifying the disallowed path
|
||||
- Outcome
|
||||
- Repo never accepts commits missing the required reference pattern
|
||||
- Users are sandboxed to allowed paths
|
||||
|
||||
### Client-side helper hooks (reduce “last-minute” rejections)
|
||||
#### Distribution limitation
|
||||
- Hooks don’t clone with the repository
|
||||
- Must distribute scripts separately and have users install them into `.git/hooks/` and make executable
|
||||
|
||||
#### Client policy 1: commit message check (`commit-msg` hook)
|
||||
- Runs before commit finalization
|
||||
- Input: commit message file path (`ARGV[0]`)
|
||||
- Enforces same regex pattern as server policy
|
||||
- Behavior
|
||||
- Non-matching message → print policy message → exit non-zero → commit aborted
|
||||
- Matching message → commit proceeds
|
||||
|
||||
#### Client policy 2: ACL check before commit (`pre-commit` hook)
|
||||
- Requires local copy of ACL file
|
||||
- Expected at: `.git/acl`
|
||||
- Key differences vs server-side ACL enforcement
|
||||
- Uses staging area (index) instead of commit history
|
||||
- File list command
|
||||
- `git diff-index --cached --name-only HEAD`
|
||||
- Same core permission logic
|
||||
- If staged changes include a disallowed path, abort commit
|
||||
- Identity caveat
|
||||
- Assumes local `$USER` matches the user used when pushing to the server; otherwise set user explicitly
|
||||
|
||||
#### Client policy 3: prevent rebasing already-pushed commits (`pre-rebase` hook)
|
||||
- Motivation
|
||||
- Server likely already denies non-fast-forward updates (`receive.denyNonFastForwards`) and deletes
|
||||
- Client hook helps prevent accidental rebases that rewrite already-pushed commits
|
||||
- Script logic (concept)
|
||||
- Determine base branch + topic branch (`HEAD` default)
|
||||
- List commits to be rewritten: `git rev-list base..topic`
|
||||
- List remote refs: `git branch -r`
|
||||
- For each commit SHA, check if reachable from any remote ref
|
||||
- Uses revision syntax `sha^@` (all parents)
|
||||
- Uses `git rev-list ^<sha>^@ refs/remotes/<remote_ref>` to test reachability
|
||||
- If any commit already exists remotely, abort rebase with policy message
|
||||
- Tradeoffs
|
||||
- Can be slow
|
||||
- Often unnecessary unless you were going to force-push
|
||||
- Still a useful preventative exercise
|
||||
|
||||
## Summary (chapter wrap-up)
|
||||
- Customization categories mastered
|
||||
- Config settings (client + server)
|
||||
- Attributes (path-specific diff/merge/filter/export behavior)
|
||||
- Hooks (client assistance + server enforcement)
|
||||
- Practical outcome
|
||||
- Git can be shaped to match nearly any workflow, including enforceable policies and automation
|
||||
926
mindmap/Distributed Git.md
Normal file
926
mindmap/Distributed Git.md
Normal file
@@ -0,0 +1,926 @@
|
||||
```markdown
|
||||
# Distributed Git
|
||||
## Context & Goals (Why this chapter)
|
||||
- Starting point
|
||||
- A remote Git repository already exists as a shared focal point
|
||||
- You already know basic local Git commands/workflow
|
||||
- What “distributed” enables
|
||||
- Git supports distributed collaboration patterns beyond centralized VCSs
|
||||
- Two roles you’ll learn to operate in
|
||||
- Contributor
|
||||
- Contribute code successfully
|
||||
- Make it easy for you + project maintainer
|
||||
- Integrator / Maintainer
|
||||
- Maintain a project with many contributors
|
||||
- Integrate others’ work sustainably and clearly
|
||||
|
||||
## Distributed Workflows (Collaboration models)
|
||||
### Git vs Centralized Version Control Systems (CVCSs)
|
||||
- CVCS mental model
|
||||
- Central hub/repository is the primary “source”
|
||||
- Developers are “nodes” consuming/syncing with that hub
|
||||
- Git mental model (distributed)
|
||||
- Every developer is potentially both:
|
||||
- A node (contributor to others)
|
||||
- A hub (maintains a public repo others can base work on)
|
||||
- Result: many possible workflow designs
|
||||
- You can choose one workflow
|
||||
- Or mix-and-match features
|
||||
|
||||
### Centralized Workflow (Single shared hub)
|
||||
- Core idea
|
||||
- One central repository (“hub”) accepts code
|
||||
- Everyone synchronizes with that central location
|
||||
- What happens when changes overlap in time
|
||||
- Two developers clone from hub and both change things
|
||||
- First developer to push succeeds
|
||||
- Second developer must first merge the upstream work locally
|
||||
- Prevents overwriting the first developer’s work
|
||||
- True in Git just like Subversion (or any CVCS)
|
||||
- Why people like it
|
||||
- Familiar paradigm for many teams
|
||||
- Git-specific note
|
||||
- You can keep using this model in Git
|
||||
- Give everyone push access
|
||||
- Git prevents overwriting (rejects non-fast-forward pushes)
|
||||
- Scale note
|
||||
- Not limited to small teams
|
||||
- Git branching makes it possible for hundreds of devs to work across dozens of branches
|
||||
|
||||
- Figure 53: Centralized workflow
|
||||
- Hub repository with multiple developers syncing to it
|
||||
|
||||
### Integration-Manager Workflow (Multiple repos + canonical “official” repo)
|
||||
- Core idea
|
||||
- Each developer:
|
||||
- Has write access to their own public repository
|
||||
- Has read access to others’ repositories
|
||||
- There is a canonical (“official”) repository
|
||||
- Contribution mechanics (typical steps)
|
||||
1. Maintainer pushes to their public repository
|
||||
2. Contributor clones that repository and makes changes
|
||||
3. Contributor pushes to their own public copy
|
||||
4. Contributor requests maintainer to pull changes (often email)
|
||||
5. Maintainer adds contributor repo as remote, tests locally, merges locally
|
||||
6. Maintainer pushes merged result to canonical repo
|
||||
- Where it’s common
|
||||
- Hub-based hosting (e.g., GitHub/GitLab-style forking)
|
||||
- Key advantage emphasized
|
||||
- Asynchronous pace
|
||||
- Contributor keeps working without waiting for acceptance
|
||||
- Maintainer can pull in changes whenever ready
|
||||
|
||||
- Figure 54: Integration-manager workflow
|
||||
- Blessed/canonical repo + integration manager + contributor public/private repos
|
||||
|
||||
### Dictator and Lieutenants Workflow (Large hierarchical projects)
|
||||
- What it is
|
||||
- Variant of multi-repo workflow
|
||||
- Used in huge projects with hundreds of collaborators (example: Linux kernel)
|
||||
- Roles
|
||||
- Lieutenants
|
||||
- Integration managers for specific subsystems/areas
|
||||
- Benevolent dictator
|
||||
- Single final integration manager
|
||||
- Pushes to reference (“blessed”) repository
|
||||
- Process (typical steps)
|
||||
1. Regular developers
|
||||
- Work on topic branches
|
||||
- Rebase their work on top of `master`
|
||||
- `master` here = reference repo’s `master` that dictator pushes to
|
||||
2. Lieutenants
|
||||
- Merge developers’ topic branches into lieutenants’ `master`
|
||||
3. Dictator
|
||||
- Merges lieutenants’ `master` branches into dictator’s `master`
|
||||
4. Dictator pushes to reference repository
|
||||
- Other developers rebase on that updated `master`
|
||||
- When it helps
|
||||
- Very large projects
|
||||
- Highly hierarchical environments
|
||||
- Delegates integration work; collects large subsets before final integration
|
||||
- Noted as
|
||||
- Not common overall
|
||||
- But useful in specific contexts
|
||||
|
||||
- Figure 55: Benevolent dictator workflow
|
||||
- Dictator integrates from lieutenants; pushes to blessed repository
|
||||
|
||||
### Patterns for Managing Source Code Branches (external guide callout)
|
||||
- Reference
|
||||
- Martin Fowler guide: “Patterns for Managing Source Code Branches”
|
||||
- Link: https://martinfowler.com/articles/branching-patterns.html
|
||||
- What the guide covers (as noted)
|
||||
- Common Git workflows
|
||||
- How/when to use them
|
||||
- Comparison of high vs low integration frequencies
|
||||
|
||||
### Workflows Summary (transition)
|
||||
- Distributed Git allows many variations
|
||||
- Choose a workflow (or combination) that fits reality
|
||||
- Next: specific contributing patterns and use cases
|
||||
|
||||
## Contributing to a Project (How to contribute effectively)
|
||||
### Why it’s hard to prescribe one “right” way
|
||||
- Git is flexible → many real-world collaboration styles
|
||||
- Every project differs
|
||||
|
||||
### Key variables that change the “best” approach
|
||||
- Active contributor count (and activity level)
|
||||
- Small/dormant: 2–3 devs, few commits/day (or less)
|
||||
- Large: thousands of devs, hundreds/thousands of commits/day
|
||||
- Practical risk with larger activity
|
||||
- Your changes may not apply cleanly later
|
||||
- Your changes may become obsolete/broken before merging
|
||||
- Need to keep work up to date and commits valid
|
||||
- Workflow in use
|
||||
- Centralized (everyone can push to main line)
|
||||
- Integration manager / maintainer gatekeeping
|
||||
- Peer review requirements
|
||||
- Lieutenant system (submit to subsystem maintainers first)
|
||||
- Your commit access
|
||||
- Write access vs no write access changes everything
|
||||
- If no access
|
||||
- How does project accept contributions (policy/method)?
|
||||
- Contribution size & frequency
|
||||
- How much you contribute at a time
|
||||
- How often you contribute
|
||||
|
||||
### Approach in chapter
|
||||
- Presents a series of use cases (simple → complex)
|
||||
- Goal
|
||||
- Let you construct the workflow you need in practice
|
||||
|
||||
### Commit Guidelines (preparing high-quality contributions)
|
||||
- Source of guidance
|
||||
- Git project’s tips: `Documentation/SubmittingPatches`
|
||||
- Guideline 1: Avoid whitespace errors
|
||||
- Check before committing:
|
||||
- `git diff --check`
|
||||
- Purpose
|
||||
- Identify whitespace problems early
|
||||
- Prevent annoying reviewers/maintainers
|
||||
- Figure 56: Output of `git diff --check`
|
||||
- Guideline 2: Make commits logically separate changesets
|
||||
- Keep changes digestible
|
||||
- Don’t bundle multiple unrelated issues into one massive commit
|
||||
- Use staging area to split work
|
||||
- Even if you did work across multiple issues before committing
|
||||
- If changes overlap in same file
|
||||
- Use partial staging:
|
||||
- `git add --patch`
|
||||
- (Referenced as covered in “Interactive Staging”)
|
||||
- Key point emphasized
|
||||
- Final snapshot can be identical whether you do 1 commit or 5
|
||||
- But review/revert is much easier with clean, separated commits
|
||||
- Benefit
|
||||
- Easier to later pull out/revert one changeset
|
||||
- Tooling reference
|
||||
- “Rewriting History” provides techniques for crafting clean history
|
||||
- Guideline 3: Write high-quality commit messages
|
||||
- Why
|
||||
- Makes using Git + collaborating easier
|
||||
- Recommended structure
|
||||
- Summary line
|
||||
- ~50 characters or less
|
||||
- Concise description of changeset
|
||||
- Blank line (important)
|
||||
- Tools (e.g., rebase) can get confused without it
|
||||
- Body (optional, but recommended when needed)
|
||||
- More detailed explanation
|
||||
- Wrap around ~72 characters
|
||||
- Include motivation for change
|
||||
- Contrast implementation with previous behavior (Git project requirement)
|
||||
- Style rules
|
||||
- Imperative mood
|
||||
- “Fix bug” (not “Fixed bug” / “Fixes bug”)
|
||||
- Matches messages auto-generated by `git merge` and `git revert`
|
||||
- Formatting details
|
||||
- Multiple paragraphs separated by blank lines
|
||||
- Bullet points are okay
|
||||
- Hyphen/asterisk + single space
|
||||
- Hanging indent
|
||||
- Conventions vary
|
||||
- Example quality reference
|
||||
- Look at Git project history:
|
||||
- `git log --no-merges`
|
||||
- Callout: “Do as we say, not as we do”
|
||||
- Book examples often use `git commit -m` for brevity
|
||||
- Not meant as best-practice formatting
|
||||
|
||||
## Use Case 1: Private Small Team (simple shared repo)
|
||||
### Setting
|
||||
- Private = closed-source, not public
|
||||
- 1–2 other developers
|
||||
- Everyone has push access to the shared repository
|
||||
- Workflow resembles centralized systems (e.g., Subversion), but with Git advantages
|
||||
- Offline commits
|
||||
- Easier branching/merging
|
||||
- Key difference vs Subversion: merges happen client-side
|
||||
|
||||
### Example scenario: John & Jessica pushing to shared repo
|
||||
- John: clone, edit, commit
|
||||
- `git clone john@githost:simplegit.git`
|
||||
- edit `lib/simplegit.rb`
|
||||
- `git commit -am 'Remove invalid default value'`
|
||||
- Jessica: clone, edit, commit
|
||||
- `git clone jessica@githost:simplegit.git`
|
||||
- edit `TODO`
|
||||
- `git commit -am 'Add reset task'`
|
||||
- Jessica pushes successfully
|
||||
- `git push origin master`
|
||||
- Push output explained (last line format)
|
||||
- `<oldref>..<newref> fromref → toref`
|
||||
- `oldref`: previous remote reference
|
||||
- `newref`: updated remote reference
|
||||
- `fromref`: local ref being pushed
|
||||
- `toref`: remote ref being updated
|
||||
- Reference: `git-push` documentation
|
||||
- John tries to push and is rejected
|
||||
- `git push origin master`
|
||||
- Error: rejected (non-fast forward)
|
||||
- Key lesson vs Subversion
|
||||
- Even if they edited different files
|
||||
- Git requires John to fetch + merge locally before pushing
|
||||
- Subversion might do server-side merge; Git does not
|
||||
|
||||
### John resolves the non-fast-forward
|
||||
- Step 1: Fetch upstream changes
|
||||
- `git fetch origin`
|
||||
- Fetch downloads changes but does not merge them
|
||||
- Figure 57: John’s divergent history (local master vs `origin/master`)
|
||||
- Step 2: Merge fetched upstream
|
||||
- `git merge origin/master`
|
||||
- Merge strategy shown: `recursive`
|
||||
- Figure 58: John’s repository after merging `origin/master`
|
||||
- Step 3: Test merged code (recommended)
|
||||
- Step 4: Push merged result
|
||||
- `git push origin master`
|
||||
- Figure 59: John’s history after pushing to origin
|
||||
|
||||
### Jessica’s parallel work: topic branch + later integration
|
||||
- Jessica created topic branch `issue54`
|
||||
- 3 commits on that branch
|
||||
- She hadn’t fetched John’s updates yet
|
||||
- Figure 60: Jessica’s topic branch
|
||||
- Jessica fetches new work
|
||||
- `git fetch origin`
|
||||
- Figure 61: Jessica’s history after fetching John’s changes
|
||||
- Jessica determines what new commits exist on `origin/master`
|
||||
- `git log --no-merges issue54..origin/master`
|
||||
- Meaning of `issue54..origin/master`
|
||||
- Show commits on `origin/master` that are not on `issue54`
|
||||
- Note: range syntax referenced as covered later in “Commit Ranges”
|
||||
- Jessica integrates (order doesn’t matter for final snapshot)
|
||||
- Switch to master
|
||||
- `git checkout master`
|
||||
- Message may indicate behind `origin/master` and fast-forwardable
|
||||
- Merge topic branch to master (chosen first)
|
||||
- `git merge issue54`
|
||||
- Result: fast-forward merge (no new merge commit)
|
||||
- Merge John’s upstream work
|
||||
- `git merge origin/master`
|
||||
- Result: merge commit created via recursive strategy
|
||||
- Figure 62: Jessica’s history after merging John’s changes
|
||||
- Jessica pushes
|
||||
- `git push origin master`
|
||||
- Figure 63: Jessica’s history after pushing all changes
|
||||
|
||||
### General “simple multi-developer” sequence (as summarized)
|
||||
- Work locally (often in a topic branch)
|
||||
- Merge topic branch into `master` when ready
|
||||
- Before sharing
|
||||
- Fetch and merge `origin/master` if it changed
|
||||
- Push `master` to server
|
||||
|
||||
- Figure 64: General sequence of events for this simple workflow
|
||||
|
||||
## Use Case 2: Private Managed Team (team branches + integrators)
|
||||
### Setting
|
||||
- Larger private group
|
||||
- Small groups collaborate on features
|
||||
- Integrators (a subset of engineers) merge into mainline
|
||||
- Only integrators can update `master` of main repo
|
||||
- Team collaboration happens on shared feature branches
|
||||
|
||||
### Scenario setup
|
||||
- FeatureA: John + Jessica
|
||||
- FeatureB: Jessica + Josie
|
||||
- Work happens on team-based branches; integrators pull together later
|
||||
|
||||
### Jessica works on FeatureA (with John)
|
||||
- Create feature branch
|
||||
- `git checkout -b featureA`
|
||||
- Work + commit
|
||||
- `git commit -am 'Add limit to log function'`
|
||||
- Share with John
|
||||
- Push feature branch (no `master` push permission)
|
||||
- `git push -u origin featureA`
|
||||
- `-u` / `--set-upstream` sets upstream tracking for easier push/pull
|
||||
- Notify John (email)
|
||||
|
||||
### Jessica works on FeatureB (with Josie)
|
||||
- Base new branch off server `master`
|
||||
- `git fetch origin`
|
||||
- `git checkout -b featureB origin/master`
|
||||
- Work + commits
|
||||
- `git commit -am 'Make ls-tree function recursive'`
|
||||
- `git commit -am 'Add ls-files'`
|
||||
- Figure 65: Jessica’s initial commit history (featureA and featureB in progress)
|
||||
|
||||
### Josie already started an upstream branch for FeatureB
|
||||
- Josie pushed initial work as branch `featureBee`
|
||||
- Jessica fetches
|
||||
- `git fetch origin`
|
||||
- New remote-tracking branch: `origin/featureBee`
|
||||
- Jessica merges Josie’s work into her local `featureB`
|
||||
- `git merge origin/featureBee`
|
||||
- Jessica pushes merged result back to the shared upstream branch
|
||||
- Uses a refspec:
|
||||
- `git push -u origin featureB:featureBee`
|
||||
- Refspec concept
|
||||
- Push local `featureB` to remote branch `featureBee`
|
||||
- Reference: “The Refspec”
|
||||
- `-u` sets upstream for simpler future pushes/pulls
|
||||
|
||||
### John updates FeatureA; Jessica reviews and merges
|
||||
- Fetch updates (includes John’s latest on featureA)
|
||||
- `git fetch origin`
|
||||
- See what John added (compare local vs fetched)
|
||||
- `git log featureA..origin/featureA`
|
||||
- Merge it in
|
||||
- `git checkout featureA`
|
||||
- `git merge origin/featureA` (fast-forward in example)
|
||||
- Add minor tweaks
|
||||
- `git commit -am 'Add small tweak to merged content'`
|
||||
- Push featureA back to server
|
||||
- `git push`
|
||||
- Figure 66: Jessica’s history after committing on a feature branch
|
||||
|
||||
### Integrators merge FeatureA and FeatureBee into mainline
|
||||
- Team informs integrators the branches are ready
|
||||
- Integrators merge into mainline
|
||||
- After a fetch, Jessica sees merge commit(s)
|
||||
- Figure 67: Jessica’s history after integrators merged both topic branches
|
||||
|
||||
### Benefits emphasized
|
||||
- Multiple teams can work in parallel
|
||||
- Late merging of independent lines of work
|
||||
- Remote branches let subgroups collaborate without blocking entire team
|
||||
|
||||
- Figure 68: Basic sequence of the managed-team workflow
|
||||
|
||||
## Use Case 3: Forked Public Project (contribute via forks & pull requests)
|
||||
### Why this differs
|
||||
- Public project: you typically cannot push to the official repo
|
||||
- Need a different path to get work to maintainers
|
||||
|
||||
### Typical fork-based flow
|
||||
- Clone main repository
|
||||
- `git clone <url>`
|
||||
- Create a topic branch for your work
|
||||
- `git checkout -b featureA`
|
||||
- Commit as you work
|
||||
- `git commit` (repeat as needed)
|
||||
- Optional cleanup for review
|
||||
- Use interactive rebase:
|
||||
- `rebase -i`
|
||||
- Goals: squash commits, reorder, make review easier
|
||||
- Reference: “Rewriting History”
|
||||
|
||||
### Fork + push topic branch to your fork
|
||||
- Fork via hosting site (“Fork” button) → writable fork
|
||||
- Add fork as remote
|
||||
- `git remote add myfork <url>`
|
||||
- Push only the topic branch (recommended)
|
||||
- `git push -u myfork featureA`
|
||||
- Why avoid merging into your `master` before pushing?
|
||||
- If rejected or cherry-picked, you don’t need to rewind your master
|
||||
- Maintainers may merge/rebase/cherry-pick; you’ll receive it later by pulling upstream
|
||||
|
||||
### Notify maintainers: Pull request / request-pull
|
||||
- “Pull request” can be created:
|
||||
- Through the website (e.g., GitHub mechanism)
|
||||
- Or manually via `git request-pull` + email
|
||||
- `git request-pull` purpose
|
||||
- Produces a summary of changes being requested for pull
|
||||
- Inputs
|
||||
- Base branch to pull into (e.g., `origin/master`)
|
||||
- Repo URL to pull from (your fork)
|
||||
- Output includes (as shown)
|
||||
- Base commit reference (“changes since commit …”)
|
||||
- Where to pull from (URL + branch)
|
||||
- Commit list + diffstat summary
|
||||
|
||||
### Best practice for multiple contributions
|
||||
- Keep a local `master` tracking `origin/master`
|
||||
- Work in topic branches
|
||||
- Easy to discard if rejected
|
||||
- Easy to rebase if upstream moves
|
||||
|
||||
### Starting a second topic: don’t stack topics on old branches
|
||||
- Start new branch from current upstream master
|
||||
- `git checkout -b featureB origin/master`
|
||||
- Work + commit
|
||||
- Push
|
||||
- `git push myfork featureB`
|
||||
- Request pull
|
||||
- `git request-pull origin/master myfork`
|
||||
- Update your view of upstream
|
||||
- `git fetch origin`
|
||||
- Resulting structure
|
||||
- Topics become separate silos (patch-queue-like)
|
||||
- Figure 69: Initial commit history with featureB work
|
||||
|
||||
### Scenario: maintainer can’t merge your featureA cleanly anymore
|
||||
- Cause
|
||||
- Upstream `origin/master` moved; your topic doesn’t apply cleanly
|
||||
- Fix
|
||||
- Rebase your topic onto current upstream
|
||||
- `git checkout featureA`
|
||||
- `git rebase origin/master`
|
||||
- Force push updated branch to your fork
|
||||
- `git push -f myfork featureA`
|
||||
- Why `-f` is required
|
||||
- Rebase rewrites history
|
||||
- New commits may not be descendants of the remote branch tip
|
||||
- Alternative mentioned
|
||||
- Push to a new branch (e.g., `featureAv2`) instead of force-updating
|
||||
- Figure 70: Commit history after rebasing featureA work
|
||||
|
||||
### Scenario: maintainer likes featureB but requests implementation changes
|
||||
- Goal
|
||||
- Re-base on current `origin/master`
|
||||
- Provide revised branch version
|
||||
- Workflow
|
||||
- Create new branch from current upstream
|
||||
- `git checkout -b featureBv2 origin/master`
|
||||
- Squash merge old feature branch changes
|
||||
- `git merge --squash featureB`
|
||||
- Make requested implementation changes
|
||||
- Commit
|
||||
- `git commit`
|
||||
- Push new branch
|
||||
- `git push myfork featureBv2`
|
||||
- Meaning of `--squash`
|
||||
- Combines all changes into one changeset
|
||||
- Produces final state as if merged, but without a merge commit
|
||||
- New commit has only one parent
|
||||
- Lets you add more edits before recording the final commit
|
||||
- Extra option callout
|
||||
- `--no-commit` can delay commit in default merge process
|
||||
- Figure 71: Commit history after featureBv2 work
|
||||
|
||||
## Use Case 4: Public Project over Email (patch series via mailing list)
|
||||
### When this is used
|
||||
- Many older/larger projects accept patches via mailing lists
|
||||
- Each project has specific procedures → you must check their rules
|
||||
|
||||
### High-level flow
|
||||
- Create a topic branch per patch series
|
||||
- Instead of forking/pushing
|
||||
- Generate email-ready patches
|
||||
- Email to developer mailing list
|
||||
|
||||
### Create commits on a topic branch
|
||||
- `git checkout -b topicA`
|
||||
- Work + commit
|
||||
- `git commit` (repeat)
|
||||
|
||||
### Generate mbox-formatted patch emails: `git format-patch`
|
||||
- Command example
|
||||
- `git format-patch -M origin/master`
|
||||
- What it produces
|
||||
- One `*.patch` file per commit
|
||||
- Each patch file = one email message
|
||||
- Subject = first line of commit message
|
||||
- Body = remainder of message + the diff
|
||||
- Why it’s nice
|
||||
- Applying patches generated this way preserves commit info properly
|
||||
- Option noted
|
||||
- `-M` makes Git detect renames
|
||||
|
||||
### Patch file structure (what maintainers/reviewers see)
|
||||
- Email-like headers
|
||||
- `From <sha> Mon Sep 17 00:00:00 2001`
|
||||
- `From: <author>`
|
||||
- `Date: <date>`
|
||||
- `Subject: [PATCH x/y] <summary>`
|
||||
- Commit message body text
|
||||
- Separator
|
||||
- `---`
|
||||
- Patch begins
|
||||
- `diff --git ...`
|
||||
- Version footer (as shown in example)
|
||||
|
||||
### Adding extra explanation without changing commit message
|
||||
- You can edit patch files
|
||||
- Place extra notes between:
|
||||
- the `---` line
|
||||
- and the `diff --git` line
|
||||
- These notes
|
||||
- are readable by developers
|
||||
- are ignored by patch application
|
||||
|
||||
### Sending patches without breaking formatting
|
||||
- Copy/paste into email client can break whitespace/newlines
|
||||
- Git-provided tools to send properly formatted patches
|
||||
|
||||
#### Option A: IMAP (drafts workflow) with `git imap-send`
|
||||
- Setup `~/.gitconfig` `[imap]` section (example values shown)
|
||||
- `folder` (e.g., `[Gmail]/Drafts`)
|
||||
- `host` (e.g., `imaps://imap.gmail.com`)
|
||||
- `user`
|
||||
- `pass`
|
||||
- `port` (e.g., `993`)
|
||||
- `sslverify = false`
|
||||
- SSL note
|
||||
- If IMAP server doesn’t use SSL
|
||||
- last lines may be unnecessary
|
||||
- host uses `imap://` not `imaps://`
|
||||
- Send patches to Drafts folder
|
||||
- `cat *.patch | git imap-send`
|
||||
- Then in email client
|
||||
- Set `To:` mailing list
|
||||
- Possibly CC maintainer/area owner
|
||||
- Send
|
||||
|
||||
#### Option B: SMTP with `git send-email`
|
||||
- Setup `~/.gitconfig` `[sendemail]` section (example values shown)
|
||||
- `smtpencryption = tls`
|
||||
- `smtpserver = smtp.gmail.com`
|
||||
- `smtpuser`
|
||||
- `smtpserverport = 587`
|
||||
- Send patch files
|
||||
- `git send-email *.patch`
|
||||
- Interactive prompts noted
|
||||
- “From” identity
|
||||
- Recipients
|
||||
- Message-ID / In-Reply-To for threading
|
||||
- Output includes per-patch send logs and headers
|
||||
|
||||
- Tip resource
|
||||
- Configuration help + sandbox for trial patches:
|
||||
- https://git-send-email.io
|
||||
|
||||
## Contribution Summary (end of “Contributing” portion)
|
||||
- Covered
|
||||
- Multiple workflows (private vs public)
|
||||
- How to handle merges in those workflows
|
||||
- Commit hygiene
|
||||
- whitespace checks
|
||||
- logically separated commits
|
||||
- strong commit messages
|
||||
- Patch generation and emailing
|
||||
- Transition
|
||||
- Next: maintaining a project (integration/maintainer side)
|
||||
|
||||
## Maintaining a Project (Integrator/Maintainer perspective)
|
||||
### What “maintaining” involves
|
||||
- Accepting and applying patches from email
|
||||
- Often produced by `format-patch`
|
||||
- Integrating changes from remote branches
|
||||
- From repos you add as remotes
|
||||
- Applies whether you
|
||||
- maintain a canonical repository
|
||||
- or help by verifying/approving patches
|
||||
- Goal
|
||||
- Accept work in a way that is clear for contributors
|
||||
- Sustainable long-term
|
||||
|
||||
### Working in Topic Branches (safe integration practice)
|
||||
- Best practice
|
||||
- Try new contributions in a temporary topic branch
|
||||
- Why
|
||||
- Easy to test and tweak
|
||||
- Easy to abandon temporarily and return later
|
||||
- Naming guidance
|
||||
- Use descriptive theme-based names (e.g., `ruby_client`)
|
||||
- Git maintainer convention:
|
||||
- namespace: `sc/ruby_client`
|
||||
- `sc` = contributor shorthand
|
||||
- Create topic branch from `master`
|
||||
- Create only:
|
||||
- `git branch sc/ruby_client master`
|
||||
- Create and switch immediately:
|
||||
- `git checkout -b sc/ruby_client master`
|
||||
|
||||
### Applying Patches from Email (two main tools)
|
||||
- Two methods
|
||||
- `git apply`
|
||||
- `git am`
|
||||
|
||||
#### Applying with `git apply` (for raw diffs)
|
||||
- When to use
|
||||
- Patch generated from `git diff` or generic Unix diff (not recommended if `format-patch` available)
|
||||
- Apply a patch file
|
||||
- `git apply /tmp/patch-ruby-client.patch`
|
||||
- What it does
|
||||
- Modifies files in working directory
|
||||
- Similar to `patch -p1`, but:
|
||||
- More paranoid (fewer fuzzy matches)
|
||||
- Understands Git diff format adds/deletes/renames (patch tool may not)
|
||||
- “Apply all or abort all” (atomic)
|
||||
- Unlike `patch`, which can partially apply and leave a messy state
|
||||
- Important limitation
|
||||
- Does not create a commit
|
||||
- You must stage and commit manually afterward
|
||||
- Preflight check
|
||||
- `git apply --check <patch>`
|
||||
- Behavior
|
||||
- No output → should apply cleanly
|
||||
- Non-zero exit status on failure → script-friendly
|
||||
|
||||
#### Applying with `git am` (for `format-patch` / mbox)
|
||||
- When to use (preferred)
|
||||
- Contributor used `git format-patch`
|
||||
- Patch includes author info and commit message
|
||||
- Meaning / concept
|
||||
- `am` = apply patches from a mailbox
|
||||
- Reads mbox format (plain-text emails in one file)
|
||||
- Apply a patch file generated by `format-patch`
|
||||
- `git am 0001-limit-log-function.patch`
|
||||
- What it does automatically
|
||||
- Creates commits for you
|
||||
- Uses email headers/body to populate:
|
||||
- Author info: From + Date
|
||||
- Commit message: Subject + body (before diff)
|
||||
- Committer info becomes the applier + apply time
|
||||
- Inspecting result (example command shown)
|
||||
- `git log --pretty=fuller -1`
|
||||
- Distinction highlighted
|
||||
- Author vs Committer (applier)
|
||||
|
||||
- If patch fails to apply cleanly
|
||||
- Common causes noted
|
||||
- Your branch diverged too far
|
||||
- Patch depends on another patch not applied yet
|
||||
- Failure behavior
|
||||
- Stops and shows options:
|
||||
- Continue after fixing: `git am --resolved`
|
||||
- Skip patch: `git am --skip`
|
||||
- Abort and restore original branch: `git am --abort`
|
||||
- Adds conflict markers to files (like merge/rebase)
|
||||
- Manual conflict workflow
|
||||
- Fix file(s)
|
||||
- Stage:
|
||||
- `git add <file>`
|
||||
- Continue:
|
||||
- `git am --resolved`
|
||||
|
||||
- Smarter conflict handling option: `-3`
|
||||
- `git am -3 <patch>`
|
||||
- What it does
|
||||
- Attempts a three-way merge
|
||||
- Caveat
|
||||
- Doesn’t work if the base commit referenced by patch isn’t in your repo
|
||||
- When it works well
|
||||
- Patch based on a public commit you have
|
||||
- Example behavior shown
|
||||
- Can detect “Patch already applied” when appropriate
|
||||
|
||||
- Interactive mode for patch series
|
||||
- `git am -3 -i <mbox>`
|
||||
- Stops at each patch and asks:
|
||||
- yes / no / edit / view patch / accept all
|
||||
- Useful when
|
||||
- You have many patches saved
|
||||
- You want to preview or skip already-applied patches
|
||||
|
||||
### Checking Out Remote Branches (pulling history from contributor repos)
|
||||
- When to use
|
||||
- Contributor provides:
|
||||
- repository URL
|
||||
- branch name containing their changes
|
||||
- One-time setup + local testing
|
||||
- Add remote:
|
||||
- `git remote add jessica git://github.com/jessica/myproject.git`
|
||||
- Fetch:
|
||||
- `git fetch jessica`
|
||||
- Checkout local branch from remote-tracking branch:
|
||||
- `git checkout -b rubyclient jessica/ruby-client`
|
||||
- Ongoing benefit
|
||||
- If same contributor sends more branches
|
||||
- you can fetch/checkout without re-adding remote
|
||||
- Pros emphasized
|
||||
- You get the full commit history
|
||||
- You know where it’s based → proper three-way merges by default
|
||||
- Avoid needing `-3` guesswork
|
||||
- Cons / practicality
|
||||
- Not efficient to maintain hundreds of remotes for occasional contributors
|
||||
- For one-off patches, email may be easier
|
||||
- Scripts/hosted services may change the trade-off
|
||||
|
||||
- One-time pull without saving a remote
|
||||
- `git pull <url>`
|
||||
- Does not store the remote in your config
|
||||
|
||||
### Determining What Is Introduced (reviewing a topic branch)
|
||||
- Review commits unique to topic branch
|
||||
- Exclude master commits:
|
||||
- `git log contrib --not master`
|
||||
- Equivalent idea to `master..contrib`
|
||||
- Review changes per commit
|
||||
- `git log -p ...` to append diffs
|
||||
|
||||
- Review overall diff of what merging would introduce
|
||||
- Pitfall
|
||||
- `git diff master` can be misleading if histories diverged
|
||||
- It compares tip snapshots and may make it look like topic removes master-only changes
|
||||
- Correct intention
|
||||
- Diff topic tip vs common ancestor with master
|
||||
- Compute common ancestor explicitly
|
||||
- `git merge-base contrib master`
|
||||
- Then:
|
||||
- `git diff <merge-base-sha>`
|
||||
- or `git diff $(git merge-base contrib master)`
|
||||
- Shorthand: triple-dot diff
|
||||
- `git diff master...contrib`
|
||||
- Shows only changes introduced on topic branch since divergence
|
||||
|
||||
### Integrating Contributed Work (strategies)
|
||||
#### Merging Workflows (merge-based integration)
|
||||
- Simple merge-into-master workflow
|
||||
- `master` contains stable code
|
||||
- For each completed/verified topic branch
|
||||
- merge into `master`
|
||||
- delete topic branch
|
||||
- repeat
|
||||
- Figures
|
||||
- Figure 72: History with several topic branches (`ruby_client`, `php_client`)
|
||||
- Figure 73: After merging topic branches
|
||||
|
||||
- Two-phase merge cycle (master + develop)
|
||||
- Two long-running branches
|
||||
- `master` = only updated on stable releases
|
||||
- `develop` = integration branch for new code
|
||||
- Both pushed to public repository
|
||||
- Process
|
||||
- Merge topic branches into `develop`
|
||||
- When ready to release
|
||||
- tag release
|
||||
- fast-forward `master` to `develop`
|
||||
- Figures
|
||||
- Figure 74: Before topic merge
|
||||
- Figure 75: After topic merge (into develop)
|
||||
- Figure 76: After project release (master fast-forward)
|
||||
- User-facing implication
|
||||
- Users can choose:
|
||||
- `master` for stable builds
|
||||
- `develop` for cutting-edge
|
||||
|
||||
- Extension: add `integrate` branch
|
||||
- `integrate` collects work together
|
||||
- When stable + tests pass
|
||||
- merge into `develop`
|
||||
- After `develop` proves stable
|
||||
- fast-forward `master`
|
||||
|
||||
#### Large-Merging Workflows (Git project example)
|
||||
- Git project long-running branches
|
||||
- `master`
|
||||
- `next`
|
||||
- `seen` (formerly `pu` = proposed updates)
|
||||
- `maint` (maintenance backports)
|
||||
- Workflow
|
||||
- New contributions collected as topic branches
|
||||
- Topics evaluated
|
||||
- Safe/ready → merge into `next` and push for wider testing
|
||||
- Need work → merge into `seen`
|
||||
- Totally stable → re-merge into `master`
|
||||
- After master updates
|
||||
- `next` and `seen` rebuilt from `master`
|
||||
- Behavior noted
|
||||
- `master` moves forward steadily
|
||||
- `next` rebased occasionally
|
||||
- `seen` rebased more often
|
||||
- Topic branches removed after they reach `master`
|
||||
- `maint` branch purpose
|
||||
- Forked from last release for backports / maintenance releases
|
||||
- Figures
|
||||
- Figure 77: Managing many parallel contributed topic branches
|
||||
- Figure 78: Merging topics into `next`/`seen` and re-merging to `master`
|
||||
- Note
|
||||
- Specialized; refer to Git Maintainer’s guide for full clarity
|
||||
|
||||
#### Rebasing and Cherry-Picking Workflows (linear history preference)
|
||||
- Rebase-based integration
|
||||
- Maintainer rebases topic branch on top of current `master` (or `develop`)
|
||||
- If successful
|
||||
- fast-forward `master`
|
||||
- Outcome
|
||||
- Mostly linear history
|
||||
- Cherry-pick-based integration
|
||||
- Cherry-pick = reapply the patch from a single commit onto current branch
|
||||
- Useful when
|
||||
- You want only some commits from a topic branch
|
||||
- Or topic branch contains only one commit
|
||||
- Example
|
||||
- Before: Figure 79 (commit `e43a6` on topic branch)
|
||||
- Command:
|
||||
- `git cherry-pick e43a6`
|
||||
- After: Figure 80 (new commit SHA because applied at different time)
|
||||
- After cherry-picking
|
||||
- remove topic branch / drop unwanted commits
|
||||
|
||||
### Rerere (Reuse Recorded Resolution)
|
||||
- When it helps
|
||||
- Lots of merges/rebases
|
||||
- Long-lived topic branches
|
||||
- Meaning
|
||||
- “reuse recorded resolution”
|
||||
- What it does
|
||||
- Records successful conflict resolutions (pre/post images)
|
||||
- Reapplies the same resolution automatically if conflict repeats
|
||||
- Enable (recommended global)
|
||||
- `git config --global rerere.enabled true`
|
||||
- Interacting with rerere
|
||||
- `git rerere` command
|
||||
- With no args:
|
||||
- attempts to match current conflicts to recorded resolutions
|
||||
- (automatic if enabled)
|
||||
- Subcommands mentioned
|
||||
- show what will be recorded
|
||||
- erase specific resolutions
|
||||
- clear entire cache
|
||||
- Reference
|
||||
- Covered in more detail later in “Rerere”
|
||||
|
||||
### Tagging Your Releases
|
||||
- Purpose
|
||||
- Mark releases so they can be recreated later
|
||||
- Signed tagging example
|
||||
- `git tag -s v1.5 -m 'my signed 1.5 tag'`
|
||||
- Requires PGP key + passphrase
|
||||
- Distributing public PGP key (for verifying signed tags)
|
||||
- Problem
|
||||
- Others need your public key to verify signatures
|
||||
- Git project’s approach
|
||||
- Store public key in repo as a blob
|
||||
- Add a tag pointing directly to that blob
|
||||
- Steps
|
||||
1. Find the key
|
||||
- `gpg --list-keys`
|
||||
2. Export key and write to Git object database (blob)
|
||||
- `gpg -a --export <KEYID> | git hash-object -w --stdin`
|
||||
- Output is the blob SHA-1
|
||||
3. Tag that blob
|
||||
- `git tag -a maintainer-pgp-pub <blob-sha>`
|
||||
4. Share tag(s)
|
||||
- `git push --tags`
|
||||
5. Users import key from repo
|
||||
- `git show maintainer-pgp-pub | gpg --import`
|
||||
6. Users verify signed tags using imported key
|
||||
- Extra note
|
||||
- Put verification instructions in tag message
|
||||
- `git show <tag>` displays them
|
||||
|
||||
### Generating a Build Number (human-readable commit identifier)
|
||||
- Problem
|
||||
- Git doesn’t provide monotonically increasing build numbers per commit
|
||||
- Solution
|
||||
- `git describe <commit>`
|
||||
- Output format
|
||||
- `<most recent tag>-<commits since tag>-g<abbrev sha>`
|
||||
- `g` indicates Git
|
||||
- Example
|
||||
- `git describe master` → `v1.6.2-rc1-20-g8c5b85c`
|
||||
- Behavior notes
|
||||
- If commit itself is tagged
|
||||
- Output is just the tag name
|
||||
- Default requires annotated tags (`-a` or `-s`)
|
||||
- Include lightweight tags with `--tags`
|
||||
- Usability note
|
||||
- Can use describe string with `git checkout` / `git show`
|
||||
- But relies on abbreviated SHA → may become invalid if abbreviation length changes
|
||||
- Example mentioned: Linux kernel increased abbrev length (8 → 10) for uniqueness
|
||||
|
||||
### Preparing a Release (archives for non-Git users)
|
||||
- Tool
|
||||
- `git archive`
|
||||
- Create tar.gz snapshot (example)
|
||||
- `git archive master --prefix='project/' | gzip > \`git describe master\`.tar.gz`
|
||||
- Create zip snapshot (example)
|
||||
- `git archive master --prefix='project/' --format=zip > \`git describe master\`.zip`
|
||||
- Resulting archive contents
|
||||
- Latest snapshot
|
||||
- Under a top-level directory prefix (e.g., `project/`)
|
||||
|
||||
### The Shortlog (release notes / mailing list summary)
|
||||
- Purpose
|
||||
- Quick changelog summary since last release (or last email)
|
||||
- Tool
|
||||
- `git shortlog`
|
||||
- Example
|
||||
- `git shortlog --no-merges master --not v1.0.1`
|
||||
- Output properties
|
||||
- Groups commits by author
|
||||
- Lists commit summaries
|
||||
- Excludes merge commits with `--no-merges`
|
||||
|
||||
## Chapter Summary (end)
|
||||
- You should now be comfortable
|
||||
- Contributing using multiple distributed workflows
|
||||
- Maintaining/integrating contributed work
|
||||
- Next chapter preview
|
||||
- GitHub (major Git hosting service)
|
||||
```
|
||||
798
mindmap/Git Branching.md
Normal file
798
mindmap/Git Branching.md
Normal file
@@ -0,0 +1,798 @@
|
||||
```markmap
|
||||
# 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 Git’s model works)
|
||||
- Why you must understand Git’s 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
|
||||
- Git’s 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 what’s 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
|
||||
- It’s identical to any other branch
|
||||
- It’s 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 you’re 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` doesn’t show all branches by default
|
||||
- Default behavior
|
||||
- `git log` shows the history reachable from the currently checked-out branch
|
||||
- To see another branch’s 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 can’t 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 it’s 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 it’s 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 isn’t 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` isn’t 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 (topic’s 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 can’t 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 origin’s master
|
||||
|
||||
#### Note: “origin” is not special
|
||||
- It’s 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 don’t 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 teamone’s 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` doesn’t 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 doesn’t 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 branch’s 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 you’ve 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
|
||||
```
|
||||
667
mindmap/Git Internals.md
Normal file
667
mindmap/Git Internals.md
Normal file
@@ -0,0 +1,667 @@
|
||||
```markmap
|
||||
# Git Internals (Chapter 8)
|
||||
## Why this chapter exists / positioning in the book
|
||||
- Can be read early (curiosity) or late (after learning porcelain)
|
||||
- Understanding internals helps explain *why* Git behaves as it does
|
||||
- Tradeoff: powerful insight vs. potential complexity for beginners
|
||||
- Core premise
|
||||
- Git = **content-addressable filesystem** + **VCS user interface** layered on top
|
||||
- Historical note
|
||||
- Early Git (mostly pre-1.5) UI emphasized filesystem concepts → felt complex
|
||||
- Modern Git UI refined; early “complex Git” stereotype lingers
|
||||
- Chapter flow
|
||||
- Content-addressable storage layer (objects) first
|
||||
- Then transports (protocols)
|
||||
- Then maintenance + recovery tasks
|
||||
|
||||
## Plumbing and Porcelain
|
||||
- Porcelain commands (high-level UX)
|
||||
- Examples: `checkout`, `branch`, `remote`, …
|
||||
- Most of the book focuses on these
|
||||
- Plumbing commands (low-level toolkit)
|
||||
- Designed to be chained (UNIX-style) or used from scripts/tools
|
||||
- Used here to expose internals and demonstrate implementation
|
||||
- Often not meant for humans to type frequently
|
||||
|
||||
## The `.git` directory (what Git stores/manipulates)
|
||||
- Created by `git init`
|
||||
- Backups/clones
|
||||
- Copying `.git/` elsewhere gives *nearly everything* needed
|
||||
- Fresh repo typical contents
|
||||
- `config`
|
||||
- Project-specific configuration
|
||||
- `description`
|
||||
- Used by GitWeb only
|
||||
- `HEAD`
|
||||
- Points to current branch (or object in detached HEAD)
|
||||
- `hooks/`
|
||||
- Client/server hook scripts (covered elsewhere)
|
||||
- `info/`
|
||||
- Global excludes (patterns you don’t want in `.gitignore`)
|
||||
- `objects/`
|
||||
- Object database (content store)
|
||||
- `refs/`
|
||||
- Pointers into commits (branches, tags, remotes, …)
|
||||
- `index` (not shown initially)
|
||||
- Staging area data (created when needed)
|
||||
- “Core” pieces emphasized here
|
||||
- `objects/` — all stored content
|
||||
- `refs/` — names/pointers into commit graph
|
||||
- `HEAD` — what’s checked out
|
||||
- `index` — staging area snapshot used to build trees/commits
|
||||
|
||||
## Git Objects (content-addressable store)
|
||||
### Concept: a key–value database
|
||||
- Insert arbitrary data → receive a unique key → retrieve later
|
||||
- Key is a checksum (SHA-1 in these examples) of:
|
||||
- a header + the content (details later)
|
||||
|
||||
### Creating a blob object with `git hash-object`
|
||||
- What it does
|
||||
- hashes content
|
||||
- optionally writes object into `.git/objects/`
|
||||
- returns the object id (40 hex chars = SHA-1)
|
||||
- Key options
|
||||
- `-w` — write object to object database
|
||||
- `--stdin` — read content from stdin (otherwise expects a filename)
|
||||
- Object storage layout on disk (loose objects)
|
||||
- Path: `.git/objects/<first2>/<remaining38>`
|
||||
- Directory name = first 2 chars of SHA-1
|
||||
- Filename = remaining 38 chars
|
||||
- Inspecting an object
|
||||
- `git cat-file -p <sha>` — pretty-print content (auto-detect type)
|
||||
- `git cat-file -t <sha>` — print object type
|
||||
- Blob objects
|
||||
- store *only content* (no filename)
|
||||
- example: versions of `test.txt` stored as different blobs
|
||||
|
||||
### Retrieving content
|
||||
- You can “recreate” a file from a blob by redirecting `cat-file` output
|
||||
- `git cat-file -p <sha> > test.txt`
|
||||
- Limitations of blobs alone
|
||||
- Must remember SHA-1 per version
|
||||
- No filenames or directory structure
|
||||
|
||||
## Tree Objects (filenames + directories + grouping)
|
||||
### What a tree is
|
||||
- Stores a directory listing-like structure
|
||||
- Entries contain
|
||||
- mode
|
||||
- type (`blob` or `tree`)
|
||||
- SHA-1 of target object
|
||||
- filename
|
||||
- Conceptual model (simplified UNIX-like)
|
||||
- tree ↔ directory entries
|
||||
- blob ↔ file contents
|
||||
|
||||
### Inspecting trees
|
||||
- `git cat-file -p master^{tree}`
|
||||
- shows top-level tree for the last commit on `master`
|
||||
- example entries include blobs (files) and trees (subdirectories)
|
||||
- Subtrees
|
||||
- a directory entry points to another tree object
|
||||
- Shell quoting pitfalls for `master^{tree}`
|
||||
- Windows CMD: `^` is escape → use `master^^{tree}`
|
||||
- PowerShell: quote braces → `git cat-file -p 'master^{tree}'`
|
||||
- ZSH: `^` globbing → quote expression → `git cat-file -p "master^{tree}"`
|
||||
|
||||
### Building trees manually (via the index)
|
||||
- Normal Git behavior
|
||||
- Creates trees from the staging area (index)
|
||||
- Plumbing commands used
|
||||
- `git update-index`
|
||||
- manipulate index entries
|
||||
- `--add` required if path not in index yet
|
||||
- `--cacheinfo` used when content isn’t in working tree (already in DB)
|
||||
- requires: `<mode> <sha> <path>`
|
||||
- valid file modes for blobs
|
||||
- `100644` normal file
|
||||
- `100755` executable
|
||||
- `120000` symlink
|
||||
- `git write-tree`
|
||||
- writes current index to a tree object
|
||||
- `git read-tree`
|
||||
- reads a tree into index
|
||||
- `--prefix=<dir>/` stages it as a subtree
|
||||
|
||||
### Example sequence (three trees)
|
||||
- Tree 1: `test.txt` v1
|
||||
- stage blob via `update-index --add --cacheinfo 100644 <sha_v1> test.txt`
|
||||
- `write-tree` → tree1 (contains `test.txt` → blob v1)
|
||||
- Tree 2: `test.txt` v2 + `new.txt`
|
||||
- update index to point `test.txt` to blob v2
|
||||
- add `new.txt`
|
||||
- `write-tree` → tree2 (two file entries)
|
||||
- Tree 3: include Tree 1 under `bak/`
|
||||
- `read-tree --prefix=bak <tree1>`
|
||||
- `write-tree` → tree3
|
||||
- tree3 contains
|
||||
- `bak/` → tree1
|
||||
- `new.txt` → blob
|
||||
- `test.txt` → blob v2
|
||||
|
||||
## Commit Objects (snapshots + history + metadata)
|
||||
### Why commits exist
|
||||
- Trees represent snapshots but:
|
||||
- SHA-1s are not memorable
|
||||
- need who/when/why metadata
|
||||
- need parent links to form history
|
||||
|
||||
### Creating commits with `git commit-tree`
|
||||
- Inputs
|
||||
- a tree SHA-1 (snapshot)
|
||||
- optional parent commit SHA-1(s)
|
||||
- message from stdin
|
||||
- Commit object fields
|
||||
- `tree <tree_sha>`
|
||||
- `parent <parent_sha>` (none for first commit)
|
||||
- `author ...` (from `user.name`, `user.email`, timestamp)
|
||||
- `committer ...` (same source)
|
||||
- blank line
|
||||
- commit message
|
||||
- Note about hashes in book
|
||||
- commit hashes differ due to timestamps/author data; use your own
|
||||
|
||||
### Example history
|
||||
- Commit 1 points to tree1 (no parent)
|
||||
- Commit 2 points to tree2, parent = commit1
|
||||
- Commit 3 points to tree3, parent = commit2
|
||||
- View history
|
||||
- `git log --stat <commit3_sha>`
|
||||
- Key takeaway
|
||||
- Porcelain `git add`/`git commit` do essentially:
|
||||
- write blobs for changed content
|
||||
- update index
|
||||
- write tree(s)
|
||||
- write commit referencing tree + parent
|
||||
|
||||
## Object Storage (how objects are actually stored)
|
||||
### Common storage recipe
|
||||
- Each object stored as:
|
||||
- header + content
|
||||
- Header format
|
||||
- `<type> <size>\0`
|
||||
- type: `blob`, `tree`, `commit`, `tag`
|
||||
- size: bytes in content
|
||||
- null byte terminator
|
||||
- Object id
|
||||
- SHA-1 of (header + content)
|
||||
- Compression
|
||||
- zlib-compressed before writing to disk
|
||||
|
||||
### Ruby walk-through (blob example)
|
||||
- Build content string
|
||||
- Build header (`"blob #{bytesize}\0"`)
|
||||
- Concatenate and hash with SHA-1
|
||||
- matches `git hash-object` (use `echo -n` to avoid newline)
|
||||
- Compress with zlib
|
||||
- Write to `.git/objects/<sha[0,2]>/<sha[2,38]>`
|
||||
- Validate with `git cat-file -p <sha>`
|
||||
|
||||
## Git References (refs) — naming commits/objects
|
||||
### What refs are
|
||||
- Human-friendly names → files containing SHA-1s
|
||||
- Stored under `.git/refs/`
|
||||
- `refs/heads/` — branches
|
||||
- `refs/tags/` — tags
|
||||
- (later) `refs/remotes/` — remote-tracking refs
|
||||
|
||||
### Creating/updating refs
|
||||
- Direct edit possible but discouraged
|
||||
- `echo <sha> > .git/refs/heads/master`
|
||||
- Safer: `git update-ref`
|
||||
- `git update-ref refs/heads/master <sha>`
|
||||
- Branch meaning
|
||||
- A branch is a ref that points to the tip commit of a line of work
|
||||
- Example: create branch at older commit
|
||||
- `git update-ref refs/heads/test <sha_of_commit2>`
|
||||
- `git log test` shows only commits reachable from that ref
|
||||
|
||||
## `HEAD` — what you have checked out
|
||||
### Symbolic reference (usual case)
|
||||
- `.git/HEAD` commonly contains
|
||||
- `ref: refs/heads/<branch>`
|
||||
- On checkout, Git updates `HEAD` to point at chosen branch ref
|
||||
- Commit parent determination
|
||||
- `git commit` uses commit pointed to by ref that `HEAD` references
|
||||
|
||||
### Detached HEAD (special case)
|
||||
- Sometimes `HEAD` contains a raw SHA-1
|
||||
- Happens when checking out
|
||||
- a tag
|
||||
- a commit
|
||||
- a remote-tracking branch
|
||||
|
||||
### Managing HEAD safely
|
||||
- `git symbolic-ref HEAD` — read where HEAD points
|
||||
- `git symbolic-ref HEAD refs/heads/test` — set symbolic HEAD
|
||||
- Constraint
|
||||
- cannot point outside `refs/` namespace
|
||||
|
||||
## Tags (lightweight vs annotated)
|
||||
### Tag object
|
||||
- Fourth object type: `tag`
|
||||
- Similar to commit object (tagger/date/message/pointer)
|
||||
- Usually points to a commit, but can tag any object (blob/tree/commit)
|
||||
|
||||
### Lightweight tags
|
||||
- Just a ref under `refs/tags/` pointing directly to an object
|
||||
- `git update-ref refs/tags/v1.0 <commit_sha>`
|
||||
- Never moves (unlike branch tips)
|
||||
|
||||
### Annotated tags
|
||||
- Create a tag object and a ref that points to it
|
||||
- `git tag -a v1.1 <commit_sha> -m '...'`
|
||||
- `.git/refs/tags/v1.1` contains SHA-1 of the *tag object*
|
||||
- Tag object content includes
|
||||
- `object <target_sha>`
|
||||
- `type <target_type>`
|
||||
- `tag <name>`
|
||||
- `tagger ...`
|
||||
- message
|
||||
- Examples mentioned
|
||||
- Tagging a maintainer’s GPG key stored as a blob
|
||||
- Kernel repo has an early tag pointing at an initial tree
|
||||
|
||||
## Remotes (remote-tracking references)
|
||||
### What they are
|
||||
- Refs under `refs/remotes/<remote>/...`
|
||||
- Store last known state of remote branches after communicating
|
||||
|
||||
### Example
|
||||
- After `git remote add origin ...` and `git push origin master`
|
||||
- `.git/refs/remotes/origin/master` stores last known remote SHA-1
|
||||
|
||||
### Key characteristics
|
||||
- Read-only from user standpoint
|
||||
- You can checkout one, but Git won’t set `HEAD` as symbolic ref to it
|
||||
- They act as bookmarks managed by Git for remote state
|
||||
|
||||
## Packfiles (space-efficient object storage)
|
||||
### Loose objects vs packed objects
|
||||
- Loose object: one zlib file per object
|
||||
- Packfile:
|
||||
- single `.pack` containing many objects
|
||||
- `.idx` index mapping SHA-1 → offsets
|
||||
|
||||
### When packing happens
|
||||
- Automatically when:
|
||||
- many loose objects
|
||||
- many packfiles
|
||||
- Manually via `git gc`
|
||||
- Often during push to a server
|
||||
|
||||
### Demonstration scenario (why deltas matter)
|
||||
- Add large file (`repo.rb`, ~22K) and commit
|
||||
- file stored as blob
|
||||
- Modify it slightly and commit again
|
||||
- creates a whole new blob
|
||||
- two near-identical large blobs now exist
|
||||
|
||||
### `git gc` effects
|
||||
- Creates pack + index
|
||||
- Removes many loose objects (reachable ones)
|
||||
- Leaves dangling/unreachable blobs loose (not in pack)
|
||||
|
||||
### Inspecting what’s packed
|
||||
- `git verify-pack -v <pack>.idx`
|
||||
- shows objects, sizes, offsets, delta bases
|
||||
- Delta storage behavior shown
|
||||
- newer version often stored in full
|
||||
- older version stored as delta against newer
|
||||
- optimized for fast access to most recent version
|
||||
- Repacking
|
||||
- can happen automatically
|
||||
- can be triggered any time via `git gc`
|
||||
|
||||
## Refspec (ref mapping rules for fetch/push)
|
||||
### Where it appears
|
||||
- `.git/config` remote section created by `git remote add`
|
||||
- `fetch = +refs/heads/*:refs/remotes/origin/*`
|
||||
|
||||
### Syntax
|
||||
- `(+)?<src>:<dst>`
|
||||
- optional `+` forces update even if not fast-forward
|
||||
- `<src>`: refs on remote
|
||||
- `<dst>`: local tracking refs
|
||||
|
||||
### Default fetch behavior
|
||||
- Fetch all remote branches (`refs/heads/*`)
|
||||
- Track locally as `refs/remotes/origin/*`
|
||||
- Equivalent references
|
||||
- `origin/master`
|
||||
- `remotes/origin/master`
|
||||
- `refs/remotes/origin/master`
|
||||
|
||||
### Custom fetch examples
|
||||
- Fetch only master always
|
||||
- `fetch = +refs/heads/master:refs/remotes/origin/master`
|
||||
- One-time fetch to a different local name
|
||||
- `git fetch origin master:refs/remotes/origin/mymaster`
|
||||
- Multiple refspecs
|
||||
- CLI or multiple `fetch =` lines in config
|
||||
- Fast-forward enforcement and overrides
|
||||
- non-FF rejected unless `+` used
|
||||
- Partial globs (Git ≥ 2.6.0)
|
||||
- `qa*` patterns for multiple branches
|
||||
- Namespaces/directories for teams
|
||||
- e.g., `refs/heads/qa/*` → `refs/remotes/origin/qa/*`
|
||||
|
||||
## Pushing refspecs & deleting remote refs
|
||||
### Pushing into a namespace
|
||||
- Push local `master` to remote `qa/master`
|
||||
- `git push origin master:refs/heads/qa/master`
|
||||
- Configure default push mapping
|
||||
- `push = refs/heads/master:refs/heads/qa/master`
|
||||
|
||||
### Deleting remote references
|
||||
- Old refspec deletion form
|
||||
- `git push origin :topic`
|
||||
- Newer explicit flag (Git ≥ 1.7.0)
|
||||
- `git push origin --delete topic`
|
||||
|
||||
### Note/limitation
|
||||
- Refspecs can’t fetch from one repo and push to another (as a single refspec trick)
|
||||
|
||||
## Transfer Protocols (moving data between repositories)
|
||||
### Two major approaches
|
||||
- Dumb protocol
|
||||
- simple, HTTP read-only, no Git server-side logic
|
||||
- inefficient, hard to secure/private; rarely used now
|
||||
- Smart protocol
|
||||
- Git-aware server process
|
||||
- negotiates what data is needed
|
||||
- supports pushes
|
||||
|
||||
### Dumb protocol (HTTP) — conceptual clone walkthrough
|
||||
- `git clone http://server/<repo>.git`
|
||||
- Fetch refs list (requires server-generated metadata)
|
||||
- `GET info/refs`
|
||||
- generated by `update-server-info` (often via post-receive hook)
|
||||
- Fetch HEAD to determine default branch
|
||||
- `GET HEAD` → `ref: refs/heads/master`
|
||||
- Walk objects starting from advertised commit SHA
|
||||
- `GET objects/<sha_prefix>/<sha_rest>` for loose objects
|
||||
- parse commit → learn `tree` + `parent`
|
||||
- If tree object not found as loose (404)
|
||||
- check alternates
|
||||
- `GET objects/info/http-alternates`
|
||||
- check available packfiles
|
||||
- `GET objects/info/packs`
|
||||
- `GET objects/pack/pack-....idx`
|
||||
- `GET objects/pack/pack-....pack`
|
||||
- Once required objects are fetched
|
||||
- checkout working tree for branch pointed to by downloaded `HEAD`
|
||||
|
||||
### Smart protocol — overview
|
||||
- Upload (push): `send-pack` (client) ↔ `receive-pack` (server)
|
||||
- Download (fetch/clone): `fetch-pack` (client) ↔ `upload-pack` (server)
|
||||
|
||||
#### Uploading data (push)
|
||||
- SSH transport
|
||||
- client runs remote command (conceptually)
|
||||
- `ssh ... "git-receive-pack '<repo>.git'"`
|
||||
- server advertises
|
||||
- current refs + SHA-1s
|
||||
- capabilities appended on the first line after a NUL separator
|
||||
- pkt-line framing
|
||||
- each chunk begins with 4 hex chars = length (including those 4 chars)
|
||||
- `0000` indicates end
|
||||
- client sends per-ref updates
|
||||
- `<old_sha> <new_sha> <refname>`
|
||||
- all zeros on left = create ref
|
||||
- all zeros on right = delete ref
|
||||
- client sends a packfile of objects server lacks
|
||||
- server replies success/failure
|
||||
- e.g., `unpack ok`
|
||||
- HTTP(S) transport
|
||||
- discovery
|
||||
- `GET .../info/refs?service=git-receive-pack`
|
||||
- push
|
||||
- `POST .../git-receive-pack` with update commands + packfile
|
||||
- note: HTTP may wrap in chunked transfer encoding
|
||||
|
||||
#### Downloading data (fetch/clone)
|
||||
- SSH transport
|
||||
- client runs remote command
|
||||
- `ssh ... "git-upload-pack '<repo>.git'"`
|
||||
- server advertises
|
||||
- refs and capabilities
|
||||
- `symref=HEAD:refs/heads/master` so client knows default branch
|
||||
- negotiation
|
||||
- client sends `want <sha>`
|
||||
- client sends `have <sha>`
|
||||
- client sends `done` to request packfile generation
|
||||
- server returns packfile (optionally multiplexing progress via side-band)
|
||||
- HTTP(S) transport
|
||||
- discovery
|
||||
- `GET .../info/refs?service=git-upload-pack`
|
||||
- negotiation/data request
|
||||
- `POST .../git-upload-pack` with want/have data
|
||||
- response includes packfile
|
||||
|
||||
### Protocols summary note
|
||||
- Only the high-level handshake is covered
|
||||
- Many capabilities/features (e.g., `multi_ack`, `side-band`) exist beyond this chapter’s scope
|
||||
|
||||
## Maintenance and Data Recovery
|
||||
### Maintenance (`gc`, packing, pruning)
|
||||
- Auto maintenance
|
||||
- Git may run `auto gc` occasionally
|
||||
- Usually no-op unless thresholds exceeded
|
||||
- What `git gc` does
|
||||
- packs loose objects into packfiles
|
||||
- consolidates packfiles
|
||||
- removes unreachable objects older than a few months
|
||||
- Trigger thresholds (approx)
|
||||
- ~7000 loose objects
|
||||
- >50 packfiles
|
||||
- Config knobs
|
||||
- `gc.auto`
|
||||
- `gc.autopacklimit`
|
||||
- Manual auto-gc run
|
||||
- `git gc --auto` (often does nothing)
|
||||
|
||||
### Packing refs into `packed-refs`
|
||||
- Before gc: refs stored as many small files
|
||||
- `.git/refs/heads/*`, `.git/refs/tags/*`, …
|
||||
- After gc: moved for efficiency into `.git/packed-refs`
|
||||
- format lines: `<sha> <refname>`
|
||||
- annotated tags include a “peeled” line starting with `^`
|
||||
- indicates the commit the tag ultimately points to
|
||||
- Updating a ref after packing
|
||||
- Git writes a new loose ref file under `.git/refs/...`
|
||||
- doesn’t edit `packed-refs`
|
||||
- Lookup behavior
|
||||
- Git checks loose refs first, then `packed-refs` fallback
|
||||
|
||||
### Data Recovery (finding lost commits)
|
||||
#### Common loss causes
|
||||
- force-delete a branch containing work you later want
|
||||
- `git reset --hard` moving a branch tip back, abandoning newer commits
|
||||
|
||||
#### Reflog-based recovery
|
||||
- Reflog records where `HEAD` pointed whenever it changes
|
||||
- commits, branch switches, resets
|
||||
- also updated by `git update-ref` (reason to prefer it over manual ref edits)
|
||||
- Useful commands
|
||||
- `git reflog` — concise HEAD history
|
||||
- `git log -g` — reflog shown as a log
|
||||
- Recovery technique
|
||||
- find lost commit SHA-1 in reflog
|
||||
- create a ref/branch pointing to it
|
||||
- `git branch recover-branch <sha>`
|
||||
|
||||
#### Recovery without reflog
|
||||
- If reflog is missing (e.g., `.git/logs/` removed)
|
||||
- Use integrity checker
|
||||
- `git fsck --full`
|
||||
- shows dangling/unreachable objects
|
||||
- `dangling commit <sha>`
|
||||
- Recover similarly
|
||||
- create a new branch ref pointing to the dangling commit
|
||||
|
||||
### Removing objects (purging big files from history)
|
||||
#### Problem statement
|
||||
- Git clones fetch full history
|
||||
- A huge file added once remains in history forever if reachable
|
||||
- even if deleted next commit
|
||||
- Especially painful in imported repos (SVN/Perforce)
|
||||
|
||||
#### Strong warning
|
||||
- Destructive: rewrites commit history (new commit IDs)
|
||||
- Must coordinate contributors (rebase onto rewritten history)
|
||||
|
||||
#### Workflow to locate and remove large objects
|
||||
- Confirm repo size after packing
|
||||
- `git gc`
|
||||
- `git count-objects -v` (check `size-pack`)
|
||||
- Find largest packed objects
|
||||
- `git verify-pack -v <pack>.idx | sort -k 3 -n | tail -3`
|
||||
- third field in output is object size
|
||||
- Map blob SHA to filename
|
||||
- `git rev-list --objects --all | grep <blob_sha_prefix>`
|
||||
- Identify commits that touched the path
|
||||
- `git log --oneline --branches -- <file>`
|
||||
- Rewrite history to remove the file from every tree
|
||||
- `git filter-branch --index-filter 'git rm --ignore-unmatch --cached <file>' -- <bad_commit>^..`
|
||||
- `--index-filter` is fast (no full checkout per commit)
|
||||
- `git rm --cached` removes from index/tree, not just working dir
|
||||
- Remove pointers to old history
|
||||
- `rm -Rf .git/refs/original`
|
||||
- `rm -Rf .git/logs/`
|
||||
- Repack/clean
|
||||
- `git gc`
|
||||
- optionally remove remaining loose objects
|
||||
- `git prune --expire now`
|
||||
|
||||
## Environment Variables (controlling Git behavior)
|
||||
> Chapter note: not exhaustive; highlights the most useful
|
||||
|
||||
### Global behavior
|
||||
- `GIT_EXEC_PATH`
|
||||
- where Git finds sub-programs (e.g., `git-commit`, `git-diff`)
|
||||
- inspect via `git --exec-path`
|
||||
- `HOME`
|
||||
- where Git finds global config
|
||||
- can be overridden for portable Git setups
|
||||
- `PREFIX`
|
||||
- system-wide config path: `$PREFIX/etc/gitconfig`
|
||||
- `GIT_CONFIG_NOSYSTEM`
|
||||
- disable system-wide config
|
||||
- Output paging/editing
|
||||
- `GIT_PAGER` (fallback `PAGER`)
|
||||
- `GIT_EDITOR` (fallback `EDITOR`)
|
||||
|
||||
### Repository locations
|
||||
- `GIT_DIR`
|
||||
- where `.git` directory is
|
||||
- if unset, Git walks up directory tree searching
|
||||
- `GIT_CEILING_DIRECTORIES`
|
||||
- stops upward search early (useful for slow filesystems)
|
||||
- `GIT_WORK_TREE`
|
||||
- working tree root for non-bare repos
|
||||
- `GIT_INDEX_FILE`
|
||||
- alternate index path
|
||||
- Object database
|
||||
- `GIT_OBJECT_DIRECTORY` — override `.git/objects`
|
||||
- `GIT_ALTERNATE_OBJECT_DIRECTORIES`
|
||||
- colon-separated additional object stores (share objects across repos)
|
||||
|
||||
### Pathspecs (path matching rules)
|
||||
- Pathspecs used in `.gitignore` and CLI patterns (e.g., `git add *.c`)
|
||||
- Wildcard behavior toggles
|
||||
- `GIT_GLOB_PATHSPECS=1` — wildcards enabled (default)
|
||||
- `GIT_NOGLOB_PATHSPECS=1` — wildcards literal (e.g., `*.c` matches file named `*.c`)
|
||||
- Per-argument overrides
|
||||
- prefix with `:(glob)` or `:(literal)`
|
||||
- `GIT_LITERAL_PATHSPECS`
|
||||
- disables wildcard matching and override prefixes
|
||||
- `GIT_ICASE_PATHSPECS`
|
||||
- case-insensitive pathspec matching
|
||||
|
||||
### Committing (author/committer identity)
|
||||
- Used primarily by `git-commit-tree` (then falls back to config)
|
||||
- Author fields
|
||||
- `GIT_AUTHOR_NAME`
|
||||
- `GIT_AUTHOR_EMAIL`
|
||||
- `GIT_AUTHOR_DATE`
|
||||
- Committer fields
|
||||
- `GIT_COMMITTER_NAME`
|
||||
- `GIT_COMMITTER_EMAIL`
|
||||
- `GIT_COMMITTER_DATE`
|
||||
- `EMAIL`
|
||||
- fallback email if `user.email` is unset
|
||||
|
||||
### Networking (HTTP behavior)
|
||||
- `GIT_CURL_VERBOSE`
|
||||
- emit libcurl debug messages
|
||||
- `GIT_SSL_NO_VERIFY`
|
||||
- skip SSL cert verification (self-signed/setup scenarios)
|
||||
- Low-speed abort settings
|
||||
- `GIT_HTTP_LOW_SPEED_LIMIT`
|
||||
- `GIT_HTTP_LOW_SPEED_TIME`
|
||||
- override `http.lowSpeedLimit` / `http.lowSpeedTime`
|
||||
- `GIT_HTTP_USER_AGENT`
|
||||
- override user-agent string
|
||||
|
||||
### Diffing and merging
|
||||
- `GIT_DIFF_OPTS`
|
||||
- only supports unified context count: `-u<n>` / `--unified=<n>`
|
||||
- `GIT_EXTERNAL_DIFF`
|
||||
- program invoked instead of built-in diff
|
||||
- Batch diff metadata for external diff tool
|
||||
- `GIT_DIFF_PATH_COUNTER`
|
||||
- `GIT_DIFF_PATH_TOTAL`
|
||||
- `GIT_MERGE_VERBOSITY` (recursive merge)
|
||||
- 0: only errors
|
||||
- 1: conflicts only
|
||||
- 2: + file changes (default)
|
||||
- 3: + skipped unchanged
|
||||
- 4: + all processed paths
|
||||
- 5+: deep debug
|
||||
|
||||
### Debugging/tracing (observability)
|
||||
- Output destinations
|
||||
- `"true"`, `"1"`, `"2"` → stderr
|
||||
- absolute path `/...` → write to file
|
||||
- `GIT_TRACE`
|
||||
- general tracing (alias expansion, sub-program exec)
|
||||
- `GIT_TRACE_PACK_ACCESS`
|
||||
- pack access tracing: packfile + offset
|
||||
- `GIT_TRACE_PACKET`
|
||||
- packet-level tracing for network operations
|
||||
- `GIT_TRACE_PERFORMANCE`
|
||||
- timing for each internal step/subcommand
|
||||
- `GIT_TRACE_SETUP`
|
||||
- shows discovered repo paths (`git_dir`, `worktree`, `cwd`, `prefix`, ...)
|
||||
|
||||
### Miscellaneous
|
||||
- `GIT_SSH`
|
||||
- program used instead of `ssh`
|
||||
- invoked as: `$GIT_SSH [user@]host [-p <port>] <command>`
|
||||
- wrapper script often needed for extra args; `~/.ssh/config` may be easier
|
||||
- `GIT_ASKPASS`
|
||||
- program to prompt for credentials (returns answer on stdout)
|
||||
- `GIT_NAMESPACE`
|
||||
- namespaced refs (like `--namespace`), often server-side
|
||||
- `GIT_FLUSH`
|
||||
- stdout buffering
|
||||
- `1` flush frequently; `0` buffer
|
||||
- `GIT_REFLOG_ACTION`
|
||||
- custom text written to reflog entries (action descriptor)
|
||||
|
||||
## Summary (what you should now understand)
|
||||
- Git internals = object database + refs + a UI on top
|
||||
- Main object types
|
||||
- blob (content), tree (directories), commit (history + metadata), tag (named pointer + metadata)
|
||||
- Refs and `HEAD` provide human-friendly naming and current-state tracking
|
||||
- Packfiles optimize storage through compression and deltas
|
||||
- Refspecs control fetch/push mappings and enable namespaced workflows
|
||||
- Transfer protocols
|
||||
- dumb: simple HTTP reads (rare)
|
||||
- smart: negotiated pack exchange (common) for fetch/push
|
||||
- Maintenance/recovery tools
|
||||
- `gc`, `packed-refs`, `reflog`, `fsck`, `filter-branch`, `prune`
|
||||
- Environment variables provide control, portability, and deep debugging capabilities
|
||||
```
|
||||
1122
mindmap/Git Tools.md
Normal file
1122
mindmap/Git Tools.md
Normal file
File diff suppressed because it is too large
Load Diff
1152
mindmap/Git and Other Systems.md
Normal file
1152
mindmap/Git and Other Systems.md
Normal file
File diff suppressed because it is too large
Load Diff
774
mindmap/Git on the Server.md
Normal file
774
mindmap/Git on the Server.md
Normal file
@@ -0,0 +1,774 @@
|
||||
```markmap
|
||||
# Git on the Server
|
||||
|
||||
## Purpose & context
|
||||
- Current baseline
|
||||
- You should now be able to handle most day-to-day Git tasks
|
||||
- Why a remote repository is needed for collaboration
|
||||
- Collaboration requires a remote Git repository
|
||||
- While you *can* push/pull directly between individuals’ repositories:
|
||||
- It’s discouraged (easy to confuse what others are working on)
|
||||
- Collaborators need access even if your computer is offline
|
||||
- Preferred approach
|
||||
- Set up an *intermediate* repository that everyone can access
|
||||
- Everyone pushes to / pulls from that common repository
|
||||
- Running a Git server (high-level)
|
||||
- Choose which protocols your server should support
|
||||
- Chapter structure
|
||||
- Protocol options + pros/cons
|
||||
- Typical setups and how to get them running
|
||||
- Hosted options (if you don’t want to self-host)
|
||||
- If you don’t want to run your own server
|
||||
- Skip to “Third Party Hosted Options”
|
||||
- Then continue to the next chapter about distributed workflows
|
||||
- What a “remote repository” usually is
|
||||
- Generally a **bare repository**
|
||||
- No working directory
|
||||
- Used only as a collaboration point
|
||||
- Bare repository in simplest terms
|
||||
- Contents of your project’s `.git` directory
|
||||
- And nothing else
|
||||
|
||||
## The Protocols (ways Git transfers data)
|
||||
- Four distinct protocols
|
||||
- **Local**
|
||||
- **HTTP** (Smart + Dumb)
|
||||
- **SSH**
|
||||
- **Git** (git://)
|
||||
- Selection depends on
|
||||
- Authentication requirements
|
||||
- Public vs private access needs
|
||||
- Firewall constraints
|
||||
- Ease of setup/maintenance
|
||||
- Performance expectations
|
||||
|
||||
### Local Protocol
|
||||
- Definition
|
||||
- Remote repository is just another directory on the **same host**
|
||||
- Typical use cases
|
||||
- Team shares a filesystem (e.g., **NFS mount**)
|
||||
- Less likely: everyone logs into the **same computer**
|
||||
- Not ideal: all repos on one machine → catastrophic loss risk higher
|
||||
- How to use (clone / add remote)
|
||||
- Clone using a filesystem path
|
||||
- `git clone /srv/git/project.git`
|
||||
- Clone explicitly using `file://`
|
||||
- `git clone file:///srv/git/project.git`
|
||||
- Add as a remote to an existing project
|
||||
- `git remote add local_proj /srv/git/project.git`
|
||||
- Then push/pull using `local_proj` like a network remote
|
||||
- Path vs `file://` behavior
|
||||
- Plain path (no `file://`)
|
||||
- Git tries to use **hardlinks** or directly **copies** needed files
|
||||
- With `file://`
|
||||
- Git uses network-style transfer processes
|
||||
- Generally **less efficient**
|
||||
- Why ever use `file://`?
|
||||
- To get a “clean” copy (leave out extraneous refs/objects)
|
||||
- Often after importing from another VCS (maintenance tasks noted in “Git Internals”)
|
||||
- Recommended in this chapter
|
||||
- Use the normal path (almost always faster)
|
||||
- Pros
|
||||
- Simple to set up
|
||||
- Uses existing filesystem permissions and access
|
||||
- Easy when you already have a shared filesystem
|
||||
- Put a bare repo where everyone can access it
|
||||
- Set read/write permissions like any shared directory
|
||||
- Convenient for quick sharing from someone’s working repo
|
||||
- e.g., `git pull /home/john/project` can be simpler than using a server
|
||||
- Cons
|
||||
- Shared filesystem access can be harder from multiple locations than network access
|
||||
- Example: pushing from home may require mounting a remote disk (slow/difficult)
|
||||
- Performance caveat on shared mounts
|
||||
- “Local” is fast only if data access is fast
|
||||
- NFS can be slower than SSH (even to same server) because SSH lets Git use local disks
|
||||
- Risk of accidental repository damage
|
||||
- Users have full shell access to the “remote” directory
|
||||
- Nothing prevents deleting/modifying internal Git files → corruption risk
|
||||
|
||||
### HTTP Protocols
|
||||
- Two modes
|
||||
- **Dumb HTTP**
|
||||
- Older (pre Git 1.6.6)
|
||||
- Simple, generally read-only
|
||||
- **Smart HTTP**
|
||||
- Introduced in Git 1.6.6
|
||||
- More capable: negotiates transfers intelligently (similar to SSH)
|
||||
- Has become very popular due to usability + efficiency
|
||||
|
||||
#### Smart HTTP
|
||||
- How it works (conceptually)
|
||||
- Similar to SSH/Git protocols but runs over standard **HTTPS ports**
|
||||
- Can use multiple HTTP authentication mechanisms
|
||||
- Often easier than SSH key setup
|
||||
- Supports username/password prompting
|
||||
- Usability benefits
|
||||
- Single URL can support
|
||||
- Anonymous reads (like `git://`)
|
||||
- Authenticated/encrypted pushes (like SSH)
|
||||
- Client behavior
|
||||
- If push requires auth → server prompts for username/password
|
||||
- Same for reads if configured
|
||||
- Example behavior (hosted services)
|
||||
- For GitHub-like services
|
||||
- The web URL (e.g., `https://github.com/...`) can also be used to clone/push (if authorized)
|
||||
|
||||
#### Dumb HTTP
|
||||
- When used
|
||||
- Git client falls back to Dumb HTTP if server doesn’t respond with a smart HTTP service
|
||||
- Expectations
|
||||
- Bare Git repository is served as static files by a web server
|
||||
- Setup (read access)
|
||||
- Place bare repo under HTTP document root + enable a `post-update` hook
|
||||
- Example sequence
|
||||
- `cd /var/www/htdocs/`
|
||||
- `git clone --bare /path/to/git_project gitproject.git`
|
||||
- `cd gitproject.git`
|
||||
- `mv hooks/post-update.sample hooks/post-update`
|
||||
- `chmod a+x hooks/post-update`
|
||||
- Why the hook matters
|
||||
- Default `post-update` runs `git update-server-info`
|
||||
- That makes HTTP fetching/cloning work properly
|
||||
- Typically triggered when someone pushes to the repo (often over SSH)
|
||||
- Cloning from Dumb HTTP
|
||||
- `git clone https://example.com/gitproject.git`
|
||||
- Server flexibility
|
||||
- Apache example uses `/var/www/htdocs`
|
||||
- Any static web server works if it can serve the bare repo files
|
||||
- “Git Internals” referenced for details of how the data is served
|
||||
- Common deployment choice
|
||||
- Usually you run either:
|
||||
- Smart HTTP read/write, **or**
|
||||
- Dumb HTTP read-only
|
||||
- Rare to run a mix
|
||||
|
||||
#### HTTP Pros (focus on Smart HTTP)
|
||||
- Single URL for all access types
|
||||
- Server prompts only when authentication is needed
|
||||
- Username/password authentication
|
||||
- Avoids SSH key generation/upload steps
|
||||
- Especially useful for less sophisticated users or environments where SSH is uncommon
|
||||
- Performance
|
||||
- Fast and efficient (comparable to SSH)
|
||||
- Security options
|
||||
- Serve read-only over HTTPS with encrypted transfer
|
||||
- Can require signed SSL client certificates (stronger client auth)
|
||||
- Firewall friendliness
|
||||
- HTTP/HTTPS ports are commonly allowed through corporate firewalls
|
||||
|
||||
#### HTTP Cons
|
||||
- Setup complexity
|
||||
- HTTPS Git can be trickier to set up than SSH on some servers
|
||||
- Otherwise, other protocols offer little advantage over Smart HTTP for serving Git content
|
||||
- Credential handling for authenticated pushes
|
||||
- Sometimes more complicated than SSH keys
|
||||
- Mitigations (credential caching tools)
|
||||
- Keychain access (macOS)
|
||||
- Credential Manager (Windows)
|
||||
- “Credential Storage” referenced for secure password caching setup
|
||||
|
||||
### SSH Protocol
|
||||
- Why it’s common for self-hosting
|
||||
- SSH is often already installed/configured on servers
|
||||
- If not, it’s generally easy to set up
|
||||
- Provides authenticated, encrypted transport
|
||||
- Clone URL forms
|
||||
- Explicit SSH URL
|
||||
- `git clone ssh://[user@]server/project.git`
|
||||
- scp-like shorthand
|
||||
- `git clone [user@]server:project.git`
|
||||
- Username handling
|
||||
- If not specified, Git assumes your current local username
|
||||
- Pros
|
||||
- Easy to set up (SSH daemon is common; admins often know it; OS tools exist)
|
||||
- Secure
|
||||
- Encrypted + authenticated transfer
|
||||
- Efficient
|
||||
- Data compacted before transfer (like HTTPS/Git/Local)
|
||||
- Cons
|
||||
- No anonymous access
|
||||
- Users need SSH access even for read-only cloning
|
||||
- Not ideal for open source “browse/clone without accounts”
|
||||
- If you want anonymous read-only + authenticated writes
|
||||
- Use SSH for push
|
||||
- Add another protocol for public fetch (e.g., HTTPS or git://)
|
||||
|
||||
### Git Protocol (git://)
|
||||
- What it is
|
||||
- A Git-provided daemon
|
||||
- Listens on port **9418**
|
||||
- Similar transfer behavior to SSH but:
|
||||
- **No authentication**
|
||||
- (No encryption/auth overhead)
|
||||
- Repository export control
|
||||
- Repo must contain a file named `git-daemon-export-ok`
|
||||
- Without it, the daemon won’t serve the repository
|
||||
- Push behavior
|
||||
- Typically no pushing
|
||||
- You *can* enable pushes, but it’s insecure:
|
||||
- Anyone who discovers the URL could push
|
||||
- Rare in practice
|
||||
- Pros
|
||||
- Often the fastest network transfer option
|
||||
- Useful for
|
||||
- high-traffic public projects, or
|
||||
- very large projects
|
||||
- when no user authentication is required for read access
|
||||
- Uses SSH-like transfer mechanism without encryption/auth overhead
|
||||
- Cons
|
||||
- No authentication (major downside)
|
||||
- Usually should not be the only access method
|
||||
- Common pairing
|
||||
- Developers: SSH or HTTPS (write access)
|
||||
- Everyone else: `git://` (read-only)
|
||||
- Harder to set up than others
|
||||
- Requires its own daemon
|
||||
- Needs system integration (xinetd, systemd, etc.)
|
||||
- Firewall constraints
|
||||
- Requires port **9418**
|
||||
- Often blocked behind corporate firewalls
|
||||
|
||||
## Getting Git on a Server (self-host setup)
|
||||
- Scope note (environment assumptions)
|
||||
- Commands shown are simplified for a Linux-based server
|
||||
- Possible on macOS or Windows servers too
|
||||
- Production deployments will differ:
|
||||
- security measures
|
||||
- OS tooling
|
||||
- Step 1: create/export a bare repository
|
||||
- Requirement
|
||||
- Export an existing repo into a **new bare repository** (no working dir)
|
||||
- Create a bare clone
|
||||
- `git clone --bare my_project my_project.git`
|
||||
- Naming convention
|
||||
- bare repos typically end with `.git`
|
||||
- Rough equivalent (not identical)
|
||||
- `cp -Rf my_project/.git my_project.git`
|
||||
- Result
|
||||
- Git data only (no checked-out snapshot)
|
||||
- Directory dedicated to the repository’s internal data
|
||||
- Step 2: put the bare repository on a server
|
||||
- Example environment
|
||||
- Server: `git.example.com`
|
||||
- Repos stored under: `/srv/git`
|
||||
- SSH access available
|
||||
- Copy bare repo to server
|
||||
- `scp -r my_project.git user@git.example.com:/srv/git`
|
||||
- Cloning for other users (with SSH read access to `/srv/git`)
|
||||
- `git clone user@git.example.com:/srv/git/my_project.git`
|
||||
- Push access rule of thumb
|
||||
- SSH + filesystem write permissions to `/srv/git/my_project.git` ⇒ push access
|
||||
- Group write permissions (recommended)
|
||||
- Run inside the repo:
|
||||
- `git init --bare --shared`
|
||||
- Effects
|
||||
- Adds group write permissions appropriately
|
||||
- Does not remove commits/refs/etc.
|
||||
- Minimal “useful Git server” takeaway
|
||||
- Add SSH-capable accounts for collaborators
|
||||
- Place a bare repository where they have read/write permissions
|
||||
- That’s enough for private collaboration
|
||||
- What later sections add (optional sophistication)
|
||||
- avoid per-user accounts
|
||||
- add public read access
|
||||
- add web UIs
|
||||
- etc.
|
||||
|
||||
## Small Setups (few developers / trying Git)
|
||||
- Common pain point
|
||||
- User management + permissions
|
||||
- Some repos read-only for some users
|
||||
- Read/write for others
|
||||
- SSH Access approach
|
||||
- If everyone already has SSH access to a server
|
||||
- Easiest initial setup (almost no additional work)
|
||||
- For more complex access control
|
||||
- Use OS filesystem permissions
|
||||
- If server has no accounts for all writers
|
||||
- Set up SSH access for those users
|
||||
- Assumption stated
|
||||
- If you have a server for this, you likely already have SSH installed and use it to access the server
|
||||
- Ways to grant SSH write access
|
||||
- Option 1: create an account for each person
|
||||
- Straightforward
|
||||
- Can be cumbersome (adduser/useradd + temporary passwords)
|
||||
- Option 2: single shared `git` account using `authorized_keys`
|
||||
- Create one `git` user on server
|
||||
- Collect users’ SSH public keys
|
||||
- Append to `~git/.ssh/authorized_keys`
|
||||
- Everyone connects as `git`
|
||||
- Commit data unaffected by SSH username used to connect
|
||||
- Option 3: centralized auth
|
||||
- LDAP or other central auth source
|
||||
- Any SSH authentication method works if user can get shell access
|
||||
|
||||
### Generating an SSH public key (client side)
|
||||
- Purpose
|
||||
- Many Git servers authenticate using SSH public keys
|
||||
- Each user must generate a key pair if they don’t have one
|
||||
- Check for an existing key
|
||||
- SSH keys usually stored in `~/.ssh`
|
||||
- Example checks
|
||||
- `cd ~/.ssh`
|
||||
- `ls`
|
||||
- Look for pairs like
|
||||
- `id_dsa` + `id_dsa.pub`
|
||||
- `id_rsa` + `id_rsa.pub`
|
||||
- Meaning
|
||||
- `.pub` file = public key
|
||||
- non-`.pub` file = private key
|
||||
- Generate a key if missing
|
||||
- Tool
|
||||
- `ssh-keygen` (Linux/macOS SSH package; also included with Git for Windows)
|
||||
- Recommended command shown
|
||||
- `ssh-keygen -o`
|
||||
- Prompts and outputs
|
||||
- Choose file path (default `~/.ssh/id_rsa`)
|
||||
- Enter passphrase twice (optional)
|
||||
- Key is saved as:
|
||||
- private key: `~/.ssh/id_rsa`
|
||||
- public key: `~/.ssh/id_rsa.pub`
|
||||
- Passphrase guidance
|
||||
- Can be empty (no password prompts when using the key)
|
||||
- If you do set a password
|
||||
- use `-o` (more resistant key format than default)
|
||||
- `ssh-agent` can help avoid typing passphrase repeatedly
|
||||
- Sharing the public key
|
||||
- User sends the contents of the `.pub` file to the admin
|
||||
- Example command
|
||||
- `cat ~/.ssh/id_rsa.pub`
|
||||
- Reference link mentioned
|
||||
- GitHub SSH key guide:
|
||||
- `https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent`
|
||||
|
||||
### Setting up the server (authorized_keys method)
|
||||
- Note about automation
|
||||
- Much can be automated with `ssh-copy-id` (instead of manual key install)
|
||||
- Create the `git` user and SSH directory
|
||||
- `sudo adduser git`
|
||||
- `su git`
|
||||
- `cd`
|
||||
- `mkdir .ssh && chmod 700 .ssh`
|
||||
- `touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys`
|
||||
- Add developer public keys
|
||||
- Assumption
|
||||
- Trusted public keys saved to temporary files (e.g., `/tmp/id_rsa.john.pub`)
|
||||
- Append to `authorized_keys`
|
||||
- `cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys`
|
||||
- `cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys`
|
||||
- `cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys`
|
||||
- Create a bare repository on the server
|
||||
- `cd /srv/git`
|
||||
- `mkdir project.git`
|
||||
- `cd project.git`
|
||||
- `git init --bare`
|
||||
- First push into the empty bare repository (example workflow)
|
||||
- Note
|
||||
- Someone must create a bare repo on the server for each new project
|
||||
- Example (on John’s computer)
|
||||
- `cd myproject`
|
||||
- `git init`
|
||||
- `git add .`
|
||||
- `git commit -m 'Initial commit'`
|
||||
- `git remote add origin git@gitserver:/srv/git/project.git`
|
||||
- `git push origin master`
|
||||
- Typical collaboration thereafter
|
||||
- Clone
|
||||
- `git clone git@gitserver:/srv/git/project.git`
|
||||
- Edit/commit/push example
|
||||
- `cd project`
|
||||
- `vim README`
|
||||
- `git commit -am 'Fix for README file'`
|
||||
- `git push origin master`
|
||||
- Restricting interactive shell access (optional)
|
||||
- Default situation
|
||||
- Users can log in and get a shell as `git`
|
||||
- Approach
|
||||
- Change shell in `/etc/passwd`
|
||||
- Use `git-shell` (limited shell bundled with Git)
|
||||
- Allows Git push/pull via SSH
|
||||
- Denies normal interactive shell access
|
||||
- Ensure `git-shell` is listed as a valid shell
|
||||
- Check `/etc/shells`
|
||||
- `cat /etc/shells`
|
||||
- Find `git-shell`
|
||||
- `which git-shell`
|
||||
- Add its path to `/etc/shells` if missing
|
||||
- `sudo -e /etc/shells`
|
||||
- Set login shell for user
|
||||
- `sudo chsh git -s $(which git-shell)`
|
||||
- Result of interactive SSH attempt
|
||||
- `ssh git@gitserver`
|
||||
- Message includes
|
||||
- `fatal: Interactive git shell is not enabled.`
|
||||
- hint about `~/git-shell-commands` existing and being executable/readable
|
||||
- Customize git-shell behavior
|
||||
- Create `~/git-shell-commands`
|
||||
- Possible customizations
|
||||
- restrict accepted Git commands
|
||||
- customize the SSH login rejection message
|
||||
- Reference
|
||||
- `git help shell`
|
||||
- Preventing SSH forwarding features (optional hardening)
|
||||
- Even with `git-shell`, users may still use SSH port forwarding
|
||||
- To prevent, prepend options to each key line in `authorized_keys`
|
||||
- `no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty`
|
||||
- Effect
|
||||
- Git network commands still work
|
||||
- Users can’t get a shell / can’t use those forwarding mechanisms
|
||||
|
||||
## Git Daemon (Git protocol: git://)
|
||||
- Purpose
|
||||
- Fast, unauthenticated access to Git data
|
||||
- Security reminder
|
||||
- Not authenticated
|
||||
- Anything served is public within its network
|
||||
- Recommended use
|
||||
- Outside firewall: only for publicly visible projects
|
||||
- Inside firewall: useful for many read-only consumers (e.g., CI/build servers) without managing many SSH keys
|
||||
- Run the daemon (base command)
|
||||
- `git daemon --reuseaddr --base-path=/srv/git/ /srv/git/`
|
||||
- Options
|
||||
- `--reuseaddr`
|
||||
- Restart without waiting for old connections to time out
|
||||
- `--base-path=/srv/git/`
|
||||
- Allows cloning without specifying full paths
|
||||
- Trailing `/srv/git/`
|
||||
- Where to look for repos to export
|
||||
- Firewall
|
||||
- Open port `9418`
|
||||
- Daemonizing & supervising the process
|
||||
- Depends on OS/init system
|
||||
- systemd example (common on modern Linux)
|
||||
- Create `/etc/systemd/system/git-daemon.service`:
|
||||
- `[Unit]`
|
||||
- `Description=Start Git Daemon`
|
||||
- `[Service]`
|
||||
- `ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/`
|
||||
- `Restart=always`
|
||||
- `RestartSec=500ms`
|
||||
- `StandardOutput=syslog`
|
||||
- `StandardError=syslog`
|
||||
- `SyslogIdentifier=git-daemon`
|
||||
- `User=git`
|
||||
- `Group=git`
|
||||
- `[Install]`
|
||||
- `WantedBy=multi-user.target`
|
||||
- Adjust as needed
|
||||
- Ensure the `git` user exists or change user/group
|
||||
- Verify Git binary path is `/usr/bin/git` (change if needed)
|
||||
- Service control
|
||||
- Enable on boot: `systemctl enable git-daemon`
|
||||
- Start: `systemctl start git-daemon`
|
||||
- Stop: `systemctl stop git-daemon`
|
||||
- Other alternatives mentioned
|
||||
- xinetd
|
||||
- sysvinit scripts
|
||||
- anything that daemonizes + monitors the process
|
||||
- Exporting repositories over git://
|
||||
- Per-repository opt-in via file:
|
||||
- `cd /path/to/project.git`
|
||||
- `touch git-daemon-export-ok`
|
||||
|
||||
## Smart HTTP (Git over HTTP with smart negotiation)
|
||||
- Goal
|
||||
- One protocol that can provide both:
|
||||
- authenticated push/pull
|
||||
- unauthenticated read-only access
|
||||
- Mechanism
|
||||
- Enable Git’s CGI script: `git-http-backend`
|
||||
- How it behaves
|
||||
- CGI reads URL path + headers from `git fetch` / `git push`
|
||||
- Determines if client supports Smart HTTP (true for clients since Git 1.6.6)
|
||||
- If client is smart
|
||||
- speaks Smart HTTP
|
||||
- Else
|
||||
- falls back to Dumb HTTP behavior (backward-compatible reads)
|
||||
- Basic Apache setup example
|
||||
- Install Apache + utilities
|
||||
- `sudo apt-get install apache2 apache2-utils`
|
||||
- Enable needed modules
|
||||
- `a2enmod cgi alias env`
|
||||
- Enables: `mod_cgi`, `mod_alias`, `mod_env`
|
||||
- Ensure Apache can read/write repositories
|
||||
- Set group of `/srv/git` to `www-data`:
|
||||
- `chgrp -R www-data /srv/git`
|
||||
- Rationale
|
||||
- Apache CGI runs as `www-data` by default
|
||||
- Apache configuration for `/git` path
|
||||
- Environment variables
|
||||
- `SetEnv GIT_PROJECT_ROOT /srv/git`
|
||||
- `SetEnv GIT_HTTP_EXPORT_ALL`
|
||||
- Route `/git/` to the backend
|
||||
- `ScriptAlias /git/ /usr/lib/git-core/git-http-backend/`
|
||||
- Note about `GIT_HTTP_EXPORT_ALL`
|
||||
- If omitted:
|
||||
- unauthenticated clients can only access repos containing `git-daemon-export-ok`
|
||||
- Authenticate writes (example Auth block)
|
||||
- `<Files "git-http-backend">`
|
||||
- `AuthType Basic`
|
||||
- `AuthName "Git Access"`
|
||||
- `AuthUserFile /srv/git/.htpasswd`
|
||||
- `Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)`
|
||||
- `Require valid-user`
|
||||
- Create `.htpasswd` (example user `schacon`)
|
||||
- `htpasswd -c /srv/git/.htpasswd schacon`
|
||||
- Notes
|
||||
- Many authentication methods exist in Apache; this is just a simple example
|
||||
- Strongly recommended to use SSL so data is encrypted
|
||||
- Key architectural point
|
||||
- `git-http-backend` handles Git protocol negotiation and data transfer
|
||||
- Authentication is handled by the *web server layer* (Apache or other CGI-capable server)
|
||||
- Web server flexibility
|
||||
- Works with nearly any CGI-capable web server
|
||||
- Reference (Apache auth docs)
|
||||
- `https://httpd.apache.org/docs/current/howto/auth.html`
|
||||
|
||||
## GitWeb (simple web UI)
|
||||
- Motivation
|
||||
- After enabling read/write and/or read-only access, you may want a basic web visualizer
|
||||
- What it is
|
||||
- Git includes a CGI script called **GitWeb**
|
||||
- (Figure 49 referenced as the GitWeb UI screenshot)
|
||||
- Quick temporary instance: `git instaweb`
|
||||
- Uses a lightweight web server (e.g., `lighttpd` or `webrick`)
|
||||
- Linux note
|
||||
- `lighttpd` often installed → `git instaweb` may “just work”
|
||||
- macOS note (example)
|
||||
- Ruby (and thus `webrick`) may be a convenient choice
|
||||
- Start with a specified handler
|
||||
- `git instaweb --httpd=webrick`
|
||||
- Starts HTTP server on port `1234` and opens a browser automatically
|
||||
- Example log lines shown include WEBrick and Ruby version info
|
||||
- Stop the server
|
||||
- `git instaweb --httpd=webrick --stop`
|
||||
- Running GitWeb continuously (server deployment)
|
||||
- Option 1: install a distro package
|
||||
- Some distros offer a `gitweb` package (via `apt` or `dnf`)
|
||||
- Option 2: install manually (quick walkthrough)
|
||||
- Clone Git source (GitWeb included)
|
||||
- `git clone git://git.kernel.org/pub/scm/git/git.git`
|
||||
- Build GitWeb with project root configured
|
||||
- `cd git/`
|
||||
- `make GITWEB_PROJECTROOT="/srv/git" prefix=/usr gitweb`
|
||||
- Generates `gitweb.cgi` + static assets (e.g., `static/gitweb.js`)
|
||||
- Deploy to web directory
|
||||
- `sudo cp -Rf gitweb /var/www/`
|
||||
- Apache VirtualHost example (CGI enablement)
|
||||
- `<VirtualHost *:80>`
|
||||
- `ServerName gitserver`
|
||||
- `DocumentRoot /var/www/gitweb`
|
||||
- `<Directory /var/www/gitweb>`
|
||||
- `Options +ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch`
|
||||
- `AllowOverride All`
|
||||
- `order allow,deny`
|
||||
- `Allow from all`
|
||||
- `AddHandler cgi-script cgi`
|
||||
- `DirectoryIndex gitweb.cgi`
|
||||
- `</Directory>`
|
||||
- `</VirtualHost>`
|
||||
- Result
|
||||
- Visit `http://gitserver/` to browse repositories
|
||||
- Server flexibility
|
||||
- Can be served by any CGI-/Perl-capable web server
|
||||
|
||||
## GitLab (modern, fully featured Git server example)
|
||||
- Why mentioned
|
||||
- GitWeb is simplistic
|
||||
- GitLab is a popular open source alternative:
|
||||
- more capable
|
||||
- more complex to install/maintain
|
||||
- database-backed web application
|
||||
|
||||
### Installation
|
||||
- Recommended approach
|
||||
- Install via official **Omnibus GitLab** package
|
||||
- Other installation options listed
|
||||
- GitLab Helm chart (Kubernetes)
|
||||
- Dockerized GitLab packages (Docker)
|
||||
- Install from source
|
||||
- Cloud providers / platforms
|
||||
- AWS
|
||||
- Google Cloud Platform
|
||||
- Azure
|
||||
- OpenShift
|
||||
- Digital Ocean
|
||||
- Reference mentioned
|
||||
- GitLab Community Edition (CE) README
|
||||
|
||||
### Administration (web UI)
|
||||
- Access method
|
||||
- Browser to GitLab hostname/IP
|
||||
- Log in as admin
|
||||
- Default credentials (must change immediately)
|
||||
- Username: `admin@local.host`
|
||||
- Password: `5iveL!fe`
|
||||
- Entering admin interface
|
||||
- Click “Admin area” icon (top right menu)
|
||||
- (Figure 50 referenced)
|
||||
|
||||
### Users
|
||||
- Requirement
|
||||
- Everyone must have a GitLab user account
|
||||
- Account contents
|
||||
- Personal info tied to login data
|
||||
- Namespaces
|
||||
- Each user has a namespace grouping their projects
|
||||
- Example
|
||||
- user `jane`, project `project`
|
||||
- URL: `http://server/jane/project`
|
||||
- Removing accounts (two modes)
|
||||
- Blocking
|
||||
- Prevents login
|
||||
- Preserves namespace data
|
||||
- Commits signed with that email still link to profile
|
||||
- Destroying
|
||||
- Removes user from database and filesystem
|
||||
- Deletes projects/data in their namespace
|
||||
- Removes groups they own
|
||||
- More permanent/destructive; rarely needed
|
||||
- (Figure 51 referenced as user admin screen)
|
||||
|
||||
### Groups
|
||||
- Definition
|
||||
- Collection of projects + access control data for those projects
|
||||
- Group namespace
|
||||
- Similar to user namespaces
|
||||
- Example
|
||||
- group `training`, project `materials`
|
||||
- URL: `http://server/training/materials`
|
||||
- Permissions
|
||||
- Group users have permission levels for group and projects
|
||||
- Range example
|
||||
- Guest: issues/chat only
|
||||
- Owner: full control (group, members, projects)
|
||||
- Too numerous to list (GitLab links from admin screen)
|
||||
- (Figure 52 referenced as group admin screen)
|
||||
|
||||
### Projects
|
||||
- Meaning
|
||||
- Roughly corresponds to a single Git repository
|
||||
- Namespace association
|
||||
- Every project belongs to exactly one namespace:
|
||||
- user, or
|
||||
- group
|
||||
- Access control behavior
|
||||
- User-owned project
|
||||
- owner directly controls access
|
||||
- Group-owned project
|
||||
- group member permissions apply
|
||||
- Visibility levels (read access control)
|
||||
- Private
|
||||
- owner explicitly grants access to specific users
|
||||
- Internal
|
||||
- visible to any logged-in user
|
||||
- Public
|
||||
- visible to anyone
|
||||
- Applies to both
|
||||
- `git fetch` access
|
||||
- web UI access
|
||||
|
||||
### Hooks
|
||||
- Hook support
|
||||
- Project-level hooks
|
||||
- System-level hooks
|
||||
- Behavior
|
||||
- GitLab sends HTTP POST with descriptive JSON when events occur
|
||||
- Purpose
|
||||
- Integrate with automation and tooling
|
||||
- CI servers
|
||||
- chat rooms
|
||||
- deployment tools
|
||||
|
||||
### Basic Usage
|
||||
- Create a project
|
||||
- Click “+” icon on toolbar
|
||||
- Provide
|
||||
- project name
|
||||
- namespace
|
||||
- visibility level
|
||||
- Most settings can be changed later
|
||||
- Click “Create Project”
|
||||
- Connect project to local Git workflow
|
||||
- Access methods
|
||||
- HTTPS
|
||||
- SSH
|
||||
- URLs shown at top of project home page
|
||||
- Add remote for an existing local repository (example remote name `gitlab`)
|
||||
- `git remote add gitlab https://server/namespace/project.git`
|
||||
- Or clone if you don’t have a local copy
|
||||
- `git clone https://server/namespace/project.git`
|
||||
- Web UI repository views
|
||||
- Project home: recent activity
|
||||
- Navigation links: files view + commit log
|
||||
|
||||
### Working Together
|
||||
- Model 1: direct push access
|
||||
- Add users via project settings → “Members”
|
||||
- Assign access level
|
||||
- “Developer” or above can push commits/branches directly
|
||||
- Model 2: merge requests (more decoupled)
|
||||
- Users with push access
|
||||
- create branch
|
||||
- push commits
|
||||
- open merge request back into `master` (or another branch)
|
||||
- Users without push permission
|
||||
- fork project
|
||||
- push to fork
|
||||
- open merge request from fork into main project
|
||||
- Benefits
|
||||
- owner controls what/when changes merge
|
||||
- supports contributions from untrusted users
|
||||
- Discussion units
|
||||
- Merge requests + issues are main long-lived discussion objects
|
||||
- Merge requests support
|
||||
- line-by-line discussion (lightweight code review)
|
||||
- overall discussion thread
|
||||
- Both can be
|
||||
- assigned to users
|
||||
- organized into milestones
|
||||
- Broader feature note (beyond Git)
|
||||
- Also provides features like
|
||||
- project wikis
|
||||
- system maintenance tools
|
||||
- Operational benefit
|
||||
- after initial setup, little need for config-file edits or SSHing to server
|
||||
- most admin/usage via browser UI
|
||||
|
||||
## Third Party Hosted Options
|
||||
- When to choose
|
||||
- You don’t want to set up/maintain your own Git server
|
||||
- Advantages
|
||||
- quick setup
|
||||
- easy project creation
|
||||
- no maintenance/monitoring
|
||||
- even if you self-host internally:
|
||||
- public hosting for open source can be easier for the community to find/contribute
|
||||
- Choosing a host
|
||||
- Many options with different pros/cons
|
||||
- Up-to-date list referenced
|
||||
- GitHosting page on the main Git wiki:
|
||||
- `https://git.wiki.kernel.org/index.php/GitHosting`
|
||||
- GitHub note
|
||||
- GitHub covered in detail in the “GitHub” chapter
|
||||
- It’s the largest Git host, and you may need to interact with GitHub-hosted projects
|
||||
- Many other hosts exist if you prefer alternatives
|
||||
|
||||
## Summary (decision guidance)
|
||||
- You have multiple options for running a remote Git repository to collaborate/share work
|
||||
- Self-hosting
|
||||
- Pros
|
||||
- high control
|
||||
- can run within your firewall
|
||||
- Cons
|
||||
- time/effort to set up
|
||||
- ongoing maintenance burden
|
||||
- Hosted services
|
||||
- Pros
|
||||
- easy to set up and maintain
|
||||
- Cons
|
||||
- your code resides on someone else’s servers
|
||||
- some organizations prohibit this
|
||||
- Practical takeaway
|
||||
- Choose the solution (or combination) that fits your organization’s needs
|
||||
```
|
||||
954
mindmap/GitHub.md
Normal file
954
mindmap/GitHub.md
Normal file
@@ -0,0 +1,954 @@
|
||||
# GitHub
|
||||
|
||||
## What GitHub is (context)
|
||||
- Largest host for Git repositories
|
||||
- Central collaboration hub for millions of developers and projects
|
||||
- Commonly used for
|
||||
- Git hosting
|
||||
- Issue tracking
|
||||
- Code review
|
||||
- Other collaboration features
|
||||
- Not part of the Git open source project itself
|
||||
- But very likely you’ll need to interact with it professionally
|
||||
|
||||
## Chapter scope (what you’ll learn)
|
||||
- Use GitHub effectively:
|
||||
- Sign up for and manage an account
|
||||
- Create and use Git repositories on GitHub
|
||||
- Contribute to other projects (and accept contributions to yours)
|
||||
- Use GitHub’s programmatic interface (API)
|
||||
- Tips and small features that make workflows easier
|
||||
- If you don’t plan to use GitHub for hosting/collaboration
|
||||
- You can skip ahead to **Git Tools**
|
||||
|
||||
## Note: Interfaces change (UI disclaimer)
|
||||
- GitHub UI and screenshots change over time
|
||||
- The *concepts* should remain applicable
|
||||
- Online versions of the book may have newer screenshots
|
||||
|
||||
---
|
||||
|
||||
## Account Setup and Configuration
|
||||
|
||||
### Create a free account (sign-up)
|
||||
- Go to: `https://github.com`
|
||||
- Fill in:
|
||||
- Username (must be unique)
|
||||
- Email address
|
||||
- Password
|
||||
- Click **“Sign up for GitHub”** (green button)
|
||||
- You may see an upgrades/pricing page next
|
||||
- Safe to ignore initially
|
||||
- Verify your email address (GitHub sends a verification email)
|
||||
- Important for later steps/workflows
|
||||
- Account capabilities & plans
|
||||
- Free accounts provide almost all functionality
|
||||
- Paid plans: advanced tools/features + increased limits
|
||||
- More info: `https://github.com/pricing`
|
||||
- Navigation
|
||||
- Clicking the **Octocat** logo (top-left) takes you to your dashboard
|
||||
|
||||
### SSH Access (HTTPS vs SSH)
|
||||
- HTTPS remotes
|
||||
- You can connect to Git repos over HTTPS using username/password
|
||||
- Cloning public projects doesn’t require an account
|
||||
- Account becomes important for:
|
||||
- forking projects
|
||||
- pushing to your fork
|
||||
- SSH remotes
|
||||
- Requires configuring an SSH public key
|
||||
- If you don’t have a key yet: generate one (referenced elsewhere in the book)
|
||||
|
||||
#### Add an SSH key to your GitHub account
|
||||
- Open **Account settings** (link at the top-right)
|
||||
- Select **“SSH keys”** in the left sidebar
|
||||
- Click **“Add an SSH key”**
|
||||
- Provide:
|
||||
- A recognizable **title/name** for the key (helps later revocation)
|
||||
- Example naming patterns: “My Laptop”, “Work Account”
|
||||
- Paste the contents of your public key file (e.g. `~/.ssh/id_rsa.pub`)
|
||||
- Click **“Add key”**
|
||||
|
||||
### Your Avatar (profile picture)
|
||||
- Optional customization
|
||||
- Steps
|
||||
- Go to **Profile** tab (in account settings)
|
||||
- Click **“Upload new picture”**
|
||||
- Select an image
|
||||
- Crop it
|
||||
- Effect
|
||||
- Your avatar appears next to your username everywhere you interact on GitHub
|
||||
- Gravatar integration
|
||||
- If you already have a Gravatar avatar, GitHub may use it by default
|
||||
|
||||
### Your Email Addresses (commit ↔ account mapping)
|
||||
- How GitHub associates commits with your account
|
||||
- By **email address** in commits
|
||||
- If you commit with multiple emails
|
||||
- Add all of them in the **Emails** section in settings
|
||||
- Email address states (as shown in the example)
|
||||
- Verified + Primary
|
||||
- Receives notifications/receipts
|
||||
- Verified (non-primary)
|
||||
- Can be promoted to primary
|
||||
- Unverified
|
||||
- Cannot be primary
|
||||
- Once added
|
||||
- Any commit on GitHub using one of these emails will link to your user
|
||||
|
||||
### Two-Factor Authentication (2FA)
|
||||
- Purpose
|
||||
- Extra security
|
||||
- Reduces impact if password is stolen/compromised
|
||||
- Location
|
||||
- **Security** tab in account settings
|
||||
- Setup
|
||||
- Click **“Set up two-factor authentication”**
|
||||
- Choose a second factor method:
|
||||
- Phone app generating a **time-based one-time password (TOTP)**
|
||||
- SMS code sent each login
|
||||
- After enabling
|
||||
- GitHub requires password + code on login
|
||||
|
||||
---
|
||||
|
||||
## Contributing to a Project
|
||||
|
||||
### Forking Projects (contribute without push access)
|
||||
- Problem: you want to contribute but you can’t push to the upstream repo
|
||||
- Solution: **Fork**
|
||||
- GitHub creates a full copy of the repo under your namespace
|
||||
- You can push to your fork
|
||||
- Terminology note (historical vs GitHub meaning)
|
||||
- Historically “fork” could imply a split/competing direction
|
||||
- On GitHub: “fork” generally means “same project under your account to propose changes”
|
||||
- Why this works well
|
||||
- Upstream maintainers don’t need to add you as a collaborator
|
||||
- You propose changes via a **Pull Request (PR)**
|
||||
- PR becomes a discussion + review thread
|
||||
- Maintainer merges when satisfied
|
||||
- How to fork
|
||||
- Visit the project page
|
||||
- Click **“Fork”** (top-right)
|
||||
- GitHub redirects you to your forked repo page
|
||||
|
||||
### The GitHub Flow (PR-centered collaboration model)
|
||||
- Works for:
|
||||
- Small teams sharing a repo
|
||||
- Large distributed groups and many forks
|
||||
- Built around **Topic Branches** (as covered in Git Branching)
|
||||
- Typical sequence
|
||||
1. Fork the project
|
||||
2. Create a topic branch from `master`
|
||||
3. Commit improvements
|
||||
4. Push the topic branch to your GitHub fork
|
||||
5. Open a Pull Request
|
||||
6. Discuss; optionally keep committing to the same branch
|
||||
7. Owner merges or closes the PR
|
||||
8. Sync upstream changes back into your fork
|
||||
- Related concept
|
||||
- Similar to the **Integration Manager** workflow, but discussion/review is web-based rather than email-based
|
||||
- Alternative tooling tip
|
||||
- GitHub CLI can do most web-interface tasks
|
||||
- Runs on Windows, macOS, Linux (installation/manual referenced in chapter)
|
||||
|
||||
---
|
||||
|
||||
## Creating a Pull Request (walkthrough example)
|
||||
|
||||
### Scenario
|
||||
- Tony wants Arduino code and finds: `https://github.com/schacon/blink`
|
||||
- Problem
|
||||
- Blink delay is too fast
|
||||
- Goal
|
||||
- Change delay from 1 second to 3 seconds
|
||||
- Submit improvement via PR
|
||||
|
||||
### Local workflow steps (fork → branch → change → push)
|
||||
- Fork upstream repo (`schacon/blink`) to your namespace
|
||||
- Example fork URL: `https://github.com/tonychacon/blink`
|
||||
- Clone your fork locally
|
||||
- `git clone https://github.com/tonychacon/blink`
|
||||
- Create a descriptive topic branch
|
||||
- `git checkout -b slow-blink`
|
||||
- Make the code change (example uses `sed`)
|
||||
- macOS:
|
||||
- `sed -i '' 's/1000/3000/' blink.ino`
|
||||
- Linux:
|
||||
- `sed -i 's/1000/3000/' blink.ino`
|
||||
- Review the change
|
||||
- `git diff --word-diff`
|
||||
- Commit
|
||||
- `git commit -a -m 'Change delay to 3 seconds'`
|
||||
- Push the topic branch to your fork
|
||||
- `git push origin slow-blink`
|
||||
- If using HTTPS remote, you may be prompted for GitHub username/password
|
||||
|
||||
#### Meaning of the numbered actions (as presented in the example)
|
||||
- ① clone fork locally
|
||||
- ② create topic branch
|
||||
- ③ edit code
|
||||
- ④ verify diff
|
||||
- ⑤ commit to topic branch
|
||||
- ⑥ push topic branch to GitHub fork
|
||||
|
||||
### Open the Pull Request on GitHub
|
||||
- GitHub notices the new branch on your fork and suggests creating a PR (green button)
|
||||
- Alternative path
|
||||
- Use the Branches page:
|
||||
- `https://github.com/<user>/<project>/branches`
|
||||
- PR creation page typically shows
|
||||
- Title + description fields (recommended to write clearly)
|
||||
- Commits “ahead” of `master`
|
||||
- Unified diff of all changes that would be merged
|
||||
- After clicking **Create pull request**
|
||||
- The upstream maintainer is notified
|
||||
- They can review and respond
|
||||
|
||||
### PRs can be opened early (not only “final” work)
|
||||
- Common in internal/team settings
|
||||
- Because you can keep pushing commits to the PR branch after opening the PR
|
||||
- PR becomes a shared context for iterative development and review
|
||||
|
||||
---
|
||||
|
||||
## Iterating on a Pull Request (review + updates)
|
||||
|
||||
### How review happens on GitHub
|
||||
- Maintainer can:
|
||||
- merge
|
||||
- reject/close
|
||||
- comment (line-level or general)
|
||||
- Line-level comments
|
||||
- Maintainer comments by clicking specific lines in the diff
|
||||
- General comments
|
||||
- In the PR discussion thread
|
||||
- Line comments are also pulled into the overall conversation
|
||||
|
||||
### Notifications during PR discussion
|
||||
- PR author and watchers get notified on comments/activity
|
||||
- If email notifications are enabled
|
||||
- Comments may arrive as emails
|
||||
|
||||
### Updating an existing PR
|
||||
- GitHub workflow approach
|
||||
- Don’t “re-roll” patches like mailing lists
|
||||
- Instead:
|
||||
- add commits to the same topic branch
|
||||
- push again
|
||||
- PR updates automatically
|
||||
- Old line comments may collapse when code changes (they become “outdated”)
|
||||
- Note about notifications
|
||||
- Adding commits to an open PR does **not** necessarily trigger a notification
|
||||
- Contributors often add a comment saying they pushed updates
|
||||
|
||||
### “Files Changed” tab meaning (unified diff)
|
||||
- Shows total aggregate difference introduced by merging the PR branch
|
||||
- Equivalent to:
|
||||
- `git diff master...<branch>` (three-dot diff) for the PR base
|
||||
|
||||
### Merging the PR (server-side vs local)
|
||||
- GitHub checks if PR merges cleanly
|
||||
- If you have write access and merge is trivial
|
||||
- GitHub shows a merge button
|
||||
- Clicking it performs a **non-fast-forward merge**
|
||||
- Creates a merge commit even if fast-forward was possible
|
||||
- Alternative
|
||||
- Pull the PR branch and merge locally
|
||||
- If you push the merge to GitHub, the PR closes automatically
|
||||
|
||||
### Not only forks (internal PRs)
|
||||
- You can open PRs between branches in the same repository
|
||||
- Useful when:
|
||||
- multiple collaborators with write access
|
||||
- you want structured review/discussion without forking
|
||||
|
||||
---
|
||||
|
||||
## Advanced Pull Requests
|
||||
|
||||
### Pull Requests as iterative conversations (vs “perfect patch queues”)
|
||||
- Many GitHub projects view PRs as:
|
||||
- a branch where the change evolves through discussion
|
||||
- culminating in the final unified diff applied via merge
|
||||
- Contrast with mailing-list patch series
|
||||
- Mailing lists often expect a clean sequence of patches
|
||||
- GitHub supports earlier engagement and incremental improvements
|
||||
- Practical implication
|
||||
- Contributors frequently add commits instead of rebasing/resubmitting PRs
|
||||
- Merge commits created by GitHub can reference the PR for traceability
|
||||
|
||||
---
|
||||
|
||||
## Keeping up with upstream (fixing out-of-date/conflicting PR branches)
|
||||
|
||||
### When you need this
|
||||
- PR becomes out of date
|
||||
- GitHub reports: PR “does not merge cleanly”
|
||||
- Goal
|
||||
- Make PR mergeable (green) so maintainers don’t have extra work
|
||||
|
||||
### Two main strategies
|
||||
- Rebase onto upstream target branch (usually upstream `master`)
|
||||
- Merge upstream target branch into your topic branch
|
||||
- Common preference on GitHub:
|
||||
- preserves history/context
|
||||
- simpler/less error-prone than rebasing for many teams
|
||||
|
||||
### Merge upstream into your topic branch (step-by-step)
|
||||
- Add upstream repo as remote
|
||||
- `git remote add upstream https://github.com/schacon/blink`
|
||||
- Fetch upstream
|
||||
- `git fetch upstream`
|
||||
- Merge upstream main branch into your topic branch
|
||||
- `git merge upstream/master`
|
||||
- Resolve conflicts (if any)
|
||||
- edit conflicting files (example: `blink.ino`)
|
||||
- `git add <file>`
|
||||
- `git commit` (records the merge)
|
||||
- Push updated topic branch back to your fork/branch
|
||||
- `git push origin slow-blink`
|
||||
- Result
|
||||
- GitHub updates PR and re-checks mergeability automatically
|
||||
|
||||
### Long-running work
|
||||
- You can repeat “merge from upstream” regularly
|
||||
- Conflicts are limited to changes since your last merge
|
||||
|
||||
### Rebasing caution (especially once PR is open)
|
||||
- If you rebase and force-push over the branch used by an open PR
|
||||
- it can disrupt collaborators who fetched the branch
|
||||
- it can trigger the issues described in “Perils of Rebasing” (referenced)
|
||||
- Recommended alternative if you want a clean rebased history
|
||||
- push rebased commits to a **new** branch
|
||||
- open a **new** PR referencing the old PR
|
||||
- close the original PR
|
||||
|
||||
---
|
||||
|
||||
## References (cross-linking Issues, PRs, commits)
|
||||
|
||||
### Issue/PR number references (within a repository)
|
||||
- Every Issue and PR has a unique number within a project
|
||||
- Quick reference syntax
|
||||
- `#<num>` in comments/descriptions links automatically
|
||||
|
||||
### Cross-repo / cross-fork references
|
||||
- In a fork of the repo you’re in:
|
||||
- `username#<num>`
|
||||
- In a different repository:
|
||||
- `username/repo#<num>`
|
||||
- Full GitHub URLs can also be pasted
|
||||
- GitHub renders them as shortened references
|
||||
|
||||
### Trackbacks
|
||||
- Mentioning a PR in another PR can create timeline cross-links
|
||||
- Helps connect superseding PRs when one is closed
|
||||
|
||||
### Commit references
|
||||
- You can reference a commit by SHA-1
|
||||
- Requirement in chapter
|
||||
- must use the **full 40-character SHA-1** for auto-linking
|
||||
- Same cross-repo patterns apply (similar to issue references)
|
||||
|
||||
---
|
||||
|
||||
## GitHub Flavored Markdown (GFM)
|
||||
|
||||
### Where it works
|
||||
- PR descriptions
|
||||
- Issue descriptions
|
||||
- Comments
|
||||
- Code comments
|
||||
- Many GitHub text boxes
|
||||
|
||||
### What it is
|
||||
- Markdown: plain text that renders richly
|
||||
- GitHub adds extensions beyond base Markdown
|
||||
|
||||
### Task Lists
|
||||
- Purpose
|
||||
- Checklist of work items (often “before merge/complete” items)
|
||||
- Syntax
|
||||
- `- [X]` checked
|
||||
- `- [ ]` unchecked
|
||||
- Convenience
|
||||
- Checkboxes can be clicked directly (no need to edit Markdown)
|
||||
- Visibility
|
||||
- GitHub summarizes task progress on PR/Issue list pages
|
||||
- Common usage pattern
|
||||
- Open PR early, track progress via tasks
|
||||
|
||||
### Code Snippets (fenced code blocks)
|
||||
- Use cases
|
||||
- propose code ideas before committing
|
||||
- share failing examples
|
||||
- demonstrate intended behavior
|
||||
- Syntax
|
||||
- Fence with triple backticks
|
||||
- Add a language name for syntax highlighting (example: `java`)
|
||||
|
||||
### Quoting
|
||||
- Quote lines by prefixing with `>`
|
||||
- Shortcut
|
||||
- Select text in a comment and press `r` to quote it in the reply box
|
||||
|
||||
### Emoji
|
||||
- Emoji helper/autocomplete appears when typing `:`
|
||||
- Syntax
|
||||
- `:<name>:` (e.g., `:+1:`)
|
||||
- Comment tone
|
||||
- Adds emotion/fun; not essential but commonly used
|
||||
- Emoji cheat sheet link provided
|
||||
- `https://www.webfx.com/tools/emoji-cheat-sheet/`
|
||||
|
||||
### Images (drag & drop)
|
||||
- Not strictly a “GFM extension,” but supported
|
||||
- Easier than manually creating Markdown image links
|
||||
- Drag and drop images into comment text areas
|
||||
- GitHub uploads and auto-embeds
|
||||
- “Parsed as Markdown” hint
|
||||
- Provides a cheat sheet of supported Markdown features
|
||||
|
||||
---
|
||||
|
||||
## Keep your GitHub public fork up-to-date (syncing your fork’s `master`)
|
||||
|
||||
### Key point
|
||||
- A fork is independent of the original repo
|
||||
- GitHub may show “X commits behind upstream”
|
||||
- GitHub will not automatically update your fork
|
||||
|
||||
### Simple method (no extra configuration)
|
||||
- `git checkout master`
|
||||
- `git pull https://github.com/progit/progit2.git`
|
||||
- fetch + merge into your `master`
|
||||
- `git push origin master`
|
||||
- update your fork on GitHub
|
||||
- Downside
|
||||
- Typing the upstream URL repeatedly is tedious
|
||||
|
||||
### Configured method (more convenient)
|
||||
- Add upstream remote
|
||||
- `git remote add progit https://github.com/progit/progit2.git`
|
||||
- Fetch upstream
|
||||
- `git fetch progit`
|
||||
- Set your local `master` to pull from upstream `master`
|
||||
- `git branch --set-upstream-to=progit/master master`
|
||||
- Set default push destination to your fork
|
||||
- `git config --local remote.pushDefault origin`
|
||||
- Then the routine becomes
|
||||
- `git checkout master`
|
||||
- `git pull`
|
||||
- `git push`
|
||||
|
||||
### Important caution
|
||||
- With this setup Git won’t warn if you:
|
||||
- commit to `master`
|
||||
- pull from upstream
|
||||
- push to origin
|
||||
- You must treat `master` as “belonging to upstream”
|
||||
- avoid committing directly to `master`
|
||||
|
||||
---
|
||||
|
||||
## Maintaining a Project
|
||||
|
||||
## Creating a New Repository
|
||||
- Entry points
|
||||
- “New repository” button on dashboard
|
||||
- `+` menu in top toolbar → “New repository”
|
||||
- New repository form
|
||||
- Required: repository/project name
|
||||
- All other fields optional
|
||||
- After creation
|
||||
- Repo available as `<user>/<project_name>`
|
||||
- If empty, GitHub provides instructions to:
|
||||
- create a new repo locally and push
|
||||
- connect an existing repo
|
||||
- (Refresher referenced: Git Basics)
|
||||
- Repo URLs
|
||||
- HTTPS: `https://github.com/<user>/<project_name>`
|
||||
- SSH: `git@github.com:<user>/<project_name>`
|
||||
- Sharing tip (public projects)
|
||||
- Prefer sharing HTTPS URL
|
||||
- cloning doesn’t require a GitHub account
|
||||
- SSH requires account + SSH key
|
||||
|
||||
## Adding Collaborators
|
||||
- Purpose
|
||||
- Grant push access (read + write)
|
||||
- Steps
|
||||
- Repo page → **Settings**
|
||||
- Left menu → **Collaborators**
|
||||
- Add by username → “Add collaborator”
|
||||
- Remove access by clicking “X” next to collaborator
|
||||
|
||||
---
|
||||
|
||||
## Managing Pull Requests (as a maintainer)
|
||||
|
||||
### Where PRs come from
|
||||
- Fork-based PRs
|
||||
- contributor’s branch in their fork
|
||||
- usually you cannot push to their branch
|
||||
- Internal PRs (same repo)
|
||||
- branches inside your repo
|
||||
- typically both sides can push to the branch
|
||||
|
||||
### Email notifications (new PR)
|
||||
- Maintainer receives email for a new PR
|
||||
- Email includes
|
||||
- Diffstat (files changed and how much)
|
||||
- Link to the PR on GitHub
|
||||
- Useful command-line URLs/commands
|
||||
- `git pull <url> patch-1` (merge remote branch without adding remote)
|
||||
- `.diff` and `.patch` links for PR content
|
||||
- Example patch application:
|
||||
- `curl https://github.com/<user>/<repo>/pull/<id>.patch | git am`
|
||||
|
||||
### Collaborating on the PR (discussion + review)
|
||||
- You can comment on
|
||||
- specific lines
|
||||
- whole commits
|
||||
- general PR discussion
|
||||
- Uses GitHub Flavored Markdown everywhere
|
||||
- Email replies can be included back into the GitHub thread (metadata supports this)
|
||||
|
||||
### Merging or closing
|
||||
- Merge locally (various ways)
|
||||
- `git pull <url> <branch>`
|
||||
- or add remote for the fork, fetch, then merge
|
||||
- Merge on GitHub site
|
||||
- If merge is trivial, use **Merge** button
|
||||
- Creates **non-fast-forward** merge commit even if fast-forward is possible
|
||||
- If you decide not to merge
|
||||
- Close the PR
|
||||
- Author is notified
|
||||
|
||||
---
|
||||
|
||||
## Pull Request Refs (advanced: fetching PRs like branches)
|
||||
|
||||
### Motivation
|
||||
- Many PRs → avoid:
|
||||
- adding numerous remotes
|
||||
- repeating one-off `git pull <url>` operations
|
||||
|
||||
### Key idea
|
||||
- GitHub exposes PRs as “pseudo-branches”
|
||||
- They exist under:
|
||||
- `refs/pull/…`
|
||||
- Not fetched by default because normal fetch refspec targets:
|
||||
- `refs/heads/*`
|
||||
|
||||
### Discover PR refs on the remote
|
||||
- Use plumbing command:
|
||||
- `git ls-remote <repo-url>`
|
||||
- You’ll see entries like:
|
||||
- `refs/heads/master`
|
||||
- `refs/pull/<id>/head`
|
||||
- `refs/pull/<id>/merge`
|
||||
|
||||
### Two refs per PR (what they mean)
|
||||
- `refs/pull/<id>/head`
|
||||
- points to the tip commit of the PR branch
|
||||
- `refs/pull/<id>/merge`
|
||||
- points to the merge commit GitHub would create when using the merge button
|
||||
- useful for testing the would-be merge result
|
||||
|
||||
### Fetch a single PR head ref directly
|
||||
- Example
|
||||
- `git fetch origin refs/pull/958/head`
|
||||
- Result
|
||||
- stored in `.git/FETCH_HEAD`
|
||||
- Downsides
|
||||
- repetitive for many PRs
|
||||
- merging `FETCH_HEAD` can produce awkward merge messages
|
||||
|
||||
### Fetch all PR heads automatically via refspec
|
||||
- Edit `.git/config` and add a second `fetch =` line under the `origin` remote:
|
||||
- Existing (typical):
|
||||
- `fetch = +refs/heads/*:refs/remotes/origin/*`
|
||||
- Add:
|
||||
- `fetch = +refs/pull/*/head:refs/remotes/origin/pr/*`
|
||||
- After `git fetch`
|
||||
- PRs appear locally as:
|
||||
- `origin/pr/<id>`
|
||||
- You can test a PR locally
|
||||
- `git checkout pr/2`
|
||||
- Creates a local branch tracking the fetched PR ref
|
||||
- Note in chapter
|
||||
- The `/head` suffix is intentional; GitHub also provides `/merge` refs
|
||||
|
||||
---
|
||||
|
||||
## Pull Requests on Pull Requests
|
||||
- PR target is not limited to `master`
|
||||
- You can target
|
||||
- any branch in the network
|
||||
- even another Pull Request branch
|
||||
- Why this is useful
|
||||
- proposed change depends on another PR
|
||||
- exploratory/uncertain change
|
||||
- you don’t have push access to the target branch
|
||||
- How to do it (PR creation UI)
|
||||
- edit the base/compare selection
|
||||
- can change both:
|
||||
- branches
|
||||
- forks (where the branches live)
|
||||
|
||||
---
|
||||
|
||||
## Mentions and Notifications
|
||||
|
||||
### @mentions
|
||||
- Type `@` in a comment to autocomplete:
|
||||
- collaborators
|
||||
- contributors
|
||||
- Can mention users not in the dropdown too
|
||||
|
||||
### Notification effects
|
||||
- Mentioned user is notified
|
||||
- Mentioned user becomes subscribed (keeps receiving updates)
|
||||
- You are also subscribed if you:
|
||||
- open the Issue/PR
|
||||
- watch the repo
|
||||
- comment on the thread
|
||||
|
||||
### Unsubscribe
|
||||
- Use **Unsubscribe** button on Issue/PR page to stop updates
|
||||
|
||||
---
|
||||
|
||||
## The Notifications Page (config + handling)
|
||||
|
||||
### Where to configure
|
||||
- Settings → **Notification center**
|
||||
- Two delivery channels
|
||||
- Email
|
||||
- Web
|
||||
- Each can be toggled separately for:
|
||||
- **Participating** (threads you engage in / @mentioned)
|
||||
- **Watching** (repos you watch)
|
||||
|
||||
### Web notifications
|
||||
- GitHub-only
|
||||
- Indicated by a blue dot on the notifications icon
|
||||
- Notification center features
|
||||
- grouped by project
|
||||
- filter by project (left sidebar)
|
||||
- mark read individually (checkmark)
|
||||
- mark all in project read
|
||||
- mute an item (stop future notifications)
|
||||
|
||||
### Email notifications
|
||||
- Emails are threaded in many email clients
|
||||
- Headers include metadata useful for filtering/rules, such as:
|
||||
- `Message-ID` encoding: `<user>/<project>/<type>/<id>`
|
||||
- `<type>` differs for issues vs pull requests
|
||||
- List-style headers:
|
||||
- `List-Post`
|
||||
- `List-Unsubscribe`
|
||||
- `List-Archive`
|
||||
- Mail clients can use these headers to:
|
||||
- reply-post into the thread
|
||||
- unsubscribe/mute via email
|
||||
- Read synchronization
|
||||
- if both web + email are enabled:
|
||||
- reading the email can mark the web notification as read (when images are allowed)
|
||||
|
||||
---
|
||||
|
||||
## Special Files GitHub Recognizes
|
||||
|
||||
### README
|
||||
- GitHub renders a README on the project landing page
|
||||
- Recognized formats include:
|
||||
- `README`
|
||||
- `README.md`
|
||||
- `README.asciidoc`
|
||||
- etc.
|
||||
- Common README contents
|
||||
- project purpose
|
||||
- install/config instructions
|
||||
- usage/running example
|
||||
- license
|
||||
- contribution guidance
|
||||
- Because GitHub renders it, you can include
|
||||
- images
|
||||
- links
|
||||
|
||||
### CONTRIBUTING
|
||||
- A `CONTRIBUTING` file (any extension) triggers GitHub to show contribution guidelines when opening a PR
|
||||
- Purpose
|
||||
- define what you want/don’t want in PR submissions
|
||||
- increase chance contributors read guidelines before submitting
|
||||
|
||||
---
|
||||
|
||||
## Project Administration
|
||||
|
||||
### Changing the default branch
|
||||
- If you want a default branch other than `master`
|
||||
- affects what users see by default
|
||||
- affects PR defaults
|
||||
- affects default branch checked out on clone
|
||||
- Location
|
||||
- Repo settings → **Options** → Default branch dropdown
|
||||
|
||||
### Transferring a project (ownership transfer)
|
||||
- Repo settings → **Options** → “Transfer ownership”
|
||||
- Transfer to:
|
||||
- another user
|
||||
- an organization
|
||||
- Useful for:
|
||||
- handing off a project you no longer maintain
|
||||
- moving a growing project into an organization
|
||||
- Effects
|
||||
- moves repo with watchers and stars
|
||||
- creates redirects for:
|
||||
- web URLs
|
||||
- Git clone/fetch URLs (not only web)
|
||||
|
||||
---
|
||||
|
||||
## Managing an Organization
|
||||
|
||||
## Organization basics
|
||||
- Organizations have:
|
||||
- shared namespace for projects
|
||||
- shared ownership and management features
|
||||
- Common usage
|
||||
- open source groups
|
||||
- companies
|
||||
- Create an organization
|
||||
- `+` menu (top-right) → “New organization”
|
||||
- provide:
|
||||
- organization name
|
||||
- main contact email
|
||||
- optionally invite other users as co-owners
|
||||
- Free tier note (as stated)
|
||||
- organizations are free if everything stored is open source
|
||||
- Owner capabilities
|
||||
- fork a repo into:
|
||||
- personal namespace
|
||||
- org namespace
|
||||
- create repos under:
|
||||
- personal account
|
||||
- any org you own
|
||||
- automatically watch new repos created under the org
|
||||
- Customization
|
||||
- upload an org avatar
|
||||
- Org landing page
|
||||
- lists org repositories and is viewable by others
|
||||
|
||||
## Teams
|
||||
- Teams connect:
|
||||
- people (user accounts)
|
||||
- repositories
|
||||
- access levels
|
||||
- Example use case
|
||||
- repos: `frontend`, `backend`, `deployscripts`
|
||||
- team-based permissions for devs vs ops
|
||||
- Team management includes
|
||||
- adding members
|
||||
- granting repo access
|
||||
- adjusting access levels
|
||||
- Access levels
|
||||
- read-only
|
||||
- read/write
|
||||
- administrative
|
||||
- Team invitations
|
||||
- invited members get an email
|
||||
- Team mentions
|
||||
- `@org/team` mentions notify all team members and subscribe them
|
||||
- Team strategy tip
|
||||
- users can be in multiple teams
|
||||
- create special-interest teams (not only access-control teams)
|
||||
- `ux`, `css`, `refactoring`
|
||||
- `legal`, `colorblind`, etc.
|
||||
|
||||
## Audit log
|
||||
- Available to organization owners
|
||||
- Shows
|
||||
- org-level events
|
||||
- who performed them
|
||||
- where they were performed (geographic context)
|
||||
- Filtering available by
|
||||
- event type
|
||||
- place
|
||||
- person
|
||||
|
||||
---
|
||||
|
||||
## Scripting GitHub
|
||||
|
||||
## Services and Hooks (integrations)
|
||||
|
||||
### Where to find
|
||||
- Repo **Settings**
|
||||
- **Webhooks and Services** section/tab
|
||||
|
||||
### Services (prebuilt integrations)
|
||||
- Dozens of integrations available
|
||||
- Common categories
|
||||
- CI
|
||||
- issue trackers
|
||||
- chat systems
|
||||
- documentation systems
|
||||
- Example: Email service
|
||||
- choose “email” from “Add Service”
|
||||
- configure email address
|
||||
- “Add service”
|
||||
- result: email sent on every push
|
||||
- Event model
|
||||
- services may support multiple events
|
||||
- many focus on push events
|
||||
- Integration tip
|
||||
- check for built-in service for your tool (example given: Jenkins)
|
||||
|
||||
### Hooks (generic webhooks)
|
||||
- Use when
|
||||
- you need a custom integration
|
||||
- a service isn’t available as a built-in “Service”
|
||||
- How it works
|
||||
- configure a URL
|
||||
- GitHub POSTs an HTTP payload to that URL on selected events
|
||||
- Enabling/configuring
|
||||
- click “Add webhook”
|
||||
- provide:
|
||||
- payload URL
|
||||
- secret key
|
||||
- choose events (default: push events on any branch)
|
||||
|
||||
#### Example webhook service logic (Sinatra)
|
||||
- Goal example
|
||||
- send email if:
|
||||
- a specific user pushes
|
||||
- to a specific branch
|
||||
- touching a specific file
|
||||
- Steps in the handler
|
||||
- parse JSON payload from request body
|
||||
- identify:
|
||||
- pusher name
|
||||
- ref/branch
|
||||
- gather files touched across commits (added/modified/removed)
|
||||
- if criteria match → send email alert
|
||||
|
||||
#### Webhook debugging & redelivery
|
||||
- GitHub provides a webhook delivery console
|
||||
- shows recent deliveries
|
||||
- success/failure
|
||||
- request/response headers and bodies
|
||||
- Can “redeliver” old payloads to test your service
|
||||
- Webhook docs reference
|
||||
- `https://developer.github.com/webhooks/`
|
||||
|
||||
---
|
||||
|
||||
## The GitHub API
|
||||
|
||||
### What it’s for
|
||||
- Automate actions or retrieve information beyond webhook notifications
|
||||
- Can do (as stated)
|
||||
- nearly anything you can do on the website programmatically
|
||||
|
||||
### Basic usage (unauthenticated GET)
|
||||
- Example: user info
|
||||
- `curl https://api.github.com/users/schacon`
|
||||
- Many read-only endpoints exist:
|
||||
- orgs, repos, issues, commits, etc.
|
||||
- Example: get a `.gitignore` template
|
||||
- `curl https://api.github.com/gitignore/templates/Java`
|
||||
- Also mentioned capability
|
||||
- render arbitrary Markdown via the API
|
||||
|
||||
### Authentication (for write actions/private data)
|
||||
- Options mentioned
|
||||
- basic auth (username/password)
|
||||
- personal access token (recommended)
|
||||
|
||||
#### Personal access tokens
|
||||
- Generated in settings → **Applications**
|
||||
- Configure:
|
||||
- scopes
|
||||
- description (helps later cleanup)
|
||||
- Token visibility
|
||||
- shown only once → copy it
|
||||
- Advantages
|
||||
- scoped + revocable
|
||||
- higher rate limits
|
||||
- unauthenticated: 60 requests/hour
|
||||
- authenticated: 5,000 requests/hour
|
||||
|
||||
### Commenting on an Issue (API example)
|
||||
- Endpoint pattern
|
||||
- `repos/<user>/<repo>/issues/<num>/comments`
|
||||
- HTTP method
|
||||
- `POST`
|
||||
- Headers
|
||||
- `Content-Type: application/json`
|
||||
- `Authorization: token TOKEN`
|
||||
- Example payload
|
||||
- JSON with `"body"` (can include emoji codes like `:+1:`)
|
||||
- Result
|
||||
- API returns comment data (id, URLs, timestamps, author info)
|
||||
- Comment appears on the GitHub issue
|
||||
|
||||
### Changing the status of a Pull Request (commit status API)
|
||||
- Concept
|
||||
- Each commit can have one or more statuses
|
||||
- API supports adding/querying statuses
|
||||
- Typical users
|
||||
- CI and testing services
|
||||
- Other validation examples (as stated)
|
||||
- commit message formatting checks
|
||||
- contribution guideline validation
|
||||
- signed/valid commit checks
|
||||
- Example webhook-based validator (Signed-off-by)
|
||||
- On push:
|
||||
- inspect each commit message
|
||||
- set status `state` to one of:
|
||||
- `success`
|
||||
- `failure`
|
||||
- `error`
|
||||
- include:
|
||||
- description
|
||||
- target URL for more info
|
||||
- context (e.g., `validate/signoff`) to distinguish multiple status providers
|
||||
- Status POST endpoint pattern
|
||||
- `/repos/<user>/<repo>/statuses/<commit_sha>`
|
||||
- UI effect on PR
|
||||
- green check vs red X per commit
|
||||
- PR overall status reflects last commit’s status
|
||||
- warns you if the last commit is failing (useful to avoid merging broken state)
|
||||
|
||||
### Octokit (API client libraries)
|
||||
- Purpose
|
||||
- Provide idiomatic wrappers around GitHub API (avoid manual HTTP)
|
||||
- Languages supported (at time of writing in chapter)
|
||||
- Go
|
||||
- Objective-C
|
||||
- Ruby
|
||||
- .NET
|
||||
- Info link
|
||||
- `https://github.com/octokit`
|
||||
|
||||
### Documentation link (API)
|
||||
- Full API docs + guides
|
||||
- `https://developer.github.com`
|
||||
|
||||
---
|
||||
|
||||
## Summary (end of chapter)
|
||||
- After this chapter you can:
|
||||
- create/manage a GitHub account
|
||||
- create repos and push code
|
||||
- contribute via forks + pull requests
|
||||
- review/merge/close PRs as a maintainer
|
||||
- manage orgs, teams, audit logs
|
||||
- integrate via services/webhooks
|
||||
- automate via the GitHub API (tokens, comments, statuses)
|
||||
- Next step (as stated)
|
||||
- learn more powerful Git tools/tips for complex situations to become a “Git master”
|
||||
Reference in New Issue
Block a user