Slide 1

Slide 1 text

Understanding Git by @tednaleid 1

Slide 2

Slide 2 text

you can't modify commits only add new ones 2

Slide 3

Slide 3 text

commits are completely immutable and are impossible to accidentally destroy with git commands though rm -rf .git will lose anything not yet pushed out 3

Slide 4

Slide 4 text

uncommitted work is easily destroyed, so commit early & often 4

Slide 5

Slide 5 text

garbage collection is the only truly destructive git action 5

Slide 6

Slide 6 text

garbage collection only destroys commits with nothing pointing at them 6

Slide 7

Slide 7 text

what points at commits? other commits tags branches the reflog 7

Slide 8

Slide 8 text

commit point at 0..N parent commits E---F---G / \ A---B---C---D---H---I most commonly 1 or 2 parent commits 8

Slide 9

Slide 9 text

tag fixed commit pointers A---B---C ↑ release_1.0 % git commit -m "adding stuff to C" A---B---C---D ↑ release_1.0 9

Slide 10

Slide 10 text

branch floating commit pointer A---B---C ↑ master % git commit -m "adding stuff to B" A---B---C---D ↑ master 10

Slide 11

Slide 11 text

remote branch a “remote” branch is just a commit pointer in your local repo master ↓ A---B---C---D---E ↑ origin/master it's updated whenever you do a fetch or pull , otherwise nothing remote about them 11

Slide 12

Slide 12 text

branch text files in the .git directory % ls -1 .git/refs/heads/**/* .git/refs/heads/master .git/refs/heads/my_feature_branch % ls -1 .git/refs/remotes/**/* .git/refs/remotes/origin/HEAD .git/refs/remotes/origin/master .git/refs/remotes/origin/my_feature_branch 12

Slide 13

Slide 13 text

branch contains is the SHA of the commit it's pointing at % cat .git/refs/heads/master 0981e8c8ffbd3a1277dda1173fb6f5cbf4750d51 # .git/objects/09/81e8c8ffbd3a1277dda1173fb6f5cbf4750d51 13

Slide 14

Slide 14 text

branches point at commits Contain tree (filesystem), parent commits and commit metadata % git cat-file -p 0981e8c8ffbd3a1277dda1173fb6f5cbf4750d51 tree 4fd7894316b4659ef3f53426166697858d51a291 parent e324971ecf1e0f626d4ba8b0adfc22465091c100 parent d33700dde6d38b051ba240ee97d685afdaf07515 author Ted Naleid 1328567163 -0800 committer Ted Naleid 1328567163 -0800 merge commit of two branches The ID is the SHA of the commit's contents 14

Slide 15

Slide 15 text

branches commits don't “belong to” branches, there's nothing in the commit metadata about branches 15

Slide 16

Slide 16 text

branches a branch's commits are implied by the ancestry of the commit the branch points at feature ↓ E---F---G / A---B---C---D ↑ master master is A-B-C-D and feature is A-B-E-F-G 16

Slide 17

Slide 17 text

HEAD HEAD is the current branch/commit This will be the parent of the next commit % cat .git/HEAD ref: refs/heads/master most of the time it points to a branch, but can point directly to a SHA when “detached” 17

Slide 18

Slide 18 text

the reflog a log of recent HEAD movement % git reflog d72efc4 HEAD@{0}: commit: adding bar.txt 6435f38 HEAD@{1}: commit (initial): adding foo.txt % git commit -m "adding baz.txt" % git reflog b5416cb HEAD@{0}: commit: adding baz.txt d72efc4 HEAD@{1}: commit: adding bar.txt 6435f38 HEAD@{2}: commit (initial): adding foo.txt by default it keeps at least 30 days of history 18

Slide 19

Slide 19 text

the reflog unique to a repository instance 19

Slide 20

Slide 20 text

the reflog can be scoped to a particular branch % git reflog my_branch 347f5fe my_branch@{0}: merge master: Merge made by the recurs… 4e6007e my_branch@{1}: merge origin/my_branch: Fast-forward 32834d8 my_branch@{2}: commit (amend): upgrade redis version 2720e40 my_branch@{3}: commit: upgrade redis version 20

Slide 21

Slide 21 text

dangling commit if the only thing pointing to a commit is the reflog, it's “dangling” 21

Slide 22

Slide 22 text

dangling commit A---B---C---D---E---F ↑ master % git reset --hard SHA_OF_B A---B---C---D---E---F ↑ master C..F are now dangling 22

Slide 23

Slide 23 text

dangling commit but they will be safe for ~30 days because of the reflog HEAD@{1} ↓ A---B---C---D---E---F ↑ master (also HEAD@{0}) HEAD@{1} will become HEAD@{2} .. HEAD@{N} as refs are added to the reflog 23

Slide 24

Slide 24 text

garbage collection once a dangling commit leaves the reflog, it is “loose” and is at risk of garbage collection 24

Slide 25

Slide 25 text

garbage collection git does a gc when the number of “loose” objects hits a threshold something like every 1000 commits 25

Slide 26

Slide 26 text

garbage collection to prevent garbage collecting a commit, just point something at it % git tag mytag SHA_OF_DANGLING_COMMIT 26

Slide 27

Slide 27 text

the index a pre-commit staging area add -A :/ puts all changes in the index ready for commit some bypass the index with git commit -a -m "msg" 27

Slide 28

Slide 28 text

you should have courage to experiment you have weeks to retrieve prior commits if something doesn't work 28

Slide 29

Slide 29 text

understand where you are before you try to go somewhere else 29

Slide 30

Slide 30 text

You need (at least) one repo visualization tool that you grok 30

Slide 31

Slide 31 text

Here's Mine: ~/.gitconfig: [alias] l = log --graph --pretty='%Cred%h%Creset -%C(yellow)%d%Creset %s %Cblue[%an]%Creset %Cgreen(%cr)%Creset' --abbrev-commit --date=relative la = !git l --all git la 31

Slide 32

Slide 32 text

There are others - Git Tower 32

Slide 33

Slide 33 text

There are others - SourceTree 33

Slide 34

Slide 34 text

Learn “the good parts” and make them your own 34

Slide 35

Slide 35 text

checkout - just like cd - , takes you to your previous branch E---F ← feature & HEAD / A---B---C---D ↑ master % git checkout - E---F ← feature / A---B---C---D ↑ master & HEAD 35

Slide 36

Slide 36 text

commit --amend redo the last commit A---B---C ↑ master & HEAD <... change some files ... > % git commit -a --amend --no-edit C' ← master & HEAD / A---B---C ↑ (dangling but still in reflog) 36

Slide 37

Slide 37 text

rebasing reapplies a series of commits to a new parent commit then moves the current branch pointer 37

Slide 38

Slide 38 text

rebasing E---F ← feature & HEAD / A---B---C---D ↑ master % git rebase master (dangling but still in reflog) ↓ E---F / A---B---C---D---E'--F' ↑ ↑ master feature & HEAD 38

Slide 39

Slide 39 text

rebasing % git rebase --abort If you get in trouble --abort and try again. If you really get in trouble, you can reset --hard back to your last commit. 39

Slide 40

Slide 40 text

rebasing - a private activity should never be done with commits that have been pushed 40

Slide 41

Slide 41 text

rebasing - a private activity public rebasing is bad as others could have the same commits with different SHAs 41

Slide 42

Slide 42 text

cherry picking apply a subset of changes from another branch E---F---G / A---B---C---D ↑ master & HEAD % git cherry-pick SHA_OF_F E---F---G / A---B---C---D---F' ↑ master & HEAD 42

Slide 43

Slide 43 text

reset is for moving branch pointers 43

Slide 44

Slide 44 text

reset --soft A---B---C---D---E ↑ master % git reset --soft SHA_OF_C working dir & index still look like ↓ A---B---C---D---E ↑ master 1. moves HEAD & the current branch to the specified 2. index - unchanged 3. working directory - unchanged 44

Slide 45

Slide 45 text

reset --soft useful for squashing the last few messy commits into one pristine commit working dir & index still look like ↓ A---B---C---D---E ↑ master % git commit -m "perfect code on the 'first' try" A---B---C---E' ↑ master 45

Slide 46

Slide 46 text

reset --soft What if you've got a more complicated situation: master ↓ A---B---C---D---E \ \ F---G---H---I ← feature & HEAD Can't reset our way out of this, right? 46

Slide 47

Slide 47 text

reset --soft Just do one last merge % git merge master master ↓ A---B---C---D---E \ \ \ F---G---H---I---J ← feature & HEAD 47

Slide 48

Slide 48 text

reset --soft and then we can reset into a single commit % git reset --soft master A---B---C---D---E ← feature & HEAD & master \ J ← working dir & index % git commit -m "pristine J" master ↓ A---B---C---D---E---J' ← feature & HEAD 48

Slide 49

Slide 49 text

reset --hard % git reset --hard 1. moves HEAD & the current branch to the specified 2. clean the index, make it look like 3. clean the working copy, make it look like dangerous if you have uncommitted work, useful for undoing bad commits 49

Slide 50

Slide 50 text

reset --hard HEAD % git reset --hard HEAD just means clean out the working directory and any staged information, don't move the branch pointer for more info on reset , see: http://progit.org/2011/07/11/reset.html 50

Slide 51

Slide 51 text

fetch download new commits and update the remote branch pointer does not move any local branches 51

Slide 52

Slide 52 text

fetch origin/master (local) ↓ A---B---C---D ← master & HEAD A---B---E---F (origin) ↑ master (in remote repo) % git fetch origin/master ↓ E---F (local) / A---B---C---D ← master & HEAD 52

Slide 53

Slide 53 text

pull pull is fetch plus merge 53

Slide 54

Slide 54 text

pull origin/master (local) ↓ A---B---C---D ← master & HEAD A---B---E---F (origin) ↑ master (local ref in remote repo) % git pull origin/master ↓ E---F---- / \ (local) A---B---C---D---G ← master & HEAD 54

Slide 55

Slide 55 text

the “right” way to pull down changes from the server 1. stash any uncommitted changes (if any) 2. fetch the latest refs and commits from origin 3. rebase -p your changes (if any) onto origin's head else, just fast-forward your head to match origin's 4. un- stash any previously stashed changes fetch + rebase avoids unnecessary commits 55

Slide 56

Slide 56 text

rebasing pull As of git 1.8.5, git has finally added a rebase switch to pull : % git pull --rebase This will do the fetch + rebase for you (you still stash on your own). 56

Slide 57

Slide 57 text

git is dangerous myth #1 57

Slide 58

Slide 58 text

git is the safest version control reality 58

Slide 59

Slide 59 text

git lets you rewrite history myth #2 59

Slide 60

Slide 60 text

rewriting history is a lie reality 60

Slide 61

Slide 61 text

git syntax is terrible myth #3 61

Slide 62

Slide 62 text

git syntax is really terrible reality 62

Slide 63

Slide 63 text

git mislabels things ex: git branches aren't what you think they are 63

Slide 64

Slide 64 text

throw away your preconceptions from other version control systems 64

Slide 65

Slide 65 text

Questions? 65

Slide 66

Slide 66 text

Bonus Section! 66

Slide 67

Slide 67 text

reset (default) % git reset [--mixed] 1. moves HEAD & the current branch to the specified 2. clean the index, make it look like 3. working directory - unchanged git reset HEAD will unstage everything in the index 67

Slide 68

Slide 68 text

squashing compresses N commits into one commit that's appended to a destination branch 68

Slide 69

Slide 69 text

squashing E---F---G ← feature / A---B---C---D ↑ master & HEAD % git merge --squash feature E---F---G ← feature / A---B---C---D---G' ↑ master & HEAD cleans up history, when the thinking behind E..F is unimportant 69

Slide 70

Slide 70 text

recovering commits Oops, I really wanted C ! C' ← master & HEAD / A---B---C ← (dangling) % git reflog master # find SHA_OF_C % git reset --hard SHA_OF_C C' ← (dangling) / A---B---C ↑ master & HEAD 70