Add comprehensive GitHub guide covering account setup, collaboration, and API usage
This commit is contained in:
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)
|
||||
```
|
||||
Reference in New Issue
Block a user