alright let's get started with today's
lecture so actually before we get
started one quick note about office
hours it seemed from the poll that some
people were under the impression that
the office hours that follows each
lecture is just about that day's
lectures topics and this is not the case
you can come to office hours and ask us
questions about any lecture whether it's
the previous day or from the previous
week or even things not exactly covered
in this class that you're just curious
about so yeah come to office hours with
questions about anything office hours
are in the 32 g9 lounge so building 32
also known as a Stata Center has two
towers the G tower and the D tower so
we're in the gates tower on the ninth
floor so if you take the elevator all
the way up there's the lounge right in
front of you okay cool so today we're
going to be talking about version
control systems so I just want to get a
sense of whether you guys have used
version control systems before so could
you raise your hand if you have any
experience with git or any other version
control system like subversion or
mercurial or anything else oh great so
that's a good number of you so I won't
talk about version control systems in
general way too much then we'll pretty
quickly get into the details of git and
like it's data model and its internals
but just as a quick summary version
control systems are tools that are used
to keep track of changes to source code
or other collections of files or folders
and as the name implies these tools help
track the history of changes to some set
of documents and in addition to doing
that they facilitate collaboration so
they're really useful for working with a
group of people on a software project
Virna control systems track changes to a
folder and its contents in a series of
snapshots so you capture the entire
state of a folder and everything inside
like a software project and you have
multiple of these in a series of
snapshots each snapshot encapsulate the
entire set of files and folders
contained within some top-level
directory and then version control
systems also maintain a bunch of
metadata along with the actual changes
to the content and this is to make it
possible to figure things out like who
authored a particular change to a
particular file or when was a particular
change made
and slow version control systems
maintain metadata like authors and
commit timestamps and you can also
attach extra messages to these snapshots
and things like that and so why is
version control useful
well it's useful even when you're
working on projects by yourself so you
can use it to look at old versions of
code you've written figure out like why
something was changed by looking at
commit messages work on different things
in parallel without conflicts by using
different branches of development or be
able to work on bug fixes while keeping
work on different features independent
things like that and so it's an
invaluable tool even if you're working
just by yourself even on a small scale
project like I think the instructors of
this course use git even on things like
homework assignments or class projects
even small scale things in addition to
our research or larger software projects
and then of course version control is a
really powerful tool for working with
other people so it's useful for sending
patches of code around resolving
conflicts when different people are
working on the same piece of code at the
same time things like that and so it's a
really powerful tool for working by
yourself or with others and it also has
a neat functionality to let you answer
questions that would otherwise be kind
of hard to answer like who wrote a
particular module in a software project
or who edited a particular line in a
particular software project why was this
particular line change when was it
changed by whom things like that and
version control systems also have some
really powerful functionality that we
might cover at the end of today's
lecture
or you can find the lecture notes if we
don't have time to do things like
supposed to have some project you've
been working on for a couple years and
then you notice that some funny thing
about the project was broken like you
have some unit test that doesn't pass
anymore and it wasn't broken just now it
was broken some time ago and you don't
know exactly when this regression was
introduced well written control systems
have a way of automatically identifying
this like you can take it and give it a
unit test that's currently failing but
you know was passing at some point in
the past and it can binary search your
history and figure out exactly what
change to your code made it break so
lots of really powerful fancy features
if you know how to use these tools
properly
there are a number of version control
systems out there and get has become
kind of the de facto standard for
version control so that's what we're
going to be covering in today's lecture
one comic I want to show you which was
on the screen before hand let me bring
it back up so this is an xkcd comic that
illustrates gets reputation so let me
read it out loud for you
this is good it tries collaborative work
on projects through a beautiful
distributed graph theory tree model cool
how do we use it no idea just memorize
these shell commands and type them to
sync up if you get errors save your work
elsewhere delete the project and
download a fresh copy so maybe some
people may not want to raise their hands
for this but raise your hand if you've
ever done this before
I certainly have when I was learning
this tool so good number of you here
have done this before so the goal of
this lecture is to make it so you don't
have to do this anymore unfortunately as
this comic illustrates gets interface is
a pretty terribly designed interface
it's a leaky abstraction and so for this
reason we believe that learning get
topped down starting with the interface
is maybe not the best way to go and it
can lead to some confusion it's possible
like this comic shows to memorize a
handful of commands and think of them as
magic incantations and why everything's
working all right it kind of works out
all right but then you have to follow
the approach of this comic whenever
things go wrong
so while git has an ugly interface its
underlying design and ideas are actually
pretty beautiful an ugly interface has
to be memorized but the beautiful ideas
underlying git can actually be
understood and once you understand gets
internals its data model which is
actually not that complicated then you
can learn the interface to get you
you'll have to memorize some things but
you can understand what exactly certain
commands do by understanding how they
manipulate the underlying data model and
so the way we're going to teach get
today is first talk about the data model
almost in abstract talk about how we
might model files and folders snapshots
of history and how they relate to each
other
then after that we'll walk you through
some get commands and then finally in
the resources and exercises will link
you to tutorials that'll teach you all
the specifics because there are lots of
different commands that you will need to
learn eventually any questions so far
about our teaching approach for today
cool great so let's get started there
are probably many ad hoc approaches you
could take to version control and I'm
guessing some of you may have done this
before like say you have some file or
folder we have a bunch of different
files corresponding system software
project and you want to track changes
you could just say every day make a copy
of that entire folder and give that
folder a timestamp when you want to do
things like collaborate with other
people you could take the entire folder
turned it into a zip archive and email
it to somebody and then whenever you and
your buddy are working on two different
features of a software project you can
work on them in parallel then one of you
emails the zip file to the other person
and then you manually copy and paste the
appropriate segments from their code
into your code so that eventually you
end up with one piece of code that has
both of your features in it this kind of
sort of works raise your hand if you've
done this before
I certainly have still a decent number
of you get let's us not do this sort of
thing
it is a well-thought-out model that kind
of facilitates these sorts of
interactions things that you might want
to do like tracking your own history on
your in project or collaboration or
things like that so git has a well
thought-out model that enables things
like branches and collaboration and
merging changes from other people all
sorts of neat stuff get models history
is a collection of files and folders
within some top-level directory so
you're probably familiar with this
abstraction just from files and folders
on your own computer and so here's one
example like you might have some
top-level directory I'll just call this
like root in parentheses and this
directory might have say a folder in it
called foo and this folder inside of it
might have a file called bar dot txt and
this might have some contents in it like
say this says hello world and then maybe
this top-level directory it has one
folder in it it caalso have another file
in it so say there's some other file
and this file also has some contents in
it all right
simple enough the terminology get uses
for these different things for files and
folders is this and the top-level thing
are called trees so this is a folder and
then these things what we normally call
files are called blogs all right ok so
now we have a model of files and folders
and this is a recursive data structure
trees can contain other trees and then
trees can contain both trees and files
obviously files can't contain trees all
right so now we have a model of files
and folders and the kind of top-level of
this thing the thing I've just labeled
root is the directory being tracked like
you might have some folder on your
computer corresponding to a software
project now how do you model history
once you have a model of files and
folders well you can imagine one way of
doing it which is you take a snapshot of
this entire thing and then history is
just a linear sequence of snapshots like
you might imagine that it's you can
almost think of it like you have copies
of the folder which are dated and
time-stamped well it doesn't use a
simple linear model like that it uses
something a little bit fancier you might
have heard this terminology before but
git uses a directed acyclic graph to
model history and this might sound like
a bunch of fancy math words but it's
actually not all that complicated
so in get each snapshot has some number
of parents and basically want to know
like what change preceded what other
change so suppose here I'm going to use
circles to refer to individual snapshots
this is the entire contents within this
tree so all the files and folders in my
project my entire project may be in some
state and then I edit some files and now
it's in some other state and then I add
some more files and that's in some other
state and every state points back to
which state preceded it this so far is a
linear history
but it lets us do something a little bit
fancier than this you can also from a
certain snapshot fork your history and
say I want to base changes off of this
version and create a new snapshot like
this so this way of modeling history
allows you to do things like okay I'm
working on my project this is my main
line of development I go up to here and
now I have two different tasks I want to
work on suppose on one hand I have some
fancy new feature I want to add to my
project and so I'm going to be working
on that for a couple days but separately
from that somebody's reported a bug to
me and I need to go chase down that bug
and fix it well instead of working on
all that stuff kind of concurrently at
the same time in the same line of
development
git has its way of branching the history
into two separate Forks and working on
different things in parallel temporarily
in a way that are unrelated to each
other so I could take this base snapshot
like my project is in some state where
it works and then from here I could
implement a new feature that creates a
new snapshot so this has the base
project plus a new feature so I'll do
like plus feature and then similarly
separately from this I could go back to
this original snapshot because I don't
want to do bug fixing while implementing
my new feature go here and then work on
my bug fix and create a different
snapshot so this has only the bug fix
but not the feature and then finally
once I've done these two separate things
in parallel eventually I want to
incorporate them all into my common
source code that has both the feature
and the bug fix so eventually I might
author a new snapshot by merging the
changes present in these two different
snapshots and so this one I'll have both
of these snapshots as parents and this
version here will have both the feature
and my bug fix so does it make sense why
get models history in a way that's a
little bit fancier than just a sequence
of snapshots of my files and folders why
I want to be able to support branching
to work on things in parallel and then
also merging to combine changes from
different parallel branches of
development question
yeah so that's an excellent point it
seems that when you merge things you
could create errors that weren't
anticipated you could imagine here that
this feature actually changes something
that makes this bug-fix redundant or you
could imagine this bug fix breaking this
feature or something like that oh that's
a really good point that's a something
known as merge conflicts and this is
something that git will try to do like
when you merge your parallel branches of
development it will try to automatically
combine the changes in a way such that
it retains all the important changes but
if it gets confused it will report a
merge conflict and then leave it up to
you the programmer to figure out how to
combine kind of concurrent changes to
the same files or things like that and
then get has some tools for facilitating
this any other questions great ok so now
we have a model files and folders and
then we have a model of history how
different snapshots of our code relate
to each other
one little detail here is that each of
these circles so they kind of correspond
to a snapshot like a tree with files and
folders but they also have a little bit
of metadata so like inside here we might
have like the author of this commit is
me and we might have other metadata like
some message associated with this commit
I might describe what kinds of changes
I've made that are present in this
snapshot but not the previous one
that is not really the chair class so
next we're going to talk about kind of
one level lower than this like how
exactly is this represented as a as a
data structure inside get and so I'm
actually going to write down pseudocode
because I think it's actually easiest to
understand this way so first we have
files so a log is just a bunch of bytes
so I'll say this is an array of bytes
okay then what is a tree remember that
this is just a folder of what are
folders they're mappings from the
filename or directoryname to the actual
contents and the contents are either
another tree like a subtree or the file
and then finally we have the last thing
there what I've been calling snapshots
so far and get terminology those are
called commits and so what does a commit
[Applause]
it's a bunch of stuff commits have
parents that describes what precede them
so in the case of most normal commits
they have one parent like what they came
from what merge commits can have
multiple parents so parents are an array
of commits and then I have some metadata
like the author and maybe a message
and then finally the actual contents the
snapshot which is a tree that's the
top-level tree corresponding to a
particular commitment so this is a
really clean simple model of history and
this is basically all there is to how
get models history any questions about
that all right so now we have that going
a little bit deeper let's talk about how
it actually stores and addresses this
actual data like at some point this
actually has to turn to data on disk
right so get defines an object kind of a
big standing term but an object is any
one of those three things so it's a blob
or a tree tree or a commit and then in
get all objects are content addressed
so what get maintains on disk and you
can actually we can look at this later
is a set of objects maintained as this
content address store so if you have any
one of these objects the way you put it
into this store is its key is the hash
of the object so like in pseudocode I
might say that to store a particular
object o what I do is I compute its ID
by taking the sha-1 hash of o and then I
put it into my objects map store it to
disk a quick show of hands who here
knows what a hash function is all right
so I'll quickly summarize basically a
hash function is you can think of it as
like this magical function that takes a
big piece of data and turns it into a
short string at a high level these are
used to or maybe that's like a
sufficient
clinician I won't go into too much more
detail here but you can ask me
afterwards if you're if you're curious
so basically they give you a way to name
a thing in a way that's kind of
deterministic based on the constants of
the thing it takes into thing as input
and gives you a short name for it and
then the opposite of stores load the way
we can load things from the store you
might have just guessed you can look
them up by their ID and this is just we
retrieve it from the object store by ID
and it gives us back the contents any
questions about this so far question
that's a good question what language is
it's all written in it's written in the
language I just made up so it's
pseudocode the get implementation itself
is a mix of C it's mostly C and then
some bash and Perl scripts I think any
other questions is this made-up language
clear enough or do I need to explain any
aspects of it great okay so blobs trees
and commits and get are unified in this
way they're all objects and also as you
might think given my description here
like it looks like commits contain a
whole bunch of other commits and contain
a snapshot and things like that in
practice it doesn't actually work that
way instead all these are pointers so a
commit will be able to reference a bunch
of parents by their IDs so this is
actually not an array of commits
themselves but IDs and similarly the
snapshot inside a commit is not the
actual tree object it's the ID of the
tree and so all these objects are kind
of stored on their own in this object
store and then all the references to
different objects are just by their ID
by their sha-1 hash does that make sense
you can almost in your head map it to
like these are objects in a programming
language like Java and then this is a
reference to a tree so it's like a
pointer and then that is your realm
maybe this naughty helps maybe it
doesn't
yeah yeah exactly so I'll just repeat
that for everybody to hear on the
microphone
this is gets on disk data store it's a
Content address store where objects are
addressed by their hash all right any
questions about that so far ok so now we
have a way of identifying we've unified
all the different types of objects into
one type of thing we call object and we
have a way of identifying objects by
their sha-1 hash what do these actual
sha-1 hashes look like well they're
hexadecimal strings that are 40
characters long
like sha-1 is a 160-bit hash and so one
of the actual IDs returned by that sha-1
function is going to be a really long
string and so given that we'll have ways
of identifying these different things
like this we'll have corresponding to it
an ID like for a 3-2 CEB or something
something so now we have a way of naming
everything in this commit graph but
these names are really inconvenient
because they're super long and they're
like text strings they're not meaningful
to humans in any way so it's solution to
this problem is one other thing so get
maintains a set of objects and then it
maintains a set of references what our
references here I'll erase this bit on
the left this parts pretty logical
that's the irony another time so
references all right here
so this is another piece of data that
get maintains internally references is a
map from string to string and you can
think of this as mapping human readable
names like I might have a name like fix
encoding bug fix - encoding - bug is a
human readable name and this would be
maps to like that long hexadecimal
string there and so with these
references and you can imagine how we
might have ways of creating new
references and updating references and
things like that
with this I can now refer to things in
my commit graph by name so I might have
the same be called like fix bug or I
might have a name for something over
here things like that and so yeah with
this skit can use human readable names
to refer to particular snapshots in the
history instead of these long
hexadecimal strings one other thing to
be aware of here is given gits design
for history this entire graph is
actually immutable you can add new stuff
to it but you can't actually manipulate
anything in here I won't go into the
details of exactly how or why but just
assume that that's the case however
references are immutable so as you're
updating the history like suppose you
keep working on this piece of software
you create a new commit so I'm
representing that by the circle this
points to the previous commit I can
actually have say my fixed bug reference
is pointing here I can update this
reference to now point over here however
I can't for example make this point over
here that's not even a meaningful thing
to say because this is just the hash of
this object to change this hash I'd need
to change the contents of the object
which doesn't really make sense
all right any questions about that so
far that's basically it forgets data
model and then we'll go into actually
interacting with get via the command
line and we'll see how git commands
correspond with manipulations of a graph
data structure so any questions about
modeling history as trees of trees and
blobs and then snapshots these things
called commits being chained together
and you have references that can point
to particular nodes in this graph cool
no questions so basically once we have
objects and references like that's
basically all there is to a git
repository those are the two pieces of
data that it stores and at a high level
all get command line commands are just
manipulations of either the references
data or the objects data okay so for the
rest of this lecture I'm going to go
through some git commands it's basically
going to be an interactive demo similar
to the vim lecture and then you can
refer to the notes for full information
on these commands look of course it's a
really powerful tool we can't cover
everything in what 20 minutes all right
so I'm going to go over to this folder
called playground and I'm going to make
a new directory called demo CD into demo
and this directory is going to represent
the top level of my project it's
currently empty because I just created
it if I want to turn this into a git
repository I use the git init command
get in it stands for git initialize and
we see that it says initialized empty
git repository in blah blah slash dot
git if I do LS I still see nothing but
if I do LS - a there's a hidden file in
this directory called dot git if I do LS
get there's a bunch of stuff in here
this is the directory on disk where it
gets stores all of its internal data
namely the objects and the references
and you actually see here objects and
refs as two directories in here and
all the repository data will be stored
underneath those two directories one
letter command to keep in mind as we're
going through these is something called
get help get help takes a sub command as
an argument it gives you some help on it
so if I do get help in it for example
it'll tell me about the git init command
so now there are some commands for
figuring out what's going on with a git
repository like git status at a high
level says what is going on right now
and we see here let's ignore the first
line for now the second line says no
commits yet that's because we just
initialized a fresh repository and so
there is no history yet I'm actually
going to does anybody still want this
are kind of clear this part of the board
I'm going to as we go along draw how the
underlying objects and references data
is changing when I type in certain git
commands so right now this picture or
lack of picture represents the current
state of our repository it's empty there
are no snapshots so let's fix that let's
add something to our history here we
have no files so let me just go ahead
and create a file hello.txt with the
content hello world normally you'd have
your source code with actually useful
stuff in it now what I want to do is I
want to take the current contents of
this directory and turn it into a new
snapshot to represent say the first
state my project was in you might
imagine an interface for doing this
where there is like a git snapshot
command or get something else command
which takes a snapshot of the entire
state of the current directory for a
number of reasons git doesn't have a
command that works exactly like that
because git wants to give you a little
bit of flexibility as to what changes to
include in the next snapshot you take
this is something that's kind of
confusing to beginners sometimes so I'll
try to explain it right now git has a
concept of something called a staging
area and at a high level it's where you
tell git what changes should be included
in the next snapshot you take if we do
get status here we'll see that git says
no commits yet like it said before and
it says untracked files hello Tex
so this is saying that get notices that
there's a new file in the current
directory but it is not going to be
included in the neck
snapshot gets kind of ignoring it for
now but if I do get ad hello text and if
I do get status again it says now
changes to be committed new file
hello.txt and so now if I do the get
snapshot command which is actually get
commit which creates a new one of those
circles I drone the board over there
this file will be included in that
snapshot I'm I take so let me go ahead
and run git commit what this does is it
pops up my text editor and it lets me
type in a message that will be
associated with this commit and it's
really good to write high-quality commit
messages because then later when you're
looking back at your products version
history you'll know why you made certain
changes I'm going to add this relatively
useless commit message but we have a
link in the lecture notes for a guide on
how to write high-quality commit
messages so now that I've done that get
prints out some output master ignore
that bit for now this thing is the hash
of the commit I just created so now I
have in my history a single node this
has in it a tree that has a single blob
a single file hello.txt with the
contents hello world and then this has
the sha-1 hash for 2fb
something something something it's
actually truncated in the get interface
as well this is just printing out my
commit message again and it says as a
reminder I just added hello dot text and
so now if I use the git log command so
the git log commit is really useful in
that it helps you visualize the history
the the commit graph if I do question
that's a great question so the question
is what exactly does this hash
correspond to so this is the hash of the
commit the commit contains inside of it
the hash of the tree along with whatever
other information so I can actually use
get cat file - P this number this is
kind of like a get internals command
that will print out the contents of this
commit so you can see this kind of maps
to
data structure I drew on the board over
there so this commit has inside of it
this tree and then I'm the author and
this is the commit message and so on and
I can continue digging down here so you
can take this hash of this tree and do
get cat file - P this hash here it says
that this tree has inside of it a single
entry hello text and that file has it's
a blob and it has this hash I can do get
cat file - P this thing and it will show
me the actual contents of that file so
these are like internal git commands to
explore objects in the object store
question that's a great question so the
question is why did I have to use get
add why can't you just commit all
changes and the answer is well there
kind of is a way to commit all changes
if you do get commit - a this commits
all the changes that were made to files
that are already being tracked by git so
anything that was included in the
previous snapshot but has been modified
since then it doesn't include new things
there's also variants of git add like if
you do get add colon slash this will add
everything in the top from the top level
down of your repository but at a higher
level the reason we have this separation
between git add and git commit and why
get come it doesn't just snapshot the
entire directory is that they're often
situations where you don't want to
include everything in the current
snapshot like here's a couple examples
one is that I might be packing on my
project and I go ahead and implement two
features maybe I don't want to have a
single snapshot that comes after this
one that's like I implemented feature a
and feature B maybe I want to create two
separate nodes in the history so that it
looks like first I implemented feature a
and then after that I implemented
feature B so I have one snapshot that
only includes a and then the next one
includes both a and B git add is a tool
and like the staging area in general is
a tool that will allow me to do that
sort of thing
another example is suppose I'm working
on a bug fix and I have printf
statements I've put all over my code and
then finally I find the bug and there's
a plus one somewhere where there
shouldn't be a plus one so go fix that
and then I want to take a new snapshot
right with my fix
but the snapshot probably should include
all of my print statements it just needs
to include the fix of removing that plus
one so one way I could solve that issue
is I can go in
annually remove all the print statements
but it has a much better way of doing
that there's actually a way to specify
that I only want to add the change of
removing that plus one then I can commit
that take the new snapshot and then I
can throw away all the other changes
there are commands for doing that and
some of them are linked in the lecture
notes so those are two ways in which you
can use the staging area to help you and
why there isn't just like a snapshot
everything command yeah so mm-hmm yeah
John John points out the yeah yet
another example is you might have log
files in your current directory that
your program runs when you run it and
you probably don't want to include those
when you take a snapshot there's
probably other things like if you
compile your project you end up with a
bunch of dotto and like elf files you
probably don't want those to be part of
your history so going back to what I was
showing you before I'm going to clear
the terminal screen and then show you
the git log command so get logged lets
you visualize the version history and
this is an incredibly helpful command by
default git log shows you a flattened
version of the version history so even
though the version history is a graph
this will linearize it and just show
things in order i personally find that
confusing so I almost never use git log
and instead get log takes some arguments
that actually show the history as a
graph so you can treat this as a magic
incantation for now and you can read the
documentation if you want to figure out
exactly what each of those flags does
but for now this doesn't look all that
different because we only have one node
in our graph so visualizing it as a
flattened thing versus a graph doesn't
look all that different let me go ahead
and create a new snapshot and then we
can run this command again and then see
exactly what it does so I will put
another line into hello dot text and so
if I cat hello dot text it has the thing
it had before plus this I can do get
commit and notice this doesn't do
anything it just says no stained state
no changes staged for commit why is that
it's because I didn't add this to the
staging area I didn't tell yet but like
this is something that should be
included in the next snap
so if I do get ad hallo text get status
it says okay this change is ready to be
committed this modification to this file
and now I can do git commit I'm gonna
put in a useless commit message and the
new changes have been made and so now my
history has another note in it and then
this note has some hash that's shown on
the screen and now if I rerun that
command from earlier the git log with
all these arguments it actually starts
looking more like a graph here notice
that this is like that graph turned this
way the more recent so it's shown
vertically not horizontally and the more
recent commits are shown at the top this
is showing one commit it shows as commit
hash shows a bunch of metadata including
the commit message and then this is the
part I want to talk about next so
remember we talked about objects like
the actual contents of your repository
and then we talked about references ways
of naming things in the repository with
human readable names so master is one
reference that's created by default when
you initialize it get repository and by
convention it generally refers to like
the main branch of development in your
code so master will represent like the
most up-to-date version of your project
so here you can think of master as a
pointer to this commit and as we add
more commits this pointer will be
mutated to point to later commits then
we also see here head this is a special
reference and get it's a reference like
master but it's special in some way and
head basically is used to refer to where
you are currently looking right now any
questions so far yeah question
that's an excellent question so the
question is work with github before and
you have to create an account to do that
how does github relate to get and the
answer to that question is github is a
repository host for get so you can
create an account on github and store a
git repository there and use that to
collaborate with other people but git as
a command-line tool is just independent
from github so you don't have to use
github to use git you don't have to use
github declare it with get either like
there are other providers of git
repositories like bitbucket or get lab
or things like that and so yeah github
is a host for github repositories any
other questions yeah so the question is
if you want this repository to end up on
github how do you do that yeah there's a
separate set of commands for doing that
there's a so that concept of having your
local copy of version history interact
with another copy so the other copy is
called a remote and then their set of
commands for interacting with git
remotes and sending data from your
remote or from your copy to get remotes
and getting data from git remotes into
your local copy and we'll cover that
later in this lecture or maybe in the
lecture notes Ron might make a
supplemental video to go along with this
lecture any other questions okay a
couple other basic commands to show you
so so far I've shown you a version
history and we've taken a file and
modified it but we haven't really made
use of the history in any way besides
reading the messages so one useful git
command is something called git checkout
and this is a kind of wacky command it
lets you do a bunch of different things
but one thing it lets you do is move
around in your version history so one
thing I can do is give get checkout the
commit hash of a previous commit and I
don't need to type the whole thing I can
give it a prefix and it's
to figure out what I'm talking about and
what this will do is it will change the
state of my working directory to how it
was at that commit so here if I do cat
hello text recall that I had only one
line in here before at the first commit
and later I added that second line now
if I do that get logged command and this
command is super helpful like it shows
you all the things if I do this command
notice that this output looks a little
bit different than before like my actual
history contents the commits themselves
in the way they relate to each other and
all that have not changed but the
references have so notice that head is
down here even the master is still up
here so at high level what this is
telling me is this is what I'm looking
at right now if I want to go back here I
could type git checkout and this commit
hash
does anybody know a different thing I
could type here instead of this long
hash in order to go back to this commit
yeah you can give it the name of this is
a branch colored in green here and it
refers to this commit so I can give it
the short name or the human readable
name instead and now if I do cat hello
text notice that it has that second line
[Music]
yeah yeah so to repeat that git checkout
actually changes the contents of your
working directory and so in that way it
can be a somewhat dangerous command if
you misuse it for example you can see if
I modify hello text and then try that
get checkout command from earlier
actually notice here that it says error
it says there's a file that's been
modified and the git checkout would
destroy your modification you probably
want to do something about that but
there are flags like for example get
checkout - eff does this forcibly and
now it's throwing away my changes so
yeah get checkout has the potential to
well it certainly does modify things in
your working directory and it can
actually destroy changes if you're not
careful question
exactly yeah this is exactly what I want
you to be thinking about how these like
the crazy get interface commands
correspond to mutations to this graph
and mutations to the reference or like
additions to the graph in mutations to
the references map so yeah exactly
get checkout moves the head pointer and
then also mutates the contents of your
working directory with the contents that
the head pointer now points to of course
my name for that commit any other
questions all right so one other basic
command I want to show you is the git
diff command so I'm going to modify this
file and put some changes in it the git
diff command can show you what's changed
since the last snapshot it's just
helpful for like knowing what's going on
with your project git diff can also take
extra arguments like you can do git diff
and say compute a diff not with respect
to the last snapshot the last commit but
with respect to this and say ok two
lines have been added since this point
to hello dot text
question so your the question is what
does this command do without this extra
argument here that's a good question so
what this does is it computes a DIF with
respect to head and looking at my get
log hat is pointing to here so it's
doing a get diff with respect to this
commit and you can actually specify that
explicitly you can do get diff had
hollow text okay yes uh-huh
so that's a good question it's like how
can hello dot text be different than
head because head refers to where you
currently are so to clarify head refers
to the last snapshot so like in my
picture here had and master are both
here and the current working directory
is kind of independent of this like
you're going to delete all the files in
here it doesn't change the history graph
or the references and so yeah you can
have differences between here and here
and at a high level this is how you work
on a project like you make some changes
here you get add them to stage them and
then you get commit and that creates a
new snapshot here good question
any other questions yep
so the question is does get actually
save all this stuff kind of in the
obvious way or is it doing something
fancier the answer is is it is doing
something a little bit fancier but you
can it has an interface that lets you
think of it like it stored that way in
practice get uses Delta compression it
also does some other stuff but yeah the
on disk representation is actually
reasonably efficient question yeah
that's a good question so the question
is here we were comparing the current
working directory with a particular
snapshot in the past can we compare two
snapshots with each other like at two
different points in the history and yeah
I get diff can take yet another argument
here so I can for example compare head
with it did in the wrong order I can
compare what change from here to head in
hello text and it shows me that I added
the second line in there any other
questions
yeah so the question is you're working
on a shared project in a Dropbox folder
and anyone a migrate to get does it make
sense to turn the Dropbox folder into a
git repo do not use get inside dropbox
dropbox will corrupt your gate repo
there are good solutions to doing that
one is just use github otherwise I talk
to me after class and there ways of
using Dropbox as I get remote safely any
other questions
next we're going to talk about branching
and merging which is another powerful
feature of get that you almost certainly
use both when working on your own
projects and when collaborating with
others for this series of demos we're
going to rather than work with a simple
text file actually write a simple
computer program because it'll better
illustrate the concepts of branching and
merging and as we go through this
demonstration we'll keep in mind how the
get interface commands connect to the
underlying data model connect to objects
and references and how these commands
modify those two data structures let me
do a get status to see the current state
of my repository here I've modified
hello text I actually don't really care
about this modification anymore this is
some random file if I do get check out
folio text this is another different use
of the check out command which basically
throws away the changes that I've made
in the working directory and sets the
contents of hello text back to the way
it was in the snapshot that head points
to if I like it get logged - - all -
graft - - decorate it'll show me that
here I added the initial attacks and it
added that single line here and so now
whole text doesn't have that third line
I'd added it just has the original -
next time we should write a very simple
program we'll call this program and a
mold pie and let me just go ahead and
write a program that it prints a little
bit of output when I run it let's see
[Applause]
so when I run this program it runs main
mean calls default and then let me go
right ahead go ahead and define default
and default is going it's just going to
print hello so this is a program that
greets its user and so if I run animal
dot pi I'll see that it just prints
hello so that'll be our starting point
if I do get status it shows me that
animal dot hi is an untracked file to
begin with i want this to be part of my
part of the snapshot so i'm going to get
add animal dot hi to add it to the
staging area and do then do a git commit
here I'm going to write yet another
useless commit message don't actually
write commit messages like this in real
projects but for now this is fine so now
I have this basic animal dot pi and if I
look at my get history now I have this
latest snapshot this is the commit hash
and this is where the master branch is
pointing now we're actually way to
demonstrate how to use git branches to
have parallel lines of development they
get branch command or the branch
sub-command is used to access
functionality related to branching just
running git branch by itself lists all
the branches that are present in the
local repository it can also take an
extra argument - V V to be extra verbose
and print some extra information if we
do get branch and then specify the name
for a new branch git will create a new
branch which is just a reference that
points the same place where we're
currently looking so now there's a new
reference called cat reference in this
case is the same as branch there's a new
branch called cat which points to
wherever head was pointing if I look at
the git log again I'll see that here had
points to master masters over here and
this is also where the cat branches so
now I have two branches two references
that resolve to the same commit get is
actually aware of not only which
snapshot in the history are currently
looking at so had points to this commit
but it's also aware of had kind of being
associated with a with a branch so here
head is associated with master and it's
the case that if I create a new snapshot
if I type git commit at this point the
next snapshot will be created and
I'll point to that new snapshot master
will be updated along with head if I do
get checkout cat what this does is it
switches to the branch cat it replaces
the contents of the working directory
without with whatever cats pointing to
which in this case is the same as the
contents before but now if I look at the
git log again now I have head point to
cat instead of master and then master
also points to the same place the same
underlying commit and now at this point
if I make changes to my current working
directory and make a new commit the cat
branch the cat pointer will be updated
to point than you commit where as master
will continue pointing wherever it
pointed before so let me go ahead and
modify animal PI to add some cat related
functionality so I'm going to say that
if sISTAR V one is cat then run the cat
function otherwise run the default
function and then let me go ahead and
import define the cat function so cats
don't say hello them you know so cat
prints meow straightforward enough so
now if I run animal dot PI and give it
the cat argument it says meow if I give
it some other argument it defaults back
to the hello all right so simple change
I made if I do a get status that says
that animal that PI has been modified
Farren get diff it'll show me what's
changed since the last commit
so here I've added this cat function
highlighted in green then also change
the main function a little bit now here
if I do get add animal dot I get commit
I mean actually you write a slightly
more useful commit message this time I'm
going to add cat functionality and now
if I look at the git log I see a little
more stuff I'm going to show you one
more argument to this get logged command
there's an argument - - one line one
line spelled correctly which shows a
more compact representation of the graph
so sould be a more useful thing to use
because we're super zoomed into the
screen and there isn't that much space
to show a long commit history so here we
see the sequence of commits is still
linear and we have master still pointing
wherever it pointed before where we just
had the basic underlying animal top high
functionality but now we have this cat
branch which adds the cat functionality
we could for example get checkout master
to go back to the master branch and then
here if we look at animal dot pie it
doesn't have the cat functionality
anymore if we look at the git log we'll
see that head is pointing to master so
so we can jump back and forth between
parallel lines of development so now
that we have the cat functionality
suppose that we want to work on adding
dog functionality in parallel and
suppose that in this case like the cat
functionality is under development or
maybe somebody else is working on it so
we just want to start from the base
master commit and build the dog
functionality starting from there so now
what do I want to do I want to create a
new branch dog for adding the dog
related functionality and I'll
eventually merge it in later so I can
use the git branch dog command followed
by the git checkout dog command to
create a new dog branch and then check
it out there's actually a short form for
this get checkout - b-dawg so this does
get branch dog get checkout dog and now
if I look at my graph I have cat where
it was before master where it was before
but now head instead of pointing to
master as it did before now head points
to this newly created dog reference
which is also at the same commit so at
this base commit and now I'll go ahead
and add my dog functionality so let me
go and define my dog function dogs don't
say hello they say woof and then I'll
add some similar functionality here to
decide whether to run default or dog so
if the first argument is dog then I want
to run the dog function otherwise whoops
otherwise I want to run the default
function so here's what I've changed
with respect to the base commit wherever
master is pointing so I've added the dog
function and I've changed mean a little
bit so a kind of parallel modification
to what I did in the cat branch let me
go ahead and get add animal Titus add up
to the staging area if I do get status
I'll see that this change will be
committed when I make the next commit
and then I do get commit add
functionality now when I look at the get
graph it actually looks kind of
interesting compared to the ones we've
looked at before this shows that these
three commits
are in common with the ones that come
after it but then the history is
actually forked after this point and I
have this one commit that adds cat
functionality in one line of development
and then I have this other commit that
adds dog functionality in this other
line of development and then using the
git checkout command I can switch back
and forth between dog and cat and master
so this is great I can do development in
parallel on different features but this
is only really useful if I can
eventually combine those things back
into my original line of development to
have both features in a single version
of my source code so the command that's
used to do that is get merge so like get
branch and get merge can kind of be
thought of as opposites let me check out
get check out master let me check out my
master branch so now you see head points
to master and then I want to merge the
cat functionality and the dog
functionality into master and to do that
I can use the git merge command and get
merge is actually pretty fancy and I can
actually merge cat and dog at the same
time but for this demonstration we're
going to only merge one thing at a time
so first I'll type git merge cat and
gets us some stuff here it says
fast-forward so what is going on here
well this is one interesting thing that
get can do when you're at a particular
commit and you merge some other branch
in where that other branch has the
current commit as a predecessor it's not
necessary to create any new snapshots or
do any other fancy stuff basically this
this master branch here this pointer to
this commit can just be moved to point
here instead to incorporate that cat
functionality and so if we look at the
git log again we see that master is
basically pointing to the same places
wherever cat was pointing all right so
now we're on the master branch and it
has the cat functionality great we're
halfway there if we look at animal dock
by it has the cat functionality but it's
missing the dog stuff so let's try get
merge dog next something a little bit
more interesting happens this time so
this time the branch can't be fast
forwarded like it was before it's not
that one thing which is strictly older
than the other thing there's been
parallel development that may be kind of
incompatible with the current set of
changes and
it does its best job at automatically
merging the changes from this other
branch
so it says Auto merging animal dot pie
but in this particular case there's what
was what's called a merge conflict so it
wasn't able to automatically resolve on
the call the conflicts between these two
parallel branches of development and
this is something you'll see in practice
when you're working on real software
projects and they're complicated
slightly incompatible changes happening
in parallel so at this point it's left
up to the developer to fix this issue
and get offers some functionality in
order to help resolve merge conflicts
there's a program called git merge tool
and in my particular setup this will
launch vim diff actually this is not
configured them diff I think will start
the right program let me set up my get
to launch the correct tool actually
let's skip that part and let's just
manually look at this event if so
there's a program called vim diff which
can be set up to be launched when you
type in get merge tool which is a tool
that you use when you try get merged in
there merge conflicts but in this
particular case we'll just manually
resolve them
so let me I did get merge - - abort so
it put me back in the state I was before
I tried that git merge so this is the
current state of my repository I'm back
to the case where master is at the same
place as cat and I'm about to merge in
dog so I do get merged dog and it says
conflict merge conflict in animal Pi so
let's just look at animal dot PI
directly so it looks like this top part
looks pretty reasonable it has both the
cat function and the dog function which
is exactly what I want but now I see
some weird stuff in main and this is
where I add slightly incompatible
changes so here it says that in one
thing like basically the branch you were
on you had this content and then the
branch you're trying to merge had this
content and then these things here the
angle brackets and the equals our
conflict markers so this is where you
were and this is the thing you're trying
to merge in and it's basically saying
that it was this on one case this in the
other case and it doesn't really know
how to resolve
these two and it's left up to the
programmer to fix this problem so in
this particular case we can go ahead and
delete the conflict markers and then
turns out that we can actually
concatenate this code together and does
the right thing maybe we want to make a
small change like this should be an if
this should be an else--if and this
should be an else that might make a
little bit more sense actually I think
it's necessary for correctness here so
the programmer needed to modify the code
a little bit in order to make it
sensible when it's merged together but
once the programmer has fixed the merge
conflicts fixed the stuff between the
conflict markers you can save this file
and we can do get merged - - continue to
tell git that we fix the issues it's
necessary to re add animal PI to tell
git that we've actually fixed these
issues and then we need to get merged -
- continue it pops up an editor and we
can give a commit message for this new
commit that we're about to create and
now if we look at the git history we
have the single commit that represents
our merge commit that we just made which
merges in the dog functionality and here
this has as parents both the dog commit
and the cat commit
so both these branches appear in our
history from this point backwards and
this current commit that we're on
incorporates the functionality from both
of these branches so if we run animal
duck fight with cat it does the cat
thing if we run it with dog it does the
dog thing and if we run it with anything
else it falls back to the default
implementation so this is a
demonstration of how you branch and get
to do development on different things in
parallel and then how you can use the
merge command and get to resolve those
different branches and combine them
together into a single snapshot that
includes all the functionality that was
developed in parallel with each other
and then one thing that can happen when
you're doing get branching and merging
is you run into merge conflicts and
these conflicts show up as conflict
markers and text files you can manually
resolve them and kit also has some tools
that can help with this though these
tools are kind of advanced and will only
refer to them in the lecture notes and
not actually demonstrate them for you
so that's get branching and merging
any questions no great so moving on to
the next topic of this lecture we will
talk about git remotes so this is
basically how you collaborate with other
people using git a git repository the
stuff contained in this dot git folder
represents kind of an entire copy of the
history it has the objects in the
references and contains all the previous
snapshots and the way you collaborate
with other people using git is that
other people can also have copies of the
entire git repository and then your get
copy your local instantiation of the
repository can be aware of the existence
of other clones of the same repository
and this is a concept known as remotes
so the git remote command will list all
the remotes that git is aware of for the
current repository and in our case with
this repository right here this command
get remote just doesn't print anything
because we haven't configured any
remotes it is only aware of the single
local copy of the repository that we're
working with here but in practice if
you're collaborating with other people
your git might be aware of the copy of
the code that is on github and then
there's a set of commands to send
changes from your local copy of the
repository to a remote that your get is
aware of so sending stuff from your
computer to github for example and
there's another set of commands for
fetching changes made in a local
repository to get changes from github
into your own local copy in this
demonstration here we actually won't go
and configure a github account and log
in and create a new repository on there
you can find other tutorials for doing
that we'll actually just use a separate
folder on the same computer and treat it
like a git remote so let me I'm in the
demo folder here let me go up one
directory I have a directory called
playground that has this demo folder and
I'll go ahead and create a new directory
in here and I'll call it remote and then
do get in it - - bear in here those are
the command that you'll probably never
need to use in regular usage but now
what I've done is made remote into a
folder that's appropriate to use as a
git remote
so now going back into my demo folder
here might mean repository I can do get
remote to list the remotes
there's nothing yet but I can use the
git remote add functionality to make my
local repository aware of the existence
of a remote so I can do git remote add
and then the format for this is that
remotes have names and then they have a
URL so in this case I'll use the name
origin does often use by convention as
the name of the remote if you're only
using one and then for the URL normally
this will be like a github URL or
something like that or bitbucket URL or
get live URL if you're using an online
repository hosting service but in this
case it's just a path to a folder on my
local machine there's a folder in the
parent directory called remote that will
act as the git remote for this
repository so now once I've done that
there's a set of commands for
interacting with this remote one command
that's useful is the git push command
this command can send the changes from
your computer to the remote and the
format for this command is that git push
takes in the name of a remote and then
it takes in a local branch name : a
remote branch name and what it does is
it creates a new branch or updates a
branch on the remote with the name
specified here and sets it to the
contents of the branch specified here so
a concrete use of this might look like
git push I've only one remote called
origin and then what should I push let
me look at my history graph I have a
bunch of things I could push let me get
pushed to origin the master branch from
my local machine :
master so I want to create a branch on
the remote machine with the name master
that is going to be the same as the
master branch on my local machine so let
me go ahead and run that command it
prints out some stuff and it says on the
remote I created a new branch remote
master points to the same branch as
master on my local machine and now if I
do a git log it shows me so in blue is
head where I currently am in green are
all the branches in my local git
repository and now we see one new color
here that we had
seen before so in red get shows
references that are present on the
remotes that my local copy is aware of
so on the remote origin there's also a
branch that happens to have the name
master that points to the same place as
my local branch master points and so now
if I make updates to my local copies
like suppose here I go in and change the
capitalization of these things and then
get had animal dot hi get commit here's
a short form for commit with a message
so it doesn't pop up the editor I'll
give it a late and commit message and
now if I look at the git graph now I see
that I've created this new snapshot here
that has this lower casing stuff in it
but origin master is still back here so
if somebody else looks at the remote
they will only see the changes up to
here and we can actually demonstrate
this functionality so let me go ahead
and open up a new tab here and go into
my playground directory the git clone
command is a command that somebody can
use to start from some copy of a
repository somewhere and make their own
local copy so this is often a command to
use when starting out with a git repo
like there might be something available
on github and you want to copy it all in
your machine in order to look at it or
start doing development and so the
format for git clone is that it takes in
a URL and then it takes in a name for a
folder for where to clone it so in our
case here we're just going to clone from
this remote directory we're pretending
that this remote folder is actually a
remote machine and then we're all clone
it into the folder called demo two so
cloning into demo 2 done and I'm going
to CD into that directory and then now
here I'm going to rename these tabs at
the bottom I will say this one's machine
one and this one's machine too so you
can think of these as two different
people on different machines with their
own copy of the repository and they're
both interacting with the single remote
so if I do my get log command that I've
been doing on machine one I see on
Machine 2 I see this portion of the
history so master on machine 2 is
pointing to the same places origin
master
and it says merge branch dog so if I
look at animal dot pie here
it doesn't have the changes that I made
on machine to even though there are
sorry on machine one where I have this
new commit that is only present on this
machine but not on the remote and not on
machine too so if I want to fix that if
I want to send these changes up to the
remote like think of it as sending it up
to github err up to the machine that's
holding or maintaining the source code I
can use the git push command again git
push origin master colon master and this
will work but this is kind of annoying
to type every time you want to do this
like this is a really common operation
so git has a way of making this a little
bit simpler it has a way of maintaining
relationships between branches on your
own local machine and branches on remote
machines it is a way of knowing what
branch on a remote machine a local
branch corresponds to so that you can
type in a shortened version of git push
and it'll know what all the arguments to
the expanded form would have been and
there a couple different syntaxes for
doing this one way is to use the git
branch - - set up stream to command and
what this does is for the branch that's
currently checked out which is master it
will set the upstream - and I'll type in
origin master and see now it says branch
master set up to track remote branch
master from origin now if I type in get
branch - VV remember this is tell me
about all the branches that I know about
in a very verbose way that's what the -
VV means I have three branches on my
local machine on machine one I have cat
dog and master and master on my local
machine corresponds to origin master so
now I can type in just get push without
all the extra arguments I could have
done this as git push origin master
colon master but it wasn't necessary
it'll know that I want to push to origin
master and it will make that change
so now these changes are present on the
remote we can go over to machine to
pretend we're the other guy interacting
with this repository and if I do might
get logged command I still don't see the
changes so what's going on here
well it's necessary in order to run a
separate command
or it's necessary to run a separate
command in order to have these changes
present here by default all the get
commands don't talk to the internet it
all works locally which means it works
very fast but then there are special
commands for saying that you want to
retrieve changes that have made
somewhere else and the command that's
used for doing that is a command called
git fetch get fetch takes thee as an
argument the name of the remote but if
there's only one it'll just use that so
you can type in git fetch and then it's
talked to this remote repository and it
says that there's some update on the
remote and we can visualize it by
running git log and now we see here
another situation that we hadn't seen
before we have master on our local
machine the master branch doesn't change
the git fetch command doesn't change any
of our local history our local
references like our branches but now
it's aware that origin master has been
updated to point to this new commit and
there's a separate command we can do get
merge in order to move master up to here
or there's another command called get
pull which is the same as doing git
fetch and then get merge so if we just
do get pull here for example it will say
it's fast forwarding is merging in
origin master into our master and now if
we look at the git history graph we've
currently checked out master master
points to the same place as the origin
master that we're aware of and all the
changes between Machine 2 and Machine 1
are in sync so those are the basic
commands for interacting with git
remotes so there's the git remote
command for listing remotes and adding
and removing them and things like that
and then there's the git push command
for sending changes from your local copy
of the repository to the remote and then
there's the git fetch command which is
for retrieving changes to a repository
that are present on a remote and getting
the changes on your local machine and
once you retrieve those changes you can
use git merge to update your local
branch to point to the same place where
the remote branch does or you can use
the git pull command which does
basically the same thing as get fetch
plus git merge and then of course
separate from all these commands
is the clone command that we talked
about a little while ago which is for
taking a copy of remote repository and
initializing the local repository from
that copy so that's a quick overview of
the different commands used to interact
with git remotes and now these are kind
of complicated and it takes a while to
master all the different variations of
this and understand how they're actually
used in practice but hopefully this acts
as a quick introduction and you can see
how the different commands relate to the
underlying data model all these commands
all they do is fetch new objects from
other places or send objects from the
local mission to other places and these
commands mutate references so relating
these relating the interface of git and
some of these kind of badly designed
commands to the underlying data model
can help it make a lot more sense the
final topic we're going to cover today
is it's a kind of overview of other
things that get can do that we're not
going to go into detail in teaching you
how to do but we just want to tell you
that these functionalities exist in case
you need to do these things yourself you
can look up the documentation and find
out exactly how to do it one thing is
the git config command like a lot of
tools we've looked at like the shell and
T MUX and things like that
git is highly configurable and it's
configured using a plain text file which
can be edited either through the
command-line interface so git config can
take in flags that will modify this text
file or you can edit the dot git config
file in the home folder with plain text
configuration and so for this lecture
I've actually cut out most of them I get
config and only left in my username and
email for what will go in to get commits
but there's a lot of stuff you can put
in here which will make it behave nicer
it behaved the way you want it to and
you can look online for different ways
people have configured their get configs
oftentimes people have documentation in
their kit configs
which can be found on github there's a
couple other random commands that could
be useful one is for when you want to
clone a repository with git clone that's
really gigantic get cloned by default
copies the entire version history for
the remote it's downloading the
repository from but there's an argument
you can pass it which is - - shallow
which will avoid doing that so if
there's some copy of some code on github
say that you want to get a copy copy of
on your local machine but that
repository is really gigantic and has a
billion commits he's get cloned - -
shallow this will be much faster but
then of course he won't have the version
history on your local machine you'll
just have the latest snapshot another
command that we find really useful when
doing development on real software
projects is an interactive version of
the git add command so to demonstrate
this I'm going to go ahead and make a
couple different changes to my animal PI
one change I'll make here I'll change
some text here and then I'll put a new
print statement here so let's pretend
that this first change was some real
change I wanted to make say it's a bug
fix and this other change here was a
printf that I added for debugging but I
don't actually want to commit in the
next snapshot if I do a get diff it'll
show me that yes I've made these two
changes and if I do get add animal dot
pi it will stage both of those changes
for a commit and that's not what I want
I could go manually remove this debug
print and then do this get animal dog
get add animal dot PI but there's an
easier way to do it
there's this get add - pika man which
lets me interactively stage pieces of
files for it commit and so there's some
interface for working with this so here
it's saying do I want to stage both of
these changes and no I don't but I'm
going to split it into two smaller
changes this one I do want to keep so I
say Y for yes and this one I don't want
to keep so I say n for no and then if I
do get diff - - cached this will show me
what changes are staged for commit so
now it shows only the actual change I
wanted to keep if I do get diff it'll
still show me the other change that is
not going to be part of the next the
next commit which is the change I didn't
want to keep and then with this I can do
get commit specify some commit message
now I only have this change left and
then I can do get check out animal to
apply to throw away this change so get
add - P for interactive staging is a
useful thing a couple other commands
that you can look up on your own are the
get blame command so this commands kind
of ominous but it can be used to figure
who edited what line of a file and you
can also find the corresponding commit
that was responsible for modifying that
particular line of that file and then
you can look up commit messages
associated with that and whatnot so this
is not that interesting to do in our
current toy repository but I'll go over
to the repository for the class website
and we can look at some particular file
here and let me go to some particular
line here and I can be looking at this
me like oh why was this particular line
added what does it mean and I can look
at the git blame for this so if I do get
blame config dot yml it'll print out all
the lines kind of in the right column
and then in the left side it'll show me
what commits that change was made in and
by whom and then looking at this like I
can go down to this collections line it
was made in this commit that's the last
commit that modified that line and now I
can use the git show command to get
information for that particular commit
oh and this is kind of useful redo
lectures is a collection that's probably
what was related to that collections
line and then beyond just showing the
commit and the commit message it also
shows me the actual changes introduced
in that particular commit and they can
go look through them and understand
what's going on another kind of cool
command is a command called git stash so
let's go back to our demo repository and
demonstrate that here so say if some
changes here and I temporarily want to
put them away if I do get stash it will
revert my working directory to the state
it was in at the last commit so if I do
cat hollow text that change is gone but
it's not just deleted its saved
somewhere and if I do get stash pop it
will undo the stash so now if I look at
hello text it has the changes I made so
yet another useful command another
really neat command is something called
git bisect and this has a complicated
interface that we're not going to
demonstrate in detail but basically this
is a tool that can be used to solve a
bunch of problems where you need to
manually search history for something
suppose you're in a scenario where
you've been working on a project for a
long time you have lots and lots of
snapshots you're a thousand commits in
and then you notice that some unit test
doesn't pass anymore but you know that
this was passing like
year ago and you're trying to figure out
at what point did it break like at what
point was this regression in your code
introduced so one thing you could do is
manually check out like go back one
commit and see if the unit test is still
failing go back one commit see if it's
still failing and eventually you'll find
the first commit where the test stopped
working and it'll probably tell you like
what broke but that's kind of annoying
to do manually get by sight automates
that process and it actually binary
searches your history so it does this in
the most efficient way possible and not
only that get bisect can take in a
scripts that it uses to try to figure
out whether a committed looking at is
good or bad so it can be a fully
automated process like you can give git
bisect a unit test and say find the
first commit where this unit test
stopped passing it's a really powerful
tool another random thing that's kind of
useful is something called a git ignore
file so by default if you have random
files in a directory like let me create
the dot d s underscore store file whoops
create the dot d s underscore store file
and then do git status so D s stores
like some nuisance file that Mac OS
creates I don't know exactly what goes
in here but basically once this file is
in this directory now whenever I do get
status it says oh there's this new file
that I've never heard of it before but
it apparently here like do you want to
add it and this sort of tough stuff gets
annoying and there's a lot of other
stuff beyond OS specific garbage that
might be in a directory like for example
if you're working with C code you might
compile it and produce dot o files or
executable files or things like that and
you probably don't want binaries to be
part of your commit history you only
want the source code and so git has a
way of you being able to tell the tool
that you don't care about a particular
set of files and to ignore them and
that's something called a git ignore
file so if I go and modify the file
called git ignore in the current
directory I can specify particular file
names or patterns of file names like say
I can specify star dot o so any file
ending in dot o along with da store and
now if I touch food oh and now do a get
status
I'll see that git says okay I've
hollowed out tax which I've modified
sure and
and I have get ignore so you should
track your get ignore file using it but
notice that it doesn't mention my dot d
s store file or my food out o file
that's present in the current directory
because that has been get ignored so
that's a quick overview of a little bit
of advanced get functionality just to
give you a flavor of what sorts of cool
things this tool can do and then finally
we have a couple other topics that are
covered in the lecture notes in more
detail I'll just quickly list them here
so you know what to look for one is that
there are many graphical clients forget
we don't personally use them we like the
git command line tool but some of them
are kind of ok and you might want to
check them out just to see if you prefer
using those another thing is shell
integration so you've noticed that in
this tutorial I've done get status a
whole bunch to see kind of what's going
on with my repository well that's kind
of annoying to do and a lot of people
have their shell prompts set up so that
just within this shell prompt itself
like on every line it will show me a
very succinct summary of what's going on
with my repository so it might show me a
summary of what branch I have currently
checked out along with maybe if I've
modified files or untracked files and so
we have a link in the lecture notes on
how to get some nice shell integration
for displaying kind of get related
information in your shell prompt similar
to that you can get integrations with
your text editor so for example I use
vim and I have a plug-in for vim that
does all sorts of interesting get
related stuff one thing I can do with
this plug-in is look at get blame
information remember we just looked at
this through the command line instead I
can look at it with this plug-in and it
lets me work with it a lot faster I can
look at get blame press enter when
hovering over a specific commit and it
shows me that particular commit in my
text editor it even hides all the other
files and shows me just the one file I
was looking at which is presumably what
I care about so we have links to that in
the lecture notes as well and there are
a couple of there interesting things you
could look at there if you're interested
finally this lecture by itself is
probably not enough to teach you
everything you need to know about git
it's a good start we think that the
right way of learning get was to learn
about
the underlying data model the whole
objects and references and how get
models history and then we gave you an
introduction to using the git commands
and if you want to become really
proficient at this tool in the resources
section in the lecture notes for today
we have a link to a book called pro git
so this is a free book it's nicely
written it's pretty short and I think
going through the first couple chapters
of that book should teach you basically
everything you need to know in order to
use get proficiently for real software
projects and for contributing
it's a project on github and things like
that and then finally just like all the
other lectures we have a number of
exercises you can go to go through if
you want some interesting and
challenging problems that you can figure
out how to do