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

Intro to Git

Intro to Git

A Git training workshop.

Avatar for Connor Mendenhall

Connor Mendenhall

March 01, 2017
Tweet

More Decks by Connor Mendenhall

Other Decks in Technology

Transcript

  1. Other Stuff You’ll Need A text editor: Notepad++, Sublime Text,

    plain old notepad.exe Visual Studio: Recent versions should already have Git integration. I’ll use VS Community 2015 today.
  2. First Time Setup: Name and Email Before you can start

    using git, you’ll need to do some basic setup. Open git bash and set your name: $ git config --global user.name "Connor Mendenhall" $ git config --global user.email "[email protected]" And your email:
  3. First Time Setup: Setting Your Editor Git will sometimes pop

    open a text editor to ask for input. Before starting, make sure your favorite programming editor is associated with .txt files. I like Sublime Text: https://www.sublimetext.com/3
  4. First Time Setup: Dealing With Line Endings Different operating systems

    insert different characters at the end of lines. Make sure git is configured to correctly handle line endings by running: Read more about dealing with line endings here. $ git config --get core.autocrlf If this command doesn't' return true, run: $ git config --global core.autocrlf true
  5. Getting around Git Bash ls: list files See an extended

    command line cheat sheet here. cd: change directory mkdir: create a directory rm -r: delete a file or directory $ ls fizzbuzz.py hello_world.py $ cd /c/Users/'Connor Mendenhall'/Documents $ mkdir my_cool_project $ rm -r my_cool_project
  6. “Git gets easier once you get the basic idea that

    branches are homeomorphic endofunctors mapping submanifolds of a Hilbert Space. ” — @tabqwerty
  7. Create a new repository $ mkdir fizzbuzz $ cd fizzbuzz

    $ git init Initialized empty Git repository in C:/Users/Connor Mendenhall/Documents/GitHub/fizzbuzz/.git/ Create a repository: git init
  8. Saving changes $ git status On branch master Initial commit

    nothing to commit (create/copy files and use "git add" to track) See the current state: git status Running git status is always safe! You should use it constantly to see and understand what's going on!
  9. Saving changes See the current state: git status Let's make

    a change. Open an editor and save a new file, fizzbuzz.py def fizzbuzz(): print('hello world!') if __name__ == '__main__': fizzbuzz()
  10. $ git status On branch master Initial commit Untracked files:

    (use "git add <file>..." to include in what will be committed) fizzbuzz.py nothing added to commit but untracked files present (use "git add" to track) Saving changes See the current state: git status Now look again at the status...
  11. $ git status On branch master Initial commit Changes to

    be committed: (use "git rm --cached <file>..." to unstage) new file: fizzbuzz.py Saving changes See the current state: git status Now look again at the status...
  12. Saving changes $ git commit -m "Print hello world message"

    [master (root-commit) d0a1fb1] Print hello world message 1 file changed, 5 insertions(+) create mode 100644 fizzbuzz.py Save a set of changes: git commit -m <message> Your commit message is a very short summary of the changes you're saving. Keep it short and use the active voice!
  13. Saving changes Let's make another change. Instead of printing "hello

    world," we'll print all the numbers from 1 to 100: def fizzbuzz(): for i in range(1, 101): print(i) if __name__ == '__main__': fizzbuzz()
  14. Saving changes $ git status On branch master Changes not

    staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: fizzbuzz.py no changes added to commit (use "git add" and/or "git commit -a") See the current state: git status Check in on the status:
  15. Saving changes $ git diff diff --git a/fizzbuzz.py b/fizzbuzz.py index

    3fb2306..8f1aa82 100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,5 +1,6 @@ def fizzbuzz(): - print('hello world!') + for i in range(1, 101): + print(i) if __name__ == '__main__': fizzbuzz() See what changed: git diff Running git diff is also always safe! Use it frequently!
  16. Saving changes $ git add -A Add all new changes:

    git add -A (Short for git add --all)
  17. Saving changes $ git status On branch master Changes to

    be committed: (use "git reset HEAD <file>..." to unstage) modified: fizzbuzz.py See the current state: git status Check in on the status:
  18. Saving changes $ git commit -m "Print numbers 1 to

    100" [master 78e1706] Print numbers 1 to 100 1 file changed, 2 insertions(+), 1 deletion(-) Save a set of changes: git commit -m <message>
  19. The Staging Area Working Directory Repository Staging Area git add

    git commit The staging area is a "buffer zone" where you can compose your commits before saving them.
  20. Composing Commits To learn how to remove files from the

    staging area, let's add an unwanted file. The touch command in git bash creates an empty file: $ touch oops.txt $ ls fizzbuzz.py oops.txt Now we'll stage it: $ git add -A
  21. Composing Commits $ git status On branch master Changes to

    be committed: (use "git reset HEAD <file>..." to unstage) new file: oops.txt See the current state: git status Check in on the status:
  22. Composing Commits Remove a file from the staging area: git

    reset HEAD <file> $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: oops.txt 
 $ git reset HEAD oops.txt
  23. Composing Commits $ git status On branch master Untracked files:

    (use "git add <file>..." to include in what will be committed) oops.txt nothing added to commit but untracked files present (use "git add" to track) $ rm oops.txt See the current state: git status Check in on the status:
  24. Composing Commits Working Directory Repository Staging Area git add git

    commit You can add and remove files from the staging area before saving a snapshot with git commit git reset HEAD <file>
  25. Composing Commits • Good commits are atomic: they contain a

    small set of closely related changes. • If you're unit testing, make sure you run your tests before finalizing a commit. If you revert back to a saved snapshot later, you don't want things to be broken! • Don't be afraid to commit small chunks frequently. Remember, your project history exists for the rest of the team and your future self. You'll appreciate small, simple commits when you review the history in a few months. • This can be hard! We'll look at some tips for breaking up big commits later.
  26. $ git add fizzbuzz.py Composing Commits We'll keep improving our

    fizzbuzz script. Let's print "fizz" for multiples of 3: def fizzbuzz(): for i in range(1, 101): if i % 3 == 0: print("fizz") else: print(i) if __name__ == '__main__': fizzbuzz() (Add a change: git add) ...and stage the change.
  27. $ git diff --cached diff --git a/fizzbuzz.py b/fizzbuzz.py index 8f1aa82..ae181ec

    100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,6 +1,9 @@ def fizzbuzz(): for i in range(1, 101): - print(i) + if i % 3 == 0: + print("fizz") + else: + print(i) if __name__ == '__main__': fizzbuzz() Composing Commits See what you're going to change: git diff --cached
  28. Composing Commits $ git commit -m "Print fizz for multiples

    of 3" Save a set of changes: git commit -m <message> The diff looks good! Let's commit the change.
  29. $ git add -A (Add all new changes: git add

    -A) Stage the change... $ git commit -m "Print buzz for multiples of 5" (Save a set of changes: git commit -m <message>) ...and save a commit. Composing Commits Now let's handle printing "buzz" for multiples of 5: def fizzbuzz(): for i in range(1, 101): if i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i) if __name__ == '__main__': fizzbuzz()
  30. Add all new changes and save: git commit -am <message>

    Here's a new trick! $ git commit -am "Print fizzbuzz for multiples of 3 and 5" Composing Commits And finally, printing "fizzbuzz" for multiples of 3 and 5: def fizzbuzz(): for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i)
  31. Viewing History See history: git log $ git log commit

    1a907900d316cd28697114fc9294671373b83dce Author: Connor Mendenhall <[email protected]> Date: Sun Feb 5 21:27:48 2017 -0500 Print fizzbuzz for multiples of 3 and 5 commit 1e21dbbf51411f12821c6138b6cdd3f3f232b1e6 Author: Connor Mendenhall <[email protected]> Date: Sun Feb 5 21:24:34 2017 -0500 Print buzz for multiples of 5 commit d90ddd011b2a902ece0fde38b07bb6b1b4167941 Author: Connor Mendenhall <[email protected]> Date: Sun Feb 5 21:21:27 2017 -0500 Print fizz for multiples of 3 commit 78e170624366ce27a701ecc00e999be88e013729 Author: Connor Mendenhall <[email protected]> Date: Sun Feb 5 18:40:26 2017 -0500 Print numbers 1 to 100 commit d0a1fb1a6cb870240ca33e68559026bc51cf6036 Author: Connor Mendenhall <[email protected]> Date: Sun Feb 5 18:36:59 2017 -0500 Print hello world message
  32. Visualizing Git History Print hello world message 78e170 Print numbers

    1 to 100 d90ddd Print fizz for multiples of 3 d0a1fb
  33. Visualizing Git History Print hello world message 78e170 Print numbers

    1 to 100 d90ddd Print fizz for multiples of 3 1e21db Print buzz for multiples of 5 d0a1fb
  34. Visualizing Git History Print hello world message 78e170 Print numbers

    1 to 100 d90ddd Print fizz for multiples of 3 1e21db Print buzz for multiples of 5 1a9079 Print fizzbuzz for multiples of 3 and 5 d0a1fb
  35. Viewing History $ git diff d0a1fb1a6cb8 diff --git a/fizzbuzz.py b/fizzbuzz.py

    index 3fb2306..41cffd1 100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,5 +1,13 @@ def fizzbuzz(): - print('hello world!') + for i in range(1, 101): + if i % 3 == 0 and i % 5 == 0: + print("fizzbuzz") + elif i % 3 == 0: + print("fizz") + elif i % 5 == 0: + print("buzz") + else: + print(i) Compare current code with the past: git diff <commit>
  36. Time Travel Go back to a saved commit: git checkout

    <commit> $ git checkout 78e17 Note: checking out '78e17'. 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 78e1706... Print numbers 1 to 100
  37. Time Travel Go back to a saved commit: git checkout

    <commit> $ cat fizzbuzz.py def fizzbuzz(): for i in range(1, 101): print(i) if __name__ == '__main__': fizzbuzz()
  38. $ git commit -am "Alter the past." [detached HEAD fbc9008]

    Alter the past. 1 file changed, 1 insertion(+) Time Travel Let's make a change. Here's the result of git diff: $ git diff diff --git a/fizzbuzz.py b/fizzbuzz.py index 8f1aa82..8485759 100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,6 +1,7 @@ def fizzbuzz(): for i in range(1, 101): print(i) + print("I have only done this once before.") ...and commit. (Add all new changes and save: git commit -am <message>)
  39. Time Travel $ git log --oneline 68e10a6 Alter the past.

    78e1706 Print numbers 1 to 100 d0a1fb1 Print hello world message See compact history: git log --oneline $ git status HEAD detached from 78e1706 nothing to commit, working tree clean Let's check the current status: Detached HEAD protected us from creating time paradoxes by putting us in an isolated environment!
  40. Time Travel $ git checkout master Previous HEAD position was

    78e1706... Print numbers 1 to 100 Switched to branch 'master' Return to the main timeline: git checkout master $ git log --oneline 1a90790 Print fizzbuzz for multiples of 3 and 5 1e21dbb Print buzz for multiples of 5 d90ddd0 Print fizz for multiples of 3 78e1706 Print numbers 1 to 100 d0a1fb1 Print hello world message Let's take a look at the history: (See compact history: git log --oneline)
  41. Time Travel Go back to a saved commit (safety not

    guaranteed): git reset <commit> $ git reset 78e1706 Unstaged changes after reset: M fizzbuzz.py $ git log --oneline 78e1706 Print numbers 1 to 100 d0a1fb1 Print hello world message Our new view of history: (See compact history: git log --oneline)
  42. $ git diff diff --git a/fizzbuzz.py b/fizzbuzz.py index 8f1aa82..41cffd1 100644

    --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,6 +1,13 @@ def fizzbuzz(): for i in range(1, 101): - print(i) + if i % 3 == 0 and i % 5 == 0: + print("fizzbuzz") + elif i % 3 == 0: + print("fizz") + elif i % 5 == 0: + print("buzz") + else: + print(i) Time Travel ...but changes from the "future" are saved: (See what changed: git diff)
  43. $ git commit -am "Implement complete fizzbuzz" [master e863034] Implement

    complete fizzbuzz 1 file changed, 8 insertions(+), 1 deletion(-) Time Travel We can commit them in one large chunk... (Add all new changes and save: git commit -am <message>) $ git log --oneline e863034 Implement complete fizzbuzz 78e1706 Print numbers 1 to 100 d0a1fb1 Print hello world message But it changes history on the main timeline! (See compact history: git log --oneline) It's OK to change history when you're the only one in the universe, but it's rude when you're working with other people! Safe time travelers know it's dangerous to change the past. We'll learn how to handle this safely and politely in the next section...
  44. Creating Parallel Universes Create a new timeline: git branch <branch_name>

    $ git branch command-line-argument See all timelines: git branch $ git branch command-line-argument * master Move between timelines: git checkout <branch_name> $ git checkout command-line-argument Switched to branch 'command-line-argument'
  45. Creating Parallel Universes You can think of your new branch

    as a parallel universe that starts as an exact copy of its parent. Now let's change things by adding some code. This will make our fizzbuzz script read a number from the command line instead of counting to 100 each time: import sys def fizzbuzz(max_count): for i in range(1, max_count): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i) if __name__ == '__main__': count_argument = int(sys.argv[1]) fizzbuzz(count_argument)
  46. Creating Parallel Universes $ python fizzbuzz.py 7 1 2 fizz

    4 buzz fizz Now we can run it like this: Add all new changes and save: git commit -am <message> $ git commit -am "Add command line argument" [command-line-argument 8d8c7f2] Add command line argument 1 file changed, 6 insertions(+), 3 deletions(-)
  47. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz d0a1fb master $ git log --oneline e863034 Implement complete fizzbuzz 78e1706 Print numbers 1 to 100 d0a1fb1 Print hello world message (See compact history: git log --oneline)
  48. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz d0a1fb master command-line-argument Create a new timeline: git branch <branch_name> $ git branch command-line-argument
  49. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master command-line-argument Move between timelines: git checkout <branch_name> $ git checkout command-line-argument Add all new changes and save: git commit -am <message> $ git commit -am "Add command line argument"
  50. Visualizing Branches Oops! Our fizzbuzz program blows up if we

    run it without an argument: $ python fizzbuzz.py Traceback (most recent call last): File "fizzbuzz.py", line 15, in <module> count_argument = int(sys.argv[1]) IndexError: list index out of range
  51. Visualizing Branches Let's add some code to fall back to

    counting to 100. Here's the diff: $ git diff diff --git a/fizzbuzz.py b/fizzbuzz.py index b986f62..5191b14 100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -12,5 +12,8 @@ def fizzbuzz(max_count): print(i) if __name__ == '__main__': - count_argument = int(sys.argv[1]) - fizzbuzz(count_argument) + if len(sys.argv) > 1: + count_argument = int(sys.argv[1]) + fizzbuzz(count_argument) + else: + fizzbuzz(100) (See what changed: git diff)
  52. Visualizing Branches Add all new changes and save: git commit

    -am <message> $ git commit -am "Count to 100 by default" [command-line-argument 0d61ee0] Count to 100 by default Date: Tue Feb 7 19:23:28 2017 -0500 1 file changed, 5 insertions(+), 2 deletions(-)
  53. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master command-line-argument
  54. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master 0d61ee Count to 100 by default command-line-argument
  55. Visualizing Branches Move between timelines: git checkout <branch_name> $ git

    checkout master Switched to branch 'master' Now let's jump back to the main timeline: Return to the main timeline: git checkout master
  56. Visualizing Branches After jumping back to master, our fizzbuzz file

    is just as we left it: $ cat fizzbuzz.py def fizzbuzz(): for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i) if __name__ == '__main__': fizzbuzz()
  57. Visualizing Branches Let's make a (totally contrived) change: def fizzbuzz():

    + print('Welcome to fizzbuzz!') for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") Add all new changes and save: git commit -am <message> $ git commit -am "Print welcome message" [master 0351fbd] Print welcome message 1 file changed, 1 insertion(+)
  58. Visualizing Branches Let's make a (totally contrived) change: def fizzbuzz():

    + print('Welcome to fizzbuzz!') for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") Add all new changes and save: git commit -am <message> $ git commit -am "Print welcome message" [master 0351fbd] Print welcome message 1 file changed, 1 insertion(+)
  59. Visualizing Branches I feel like it's still missing something... def

    fizzbuzz(): + print('~*~*~* Welcome to fizzbuzz! *~*~*~') for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") Add all new changes and save: git commit -am <message> $ git commit -am "Print very fancy welcome message" [master 34a0124] Print very fancy welcome message 1 file changed, 1 insertion(+), 1 deletion(-)
  60. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master 0d61ee Count to 100 by default command-line-argument
  61. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master 0d61ee Count to 100 by default command-line-argument Here's where we left off. The command-line-argument branch was two commits "ahead" of master.
  62. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb master 0d61ee Count to 100 by default ➜ command-line-argument From now on, we'll use this arrow to mean "this branch is checked out."
  63. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument First, we checked out master...
  64. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f Print welcome message Made one commit...
  65. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message And then another. Notice how the "tip" of the master branch moves along as we commit!
  66. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message Our two branches start with a shared history, but diverge over time.
  67. Visualizing Branches Print hello world message 78e170 Print numbers 1

    to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message Our two branches start with a shared history, but diverge over time.
  68. Comparing Parallel Universes $ git diff command-line-argument diff --git a/fizzbuzz.py

    b/fizzbuzz.py index 5191b14..e3baaea 100644 --- a/fizzbuzz.py +++ b/fizzbuzz.py @@ -1,7 +1,6 @@ -import sys - -def fizzbuzz(max_count): - for i in range(1, max_count): +def fizzbuzz(): + print("~*~*~* Welcome to fizzbuzz! *~*~*~") + for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: See what's different between timelines: git diff <branch> (continued)
  69. Comparing Parallel Universes See what's different between timelines: git diff

    <branch> @@ -12,8 +11,4 @@ def fizzbuzz(max_count): print(i) if __name__ == '__main__': - if len(sys.argv) > 1: - count_argument = int(sys.argv[1]) - fizzbuzz(count_argument) - else: - fizzbuzz(100) + fizzbuzz() Git diff doesn't just let us compare commits across time—it lets us compare parallel universes!
  70. Collapsing Parallel Universes What if we want to save both

    the very fancy welcome message and the command line argument? Merge another timeline into this one: git merge <branch>
  71. Collapsing Parallel Universes Print hello world message 78e170 Print numbers

    1 to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message Let's visualize this one first...
  72. Collapsing Parallel Universes Print hello world message 78e170 Print numbers

    1 to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message We want to create a new commit...
  73. Collapsing Parallel Universes Print hello world message 78e170 Print numbers

    1 to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message ...with two parents, instead of one!
  74. Collapsing Parallel Universes Merge another timeline into this one: git

    merge <branch> $ git merge command-line-argument Auto-merging fizzbuzz.py CONFLICT (content): Merge conflict in fizzbuzz.py Automatic merge failed; fix conflicts and then commit the result.
  75. Collapsing Parallel Universes Merge another timeline into this one: git

    merge <branch> $ git merge command-line-argument Auto-merging fizzbuzz.py CONFLICT (content): Merge conflict in fizzbuzz.py Automatic merge failed; fix conflicts and then commit the result.
  76. Resolving Conflicts Resolving conflicts between parallel timelines is the hardest

    part of time travel, and sometimes Git needs human expertise to collapse two universes back into one successfully. Merge conflicts may seem scary at first, but they're just Git's way of saying "I need human assistance to combine these two histories." 
 Merge conflicts happen to everyone. Keep calm and use the tools you know to resolve them.
  77. $ git status On branch master You have unmerged paths.

    (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: fizzbuzz.py no changes added to commit (use "git add" and/or "git commit -a") Resolving Conflicts Use git status to see which files need to be fixed: (See the current state: git status)
  78. Resolving Conflicts When a conflict occurs, git automatically adds markers

    around lines of code that have changed in both histories: <<<<<<< HEAD def fizzbuzz(): print("~*~*~* Welcome to fizzbuzz! *~*~*~") for i in range(1, 101): ======= import sys def fizzbuzz(max_count): for i in range(1, max_count): >>>>>>> command-line-argument if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i)
  79. Resolving Conflicts We want to keep the welcome message... <<<<<<<

    HEAD def fizzbuzz(): print("~*~*~* Welcome to fizzbuzz! *~*~*~") for i in range(1, 101): ======= import sys def fizzbuzz(max_count): for i in range(1, max_count): >>>>>>> command-line-argument if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i)
  80. Resolving Conflicts ...as well as the changes we made to

    the fizzbuzz function. <<<<<<< HEAD def fizzbuzz(): print("~*~*~* Welcome to fizzbuzz! *~*~*~") for i in range(1, 101): ======= import sys def fizzbuzz(max_count): for i in range(1, max_count): >>>>>>> command-line-argument if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i)
  81. Resolving Conflicts It's up to us to delete the alligators

    and equals signs and keep the code we want: import sys def fizzbuzz(max_count): print("~*~*~* Welcome to fizzbuzz! *~*~*~") for i in range(1, max_count): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: print("fizz") elif i % 5 == 0: print("buzz") else: print(i)
  82. $ git diff diff --cc fizzbuzz.py index e3baaea,5191b14..0000000 --- a/fizzbuzz.py

    +++ b/fizzbuzz.py @@@ -1,6 -1,7 +1,8 @@@ - def fizzbuzz(): + import sys + + def fizzbuzz(max_count): + print("~*~*~* Welcome to fizzbuzz! *~*~*~") - for i in range(1, 101): + for i in range(1, max_count): if i % 3 == 0 and i % 5 == 0: print("fizzbuzz") elif i % 3 == 0: Resolving Conflicts Once we've told Git how to merge two timelines into one, we can commit the change. First, look at the diff (and run your tests) to make sure there are no stray merge markers: (See what changed: git diff)
  83. Resolving Conflicts $ git add fizzbuzz.py (Add a change: git

    add <file>) Add the file... $ git commit -m "Print buzz for multiples of 5" [master a473c0e] Merge branch 'command-line-argument' (Save a set of changes: git commit -m <message>) ...and commit.
  84. Resolving Conflicts $ git log -n 1 commit a473c0e0d340fb087537dfbf5f3d7741321f5517 Merge:

    34a0124 0d61ee0 Author: Connor Mendenhall <[email protected]> Date: Tue Feb 7 20:55:02 2017 -0500 Merge branch 'command-line-argument' (See history: git log) If we look at the log, we now see a new commit, and the entry includes the commit IDs of both its parents!
  85. Collapsing Parallel Universes Print hello world message 78e170 Print numbers

    1 to 100 e86303 Implement complete fizz buzz 8d8c7f Add command line argument d0a1fb ➜ master 0d61ee Count to 100 by default command-line-argument 8d8c7f 0d61ee Print welcome message Print very fancy welcome message a473c0 ...with two parents, instead of one! Merge 'command-line-argument'
  86. Exercise: Explain Git with D3 Congratulations! Your git toolbox now

    contains all the commands and concepts you need to work effectively in a local repository. But practice makes perfect! Check out the interactive site below to visualize and practice the commands we've covered so far: https://onlywei.github.io/explain-git-with-d3/
  87. Remote Repositories Add a remote repository: git remote add <name>

    <url> $ git remote add github https://github.com/ecmendenhall/horsebook Show remote repositories: git remote -v $ git remote -v github https://github.com/ecmendenhall/horsebook (fetch) github https://github.com/ecmendenhall/horsebook (push)
  88. Remote Repositories $ git log --oneline 9caac00 Fix one more

    relative path. 539a2be Missed a relative path! 374ba4c Use relative paths everywhere for gh-pages. 03bef96 Add example profile page. 1abde88 Add Horsebook logo. 258fc3e Tweak CSS gradient. 328ad0a Add splash page image. 38d4b70 Add custom CSS. 64dced6 Update homepage markup. fbd2542 Add static page scaffolding. 5718bb0 Add README. (See compact history: git log --oneline) Before we go further, let's look at the history of this repo:
  89. Remote Repositories Load updates from remote repository: git fetch <remote>

    $ git fetch github remote: Counting objects: 3, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. From https://github.com/ecmendenhall/horsebook * [new branch] master -> github/master
  90. Remote Repositories Load updates from remote repository: git fetch <remote>

    $ git fetch github remote: Counting objects: 3, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. From https://github.com/ecmendenhall/horsebook * [new branch] master -> github/master Remote branches have a prefix!
  91. Remote Repositories $ git log --oneline 9caac00 Fix one more

    relative path. 539a2be Missed a relative path! 374ba4c Use relative paths everywhere for gh-pages. 03bef96 Add example profile page. 1abde88 Add Horsebook logo. 258fc3e Tweak CSS gradient. 328ad0a Add splash page image. 38d4b70 Add custom CSS. 64dced6 Update homepage markup. fbd2542 Add static page scaffolding. 5718bb0 Add README. (See compact history: git log --oneline) Fetching from a remote does not change our history!
  92. Remote Repositories $ git branch -a * master remotes/github/master (See

    all branches: git branch -a) But it does create a new (remote) branch: Note the prefix, like we saw before!
  93. Remote Repositories Apply updates from remote repository: git pull <remote>

    <branch> $ git pull github master From https://github.com/ecmendenhall/horsebook * branch master -> FETCH_HEAD Updating 9caac00..0fcae49 Fast-forward index.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) Pulling applies changes from the remote to your local branch.
  94. Remote Repositories $ git log --oneline 0fcae49 Add signup form.

    9caac00 Fix one more relative path. 539a2be Missed a relative path! 374ba4c Use relative paths everywhere for gh-pages. 03bef96 Add example profile page. 1abde88 Add Horsebook logo. 258fc3e Tweak CSS gradient. 328ad0a Add splash page image. 38d4b70 Add custom CSS. 64dced6 Update homepage markup. fbd2542 Add static page scaffolding. 5718bb0 Add README. (See compact history: git log --oneline) Pulling from a remote applies the changes. We now have one new commit in our history.
  95. Remote Repositories $ git diff diff --git a/index.html b/index.html index

    be6ba31..8570eea 100755 --- a/index.html +++ b/index.html @@ -57,6 +57,7 @@ <a href="#">About</a> <a href="#">Terms</a> <a href="#">Privacy</a> + <a href="#">Jobs</a> </span> </footer> </div> (See what changed: git diff) What about sending our local changes to a remote repository? Let's follow the normal workflow for making a local change: $ git commit -am "Add jobs link." [master 8076269] Add jobs link. 1 file changed, 1 insertion(+) (Add all new changes and save: git commit -am <message>)
  96. Remote Repositories Save your changes in a remote repository: git

    push <remote> <branch> $ git push github master Username for 'https://github.com': ecmendenhall Password for 'https://[email protected]': Counting objects: 3, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 306 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 2 local objects. To https://github.com/ecmendenhall/horsebook 0fcae49..8076269 master -> master We've successfully "pushed up" our changes. Check out the commit IDs on the last line: the remote branch advanced from 0fcae49 to 8076269.
  97. Remote Repositories Make a local copy of a remote repository:

    git clone <repository URL> $ git clone https://github.com/ecmendenhall/horsebook Cloning into 'horsebook'... remote: Counting objects: 80, done. remote: Compressing objects: 100% (47/47), done. remote: Total 80 (delta 32), reused 75 (delta 28), pack-reused 0 Unpacking objects: 100% (80/80), done.
  98. Remote Repositories $ git remote -v origin https://github.com/ecmendenhall/horsebook (fetch) origin

    https://github.com/ecmendenhall/horsebook (push) Cloned repos come with a remote named "origin" preconfigured. (Show remote repositories: git remote -v)
  99. Remote Repositories $ git remote rename origin roflcopter $ git

    remote -v roflcopter https://github.com/ecmendenhall/horsebook (fetch) roflcopter https://github.com/ecmendenhall/horsebook (push) ...but "origin" is just a name like any other! Rename a remote repository locally: git remote rename <remote> <name>
  100. Feature Branching master ➜ hot-new-feature $ git clone <repository URL>

    $ git branch hot-new-feature $ git checkout hot-new-feature
  101. Feature Branching ➜ hot-new-feature master $ git clone <repository URL>

    $ git branch hot-new-feature $ git checkout hot-new-feature $ git commit
  102. Feature Branching master $ git clone <repository URL> $ git

    branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit ➜ hot-new-feature
  103. Feature Branching master $ git clone <repository URL> $ git

    branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit ➜ hot-new-feature
  104. Feature Branching ➜ master $ git clone <repository URL> $

    git branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master hot-new-feature
  105. Feature Branching ➜ master $ git clone <repository URL> $

    git branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master $ git pull origin master hot-new-feature
  106. Feature Branching ➜ master $ git clone <repository URL> $

    git branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master $ git pull origin master $ git merge hot-new-feature hot-new-feature
  107. Feature Branching ➜ master $ git clone <repository URL> $

    git branch hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master $ git pull origin master $ git merge hot-new-feature hot-new-feature How can we create this merge commit?
  108. Pull Requests ...They're a way to say "this branch is

    done, please review it and merge to master," and a tool to facilitate code review and conversation.
  109. master hot-new-feature $ git clone <repository URL> $ git branch

    hot-new-feature ➜ master Resolving Remote Conflicts
  110. master ➜ hot-new-feature $ git clone <repository URL> $ git

    branch hot-new-feature $ git checkout hot-new-feature Resolving Remote Conflicts
  111. ➜ hot-new-feature master $ git clone <repository URL> $ git

    branch hot-new-feature $ git checkout hot-new-feature $ git commit Resolving Remote Conflicts
  112. master $ git clone <repository URL> $ git branch hot-new-feature

    $ git checkout hot-new-feature $ git commit $ git commit ➜ hot-new-feature Resolving Remote Conflicts
  113. master $ git clone <repository URL> $ git branch hot-new-feature

    $ git checkout hot-new-feature $ git commit $ git commit $ git commit ➜ hot-new-feature Resolving Remote Conflicts
  114. ➜ master $ git clone <repository URL> $ git branch

    hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master hot-new-feature Resolving Remote Conflicts
  115. ➜ master $ git clone <repository URL> $ git branch

    hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master $ git commit hot-new-feature Resolving Remote Conflicts
  116. ➜ master $ git clone <repository URL> $ git branch

    hot-new-feature $ git checkout hot-new-feature $ git commit $ git commit $ git commit $ git checkout master $ git commit $ git commit hot-new-feature Resolving Remote Conflicts
  117. ➜ master $ git branch hot-new-feature $ git checkout hot-new-feature

    $ git commit $ git commit $ git commit $ git checkout master $ git commit $ git commit $ git commit hot-new-feature Resolving Remote Conflicts
  118. ➜ master $ git checkout hot-new-feature $ git commit $

    git commit $ git commit $ git checkout master $ git commit $ git commit $ git commit $ git merge hot-new-feature hot-new-feature Resolving Remote Conflicts
  119. ➜ master $ git checkout hot-new-feature $ git commit $

    git commit $ git commit $ git checkout master $ git commit $ git commit $ git commit $ git merge hot-new-feature hot-new-feature Auto-merging hot-new-feature CONFLICT (content): Merge conflict in file.py Automatic merge failed; fix conflicts and then commit the result. Resolving Remote Conflicts
  120. ➜ master $ git checkout hot-new-feature $ git commit $

    git commit $ git commit $ git checkout master $ git commit $ git commit $ git commit $ git merge hot-new-feature hot-new-feature Auto-merging hot-new-feature CONFLICT (content): Merge conflict in file.py Automatic merge failed; fix conflicts and then commit the result. Resolving Remote Conflicts
  121. Merging From the Command Line ➜ master hot-new-feature Auto-merging hot-new-feature

    CONFLICT (content): Merge conflict in file.py Automatic merge failed; fix conflicts and then commit the result.
  122. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  123. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  124. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  125. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  126. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  127. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  128. master $ git checkout hot-new-feature $ git rebase master ➜

    hot-new-feature Rebasing Feature Branches
  129. Exercise: Contribute to Horsebook Horsebook has the potential to be

    the world's greatest social network for horses, but it has a lot of features left to complete. Check the list of issues, clone the repo, check out a feature branch, and open a pull request to close one out! https://github.com/ecmendenhall/horsebook
  130. Writing Good Commit Messages Commit messages are important! A diff

    can describe what code changed, but only a commit message can describe why code changed. Descriptive messages help establish context later. More on this at http://chris.beams.io/posts/git-commit/ 1. Separate subject from body with a blank line 2. Limit the subject line to 50 characters 3. Capitalize the subject line 4. Do not end the subject line with a period 5. Use the imperative mood in the subject line 6. Wrap the body at 72 characters 7. Use the body to explain what and why vs. how Seven rules for great git commits:
  131. .gitignore: Choose Files To Always Ignore There may be files

    in your project directory you never want to track with Git— things like media files, build artifacts, or secret configuration values. To tell Git to ignore a file forever, create a file named .gitignore in your project directory: Github maintains a huge collection of example .gitignore files here: https://github.com/github/gitignore # User-specific files *.suo *.user *.userosscache *.sln.docstates # Visual Studio 2015 cache/options directory .vs/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ **/Properties/launchSettings.json
  132. Line-by-Line History With git blame $ git blame index.html -L

    33,33 68c240e5 (Connor Mendenhall 2017-02-07 23:00:48 -0500 33) <h3>Connect with horses and the world around you on Horsebook.</h3> $ git blame index.html -L 33,33 68c240e5^ 57e131f4 (Connor Mendenhall 2017-02-07 21:03:48 -0500 33) <h3>Finally, a social network for horses.</h3> See the last commit that changed a line: git blame <file> -L <start>,<end> Git blame can be pretty rough from the command line, but Github and other GUI tools do a nice job presenting line by line history!
  133. Commit Line-by-Line With git add -p $ git add -p

    diff --git a/index.html b/index.html index 130258d..584132c 100755 --- a/index.html +++ b/index.html @@ -30,7 +30,7 @@ <div class="homepage row"> <div class="col-md-8 splash-image"> - <h3>Horsebook helps you connect and share with the horses in your life.</h3> + <h3>Connect with horses and the world around you on Horsebook.</h3> <img src="img/world-map.png" class="img-responsive"> </div> <div class="col-md-4"> Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? Compose a commit line by line: git add -p
  134. Search Repo For Patterns $ git add -p $ git

    grep horse README.md: Finally, Facebook for horses. index.html: <img src="img/horsebook-logo.png" alt="Horsebook.. index.html: <p>Finally, a social network for horses.</p> index.html: <h3>Connect with horses and the world around you... index.html: This innovative new space for people and horses... profiles/example.html: <img src="../img/horsebook- logo.png... profiles/example.html: <img src="../img/horses/example-horse.png... profiles/example.html: We don't know very much about this horse... Search in repo: git grep <pattern>
  135. Marking Important Commits $ git tag -a v1.0 -m "Version

    1: Awesome Apricot" $ git tag -l v1.0 Mark an Important Commit: git tag -a <name> -m <message> Tags are like branches that don't change: they point to one commit forever. They can be useful for marking fixed points in time, like major releases. You can check out, branch from, and compare with tags just like you can with branches.
  136. Temporarily Saving Work in Progress Temporarily stash work in progress:

    git stash $ git stash Saved working directory and index state WIP on update-homepage- slogan: 68c240e Update homepage slogan HEAD is now at 68c240e Update homepage slogan
  137. Temporarily Saving Work in Progress Restore stashed code: git stash

    pop $ git stash pop On branch update-homepage-slogan Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: index.html no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (3c7414fd12fa7a8672d953ebd59837a3924be821)
  138. Adding Aliases For Common Commands $ git config --global alias.co

    checkout Once you're comfortable with Git, you may want to add aliases for common commands. You can do this through the configuration system: co = checkout ci = commit st = status dc = diff --cached di = diff aa = add --all unstage = reset HEAD -- last = log -1 HEAD br = branch praise = blame A few common aliases:
  139. Your Friends Need Help But You Want To Deceive Them

    https://git-man-page-generator.lokaltog.net/
  140. You Staged A File By Mistake $ git add oops.txt

    $ git status -s A oops.txt $ git reset HEAD oops.txt $ git status -s ?? oops.txt git reset HEAD <file>
  141. You Deleted A File By Mistake $ rm index.html $

    ls css/ fonts/ img/ js/ profiles/ README.md $ git checkout -- index.html $ ls css/ fonts/ img/ index.html js/ profiles/ README.md git checkout -- <file>
  142. You Wrote a Bad Commit Message $ git commit -am

    "changed some thngs" [update-homepage-slogan 2f0cd43] changed some thngs 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 widgetfactoryfactory.py $ git commit --amend -m "Add WidgetFactoryFactory" [update-homepage-slogan 1baccc2] Add WidgetFactoryFactory Date: Wed Feb 8 01:13:55 2017 -0500 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 abstractwidgetfactorybuilder.py Change a commit message: git commit --amend
  143. You Forgot a File In The Last Commit $ git

    commit --amend -m "Add WidgetFactoryFactory" [update-homepage-slogan 1baccc2] Add WidgetFactoryFactory Date: Wed Feb 8 01:13:55 2017 -0500 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 abstractwidgetfactorybuilder.py $ git add abstractwidgetfactoryconfigurator.py $ git commit --amend --no-edit [update-homepage-slogan 3595556] Add WidgetFactoryFactory Date: Wed Feb 8 01:13:55 2017 -0500 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 abstractwidgetfactorybuilder.py create mode 100644 abstractwidgetfactoryconfigurator.py Change a commit without changing the message: git commit --amend --no-edit
  144. You Pushed a Bad Commit $ git log --oneline 9bd75fe

    Add WidgetFactoryFactory $ git revert 9bd75fe [update-homepage-slogan e995730] Revert "Add WidgetFactoryFactory" 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 abstractwidgetfactorybuilder.py delete mode 100644 abstractwidgetfactoryconfigurator.py $ git log --oneline e995730 Revert "Add WidgetFactoryFactory" 9bd75fe Add WidgetFactoryFactory Undo a commit: git revert <commit>
  145. You Made Too Many Changes At Once Add changes one

    line at a time: git add -p $ git add -p diff --git a/index.html b/index.html index 130258d..584132c 100755 --- a/index.html +++ b/index.html @@ -30,7 +30,7 @@ <div class="homepage row"> <div class="col-md-8 splash-image"> - <h3>Horsebook helps you connect and share with the horses in your life.</h3> + <h3>Connect with horses and the world around you on Horsebook.</h3> <img src="img/world-map.png" class="img-responsive"> </div> <div class="col-md-4"> Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?
  146. You Tried to Push to a Remote and it Failed

    Apply remote updates and reapply commits: git pull --rebase
  147. Your Feature Branch Is Too Different From Master Reapply commits

    starting from another point in history: git rebase -i master
  148. You Merged a Github PR Too Soon Use the Github

    revert button: https://github.com/ blog/1857-introducing-the-revert-button
  149. You Checked In a Secret Use BFG Repo cleaner if

    you still need to get rid of it: https://rtyley.github.io/bfg-repo-cleaner/ More information on removing sensitive data here: https://help.github.com/articles/removing- sensitive-data-from-a-repository/ Consider it compromised forever if you pushed the commit! ⚠
  150. Git Command Cheat Sheet Create a repository: git init See

    the current state: git status Add a change: git add Save a set of changes: git commit -m <message> See what changed: git diff Add all new changes: git add -A Remove a file from the staging area: git reset HEAD <file> See what you're going to change: git diff --cached
  151. Git Command Cheat Sheet Add all new changes and save:

    git commit -am <message> See history: git log Compare current code with the past: git diff <commit> Go back to a saved commit: git checkout <commit> See compact history: git log --oneline Return to the main timeline: git checkout master Go back to a saved commit (safety not guaranteed): git reset <commit>
  152. Git Command Cheat Sheet Create a new timeline: git branch

    <branch_name> See all timelines: git branch Move between timelines: git checkout <branch_name> See what's different between timelines: git diff <branch> Add a remote repository: git remote add <name> <url> Show remote repositories: git remote -v Load updates from remote repository: git fetch <remote>
  153. Git Command Cheat Sheet Save your changes in a remote

    repository: git push <remote> <branch> Make a local copy of a remote repository: git clone <repository URL> Rename a remote repository locally: git remote rename <remote> <name> See the last commit that changed a line: git blame <file> -L <start>,<end> Search in repo: git grep <pattern> Mark an Important Commit: git tag -a <name> -m <message>
  154. Git Command Cheat Sheet Temporarily stash work in progress: git

    stash Restore stashed code: git stash pop Change a commit message: git commit --amend Change a commit without changing the message: git commit --amend --no-edit Undo a commit: git revert <commit>
  155. Git Command Cheat Sheet Add changes one line at a

    time: git add -p Copy a commit from another branch: git cherry-pick <commit>