Catalyst

Advanced Git

Workflows for Developers

Slides by Matthew B. Gray / @theflimflam and Ben Denham

Administrivia

  • Bathrooms
  • Fire exits

Special thanks to

  • Mike O' – For approving this course
  • Alison Aldred – Organise all the things
  • Evan Giles – Inspiration and advice
  • Robert Higgins – Standardisation and profesionalism
  • Matthew Gray - Original author of this course
## Course Overview -------------------------------------------------------------------------------- * Part 1: Getting Started * Part 2: Personal workflows * Part 3: Team workflows * Part 4: Releases and Client workflows
### Part 1: Getting started * Part 2: Personal workflows * Part 3: Team workflows * Part 4: Releases and Client workflows -------------------------------------------------------------------------------- ### Objectives - Basic config for these machines - Good config defaults - Quick review of basic git
### Basic config for these machines Git would like you to specify 1. Your full name 1. Your email address 1. Your favourite text editor ```bash git config --global user.name "Dr. Henry Killinger" git config --global user.email "fu@bar.baz" git config --global core.editor vim ``` All these settings are stored in **~/.gitconfig**

Quick review of basic git

http://ndpsoftware.com/git-cheatsheet.html

### Part 1: Getting started ### [COMPLETE] * Objectives - Basic config for these machines ✔ - Good config defaults ✔ - Quick review of basic git ✔
* Part 1: Getting Started ✔ ### Part 2: Personal workflows * Part 3: Team workflows * Part 4: Releases and Client workflows -------------------------------------------------------------------------------- ### Objectives - Context hunting / Isolate and Triage issues - Mastering branches - Audit work interactively - Manage merge conflicts like a pro
### Part 2: Personal workflow * Objectives - __Isolate and Triage: Context hunting <-- you are here__ - Work: Mastering branches - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
### Context hunting / Isolate, Triage This is a BEFORE YOU START thing, helps isolate and triage ---------------------------------------- Context is important so you can... * Avoid regressing your codebase * Find out if code is still under warranty * Get help if you get stuck, seek out a human ---------------------------------------- Note: Before you start editing code, use Git to understand context: - Who wrote this? - What were they doing? - What will my change effect? - When did this issue start to occur?
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting * __Log - Show commit logs <-- you are here!__ * Bisect - binary search for bugs * Blame - revision and author for lines of a file * Pickaxe - Search commit diffs for changes - Work: Mastering branches - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
Regular log ```bash git log ``` ![regular git log](images/git-log.png)
Show me contents of patches ```bash git log -p ``` ![patch mode git log](images/git-log-p.png)
Show me a summary of patches ```bash git log --stat ``` ![stats](images/git-log-stat.png)
Find changes associated with text in a commit message: ```bash git log --grep '$search_term' git log --grep 'bug#1234' ``` ![grep for messages](images/git-log-grep-term.png)
View the tree of commits: ```bash git log --graph ``` ![git log tree](images/git-log-graph.png)
You can get pretty fancy with git log: ```bash git config --global alias.treelog "log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all" git treelog ``` ![git log tree](images/git-pretty-log.png) (Or just use gitk or tig)
Filter the log: ```bash # Show commits affecting index.html git log index.html # Show commits affecting index.html (Including those made when it wasn't named index.html) git log --follow index.html # Show commits from a specific user git log --author ben-denham # Show commits in a certain date range git log --before 03-15-2014 --after 03-08-2014 # Show commits in the experiment branch that aren't in master git log master..experiment # Show commits in experiment and master that are not in both. git log master...experiment ```
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting * Log - Show commit logs ✔ * __Bisect - binary search for bugs <-- you are here!__ * Blame - revision and author for lines of a file * Pickaxe - Search commit diffs for changes - Work: Mastering branches - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
### Bisect: Binary search for bugs You can search 100 commits in 10 steps to find a bad commit! ---------------------------------------- To bisect, you need... 1. A ref (tag/hash/branch) to a known bad commit 2. A ref to a known good commit ```bash git bisect start $bad_commit $good_commit # ... test your code ... git bisect bad git bisect good # put things back with git bisect reset ```
### Bisect: When it's not testable If your history has broken commits, maybe it's impossible to test ```bash # test around an problematic commit git bisect skip # or save where you're up to, and come back later git bisect log > bisect.log # ... time passes git bisect reset git bisect replay bisect.log ```
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting * Log - Show commit logs ✔ * Bisect - binary search for bugs ✔ * __Blame - revision and author for lines of a file <-- you are here!__ * Pickaxe - Search commit diffs for changes - Work: Mastering branches - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
### Blame: Basic usage ```bash git blame $filename # to get the context around the change of a line git show $hash ``` ![git blame](images/git-blame.png)
### Blame: Power tools * Ignore whitespace changes (might be hiding a commit) * Copy paste detection in a file, and across the repo * Track refactorings of methods across a codebase ---------------------------------------- ```bash git blame -w $filename # ignore whitespace git blame -M $filename # copy paste within the same file git blame -C $filename # copy paste over the repo ```
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting * Log - Show commit logs ✔ * Bisect - binary search for bugs ✔ * Blame - revision and author for lines of a file ✔ * __Pickaxe - Search commit diffs for changes <-- you are here!__ - Work: Mastering branches - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
### Pickaxe What happened to __myFabuliousFunc()__, it's gone! When did __$mySillyVariable__ get referenced everywhere? ---------------------------------------- Search commit diffs for changes * Find all the changes to a line in your entire history * The pickaxe can help find code that’s been deleted or moved * Works with log, diff, format-patch and tig ```bash git log -S 'some distinct line that changed' git log --stat -S '$racebook_uri_result' ```
### Activity: Testing bisect 1. Clone the jabberwocky repo, pull tags 3. Use bisect with __v1__ and __v2__ tags as good/bad commits 4. find the commit that broke the page ```bash # Fetch repository and tags git clone https://github.com/catalyst-training/jabberwocky cd jabberwocky git fetch --tags # Test code firefox jabberwocky.html git log --stat # Start bisect git bisect start $bad $good # Now test the code! # When a commit exhibits wanted behaviour git bisect good # When a commit exhibits unwanted behaviour git bisect bad ```
Don't forget to tidy up with... ```bash git bisect reset ```
### Activity: Testing log, pickaxe, blame and show 1. Clone jquery repo 2. Use git log to find fixes to issue #14756 3. Use pickaxe to find commits that added or removed 'parseFloat' 4. Try git blame on the .gitignore file 5. With this info, show the commit that blacklisted node_modules ```bash git clone https://github.com/jquery/jquery cd jquery git log --grep 'asdf' git log -p -S 'asdf' git blame $file git show $hash ``` Note: - Test this the day before the course - git log about issue (use a recent issue number) - Pickaxe to find commits. - Git blame and then git show to look at a commit.
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting ✔ - __Work: Mastering branches <-- you are here!__ - Update, Test: Audit work interactively - Share: Manage merge conflicts like a pro
### Mastering branches: Overview ![Feature branches]( images/branches-multi.png ) ![Merge branches]( images/branches-typical.png ) Branching should reflect your team's workflow.
![]( images/branches-perspective.png ) Isolate work till you're ready to release
### Git commits Git thinks in Snapshots, Not Differences > The major difference between Git and any other VCS (Subversion and friends included) > is the way Git thinks about its data. _quote from git-scm.com, ch 1.3 "Getting Started: Git Basics"_
### Commits: Git vs SVN ![Subversion commits]( images/branches-svn.png ) ---------------------------------------- ![Git commits]( images/branches-commits.png ) Note: It's really easy to see what the project looked like at a particular commit.
### Commits in context * A single commit: you refer to an entire filesystem layout * Multiple commits: you usually think in diffs * Commits are immutable, but you can re-create a new history ---------------------------------------- You can refer to commits with a... * **branch** - a name to track your work * **tag** - a label, it doesn't move * **commit hash** - complete history and set of files * **HEAD** - your current checkout * **$ref^** - above are $refs, chain ^ or ~ to go up a branch ---------------------------------------- Lets look at how we can use these with commands
### Mastering branches: Commands Interesting commands with branches ```bash git checkout $branch git merge $branch git rebase $branch git rebase --interactive $branch git reset $ref ``` ---------------------------------------- * **Checkout**: context dependent command... 1. Either reset unstaged file(s) 2. Or switch branches * **Merge**: Create a new commit with multiple parent commits * **Rebase**: Batch move commits and rewrite history * **Reset**: Move branches around arbitarily * **Reflog**: Save my ass! What have I had 'checked out' recently? ---------------------------------------- Whiteboard time!

What will reset/checkout affect?

HEAD Index Workdir WD Safe?

Commit Level

reset --soft [commit]

REF

NO

NO

YES

reset [commit]

REF

YES

NO

YES

reset --hard [commit]

REF

YES

YES

NO

checkout [commit]

HEAD

YES

YES

YES

File Level

reset (commit) [file]

NO

YES

NO

YES

checkout (commit) [file]

NO

YES

YES

NO

Git Book - Chapter 7.7

```bash # ...fiddle fiddle fiddle, fixing one thing # OOP... NOOOOOOO!!!! Undo undo undo! git reflog ```
### Mastering branches: Headless state If you're not on a branch, git puts you in a headless state ```bash git checkout $tag git checkout $commit ``` Trying something like this... ```bash git checkout HEAD^ ```
But don't worry, git is being melodramatic when it says... ```bash You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b new_branch_name HEAD is now at f4b37d8... CSS: Return values should be numbers ```
### Activity: Mastering Branches 1. Navigate to your Jabberwocky repo clone 2. Checkout 'master' 3. Fix the bug, commit 4. Interactive rebase onto the tag v1 5. Squash your fix with 'Oops' and give it a message. ```bash cd $jabberwocky_dir vim jabberwocky.html git add jabberwocky.html git commit git log git rebase $ref --interactive git log -p ``` ...it's as if the error was never there. Now put it back ```bash git reset origin/master --hard ```
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting ✔ - Work: Mastering branches ✔ - __Update, Test: Audit work interactively <-- you are here!__ - Share: Manage merge conflicts like a pro
### Audit work interactively Audit your work interactively with your staging area 1. When you're ready to commit locally 2. When you want to break up a monster commit ---------------------------------------- ### Quick activity ```bash # Add new first and last verses to the jabberwocky poem, then run git add -p # Check what's happened with git status # Put stuff back with git reset HEAD ``` (``-p`` also works with reset and checkout)
### Part 2: Personal workflow * Objectives - Isolate and Triage: Context hunting ✔ - Work: Mastering branches ✔ - Update, Test: Audit work interactively ✔ - __Share: Manage merge conflicts like a pro <-- you are here!__
### Manage merge conflicts like a pro Source control is about social coding and interactions. A conflict should be a conversation. When you see ```bash CONFLICT (content): Merge conflict in jabberwocky.html Automatic merge failed; fix conflicts and then commit the result. ``` Get info with ```bash git status git blame $file ``` Markers are usually HEAD and a $ref, where: 1. HEAD is work of yours 2. $ref is the thing you're in conflict with ```bash git merge $ref ```
### Part 2: Personal workflow [COMPLETE] * Objectives - Isolate and Triage: Context hunting ✔ - Work: Mastering branches ✔ - Update, Test: Audit work interactively ✔ - Share: Manage merge conflicts like a pro ✔
* Part 1: Getting Started ✔ * Part 2: Personal workflows ✔ ### Part 3: Team workflows * Part 4: Releases and Client workflows -------------------------------------------------------------------------------- ### Objectives - Quickly setup local, network accessible repos - Working with people who don't enjoy source control - Clean history, rebase verses merge

When you use git to share your stuff

### Corporate Workflow You will probably use this
corporate
### Integration manager Workflow A quick diversion: http://www.github.com
github
### Dictator Workflow This is how the Linux kernel is managed
linux
### Peer to peer Workflow
p2p
### Quickly setup local, network accessible repos Git just tracks content. All history is stored in .git directory, and sharing is just mushing content around in there. To modify remotes... ```bash git remote add $alias $location git remote rm $alias $location ``` Location can be... 1. ssh://[user@]host.xz[:port]/path/to/repo.git/ 1. git://host.xz[:port]/path/to/repo.git/ 1. http[s]://host.xz[:port]/path/to/repo.git/ 1. ftp[s]://host.xz[:port]/path/to/repo.git/ 1. rsync://host.xz/path/to/repo.git/
### Quickly setup local, network accessible repos Enter custom alias! You just need to run this once... ```bash # Set up a global "git serve" alias. git config --global alias.serve "daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths .git/" # Allow your repository to be shared. touch .git/git-daemon-export-ok ``` Now you too can share your terrible poetry with your neighbour! Navigate to your repository, and run ```bash git serve ``` And you'll be __Ready to rumble__
### Pull work from your neighbour ```bash # Make some changes and commit. echo 'My name' >> jabberwocky.html git commit -am "Added my name". # Find your IP address (or hostname) ip ad # Serve your jabberwocky poem to the network cd ~/jabberwocky git serve # Get your neighbours network details # Lets add their work to your repo git remote add neighbour git://$host/ git fetch # What's different between our branches? git diff neighbour/master master # Merge their work in (merge conflict ahead) git merge neighbour/master ```
### Working with people who don't enjoy source control Idea #1: Empower them, let them manage their commits, but manage their merges ![](images/branches-typical.png)
### Working with people who don't enjoy source control Idea #2: Manage their commits and merges ```bash while true; do clear; git add . git commit -m "$designer updated UX." sleep 5; done; ```

Wrestling with git

### Clean history, rebase verses merge * When to merge: If you've pushed it, you can't change things without pain. * If you have multiple conflicts, try for a merge * Don't rebase long chains of commits * you'll have to repeat merge conflict resolution, unless you use rerere * Avoid squashing lots of commits, so that you keep the history. ---------------------------------------- Discuss: ```bash git pull --rebase ``` ```bash git config --global pull.rebase true git pull ``` ```bash git rebase --abort git merge --abort ``` Note: - rerere = reuse recorded resolution - git config rerere.enabled true
### Part 3: Team workflows [COMPLETE] - Objectives - Quickly setup local, network accessible repos ✔ - Working with people who don't enjoy source control ✔ - Clean history, rebase verses merge ✔
* Part 1: Getting Started ✔ * Part 2: Personal workflows ✔ * Part 3: Team workflows ✔ ### Part 4: Release Management -------------------------------------------------------------------------------- ### Objectives - Strategies for dealing with release requirements - Strategies for database patching on branches
### Strategies for dealing with client requirements The battle of flexibility vs simplicity ---------------------------------------- A typical client may ask you to be flexible on the following * Track changes, find bugs and release when you can * Working on features and releases in parallel * Have feature freezes before releases * Track which version is running in each environment. * Construct release candidates based on feature sets * Release partial applications (modular)

Release all the things!

### Client requirements: Linear history ![](images/workflow-1.png) * Simple, single-branch * Track changes, find bugs and release when you can * Tag releases * Doesn't scale well for many devs (frequent merging) * You only work on one feature/release at a time
### Client requirements: Parallel features ![](images/workflow-2.png) * Each feature/issue is worked on in a separate branch. * Many devs can work independently, then merge later. * A single developer can work on multiple issues at once.
### Client requirements: Merge forward releases ![](images/workflow-3.png) * Fairly simple; each release has its own branch * Merge older release branches into newer branches when they change * Assumes each release depends on the previous one * Work on multiple releases at the same time * Release fixes for v1 while working towards v2
### Client requirements: Feature freezes and env-tracking ![](images/workflow-4.png) * Release branches can be used to enable a feature freeze. * Feature work continues on master, while only bug-fixes are made on v2. * Bug-fixes are merged back into master from v2. * You may also like to have a branch to track each environment.
### Gitflow ![](images/gitflow.png) * Explanation: http://nvie.com/posts/a-successful-git-branching-model/ * Command-line tool: https://github.com/nvie/gitflow
### Client requirements: Feature releases * Every piece of work is a feature (with its own 'feature branch') * Features are octo-merged into a release candidate * Features can be excluded from a particular release ![](images/feature-releases-1.png) Note: - Image: Creation of a release candidate. - If an octomerge has conflicts: - Find the 2+ problematic branches (can be tricky) - Merge them together into a NEW feature branch, which can then be used in the octomerge - Reason: have no conflict resolution in the release candidate, so that the merge is reproducible. - QA the release candidate, and make fixes on the feature branches. - Release candidate gets promoted to prod (stable). - Stable gets merged back into the feature branches.
### Client requirements: Microkernel architecture * Difficulty is abstracted to the application. * Modelled off the Linux kernel: many modules connect to a small core via APIs. * Usually separate repos for each module (sometimes combined using git submodules). * Modules of application can be worked on at the same time with different workflows. * A release would package together modules at different versions.

Each has its costs! Choose the one that works best

### Database migrations Git doesn't care about non-filesystem entities Database migrations (patches) are important to get right ---------------------------------------- - Have a numbering/naming convention for migrations. - Create migrations with UP and DOWN instructions. * Makes it easier to upgrade/downgrade the database working when switching between commits. - Use git bisect with a script to drop the database, re-apply your migrations, and run a test (or prompt you for input): ```bash git bisect run my_script.py ```

Further Reading


Attribution

## Course Information Slides can be found on [github.com/ben-denham/git-advanced]( https://github.com/ben-denham/git-advanced ) Feedback? Corrections? Questions? Please leave an issue against the course github page.
freedom to innovate Boom