3. Course Outline
• Getting Setup
• Git: The Big Picture
• Everyday Git
• Branching
• Merging & Rebasing
• Other Random Gitness
• Putting It All Together
• Where to from here?
4. Outcomes & Compentencies
• Install and Configure Git for Windows
• Create local and shared Git repos
• Add, Remove & Commit Files to repos
• View History of Files / Work with Diffs &
Blames
• Branch, Tag and Merge & Rebase
Branches (with Conflicts)
• Back out of trouble & drama
• Be able to Push, Pull, Fetch, Clone, Diff &
Branch Remote Repos
5. Philosophy
• “One must learn by doing the thing; for
though you think you know it, you have no
certainty, until you try.” Sophocles
• “Where there are no oxen, the manger is
clean, but abundant crops come by the
strength of an ox.” Jewish Proverb.
• Experiment. Go Crazy. Type like a
madman.
20. Everyday Git: Getting
Committed
• git init .
• git init myproject
• git status
• echo This is a sample file > sample.txt
21. Adding and Committing
• git add .
• git add myfile.txt myotherfile.txt
• git add “**.txt”
• git status
• git commit -m “My first commit!”
• git commit
• git commit -am “Add all files and commit. I
live on the edge”
22. Formatting Commits
• set GIT_EDITOR=notepad
• git config --global core.editor “notepad“
• First line for short form.
• Second line blank.
• Third line for a long description of the
commit
27. Ignoring Files
• .gitignore
• Ignore file(s), directories, patterns (one per
line)
• Great for ignoring files and directories in
your project
• Specially good for build artefacts and
generated binaries
28. Unstaging a File
• git reset HEAD myfile.txt
• git checkout myfile.txt
• git rm –cached myfile (only pre first
commit)
48. Warning!
• ONLY rebase on a local repo, never
rewrite shared history
• If you’ve pushed your changes, live with it
• You can use git revert to develop
compensating commits
49. Rebase Essentials
• git checkout mybranch
• git rebase master
• git checkout master
• git merge mybranch
50. And when there are conflicts?
• git rebase --abort
• git rebase --skip
• git rebase --continue
51. Rewrite History with Rebase
• git rebase -i <parent-of-the-commit-to-
start-from>
• (entries will appear from oldest to newest)
54. Soft and Hard Resets
• Provide a way of moving HEAD in your
current branch
• Hard resets throw away working tree
Normally HEAD
• Soft resets preserve working would point to
here
7ef7ab ef3ad2 22e4ff ee7ee7
55. Deployment Options
• Create a bare repo on the shared drive
and use file: protocol
• Host it on a shared Unix host and use the
ssh: protocol
• Run a local git daemon!
60. Choosing a Team Workflow
1. Master is always golden (merge from
CI/Dev branch)
2. Branch off master approaching release
3. Release Branch Centric
4. <Your Strategy Here>
61. Git(hub) Flows
• Anything in master is deployable
• To work on something new, create a new
named branch off master and push it
remotely
• After signoff, merge it to master (via a
Jenkins job!)
This question will shape how we approach the day! What do you want out of a revision control system? How do you want it to impact your day-to-day development?
You will be able to do these things by days end. Are there other things you want to be able to do? Ask now, and we’ll add it to our list!We’re really coving the “just in time” rather than “just in case” training programme. So all the common stuff is there, some of the fringier stuff is up to you!
This is a safe place to fail. So today is the day to try everything that you want to try!The most important thing is to type everything and see for yourself. No copy and pasting!Nothing it taught until something is learned!
This module is about some important theory concepts. Don’t switch off – git assumes that you know a few things about its internal implementation.
Git was designed by Linus Torvalds to be a supremely safe version control system! So breathe deeply.The most dangerous place for a file is *outside* of Git. If it’s committed to Git, you’ll be able to get it back (bar an “rm –fr” or “deltree”, and even then there’s hope :-)Even though you’ll hear crazy stuff today about “history rewriting”, “commit re-ordering”, “splitting commits”, it’s all a bit of a sham. Commits are immutable. And you’ll always have weeks to get back ones you mess up or orphan or otherwise appear to delete.So be brave today. And commit often
Git is perfect for the individual developer. Or for the workgroup. Or for anyone!It works when you’re disconnected from the network (and it won’t do any network-y operations unless you ask is specificially).The benefits of having local history of everything is a game changer. It makes branching fast and lightweight.
Git doesn’t track diffs, it tracks blobs. It was designed by a Filesystem hacker. Git calculates diffs when it needs to, but basically works as a snapshotting system. Git also doesn’t need any server software. It was designed to be distributed from the ground up. Every person who has a git clone of repository has the complete history locally, which enables things to be lightening fast that are impossible on CVS/SVN (such as checking out branches). Tooling support has caught up for git in most IDEs. And there are migration scripts available. So there’s no reason not to migrate!
The basic unit of git is a commit. If you’re into the scary details, commits are stored in a Directed Acyclic Graph (so each commit keeps a record of its parent commit).
This little concept is a core one to lock in. Everything in our Git workflows today is designed around these three stages.
Git is just a binary and a config file. There are no registry hacks or special magic. But the windows installer is special ;-)We’ll talk about everything you need to get setup in this module.
Today we’ll be using Git Bash for all our git-ness. When you’re getting started with git, it’s much better if you understand the basics of what is happening underneath. Once you understand how to perform commits, branching, pushing and pulling from the commandline, you’ll be much more comfortable with what your IDE or TortoiseGUI or whatever is doing.So stay with us!
You can download the latest version for Windows from http://msysgit.github.com/. You want the version for “Pure users of Git” rather than the version for users who are hacking on Git for Windows itself. At the time of writing the version we’re using is 1.8. Don’t be concerned about the “preview” or “beta” labelling, you’re a hardcore early adopter and you know it.If you’re running on Linux platforms, your integrated package manager (apt, yum, rpm, etc) can help you out. OSX users can download or brew.
Defaults are fine here. The Advanced Context Menu will give you all the “Git Bash Here” type options that you’ll need.
It’s handy to have Git in your path for all sorts of tools, so you might as well add it from the start.The third option is also unlikely to cause you any drama, so if you’re a Unix guy at heart, it might be handy to have awk/curl/vim around too.
This one is really only a concern in cross-platform environments. If you’re all on the same platform, then 3 is the option for you. Today let’s run with option one.This setting can always be changed later using gitconfig --global core.autocrlf falseNow go forth and install!
Before you start usingGit, it’s best to setup your username and email address. Git won’t email you, but these details will appear at metadata in the commit history of your repository later on. The fact it’s an email address is just part of it’s open source pedigree (working on big shared repos). So if you’re sharing a repo, it’s good to know who’s doing the committing. This has nothing to do with your authentication (git treats that as someone else’s problem – which we’ll talk about later in the day). It’s just about attribution.That --global deal is required since Git supports Global configs (which affect all Git repos for the current user), and local config which operate on a repo-by-repo basis.We’ll explain all about these config entries later in the day. These ones live in a text file at ~/.gitconfig if you’re keen.If you’re curious about the details, you can always “git help config” to find out the details.
Stuff you’ll use every day. Type in everything in this module!Even though git has several dozen commands, there are only a few everyday ones.
It’s time to kick off your first git project! The two common ways to get a Git project is to “clone” someone else’s project, or to create a brand new one. Let’s start with the second scenarioYou can create your project in the current directory (doesn’t matter if it has files already, you can add them later), or a brand new directory.Exercise:Try creating a few different git projectsFirst create them in the current directoryThen try creating them in a subdirectoryThen try creating them in a directory that already has filesUse the git status command to see the state of your repo at any timeHave a poke inside the .git directory to see what’s going on there
Remember that Git operates in two phases. First you stage a commit to the index, then you commit it to the repository.You can stage everything in your directory via the git add . command. You can also stage via a set of filenames or even a “regexp style pattern”.You can always use git status to see what has been staged (or not).Think about how much you want in a single commit. Generally small is better (eg just the files modded to fix issue ABC-241 might be a good commit)Exercise:In one your existing repos, try creating and adding a few filesThen create some subdirectories.What happens when you try and stage your empty directories?Now add a few files with different names in the subdirectories (myfile.txt, theirfile.txt, yourfile.txt) and try adding yourfile.txt using a regexp from your root directory.Try committing your files using both the -m and arg-less versions of commit
You can set the environment variable GIT_EDITOR which trumps everything. But the more common way is to use gitconfig.Notepad doesn’t handle line endings wonderfully, so you might want to upgrade to notepad++ or sublime text.When entering a commit message, you should be generous with your descriptions. Exercise:Experiment with the new 3-line format for commitsView your history in gitk and git logWhat do you notice that’s different about longer commits?
You can use git diff when you need to see what’s changed in a file.You can also use git blame to see what’s changed in a file over time (and who changed it).The gitgui blame version gives you a nice hover over each change (so you can see the commit comments too).If you just want to see the commits that changed a file from the commandline, use gitwhatchangedto list them newest to oldest, or use gitk for the GUI version.Exercise:Using the files from the previous exercise, make some mods to a file then commit. Then change a different line and commit.Use git blame to view the files changes over timeUse gitgui blame to explore the commits in more detailUse gitwhatchangedto see which commits changed the fileFinally, use gitk to see how the integrated tool handles the historyTry renaming one of your file with git mv and see how that affects the blame
Gitk provides the most convenient GUI tool for viewing history, albeit with a fairly hideous UI.If you’re more commandline, then git log --oneline is the way to go. We’ll teach you how to setup an alias for common commands shortly.Exercise:Using your sample repo, experiment using commandlinegit log argumentsTry and display the recent 3 commitsExperiement with “2 days ago”, “last week”, “today”, and “yesterday” as arguments to logCompare with the gitk version to see a GUI representation
Git uses SHA1 to track commits (and trees and blobs and tags and lots of stuff!).SHA1 is a one-way-hash algorithm that takes a large stream of data and reduces it to a small 40 byte fingerprint.
Git tracks blobs of data via hashing, so you can comfortably move files around and Git will (mostly) work out what’s happening.Using git mv means you can avoid doing a git remove/add combo, so it’s the way to go!Git clean will get rid of files that you haven’t stages (perhaps a dry run might be in order?)Exercise:Remove one your existing files from your repository using gitrmTry renaming one of your existing files using git mvHave a look at the history of your file in gitk and git blame.Add some spurious files (but don’t commit them)Try out a dry run with -n then make it happen with -f
A trailing slash means treat it as a dir right here, otherwise it will ignore it everywhere.You can have .gitignore files in subdirectories (and even ignore .gitignore)Exercise:Create a .gitignore file in the root directory of your projectAdd a line to ignore *.log files.Then add a tester.log file to the directoryConfirm you are ignoring!Commit your .gitignore file to your projectDo the same for a “bin” subdirectory
git status will give you lots of good help about how to get out of sticky situations or move forward.We’ll discuss reset later in the day, but for now, just consider it magic.Exercise:Accidently “stage” a fileThen using git reset to remove itWhat to do if you’ve already committed it?
You forgot a file for the last commit? No probs, just add it to staging and run “git commit --amend”. You’ll be prompted for a new message!git show is also a very handy command for debugging these kinds of situations. Try a git show on a commit to see all the changes in that commit.Exercise:Change two files in your working directoryAdd one of them to staging, then commitView the history in gitkAdd the other to staging them run a commit --amend
Amending a commit doesn’t actually change a commit – commits are immutable. This creates a new commit (with both sets of changes) and throws out the old one (which just has the first set of changes). When I say “throws out”, I mean puts it in the reflog. Every few weeks, orphaned commits like this are cleaned up. But you’ve got ages to find them.Exercise:Amend a commit a few timesUse gitk to see how the SHA1 changesUse gitreflog to see your old commitsUse git checkout (by SHA1) to view your old commits
This is a very core part of git workflow. Be encourages to experiment – even if you are getting lost!
Everything we’ve done so far has been linear. But life rarely happens that way.
Git makes branching very lightweight (40 bytes).Branch early, branch often!
git branch will let you know the branches in your repo (git’s default branch is called master). There is a * against your current branch.git branch mynewbranch will create a new branch (but won’t change to it!). You then need to git checkout mynewbranch to change to it. Commonly this is done in a single operation as git checkout -b mynewbranch (which both creates a new branch, and checks it out).Branches are very lightweight in git (40 bytes), and you’re encouraged to create them at will. You can create branches of branches of branches if you like!Git will autocomplete branch names, so it’s common to name branches bug/123 and bug/124 etc.Exercise:Practice creating a few branches and committing some files on each one.Then change between your branches using git checkout and see what happens to your working directoryHow does changing branches affect new files that aren’t staged for commit?
If you have some files in progress, but want to move between branches, git stash let’s you put them away for a rainy day.The stash is a stack, which you can either pop (pull off the top element, removing from stack) or apply (pull off and apply without removing from stack). You should always apply.Exercise:Create some uncommitted changes on a branchTry to checkout masterStash your changesCheckout masterCheckout branchUnstash your changes
Merging creates a commit with two parents (for example, the master and development branch).In fact, you can merge any number of changes at once (several feature branches in master) which is called an octopus merge.Exercise:Change to one of your branches, and create a new file.Then checkout master and merge your changesTake note of the “fast forward”
When a file has been modified by “both sides”, it’s sometimes handy to just accept our changes or their changes, and not resolve the issues.
Sometimes it’s helpful to be able to visualise what’s happening with branches.You can use gitk, or if you’re working from the commandlinegit log --graph --oneline to get a nice visual layout of your branches.Exercise:Change into branch and create a few new filesThen run a gitk from the branchChange back into masterThen run a gitk from masterNotice what is different
Git supports two types of tags: lightweight tags (which are just a pointer to a commit), and annotated tags (which contain metadata about who made the tag).You can move tags about using the -f option.Use git tag to see a list of tags.All tags are local to your repo, until you push them. That gives us a good chance to talk about remotes.Exercise:Use git log to see your recent commitsTry tagging a few your older commits with tags such as “1.0”, “1.1” etcSee what happens when you try and checkout a tag via “git checkout 1.0”
So far all of our changes have been local to our machine.Git won’t go out on the network unless you ask it!But a revision control system is designed for concurrent use, so it’s time to learn work with other repositories.Typically, if you have a repo that you’re sharing, you’ll setup a bare repository on a shared drive. A bare repository is just a .git directory with no working directory and no index. By convention, these directories end in the name “.git”. When you clone them, the .git part disappears. So in the example above, cloning ourrepo.git will create a new local directory called ourrepo.Exercise: Create a new bare repository on your local diskThen clone that repository to somewhere else on your disk.Then make some changes to it, and issue a git push command.
You can pull changes from a remote repository by issuing a git fetch. In this case, the changes are fetched, but your current HEAD is not rolled forward to the next changes. You need to issue a git merge to apply the changes.Issuing a git pull is the equivalent of doing a git fetch followed by a git merge. You can see the diffs of what you’ve pulled in via a git fetch using git diff master..origin/master (or whatever branches you’re on)Pushing tags is a special operation on push. Who knows why?Exercise:Create two clones of your bare repo from the last exerciseCommit files into each and try and push themCreate tags on one of them and try and push themPull the tags downCreate a branch on one of the repos. Does it get pushed?
(example of cloning existing branches and nothing there.)All the branches that you’ve worked with so far have been local branches. Same for the tags.If you want to share a branch to the repo, use a git push origin mybranch. If you want to push changes on all local branches that have matching remote branches, use git push origin. (if your push.default is matching, if it’s simple, it will only push if the branch name matches a remote branch)Exercise:Create a new branch on your repoPush that branch up to a shared repo as a remote branchCreate a fresh clone of the repoDisplay the branches (local and remote)Experiement with local and remote branches in the new repoMake mods to a branch file and push it up
Yes. The colon syntax is crazy. But there you have it. The “nothing” branch is represented by the :.Exercise:Try deleting one of the remote branches from the previous exerciseHow does that affect other clones of the repo?
This was cool, but if you’ve modified lots of the same files, someone is going to have to resolve those.
This was cool, but if you’ve modified lots of the same files, someone is going to have to resolve those.When working on Open Source, you’re encouraged to rebase before you issue a pull request (so there is less pain for the merger).Notice that when rebasing, the commit ids will change since the parents of those commits have changed (the red squares)
Rewriting shared history will just create drama and duplicate commits for everyone. Just stop!
A straightforward rebase is very painless. We’ll cover the conflicted cases shortly.Exercise:Create a new branch fix123 off masterPerform some changes in it and commitChange back to masterPerform some changes in master and commitChange back to fix123 and do a git rebase masterHave a look at your gitk to see the changes (and the reflog if you like)Now change back to masterMerge in your changes as a fast forward
You can always back out the experiment with get rebase --abort if you get into trouble.
You want to pick the first one, then squash the second and third ones.You can use fixup to discard the log message in those commits.Exercise:Perform three or four commits changing various filesUsing git log -4 to see themPick the SHA of the oldest of the four (eg e7b4a2)Issue a git rebase -i e7b4a2Experiment squashing a few commits
We introduced these late in the day because we wanted you to develop muscle memory on the basic commands.But now it’s time to alias yourself into productivity!Some common aliases:st = status ci = commit br = branch co = checkout df = diff lg = log -pExercise:Setup an alias for checkout, status and logExperiment wtih more exotic alias argsSee your current aliases with gitconfigView your ~/.gitconfig file to see how aliases are setup in text
You shouldn’t be messing with shared history, right? So this is all local territory.Be careful with resets. They will cause commits to be orphaned (but you can get them back via the reflog).Hard resets throw away your working tree, so they are particularly nasty. Remember: Hard resets change the working directory, soft resets just change the HEAD pointer. There are also MIXED resets.Exercise:Perform three commits to a repoPerform a git reset --soft ef3ad2 (or a sha of a few commits ago)Run a gitstatusSee your changed filesRun a git commitSee the reflog for discarded commitsSee how this could be used for squashing commits?Experiment with hard resets
You can run your own git daemon on your machine for others to pull from.Why would you want to do that? Because you can!touch /my/dir/myproj/.git/git-daemon-export-okgit daemon --base-path=/my/dirThen you can (readonly) git clone git://localhost/myprojExercise:Setup your own git daemon over you existing directoryTalk a friend into cloning it and making some commits!
Handling a multi-part project (core, db, web, etc)Exercise:Create a new submodule in an existing repo which will point elsewhereExperiment with submodule commitsClone your parent repo elsewhere and see how submodules interact when cloned
Reversing the changes that appear in a commit.
Honestly. You might just be better pushing and pull from a bare repo on a thumb drive
It’s time to workshop different approaches people have to shared repos..git/hooks (don’t get cloned when you clone a repo, so let’s you do things on your CI server only for instance)man gitworkflows is full of useful info too.
If you push to a named branch, every time someone does a git fetch they’ll see your changes.
Big Exercise:Create a bare repoClone that repo on to your hard driveCreate some files and push themCreate a local bugfix branchPut some files in thereMerge back to masterCreate a development branch (but don’t check it out)Make some edits to files in masterChange into the development branchChange the one of the same files that you made in masterPush your changes to a remote development branchChange back to masterMerge your changes from the development branchResolve the conflictsPush your changesMake some edits again in Master and commit themChange to the dev branch again and make some edits to other filesRebase master onto your dev branch (resolving conflicts)Merge dev back to master via fast forwardCelebrate your amazingness