58

Git for Everyone

Embed Size (px)

DESCRIPTION

Learn to use GIT fast. Easy introduction for beginners and people that need to get up to speed fast.

Citation preview

  • 1. Introduction2. The Deck3. Life in the Terminal

    i. Why Terminal?ii. Pimp your Terminaliii. Meet Bashiv. File Navv. Cheat sheetvi. Open in VIvii. In summary

    4. Git workflowi. Branchingii. Branch Managementiii. Pushiv. Pull requestv. Merge the codevi. Shortcuts using aliasesvii. Summary

    5. The Git Demoi. The foldersii. The filesiii. The contentiv. Branchingv. The deltavi. The mergevii. Kill w/fire

    6. Github7. Fork a repo8. Clone a repo9. Auto complete

    Table of Contents

  • Unless you have been living in a cave, Git is everywhere. Creative or engineering, you have directly encountered or willencounter Git in the workplace. A common misconception as well is that Git is only for teams? Regardless of work style orteam size, Git is the tool that everyone should be using.

    Dale Sande, UX Design and Development senior instructor with Code Fellows, will introduce you to Git and get you up tospeed on concepts and workflows in no time.

    Discover how working in the command line isn't all that scary. Understand how to move between projects with just a fewkey strokes. Visually experience what Git is doing behind the scenes. Gain confidence with the steps involved for acommon Git branching strategy. Cloning isn't just for sheep and galactic empires.

    Together we will all create and share Github repositories and understand why Groundhog's Day is the best Git movieEVER!

    This course will be presented with a slide deck, live demonstration and Gitbook provided with related material.

    Life in the TerminalWhat is branching?Git workflow (branching and merging)

    Create local repoAdd content and commit codeBranch the codeMerge all the codesFork a repo

    Getting Git InstalledExercise Git workflowCreate a Github account and generate your SSH keyFork a repoClone a repo

    Git for everyone

    Course material:

    Presentation outline:

    Demo outline:

    Workshop outline:

  • by Dale Sande

    Published June 18, 2014 in Programming

    Git for everyone: the deck

  • If you are reading this, you have been introduced to something called the Terminal on your Mac by one of your overlypushy developer friends/colleagues.

    I am thinking that the conversation went something like this?

    You: How can I get to that file?

    Them: Just open Terminal and then $ cd ~/Projects/boilerplate/ && vi .gitignore

    You: OMG! That is weird? What do I do?

    Them: Geeze, press the i key, go to this line and add /**/* . Then hit the esc key to save. To get out,type :wq , ok?

    Ok, we have all been there. This is weird. This is awkward. What did all of that mean?

    Not to mention, your terminal window is probably all stupid looking, am I right? On a developers screen, it's all coollooking. There is colored text that you can read and it's probably a little transparent. Yours, it's small, the type is hard toread, and it's white and weird looking. No wonder you don't like going in there. It's freaking weird and scary looking, I getthat.

    In this article, I aim to help change all of that and make your interaction with the Terminal a little bit easier.

    Life in the Terminal

    Or Bash to the UNIX kids

  • What's the big deal with Terminal lately anyway? What's wrong with good 'ole GUI tools that we can download and installusing the all too familiar install wizard? To sum it up in three words, it's speed, power and accessibility.

    Open source computing created a slew of new tools and most developers are not about creating OS specific applicationsto run these little apps. Not to mention, the majority of these developers were/are UNIX devs and they LIVE in the shell.

    A shell in computing provides a user interface for access to an operating system's services.

    As these tools became more mainstream with developers, especially with devs on Macs, the natural thing was to adoptthe use of the Terminal. Sure, there have been some who created GUI apps for some of the more popular tools, but theynever really live up to the flexibility and speed that you can get in the Terminal. Not to mention, you are now at the behestof the developer to update their GUI tool as new features are released.

    What's the big deal anyway?

  • The first step to making the Terminal easier to use it to make it easier to look at and work with. The Terminal's applicationpreferences give us some things to start with:

    If you are new to Terminal, on the Startup tab, there isn't much you should really touch there.

    Under Profiles select the theme that would like to useBe sure to click the default button at the bottom so that this becomes your default theme when opening a newTerminal session

    Font: You want to update this to your preference. Monaco 14pt is a great looking font IMHO. Characters are distinct andare difficult to confuse, which is important.

    Text: Check and uncheck these options until the terminal looks good to you. Personally, I like to have the followingchecked:

    Antialias textUse bold fontsAllow blinking textDisplay ANSI colors

    Pimp your Terminal

    The 'Settings' tab

    The 'Text' sub-tab

  • To the right of Antialias text is a color well, I suggest changing this to a color you prefer.

    ANSI Colors: For the inexperienced users I suggest leaving those alone.

    Cursor: Select a style of cursor you like and if you want it to blink or not and you can change the cursor color.

    Not sure what it is, but developers for some reason really like to tweak out their Terminal to look like old skool greenscreen terminal computers. Myself, my first computer screen was amber, so I have a nostalgic connection to this and anamber screen has been claimed to give improved ergonomics, specifically by reducing eye strain. There is no proof tothis, but who needs science?

    Title: This is what will appear in the gray bar at the top of the Terminal window. The checkboxes below, with a terminalwindow open, check/uncheck these options to see if they are of any value to you.

    Background: This is the fun one. Click on the color well for Color & Effects . This is where you can set your background toa color and adjust the transparency. There is a feature to set a background image, but this tends to be really distracting.

    Window size: This will set the default new open window size.

    And that is it for here. At this point, you should have a Terminal window that is looking pretty cool and makes you feel alittle but more comfortable working with it.

    The 'Window' sub-tab

  • Ok, now that you have your Terminal window looking nice, the fun really starts as we get to know what is inside.

    Meet Bash. Terminal is the app that runs Bash on your computer. What is Bash?

    ... an acronym for the Bourne-Again SHell, a pun on Stephen Bourne, the author of the direct ancestor of thecurrent Unix shell

    That's not very useful, but it is interesting. What you really need to know is that when you are looking up more informationon how to do things in Terminal, you will more then likely find references to this thing called Bash. Don't get confused asthe answer you are looking for is most likely there.

    Also, keep in mind that Bash is a fully featured environment that is able to run applications and completely interact withit's host OS. This is extremely powerful and maybe you are seeing why developers prefer this.

    But pay that no mind at this point. For our purposes, we are going to only go as far as the features that we need tounderstand.

    Probably one of the more confusing things of working with Terminal and Bash is how they are configured. Bash uses two(dot) files that are located in your computer's home directory. They are .bashrc and .bash_profile .

    BTW, a (dot) file is any file in the computer's file system where the name's first character is a dot. As in .bashrc . Theservice this provides is that the file is hidden from normal view.

    OSX keeps you from being able to rename a folder or file in the standard GUI for this reason. But ... we can do this fromBash.

    .bash_profile : read and the commands in it executed by Bash every time you log in to the system

    .bashrc : read and executed by Bash every time you start a subshell

    When using these files, there are some actions best suited for the .bashrc and others in the .bash_profile . Keeping thisstraight can drive you a little crazy.

    Luckily, there is a way that makes this all easy to manage. Simply put all your stuff in the .bash_profile file. In order to getthis to work, the two files need to be linked, we do this through what is called sourcing. By placing the following code inyour .bash_profile , as Terminal loads the .bash_profile it will also loop in the .bashrc file.

    if [ -f ~/.bashrc ]; then source ~/.bashrcfi

    Ok, at this time we will just let that sit there. At this point we haven't discussed how to find files in Terminal or how to openand edit files either. Further down this tutorial I will illustrate how to edit the content of these files from within the Terminal.

    Meet Bash

    .bashrc, .bash_profile

  • By now you should have a pretty cool looking Terminal window and have been introduced to some base concepts likeBash and it's core config files. It's time now to learn how to navigate around in this new text based world.

    When you first open Terminal you typically are placed in your home directory. So let's start looking and moving around.

    Note: in the following command examples, you will see the $ symbol. You are NOT to type the $ with the command.This is simply to illustrate that you should enter this command into the Terminal window.

    The first command we will learn is $ cd . What this does is Change Directory. Get it? With $ cd the next symbol we willlearn is the ~ . This symbol is simply an alias to your home directory. So, in your Terminal, do the following:

    $ cd ~

    Doing this will put you in your home directory. To make sure, in the Terminal enter $ pwd and you should see:

    /Users/[your user name]

    Great. But at this point there is a good chance that your Terminal is not telling you very much information. You knowwhere you are, but what's in your current directory? To list out the contents of your directory, do the following:

    $ ls

    File navigation

  • Great! Now you can see all the files and folders contained within your User's directory. This isn't very exciting, let's get intosome fun stuff. If you are like me, you have any number of files and folders on your Desktop. All the contents of yourDesktop are contained within your Desktop directory in your User's folder. So, let's change directory into Desktop bydoing the following:

    $ cd Desktop/

    And then list the items:

    $ ls

    Remember those (dot) files? You may notice that when you do a $ ls you only see files and folders that you can see inthe standard OS GUI. Commands in Bash can have additional attributes passed into them called flags. To see the hiddenfiles on your desktop pass in the -la flag like so:

    $ ls -la

    Now, listed in the Terminal you should see hidden files and folders, also you can see permissions, file size, modifieddates as well as some other information. Here is an example from my Desktop directory.

  • Notice is that it may be difficult to distinguish between files and folders. How can we make this easer? Passing in the -p flag with an ls command will instruct Bash to list out directories with a trailing / . To see this, do the following:

    $ ls -p

    Great! Now we can see the contents of your Desktop directory and easily tell the difference between a file and a folder.Now we can easily see that my PeepCode content is in a directory.

    Continue playing with this and $ cd further into folders within your desktop.

    Done? Did you $ cd into a folder on your desktop and get stuck? I told you how to go in, but not how to back out.Changing directories backwards is just as easy, from within a directory, do the following:

    $ cd ../

    That command will back you out one level from where you are. If you wanted to back out two directories, simply addanother ../ like so:

  • $ cd ../../

    By now I am betting that your Terminal window is looking a bit messy. By entering the clear command, this will clean upyour view and give you a nice clean Terminal window to work with:

    $ clear

    At this point, you are doing really awesome. You have mastered some of the core commands for using Bash in theTerminal app.

    Next we need to learn how to add, edit and delete files and directories. While I admit, it's a little weird at first, it's actuallypretty simple once you understand the commands.

    Starting off, creating a new file is amazingly easy and very powerful. You can create any type of file with any type of fileextension from Bash and the Terminal. The utility command you want to use is touch . This utility is capable of multiplefeatures, but the one that we care about is creating a new file when one does not exist.

    To do this, simply use the touch command, add on the name of the file you want to create and the file extension. Tocreate a simple text file called "new-file" from within the Terminal, enter the following:

    $ touch new-file.txt

    Say you wanted to create a new "index.html" file? To do so, use the following:

    $ touch index.html

    "style.css"? Do the following:

    $ touch style.css

    I think you are starting to get the point here. Remember when we spoke of (dot) files and that you can't create them fromthe default OSX GUI? This can easily be addressed in the Terminal by placing the (dot) in the name like so:

    $ touch .config

    Remember, you can't see this file in the normal OSX GUI, so from where you are, use the ls -la command to see this file.

    This brings us to the next part, how do you delete a file from the Terminal? To do this, we use the rm UNIX commandwhich is short for remove. Using this command, we can remove that .config file we previously created by doing thefollowing:

    $ rm .config

    Running this command will simply delete this file and only return feedback if there is an error, for example:

    File and directory management

    Create / Delete files

  • rm: .config: No such file or directory

    Let say for example that you are not really confident with this and want to make sure that you are deleting the correct file.To do this, simply pass in the -i flag. This will instruct the command to prompt you for confirmation. Here is an example ofcreating a file, using that prompt flag and addressing the prompt.

    Desktop$ touch .configDesktop$ rm -i .configremove .config? yDesktop$

    Now that we have files out of the way, what about folders? In the world of Bash and Terminal, folders are actually referredto as directories. The UNIX command we are looking for is mkdir , which is short for make directory. For example, on yourDesktop, let's create a new folder called foo .

    $ mkdir foo

    Now when you do a ls -p from within your Desktop you should see this new foo/ directory we created.

    ProTip: You don't actually have to be in the directory you want to create a new directory in. Remember the ~ alias foryour Home directory? For example, imagine you are in your Dropbox folder and you want to create a new folder on yourDesktop. You could do the following:

    Dropbox$ mkdir ~/Desktop/foo

    The next real-world thing you will run into is how to make a directory structure that is x number of levels deep. Making adirectory, then changing into that directory just to make another directory is turtles all the way down.

    There is a better way. When using the mkdir command, simply add on the -p flag and this will create all directoriesleading up to the given directory that does not already exist. If it does exist, ignore the error. Let's have fun here, run thefollowing in your Terminal:

    $ mkdir -p ~/Desktop/turtles/all/the/way/down

    Now that we have mastered creating directories, what about deleting them? Remember how we used the rm commandto delete a file? We need to use this, but you can't simply delete a directory, we need to add on the -r flag which meansto remove directories and removing the contents recursively beforehand. So to remove our turtles directory, we would runthe following:

    $ rm -r turtles/

    Let's imagine that there is a case where there would be non-existent files confirmation prompts that get in your way ofdeleting these directories. What is common is to add on the -f flag to force the delete like so:

    $ rm -r -f turtles/

    For most developers, adding the -f flag is just common place and as a short hand, you can combine the -r -f flag tosimply be -rf and do something like the following:

    Create / Delete directories

  • $ rm -rf turtles/

    Warning: Using the -f flag to force something and ignore any prompts, pay attention to what you are doing. Thiscommand will delete anything in it's path with no hesitation.

    Protip: When you are typing names of files and directories, start typing the first characters and then hit the tab key.Terminal will attempt autocomplete the name. If it can't hit the tab key twice and Terminal will list out all the possibleoptions.

    Now that we have created all these files and directories using the Terminal, the next obstacle to over come is to moveand rename things.

    Starting with the basics, renaming things in Bash uses the mv command which is short for *move*. The mv commandtakes two arguments, the first is the file you want to change and the second is the result you want.

    $ mv

    For example, using what we have learned so far and adding in the new mv command, let's create a new file on theDesktop within a project directory and then rename it:

    $ cd ~/Desktop$ mkdir -p project/public/stylesheets$ cd project/public/stylesheets$ touch stylesheet.css$ mv stylesheet.css app.css

    Move/copy/rename files and directories

  • Great! Now let's say that we wanted to move that new app.css file to a new location. Remember, the mv command weused for renaming is really to move things. Since we are still in that stylesheets directory, let's move the app.css file up tothe root of the public directory. To do this, use the following command:

    $ mv app.css ../../public/

    In that example, we could also rename the file if needed, for example:

    $ mv app.css ../../public/style.css

  • Moving directories is much like moving files. For example, let's say that we created a directory at the root of project called javascripts . Oops! We need that directory to be within public . To do this, use the mv command and pass in the sourceand then the destination, as this example illustrates:

    $ mv javascripts/ public/

  • Renaming directories goes the same way. Say that we had a directory on the Desktop called foo and we need to renameit to be bar as shown in the following example:

    $ mv foo/ bar/

    The last thing we will talk about here is the process of copying a file from one location to another. For this we need to usethe cp UNIX utility, short for *copy*. cp is much like mv , but instead of moving the file it makes a new copy of the originalin the new location. For files, the process should be familiar by now:

    $ cp

    What you should also know is that in defining the target for the copied version of the file, you can also rename it. Forexample, and what is very common is that in a project there will be an example configuration file. It is then left up to thedeveloper to copy that file, update the name and then edit the configurations:

    $ cp .config.exmaple .config

    Copying directories is much like copying files, except for the fact that they have directories within, so we need to pass inthe -r flag for recursive. It should also be noted that when you copy a directory, depending on how you refer to thedirectory in the command determines the outcome.

    Let's say that we have directory_1 and then directory_2 . Inside directory_1 is a file called one.html . Inside directory_2 is afile called two.html . In this first example, I will simply refer to the source and target:

  • $ cp -r directory_1 directory_2

    By doing this, the command will copy directory_1 and it's contents into directory_2 .

    But by adding the whack / into the command on a directory, this will only copy the contents of the directory in to the newlocation.

    $ cp -r directory_1/ directory_2

  • This concludes the file navigation portion of this tutorial. If using Terminal is new to you and you made it this far withoutthrowing your computer out the window, I applaud you! This is a huge step forward and you are now moving onto biggerand better things!

  • Key/Command Description

    Tab Auto-complete files and folder names

    Ctrl + A Go to the beginning of the line you are currently typing on

    Ctrl + E Go to the end of the line you are currently typing on

    Ctrl + U Clear the line before the cursor

    Ctrl + K Clear the line after the cursor

    Ctrl + W Delete the word before the cursor

    Ctrl + T Swap the last two characters before the cursor

    Esc + T Swap the last two words before the cursor

    Ctrl + R Lets you search through previously used commands

    Ctrl + L or Command + K Clears the Screen

    Ctrl + C Kill whatever you are running

    Ctrl + D Exit the current shell

    Prompt Description

    $ cd Home directory

    $ cd [folder] Change directory

    $ cd ~ Home directory, e.g. 'cd ~/folder/'

    $ cd / Root of drive

    $ ls Short listing

    $ ls -l Long listing

    $ ls -a Listing incl. hidden files

    $ ls -lh Long listing with Human readable file sizes

    $ ls -R Entire content of folder recursively

    $ sudo [command] Run command with the security privileges of the superuser (Super User DO)

    $ open [file] Opens a file

    $ open . Opens the directory

    $ top Displays active processes. Press q to quit

    $ nano [file] Opens the Terminal it's editor

    $ pico [file] Opens the Terminal it's editor

    $ q Exit

    $ clear Clear screen

    Prompt Description

    Terminal Cheatsheet for Mac ( basics )

    Keyboard Shortcuts

    Core Commands

    Command History

  • $ history n Shows the stuff typed - add a number to limit the last n items

    $ ctrl-r Interactively search through previously typed commands

    $ ![value] Execute the last command typed that starts with 'value'

    $ !! Execute the last command typed

    Prompt Description

    $ touch [file] Create new file

    $ pwd Full path to working directory

    $ .. Parent/enclosing directory, e.g.

    $ ls -l .. Long listing of parent directory

    $ cd ../../ Move 2 levels up

    $ . Current folder

    $ cat Concatenate to screen

    $ rm [file] Remove a file, e.g. rm [file] [file]

    $ rm -i [file] Remove with confirmation

    $ rm -r [dir] Remove a directory and contents

    $ rm -f [file] Force removal without confirmation

    $ rm -i [file] Will display prompt before

    $ cp [file] [newfile] Copy file to file

    $ cp [file] [dir] Copy file to directory

    $ mv [file] [new filename] Move/Rename, e.g. mv -v [file] [dir]

    Prompt Description

    $ mkdir [dir] Create new directory

    $ mkdir -p [dir]/[dir] Create nested directories

    $ rmdir [dir] Remove directory ( only operates on empty directories )

    $ rm -R [dir] Remove directory and contents

    Prompt Description

    $ more Output content delivered in screen-size chunks

    $ > [file] Push output to file, keep in mind it will get overwritten

    $ >> [file] Append output to existing file

    $ < Tell command to read content from a file

    Prompt Description

    File Management

    Directory Management

    Pipes - Allows to combine multiple commands that generate output

    Help

  • $ [command] -h Offers help

    $ [command] --help Offers help

    $ [command] help Offers help

    $ reset Resets the terminal display

    $ man [command] Show the help for 'command'

    $ whatis [command] Gives a one-line description of 'command'

  • Ok, gonna get a little rough here, but I am sure you can do it. Let's add some color to your Terminal experience. To dothis, we need to add some code to your .bash_profile . The trick here is that it's difficult to open hidden files using mosteditors that rely on a typical finder. UNIX comes with a text editor called VI built in that you can access from the Terminal.

    To get started, make sure that you are in your home directory:

    $ cd ~

    Now, open the file in VI:

    $ vi .bash_profile

    In your Terminal, you will have open this file in VI mode, so things are a little different. In order to add content, you need tohit the i key. This open the -- INSERT -- mode and add the following:

    export CLICOLOR=1export LSCLOLOLORS=GxFxCxDxBxegedabagaced

    To save these edits, hit the esc key. To exit VI mode, type :wq . I know, all a little weird, but that's how it works. Welcometo VI.

    Ok, for the fun part. If you do a ls -p here, there will be no change. To get updated to the .bash_profile to take effect, youhave to do what is called 'sourcing'. To do this, run:

    Open and edit files using VI

  • $ source ~/.bash_profile

    Now, enter ls -p and your directories will be a different color from your files.

  • There is an amazing amount of material here to consume. If you are new to using the Terminal, you may have to runthrough these a few times to really get them locked in. But trust me, once you start down this path, there is no turningback. Running your computer from the Terminal is efficient, powerful and fast.

    In conclusion

  • There are many Git workflows out there, I heavily suggest also reading the atlassian.com Git Workflow article as there ismore detail then presented here.

    The two prevailing workflows are Gitflow and feature branches. IMHO, being more of a subscriber to continuousintegration, I feel that the feature branch workflow is better suited.

    When using Bash in the command line, it leaves a bit to be desired when it comes to awareness of state. I would suggestfollowing these instructions on setting up GIT Bash autocompletion.

    Git basics - a general workflow

  • When working with a centralized workflow the concepts are simple, master represented the official history and is alwaysdeployable. With each now scope of work, aka feature, the developer is to create a new branch. For clarity, make sure touse descriptive names like transaction-fail-message or github-oauth for your branches.

    #Protip: Although you may have a feature like 'user login and registration`, this is not considered appropriate to create afeature branch at this level, there is too much work to be done. It is better to break these large deliverables down tosmaller bits of work that can be continuously integrated into the project. Remember, commit early and often.

    Before you create a branch, be sure you have all the upstream changes from the origin/master branch.

    Before I pull, I make sure I am on the right branch. I have GIT Bash autocompletion installed, this tells me the branch inthe prompt. Otherwise, the following command is good to know to list out the branches I have locally as well designatewhich branch I am currently on.

    $ git branch

    The checked out branch will have a * before the name. If the return designates anything other then master then switchto master

    $ git checkout master

    Once on master and ready to pull updates, I use the following:

    $ git pull origin master

    The git pull command combines two other commands, git fetch and git merge . When doing a fetch the resultingcommits are stored as remote branch allowing you to review the changes before merging. Merging on the other hand caninvolve additional steps and flags in the command, but more on that later. For now, I'll stick with git pull .

    Now that I am all up to date with the remote repo, I'll create a branch. For efficiency, I will use the following:

    $ git checkout -b my-new-feature-branch

    This command will create a new branch from master as well checkout out that new branch at the same time. Doing a gitbranch will list out the branches in my local repo and place a * before the branch that is checked out.

    master* my-new-feature-branch

    No. There is a command that allows me to create a new branch from any other branch while having checked out yetanother branch. WAT?!

    Basic branching

    Make sure you are on master

    Do you have to be on master to branch from master?

  • $ git checkout -b transaction-fail-message master

    In that example, say I was in branch github-oauth and I needed to create a new branch and then checkout the newbranch? By adding master at the end of that command, Git will create a new branch from master and then move me(checkout) to that new branch.

    This is a nice command, but make sure you understand what you are doing before you do this. Creating bad branchescan cause a real headache when trying to merge back into master.

  • As I am working on my new feature branch, it is a good idea to commit often. This allows me to move forward without fearthat if something goes wrong, or you have to back out for some reason, I don't lose too much work. Think of committinglike that save button habit you have so well programed into you.

    Each commit also tells a little bit about what I just worked on. That's important when other devs on the team are reviewingmy code. It's better to have more commits with messages that explain the step versus one large commit that glosses overimportant details.

    As I am creating changes in my project, these are all unseated updates. With each commit there most likely will beadditions, and there will also be deletions from time to time. To get a baring of the updates I have made, lets get thestatus.

    $ git status

    This command will give you a list of all the updated, added and deleted files.

    To add files, I can add them individually or I can add all at once. From the root of the project I can use:

    $ git add .

    In order to remove deleted files from the version control, I can again either remove individually or from the root addressthem all like so:

    $ git add -u

    I'm lazy, I don't want to think, so the following command I make heavy use of to address all additions and deletions.

    $ git add --all

    All the preceding commands will stage the updates for commitment. If I run a git status at this point, I will see my updatespresented differently, typically under the heading of Changes to be committed: . At this point, the changes are only stagedand not yet committed to the branch. To commit, do the following:

    $ git commit -m "a commit message in the present tense"

    It is considered best to illustrate your comment in the tense that this will do something to the code. It didn't do somethingin the past and it won't do something in the future. The commit is doing something now.

    A bad example would be:

    $ git commit -m "fixed bug with login feature"

    A good example would be:

    Branch management

    Commit your code

  • $ git commit -m "update app config to address login bug"

    Comments are cheap. For more on how to write expressive commit messages, read 5 Useful Tips For A Better CommitMessage.

  • When working with feature branches on a team, it is typically not appropriate to merge your own code into master.Although this is up to your team as how to manage these expectations, but the norm is to make use of pull requests. Pullrequests require that you push your branch to the remote repo.

    To push the new feature branch to the remote repo, simply do the following:

    $ git push origin my-new-feature-brach

    As far as Git is concerned, there is no real difference between master and a feature branch. So, all the same Git featuresapply.

    This is a special case when working on a team and the branch I am are pushing is out of sync with the remote. Toaddress this, it's simple, pull the latest changes:

    $ git pull origin my-new-feature-branch

    This will fetch and merge any changes on the remote repo into my local brach with the changes, thus now allowing you topush.

    When I am are creating the feature branch, this is all pretty simple. But when I need to work on a co-workers branch, thereare a few additional steps that I follow.

    My local .git/ directory will of course manage all my local branches, but my local repo is not always aware of any remotebranches. To see what knowledge my local branch has of the remote branch index, adding the -r flag to git branch willreturn a list.

    $ git branch -r

    To keep my local repo 100% in sync with deleted remote branches, I make use of this command:

    $ git fetch -p

    The -p or --prune flag, after fetching, will remove any remote-tracking branches which no longer exist.

    Doing a git pull or git fetch will update my local repo's index of remote branches. As long as co-workers have pushedtheir branch, my local repo will have knowledge of that feature branch. By doing a git branch you will see a list of my localbranches. By doing a git branch -r I will see a list of remote branches. There is a good chance that the new feature branchis not in my list of local branches.

    The process of making this remote branch a local branch to work on is easy, simply checkout the branch.

    Push your branch

    My branch was rejected?

    Working on remote feature branches

    Tracking remote branches

    Switching to a new remote feature branch

  • $ git checkout new-remote-feature-branch

    This command will pull it's knowledge of the remote branch and create a local instance for me to work on.

  • The pull request is where the rubber meets the road. As stated previously, one of the key points of the feature branchworkflow is that the developer who wrote the code does not merge the code with master until there has been a peerreview. Leveraging Github's pull request features, once you have completed the feature branch and pushed it to the repo,there will be an option to review the diff and create a pull request.

    In essence, a pull request is a notification of the new code in an experience that allows a peer developer to review theindividual updates within context of the update. For example, if the update was on line 18 of header.haml , then you willonly see header.haml and a few lines before and after line 18.

    This experience also allows the peer reviewer to place a comment on any line within the update. This will becommunicated back to the editor of origin. This review experience really allows for everyone on the team to be activelyinvolved in each update.

    Once the reviewer has approved the editors updates, there are two ways to merge in the code. One from the Githubinterface and another from the command line.

    The Pull request

  • Although I can merge from Github's interface, it is preferred to do it from the command line. After all, what happens ifGithub merging tools are broken? It can happen.

    So let's assume that I created a feature branch, edited code and pushed it to the repo. I initiated a pull request and thecode update was approved. Here are the steps I will go through to merge the new code. Keep in mind, this illustration issimply managing code, this is not including running tests, while it can be worked into this workflow, that is a separateconcern.

    Make sure that I have the latest version of the feature branch from the remote repo

    $ git checkout my-feature-branch$ git pull origin my-feature-branch

    Make sure that the feature branch is up to date with master , while in the feature branch, execrate the following:

    $ git pull origin master

    If there are any conflicts, best to address them here.

    Now that I know that the feature branch is up to date with the remote repo and that it has the latest code from master , Ican now merge these branches. I also need to make sure that my local master branch is up to date as well.

    $ git checkout master$ git pull origin master$ git merge --no-ff my-feature-branch

    Notice the --no-ff flag in the merge command. This flag keeps the repo branching history from flattening out. If I were tolook at the history of this branch, using GitX for example, when using the --no-ff flag, I will see the appropriate bumpillustrating the history of the feature branch. This is helpful information. If I didn't use this flag, then Git will move thecommit pointer forward.

    I can either enter the --no-ff flag each time I merge or I can set this as my default. I prefer the default option. Running thefollowing command will update the global gitconfig.

    $ git config --global merge.ff false

    And of course, setting the bit back to true , will return the default setting to fast forward with merging.

    NOTE: there is a mild side-effect that will happen when you set this flag to false . Every time you do a pull this will not fastforward your local repo and basically make this a new commit. That's ok, but you will see this in the commit logs

    Merging the code

    Latest version

    Branch is up to date

    Merge the branches

  • Merge branch 'master' of github.com: ...

    and

    # Your branch is ahead of 'origin/master' by 1 commit.

    If you are ok with this, then keep the flag. If this annoys or bothers you, do not use the flag and set --no-ff manually witheach merge.

    Now that I have merged the code, the feature branch by definition is obsolete. First, delete the branch from the local repo.

    $ git branch -d my-feature-branch

    The -d flag for delete will typically delete any branch. Remember, you can't delete a branch you have checked out.

    If you happen to see the following error when deleting a branch, then simply replace the -d with -D to force the delete.

    error: The branch 'name-of-branch' is not an ancestor of your current HEAD.

    If the feature branch was pushed to the repo, as it should have been per the workflow we described, you will want todelete this from the remote repo as well.

    $ git push origin --delete my-feature-branch

    Delete the local branch

    Delete the remote branch

  • There are some steps in there that we should just be doing all the time. What about making a single command alias thatwill cycle through all these commands just so we know things are always in good shape? Yup, we can do that.

    Using Git and Bash is like using a zipper and pants. They just go together. Creating a Bash alias is extremely simple.From your Terminal, enter

    $ open ~/.bash_profile

    This will open a hidden file in a default text editor. If you have a shortcut command for opening in an editor like SublimeText, use that to open the file. In the file add the following:

    alias refresh="git checkout master && dskil && git pull && git fetch -p"

    The alias dskil is useful for removing annoying .DS_Store files. You should have a .gitignore file that keeps these out ofversion control, but I like to keep a clean house too. To make that work, add the following:

    alias dskil="find . -name '*.DS_Store' -type f -delete"

    With this in your .bash_profile , you simply need to enter refresh in the command line and POW!

    If you are on Windows and using Powershell, you can use the same aliases, but the set up is different. The articleWindows PowerShell Aliases is a good tutorial of the process.

    Shortcuts using aliases

    In Bash

    In Powershell

  • Following this simple workflow has helped keep my projects clean and Git hell free. I hope it serves you well too.

    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features thatyour team can use. I am sure some of you reading this will say "What about rebasing?" This is a perfectly practicaladdition to this workflow and many teams use it. But out of all the teams I have ever worked for, only one has ever madeuse of this feature. Just saying.

    Outside of that, for more in-depth learning on Git, I invite you to read the Git book, it's free and contains awesomelearning.

    Summary

  • The easiest way to understand what Git is doing is to 'see' what it is doing. For this demo, the exercise is simple, we willuse your desktop, a folder and some simple HTML files to illustrate what Git it really doing.

    Git Demo

  • On your /Desktop let's create a folder and call it gitDemo . The following steps will make sure that you are on the Desktopof your computer, make a new directory and change into that directory.

    $ cd ~/Desktop$ mkdir gitDemo$ cd gitDemo/

    Now that we have the folder we can make this into a Git repository. Any directory at any level can be made into a Gitrepository (or repo for short). If at any point you are unaware of the status of the repo:

    $ git status

    Running the status command inside the gitDemo/ dir should produce the following:

    fatal: Not a git repository (or any of the parent directories): .git

    This simply means that this dir is not a properly set up Git repo. To make this a repo, simply run the following command:

    $ git init

    Running this command you should see something similar to the following:

    Initialized empty Git repository in /Users//Desktop/gitDemo/.git/

    Running the status command here will now produce a completely different response:

    # On branch master## Initial commit#nothing to commit (create/copy files and use "git add" to track)

    That is a little bit of a mouthful, but nothing to be concerned with. Simply, what this means is, you are on the master branch and there is nothing yet to commit.

    The folder

  • Now that we have a dir that is a properly formatted Git repo, let's create a few new files for a demo web app that we canbeing to add to version control.

    First, let's add the index.html file:

    $ touch index.html

    Great. But we need some more stuff for our demo web app. We need our primary CSS and Js files too. To do this weneed to create the proper dir for each:

    $ mkdir stylesheets$ mkdir javascripts

    Using the cd command, we need to change directory into each dir and add a app.js and a app.css file:

    $ cd stylesheets && touch app.css && cd ../$ cd javascripts && touch app.js && cd ../

    What's up with those commands? It's simple really, in Terminal you can string together commands using the && operator.If you were to take this apart:

    1. Change directory into stylesheets/ 2. Create the new app.css file3. Change directory back up a level to where we started from

    Pretty cool, huh?

    Now that we have that set up, run the status command again and you should see the following:

    # On branch master## Initial commit## Untracked files:# (use "git add ..." to include in what will be committed)## index.html# javascripts/# stylesheets/nothing added to commit but untracked files present (use "git add" to track)

    GREAT! Ok, we are still on the master branch, nothing is ready to commit, but we have new Untracked files in the output.Take note that we have files in the javascripts/ and stylesheets/ dirs but they are not listed out? This is because when youadd a new dir and create new files, unless you tell Git not to, it will simply gobble up all the files in the dir, so there is noneed to list them individually.

    Interesting experiment: Let's create a new dir and NOT put anything inside it and then run the status command again:

    $ mkdir foo$ git status

    What's this? The new dir foo is not in the output? That's weird? No, it's not really. Git tracks files, not directories. So, if youcreate a directory and don't put in any files, even if they are empty files, Git will pass on the empty dir all together.

    The files

  • Ok, let's remove that foo dir:

    $ rm -rf foo

  • At this phase we have the dir, it's a repo and it has folders and files. Great. Now to add some content. Open each file andadd the following:

    HTML

    Hello World

    CSS

    h1 { font-size: 8em;}

    JavaScript

    var today = new Date()

    Looking good. Having done this, let's look at our status again. Anything different? Nope. While Git does track everysingle turned bit in these documents, it does not display this in the status output.

    It's time to get things tracking, so let's use the add function and then append a statement to this commit :

    $ git add .

    Whoa, wait right there. Check the status now, you should see something like the following:

    # On branch master## Initial commit## Changes to be committed:# (use "git rm --cached ..." to unstage)## new file: index.html# new file: javascripts/js.css# new file: stylesheets/app.css#

    What does unstage mean? And if everything is working correctly the new files should be yellow . What this means is thatwhen we ran the git add . command, this updated the status of all the files in that directory to be staged . This means thatthe edits you have added are not yet committed to the repo.

    If you were to try and push code or switch branches at this time, these changes would not do what you expect them to do.In order to commit these changes to the branch, we need to run the commit command.

    There are a few parts of this we should talk about. There is the commit command that initiates the function and then thereis the -m flag that we need to pass in so that you can add a commit message. This is important as you need thesemessages added to the log, or the individual commit messages are meaningless. We add the message at the end of thecommand sequence using quotes " " :

    $ git commit -m "update to function ..."

    The content

  • After running this command sequence, you should see the following in your Terminal:

    # On branch masternothing to commit, working directory clean

    Great! All the code has been updated and committed to the master branch!

    When writing a commit message, you want to phrase things in the present tense. Meaning, the code you committed willnot do things in the future and they did not do things in the past. Examples of poor messages are:

    $ git commit -m "added the new background image to the header"

    or

    $ git commit -m "will add new background image to the header"

    or

    $ git commit -m "SLAAAAAAAAAAAAAAYER!"

    In both these cases, these messages when read by the other developers in the log send a confusing message. And thelast one ... well o_O

    Think of things in this way, "This commit will ..."

    $ git commit -m "add new background image to the header"

    Make sense?

    Ok now that we have committed some code, let's see the history of these events.

    $ git log

    You will see:

    the commit hash IDauthor of the committhe date of the committhe commit message

    commit 15d42d592fff5abe101e5985be0830d1bd03a1f1Author: Dale Sande Date: Tue Jun 10 18:25:26 2014 -0700

    update to function ...

    A word on commit messages

    Commit history

  • Cool, now we know things about the code being committed to the repo. Want to know more?

    $ git blame index.html

    Yes, blame is the function and index.html is what we want to know about. This is a great way to see who did what on agiven file when things go a little left.

    ^15d42d5 (Dale Sande 2014-06-10 18:25:26 -0700 1) Hello World

    You can see the initial part of the hash, the time stamp and the code that was modified. NICE!

  • So far through this demo we have been working on a single master branch. The master branch is simply a conventionfor stating what is the core branch of code that everyone should be committing to. Some don't use master and useconventions like stable and things along those lines.

    So, how do we work with branches? Pretty simple really. The first thing we want to know what branches we have andwhat branch we are on:

    $ git branch

    You should see:

    * master

    And the word master should be highlighted. Great. This means that we have only one branch and that this is the one youare on. Let's make a new branch:

    $ git checkout -b new-branch

    What did we do here? git checkout is the command to checkout a branch, passing in the -b flag is to create and checkouta new branch, then new-branch is the name we passed in here. You can name a branch anything, but I suggest keepingis short so that it is easy to type as you will be switching branches a lot.

    Ok, now let's see those branches again:

    master* new-branch

    Cool. We have two branches and since we used the -b flag when we created the branch, this also switched us to thatnew branch right away.

    Playing with branches

  • These next steps will demonstrate how we can make some edits in this branch, commit them and then switch to see thedelta between the branches.

    First, let's update some code in the index.html file. Open this up in your favorite text editor and add the following code:

    goodnight moon

    Cool. Now open the app.css file and add the following:

    p { font-size: 2em;}

    Cool, now we have a diff between what was originally in this branch and what we edited. Here there are a couple ofthings we can do, bit for now let's get out status:

    $ git status

    And we should see:

    # On branch new-branch# Changes not staged for commit:# (use "git add ..." to update what will be committed)# (use "git checkout -- ..." to discard changes in working directory)## modified: index.html# modified: stylesheets/app.css#no changes added to commit (use "git add" and/or "git commit -a")

    Ok, the next thing we want to do is commit these changes to THIS branch and switch back to the master branch:

    $ git add .$ git commit -m "update content and styles"

    Doing a git status here we will see that there is nothing to commit and the working directory is clean. Cool! Now, let'sswitch back to the master branch:

    $ git checkout master

    Great. Now open the index.html and app.css files. The code we just added and committed are GONE!!!! Ok, don't panic,it's not really gone, it's just on the other branch. Let's switch back to make sure.

    $ git checkout new-branch

    Blamo! All the code should be back. But, we need that code in master ?

    The delta

  • Getting your branched code merged into master is not a magical process, it's pretty simple really. What do we know? Weknow that we have a version of code on master and that we have more code in a brach called new-branch . It is the newcode that we want merged into master. To get started, let's checkout master`:

    $ git checkout master

    Ok, now we want to merge, but let's do a little check first. We can do a quick check to see what branches are merged andnot merged into master

    $ git branch --merged

    At this point, we should only see the master branched listed. So then run this:

    $ git branch --no-merged

    This should return the new-branch in the list. Ok, let's merge these two. BUT, we need pass in the --no-ff flag. What doesthis do?

    The --no-ff flag prevents git merge from executing a "fast-forward" if it detects that your current HEAD is an ancestor of thecommit you're trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branchpointer to point at the incoming commit.

    Occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branchtopology (e.g. you're merging in a topic branch and you want to ensure it looks that way when reading history). In order todo that, you can pass the --no-ff flag and git merge will always construct a merge instead of fast-forwarding.

    $ git merge new-branch --no-ff

    Ok, but this may have just got weird and will freak you out.

    The merge

  • You may be seeing something like this:

  • Merge branch 'new-branch'

    # Please enter a commit message to explain why this merge is necessary,# especially if it merges an updated upstream into a topic branch.## Lines starting with '#' will be ignored, and an empty message aborts# the commit.~~~~~~~~~~~~~~~~~~~~~~~~~~~~".git/MERGE_MSG" 7L, 253C

    Nothing to worry about there. Remember what I said about the --no-ff flag? It's a merge. But when we made this merge,we didn't add a commit message. This is Git telling us that we didn't leave a commit message and it's asking us for onenow.

    If we don't leave a message, then Git will insert one for us. So, do the following:

    :wq

    Weird, but trust me. Now you should see the following:

    Merge made by the 'recursive' strategy. index.html | 2 ++ stylesheets/app.css | 4 ++++ 2 files changed, 6 insertions(+)

    Here is your confirmation that index.html and app.css added some code to the master branch.

    Just to confirm that everything is all merged up, run this:

    $ git branch --merged

    You should see both our branches in this list.

    That's it, we are all merged up. Here is what our repo looked like before we merged

    The before and after

  • And here it is after

  • You may notice the out branch that we created when we created our feature branch and then it links back into the master branch. This is EXACTLY what we are looking for. This is the merge technique we want when using the --no-ff flag. If wehad not used that technique, we would see a single branch of code and that can be misleading when we are reviewingour project history.

  • Now that all our codes are merged, there is no need to keep the new-branch branch around. So, let's kill it with fire!

    $ git branch -D new-branch

    BOOM! There is no coming back from that easily. But why would we want to keep that around? Once we merge the code,the history and code are all now part of master and that's where we want it. Keeping that old branch around us useless tous. When we want to add new code, we will create a new feature branch.

    Delete the branch

  • Without a doubt, Git and Github are like peanut butter and jelly. Once you have registered yourself as a user on Github,the next thing you need to do is establish a connection to Github using SSH.

    source

    We strongly recommend using an SSH connection when interacting with GitHub. SSH keys are a way to identify trustedcomputers, without involving passwords. The steps below will walk you through generating an SSH key and then addingthe public key to your GitHub account.

    First, we need to check for existing SSH keys on your computer. Open up the command line and type:

    $ cd ~/.ssh$ ls -al

    Check the directory listing to see if you have files named either id_rsa.pub or id_dsa.pub . If you don't have either of thosefiles go to step 2. Otherwise, you can skip to step 3.

    To generate a new SSH key, copy and paste the text below, making sure to substitute in your email. The default settingsare preferred, so when you're asked to "enter a file in which to save the key,"" just press enter to continue.

    $ ssh-keygen -t rsa -C "[email protected]"# Creates a new ssh key using the provided emailGenerating public/private rsa key pair.Enter file in which to save the key (/your_home_path/.ssh/id_rsa):

    Next, you'll be asked to enter a passphrase.

    Enter passphrase (empty for no passphrase): [Type a passphrase]Enter same passphrase again: [Type passphrase again]

    Then add your new key to the ssh-agent:

    $ ssh-add ~/.ssh/id_rsa

    Open the ~/.ssh/id_rsa.pub file with a text editor. This is your SSH key. Select all and copy to your clipboard.

    Or you can also run this from the command line:

    Github

    Generating SSH Keys

    Step 1: Check for SSH keys

    Lists the files in your .ssh directory

    Step 2: Generate a new SSH key

    Step 3: Add your SSH key to GitHub

  • pbcopy < ~/.ssh/id_rsa.pub

    Now that you have the key copied, it's time to add it into GitHub:

    1. In the user bar in the top-right corner of any page, click Account Settings2. Click SSH Keys in the left sidebar.3. Click Add SSH key.4. In the Title field, add a descriptive label for the new key. For example, if you're using a personal Mac, you might call

    this key "Personal MacBook Air".5. Paste your key into the "Key" field.6. Click Add key.7. Confirm the action by entering your GitHub password.

    To make sure everything is working, you'll now try SSHing to GitHub. When you do this, you will be asked to authenticatethis action using your password, which for the passphrase you created earlier.

    Open up the command line and type:

    $ ssh -T [email protected]# Attempts to ssh to github

    You may see this warning:

    The authenticity of host 'github.com (207.97.227.239)' can't be established.RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.Are you sure you want to continue connecting (yes/no)?

    Don't worry! This is supposed to happen. Verify that the fingerprint in your terminal matches the one we've provided upabove, and then type "yes."

    Hi username! You've successfully authenticated, but GitHub does not# provide shell access.

    If that username is yours, you've successfully set up your SSH key! Don't worry about the "shell access" thing, you don'twant that anyway.

    If you receive a message about "access denied," you can read these instructions for diagnosing the issue.

    If you're switching from HTTPS to SSH, you'll now need to update your remote repository URLs. For more information, seeChanging a remote's URL.

    Step 4: Test everything out

  • Forking a repo is amazingly simple. What forking is, Github is essentially making a copy of the repo for your use, but it'snot a total carbon copy as one might imagine.

    What is happening is that Github is taking a snapshot in time and then storing that version snapshot in your account.From here out, Git and Github will remember the edits you make. This is called the delta.

    To fork a project you simply need to click the fork button on the repo page.

    Once you have forked and then cloned a project, this is now your version of the project. If you do not have permissions toedit the actual project, this is how you would contribute.

    Once you have made edits and committed them to master , you can then create a pull request that the owner of theproject will be notified of. If the updates are accepted, the admin will merge your pull request and the codes will beadded to the project.

    Fork a repo on Github

    The Pull Request

  • $ git clone

    That's really it. There isn't much more to this. By running the command above, this will tell Git to go to the URL and pull allthe codes to your local computer.

    To get the URL, go to the Github repo and in the lower right hand side there will be an aside with the title of HTTPS cloneURL

    Simply copy the URL from the text field, an example from the Node project is:

    https://github.com/joyent/node.git

    And there you have it, you own all the codes!

    Clone a repo

  • Run the following command:

    curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > ~/.git-completion.bash

    This should create the .git-completion.bash file in your home dir.

    Then add the following to your ~/.bashrc or ~/.bash_profile after PATH :

    # Set the base PS1export PS1="\t: \W$ "

    # Source the git bash completion fileif [ -f ~/.git-completion.bash ]; then source ~/.git-completion.bash GIT_PS1_SHOWDIRTYSTATE=true GIT_PS1_SHOWSTASHSTATE=true GIT_PS1_SHOWUPSTREAM="auto" PS1='\t:\[\033[32m\]$(__git_ps1 " (%s)")\[\033[00m\] \W$ 'fi

    export PS1

    If you are seeing this error, this is because the __git_ps1 function from the completion functionality was moved into a newfile ( git-prompt.sh ).

    You can either source the git-prompt.sh that comes with your installed version of Git, if it has it, or you can download andinstall a new one.

    curl -o ~/.git-prompt.sh https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh

    ... and add the following line to your ~/.bash_profile :

    source ~/.git-prompt.sh

    This will display the branch name next to the folder name in the bash prompt.

    Symbols after the branch name indicate additional information about the repo state:

    * : The branch has modifications $ : There are stashed changes = : The branch is equal with the remote branch < : The branch is behind the remote branch (can be fast-forwarded) > : The branch is ahead of the remote branch (remote branch can be fast-forwarded) : The branch and remote branch have diverged (will need merge)

    Setting up GIT Bash autocompletion

    -bash: __git_ps1: command not found

    Git status

    IntroductionThe DeckLife in the TerminalWhy Terminal?Pimp your TerminalMeet BashFile NavCheat sheetOpen in VIIn summary

    Git workflowBranchingBranch ManagementPushPull requestMerge the codeShortcuts using aliasesSummary

    The Git DemoThe foldersThe filesThe contentBranchingThe deltaThe mergeKill w/fire

    GithubFork a repoClone a repoAuto complete