Upgrade to Pro — share decks privately, control downloads, hide ads and more …

git for smartasses

git for smartasses

A continuation of my internal presentation at Celtra Technologies Inc.

Klemen Slavič

July 30, 2012
Tweet

More Decks by Klemen Slavič

Other Decks in Programming

Transcript

  1. 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 <command> You can also specify a dislocated work tree using $GIT_WORK_TREE or --work-tree.
  2. 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
  3. 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^^^
  4. MOAR SHORTCUTS Get an object prior to a point in

    time: • <refname>@{<date>} Find the first object preceding another object: • <refname>^{<type>} Find the first object that contains a message: • <refname>^{/<regex>} Find the youngest commit by message: • :/<regex>
  5. SEARCHING FOR COMMITS You can use regexes to search commit

    messages: • git log -E --grep='(fuck|shit)' More filtering options: • git help log
  6. 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
  7. „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
  8. BONUS: GIT CHERRY Get all commits not merged upstream (usually

    origin/master): • git cherry [<upstream> [<head>]] This is essentially a log of outgoing commits.
  9. 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?
  10. 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.
  11. 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
  12. 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
  13. 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.
  14. REVERTING A COMMIT To undo the effects of a commit

    in history, use the revert command: • git revert (<range>|<commit>...) 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.
  15. RESETTING Resetting moves the branch pointer to the given SHA-1

    hash, effectively leaving behind a dangling branch: • git reset <target> --hard You can then create a named branch: • git checkout -b <branch-name> This is the preferred way of reverting a merge. This modifies history, think before pushing!
  16. 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.
  17. 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.
  18. 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.
  19. 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
  20. CREATING AND APPLYING PATCHES To make a series of patches

    from commits: • git format-patch [<since>|<range>] <since> selects all commits from that commit up to the current revision (even if detached). To apply a patch: • git am < 0001-commit-message
  21. 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 (<range>|<commit>...) \ [--edit] [-x] [--no-commit] For each merge conflict, resolve and run: • git cherry-pick --continue
  22. 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
  23. 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 -- <path>... • git add . • git commit
  24. 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.
  25. REBASING A BRANCH You‘re working on a branch and need

    to sync with upstream. No worries: • git rebase <commit> 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.
  26. 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.
  27. 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.<name>.rebase true • git pull origin my-branch Caution. May cause cancer.
  28. 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.
  29. 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
  30. SKILL LEVEL ASIAN: INTERACTIVE REBASING $ git rebase -i <commit>

    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
  31. 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
  32. 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
  33. 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