Slide 1

Slide 1 text

GIT FOR SMARTASSES

Slide 2

Slide 2 text

SCRIPTING GIT You can execute operations on a git repository without cd-ing into it. You can specify it using the $GIT_DIR or --git-dir options: • GIT_DIR=~/myproject/.git \ git You can also specify a dislocated work tree using $GIT_WORK_TREE or --work-tree.

Slide 3

Slide 3 text

WALKING AROUND WITH A DETACHED HEAD Checking out a revision results in a detached head state. This means that the current working copy isn‘t the HEAD revision of any named branch. To create a branch at that point, simply: • git checkout -b new-branch-name

Slide 4

Slide 4 text

SHORTCUTS • HEAD always refers to the current branch‘s last commit • ^ means one commit before the preceding • ~n means n commits before Examples: • git checkout HEAD^^^

Slide 5

Slide 5 text

MOAR SHORTCUTS Get an object prior to a point in time: • @{} Find the first object preceding another object: • ^{} Find the first object that contains a message: • ^{/} Find the youngest commit by message: • :/

Slide 6

Slide 6 text

EVEN MOARER SHORTCUTS • man gitrevisions

Slide 7

Slide 7 text

SEARCHING FOR COMMITS You can use regexes to search commit messages: • git log -E --grep='(fuck|shit)' More filtering options: • git help log

Slide 8

Slide 8 text

SPECIFYING RANGES List commits reachable from r2 but not from r1: • git log ^r1 r2 • git log r1..r2 To get a list of commits that are reachable by either but not both: • git log r1 r2 --not • git log r1...r2

Slide 9

Slide 9 text

„WAS THIS MERGED?“ To get a list of commits not yet in master: • git log feature-branch ^master Outgoing changes? • git fetch • git log ^origin/master master Incoming? • git fetch • git log origin/master ^master

Slide 10

Slide 10 text

BONUS: GIT CHERRY Get all commits not merged upstream (usually origin/master): • git cherry [ []] This is essentially a log of outgoing commits.

Slide 11

Slide 11 text

HAVE YOU EVER DONE THIS? $ git history * 23e0ccc Klemen Slavič (2 seconds ago): If this doesn't work, I quit * e8782f5 Klemen Slavič (35 seconds ago): Reverting commit 8f314b9 * 8f314b9 Klemen Slavič (60 seconds ago): Really really fixes #313 * 9e7b3d6 Klemen Slavič (78 seconds ago): FOR FUCK'S SAKE I MUST BE BLIND * 6e410ba Klemen Slavič (2 minutes ago): FML, Samsung won't cooperate * fdc13c4 Klemen Slavič (2 minutes ago): Whoops, forgot to add dependency * 046e13b Klemen Slavič (2 minutes ago): Resolves issue #313 * ca59d46 Klemen Slavič (2 hours ago): Added greeting * 310008b Klemen Slavič (3 hours ago): Initial commit Wish you hadn‘t?

Slide 12

Slide 12 text

AMENDING A COMMIT After commiting a faulty commit, modify the working copy and stage the changes: • git add . Commit the changes using the --amend option: • git commit --amend Don‘t amend a commit you‘ve already pushed. Unless you know what you‘re doing.

Slide 13

Slide 13 text

INTERACTIVE ADDING If you happen to have applied two or more fixes in one go, you can pick and choose individual hunks to stage them for commits: • git add -i

Slide 14

Slide 14 text

DEMO: INTERACTIVE ADDING

Slide 15

Slide 15 text

FORENSIC INVESTIGATION: PINPOINTING FAILURES Git provides the bisect command which helps you search for changes that introduced a bug. • git bisect start • git bisect bad • git bisect good d34db33f • ... git checks out out next revision, test... • git bisect (good|bad) • git bisect reset

Slide 16

Slide 16 text

AUTOMATIC PERSONELL EXECUTION ON BUILD FAIL If you have test scripts available, you can use bisect to automate this: • git bisect run script [arguments] If the script exits with a 0, the revision is marked as good, otherwise a code between 1 and 127 means bad. 125 means untestable. After finding the commit, run server/bin/execute [username] to notify the firing squad.

Slide 17

Slide 17 text

REVERTING A COMMIT To undo the effects of a commit in history, use the revert command: • git revert (|...) This creates a new commit that applies an inverse patch of all the listed commits. Sometimes it‘s preferable to take out the merge commit instead of re-reverting it.

Slide 18

Slide 18 text

RESETTING Resetting moves the branch pointer to the given SHA-1 hash, effectively leaving behind a dangling branch: • git reset --hard You can then create a named branch: • git checkout -b This is the preferred way of reverting a merge. This modifies history, think before pushing!

Slide 19

Slide 19 text

CHANGING HISTORY

Slide 20

Slide 20 text

FORCE PUSHING

Slide 21

Slide 21 text

FORCE PUSHING If for some reason you‘d like to overwrite history on the remote, use the force flag: • git push origin branch-name -f DO NOT DO THIS! This overwrites all history for the pushed branch, effectively obliterating anything on the remote your history does not already contain.

Slide 22

Slide 22 text

SERIOUSLY, DON‘T.

Slide 23

Slide 23 text

RECOVERING FROM A CATASTROPHIC FUCKUP So you didn‘t heed my warning and force pushed modified history or deleted your own. Don‘t panic. Every git operation is logged in the reflog and can be navigated by simply checking out the logged history. Just don‘t run git gc.

Slide 24

Slide 24 text

REMINISCING ON YOUR PAST TRANSGRESSIONS To see a log of operations applied to your repository in the past few days: • git reflog [log options] [--verbose] You can then use git reset to return to the state at the moment you decided that drinking a bottle of absinthe yourself merging an unfinished branch was a good idea.

Slide 25

Slide 25 text

THE GHOSTS OF CHRISTMAS PAST Ever dropped, reset or lost a commit? Not to worry. Git fuck fsck to the rescue: • git fsck To idenfity dropped stashes: • git fsck --unreachable | \ grep commit | cut -d\ -f3 | \ xargs git log --merges --no-walk --grep=WIP

Slide 26

Slide 26 text

DEMO: RECOVERING FROM AN EPIC FAIL

Slide 27

Slide 27 text

CODE SURGERY (TOILET/SMOKE BREAK)

Slide 28

Slide 28 text

CREATING AND APPLYING PATCHES To make a series of patches from commits: • git format-patch [|] selects all commits from that commit up to the current revision (even if detached). To apply a patch: • git am < 0001-commit-message

Slide 29

Slide 29 text

CHERRYPICKING COMMITS Cherrypicking is essentially just an automated way of creating patches out of commits and applying them to the current branch as commits. • git cherry-pick (|...) \ [--edit] [-x] [--no-commit] For each merge conflict, resolve and run: • git cherry-pick --continue

Slide 30

Slide 30 text

CHERRYPICKING EXAMPLE To forward-port code from legacy to master: • git checkout master • git cherry-pick ^master legacy -x This creates one commit per cherrypicked commit. If you want a single commit: • git cherry-pick ^master legacy -n • (review, edit and TEST!) • git commit

Slide 31

Slide 31 text

BONUS: COPY CONTENTS OF A FILE FROM A BRANCH If you want to overwrite a file‘s contents with a specific commit or branch, you can check out that file directly: • git checkout my-branch -- ... • git add . • git commit

Slide 32

Slide 32 text

REBASING A cut-and-paste operation that takes a range of commits and appends them to the target. It‘s like merging, but avoids merge commits in favour of a more linear history. Works exactly like cherry-pick, but can be used automatically when pulling changes from upstream.

Slide 33

Slide 33 text

SAY WHAT?

Slide 34

Slide 34 text

REBASING 00 01 02 03 04 new-feature master

Slide 35

Slide 35 text

REBASING 00 01 02 05 06 new-feature master

Slide 36

Slide 36 text

REBASING A BRANCH You‘re working on a branch and need to sync with upstream. No worries: • git rebase You can do the same if you‘re working on the same branch and pulling from remote: • git pull origin my-branch --rebase This will only rebase outgoing commits onto the appended upstream history.

Slide 37

Slide 37 text

A CAUTIONARY TALE DANGER, WILL ROBINSON, DANGER! Avoid rebasing a branch that has another branch attached. Rebasing the base branch will rebase that branch but leave the other unchanged (duplicated history). You need to rebase that branch separately to avoid duplicating and mangling history for everyone.

Slide 38

Slide 38 text

AUTOMATICALLY REBASING WHEN PULLING Git can be configured to automatically rebase instead of merge. This avoids merge commits each time someone pushes to the same branch. • git config branch.autosetuprebase always • git config branch..rebase true • git pull origin my-branch Caution. May cause cancer.

Slide 39

Slide 39 text

NOT FOR THE FAINT OF HEART https://github.com/aanand/git-up

Slide 40

Slide 40 text

ADVANCED REBASE: SPLITTING BRANCHES Say you have the following situation: 00 01 02 03 04 master 05 06 new-feature bugfix Problem is, you need bugfix in master before new-feature.

Slide 41

Slide 41 text

ADVANCED REBASE: SPLITTING BRANCHES git rebase --onto master bugfix new-feature 00 01 02 03 04 master 07 08 new-feature bugfix

Slide 42

Slide 42 text

ADVANCED REBASE: SPLICING COMMITS Say 01-02 are commits that don‘t belong in master. 00 01 02 03 04 master

Slide 43

Slide 43 text

ADVANCED REBASE: SPLICING COMMITS git rebase --onto 00 02 master 00 05 06 01 02 master This will produce dangling commits that we can use to create a branch with: • git checkout -b spliced 02

Slide 44

Slide 44 text

SKILL LEVEL ASIAN: INTERACTIVE REBASING

Slide 45

Slide 45 text

SKILL LEVEL ASIAN: INTERACTIVE REBASING $ git rebase -i pick 7f3019b Removed APASUT overrides from all SDKs pick f83aba2 Added APASUT flag to all SDKs pick 5c335bc Flag checking pick 8363137 typo # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell

Slide 46

Slide 46 text

SKILL LEVEL ASIAN: SQUASHING COMMITS You would like to squash the last 3 commits into a single commit. $ git rebase -i HEAD~3 pick 01 Added README squash 02 Added heading squash 03 Added first paragraph

Slide 47

Slide 47 text

SKILL LEVEL ASIAN: SQUASHING COMMITS Alternatively, you can use fixup to discard subsequent commit messages without editing. $ git rebase -i HEAD~3 pick 01 Resolves 404 errors fixup 02 Forgot to update config fixup 03 Fixes glitch on Samsung

Slide 48

Slide 48 text

GRAMMAR NAZI MANUAL: FIXING COMMIT MESSAGES You would like to fix the commit messages for the last 3 commits. $ git rebase -i HEAD~3 reword 01 Added you‘re keyring reword 02 Fcuk u Smasung! reword 03 fixed alot of bugz

Slide 49

Slide 49 text

DEMO: INTERACTIVE REBASING

Slide 50

Slide 50 text

QUESTIONS?

Slide 51

Slide 51 text

CONGRATS. YOU KNOW GIT FU.