You can add a versioning control system to track and manage your project’s assets with Git locally — you don’t need to upload it to git.com. Here’s how.
Download Git from http://git-scm.com. It will detect your OS and provide the correct download for it. For my Mac, it was version 184.108.40.206.
The Mac version downloaded a dmg file to my Downloads folder. Double-click to open it, then double-click on the pkg file. (If your preferences prevent you from opening a file from an unidentified developer, then hold down Control, right-click on the pkg icon, and select open.) The Installer should appear; click to continue through the few steps, including providing your admin password. You’ll find a drive icon for the Git dmg package; right-click and select to Eject. (I believe “dmg” is short for “disc image.”)
Set Up a Local Git Repo
Git is used with command line tools, such as the Mac’s Terminal app. Start up the Terminal app by either clicking on it in the Dock at the bottom of the screen, or by clicking on the Spotlight icon (magnifying glass) at top of the screen and typing Terminal in the Search field.
Type “cd ” (without the quotes) in the Terminal, which is short for “change directory.”
Go to the project folder you wish to track and drag it to the Terminal window and release. Click on the Terminal window to select it, and hit Enter.
Type the following to set up a Git repo for that project:
A message confirms that a git repo has been set up: “Initialized empty Git repository in…” If you can see your hidden files, you’ll see a .git folder in your project’s folder. All tracking is done here. Each project will have its own local git repo. (To get rid of your git repo, all you need to do is delete that file and all of its tracking information is gone.)
Git has three stages:
1) Working stage. These are the files in your projects, changed and unchanged, also called the working directory. These are the files you create and/or edit.
2) Staging Index. These are the files marked “add” to send to the repo (third stage) for tracking.
3) Repo (repository). These files were put in the Staging Index and “committed” to git. Git is now tracking these files.
Type “git status” in the Terminal to see the status of your files. You’ll see the untracked files and folders in red. It will note the name of the branch; in this case “master.” Notes will tell you what you may want to do next: “(use “git add <file>…” to include in what will be committed)” and: “nothing added to commit but untracked files present (use “git add” to track).”
Create a .gitignore File
Before putting any files into the Staging Index, it’s best to decide what files we do NOT want to add to the index. Since we use git to track our document changes, we don’t want to add all those files that we never use, like system files or the binaries we upload to Apple. We just want git to track the files we have created ourselves and ignore the rest. We can add all the files or file types to a .gitignore file that we never want added to the index. Let’s do this next. Make a list of types of files in your project that you do not want in the repo. GitHub maintains an official list of recommended .gitignore files at this public repository: https://github.com/github/gitignore You’ll find lists of file types to ignore from a wide variety of programming languages, including Android, Java, and Objective-C.
You may use regular expressions in this list.
- * as in “*.apk” or any other file extension to include all files with that extension.
- [0-9] as in “version[0-9].txt” for a range of files with those variations. Can also use [aeiou] letter ranges.
- / as in “merges/” to ignore all the files in a directory with a trailing slash.
To create the file locally to apply to this project only, type in Terminal:
This will open the GNU nano text editor in the Terminal. Go ahead and type “.DS_Store”, “.cordova”, and any other files, one per line. You may preface a line with # to create a comment on that line: “# This is a note.” At this point, my file references: .DS_Store, .cordova, *.txt, myFILES/, merges/, platforms/android/assets/, platforms/android/bin/, platforms/android/cordova/, platforms/android/gen/, platforms/android/lib/. You may copy/paste from your notes into nano.
At the bottom of GNU nano is a list of commands. Do Control-X, then type y to save the changes, then Enter to accept the name of the file as “.gitignore”.
.gitignore needs to be in the git repo in order for git to start using it, otherwise, git’ll treat it as any other file if you commit it to repo along with the rest of the files. To get it into the Staging Index, in the Terminal, type and hit Enter:
git add .gitignore
Check the status:
This put the file into the Staging Index, showing as a green filename, and shows us in red the remaining, unstaged, files. The green files are tagged to go to the repo; the red files are not. It also tells you what to do in case you made a mistake and want to remove the file from staging: (use “git rm –cached <file>…” to unstage).
Let’s commit it to the Repo stage. In the Terminal, type and hit enter:
git commit -m "Add .gitignore file"
Check the status:
We see the file is no longer in the staging area. Now type:
We see the log that git keeps of our commits. The commit has several pieces of information, including the long SHA algorithm number, the parent (the previous commit), author, and the note we attached as part of our commit, “Add .gitignore file.”
The SHA number is the magic glue that keeps the git process working. Each commit references the commit before, the parent. If any SHA was missing, then it could no longer go back. To preserve the integrity of the repo, you cannot actually delete any of these commits.
We kept the commit message simple (“Add .gitignore file.”). Here are some tips for good commit messages:
- Single-line summary, <50 chars.
- Optionally followed by a blank line and a more complete description if the commit is too complicated for one line. Write it so you’ll understand the commit among all the other commits you’ll do. These notes will show up when you do git log.
- Use present tense.
- Use consistent keywords to indicate type of commit and what kind of files were changed. “UPDATE [html,js] Fixes a form bug that ….”
- Use asterisks for bullet points.
- Use ticket tracking numbers.
Here is why it’s important to have thorough commit messages — to make them searchable by git log. You can add various parameters to the git log command and bring up the logs you want.
This will list the last five commits:
git log -n 5
This will list commits since that date:
git log --since=2012-06-15
This will list commits up to that date:
git log --until=2013-08-03
This will list all commits with author of Steve.
git log --author "Steve"
Lists all commits containing a specified string of chars. So make sure your commit messages have important keywords:
git log --grep="init"
This will list a terse presentation of the log:
git log --oneline
This limits oneline list to last 3 commits:
git log --oneline -3
(Thanks to Lynda.com for this information.)
Set Some Defaults
To set the author and email for all of your project’s git commits, type the following into Terminal and hit Enter:
git config --global user.name "Your Name"
Type the following and Enter for the email:
git config --global user.email "email@example.com"
See what’s in the config file:
git config --list
Check the log to see if your name and email entries are now included:
To the Staging Index
With the .gitignore now in place as our filter, let’s move our working files to the Staging Index. There are three ways to go:
1) This will add one file to the staging area:
git add file.html
2) This will add all the files to the staging index:
git add .
3) This will add file directly to the repo, skipping the staging index. Use this method only for modified files, not new or deleted files:
git add -am "This is a note about the commit"
This is a new project, so do #2. When finished, type “git status” to see what changed. If you see a lot of files that should have been in .gitignore, it’s not too late to delete the git folder, open the .gitignore to edit it following the Nano steps above, and start over.
I’m going to add a new feature to my PhoneGap app. I’ll make a separate branch for creating and testing all the modified files. When I’m confident the new feature works well, I’ll merge the branch back into the main trunk.
What branches are present? Type the following to show all branches:
At this point, only the “master” branch is present. This is the group of files currently being worked on by you. When you switch branches, files will swap out of the .git folder into your project folder and you’ll see the files as they are on that branch. Whenever we switch to a different branch, your files will switch folder locations to that branch. That’s how git works.
Create new branch (name should have no spaces or punctuation):
git branch UPDATE_Add_new_widget
Check the branches present:
Two branches are now listed, but the asterisk is still on master, so master is still the current branch. To switch to a different branch, name the branch:
git checkout UPDATE_Add_new_widget
A list of files “checked out” appear, along with the summary: “Switched to branch ‘UPDATE_Add_new_widget’.” These are the files currently in your working directory. A shortcut way that combines these two steps is:
git checkout -b UPDATE_Add_new_widget
Confirm the branches present:
Now the new branch has the asterisk. This means that a copy of the master has been made, and my project files have been swapped out for this copy, and it is now the working directory on my hard drive. That is the branch that will be updated any time I make adds and commits.
I may be called away from the project for an extended time, or just leaving work for the day or weekend. When I return to this project, I’ll want to refresh my mind about where I left off. This process is a nice way to begin a workday. Here are helpful steps:
- git branch Make sure what branch I’m working on.
- git status Tells me what files are changed. Files may appear in green with the word “modified” next to them if I’ve already done a git add.
- git diff –staged Will show me a summary of what changes I made to the files after I did a git add but before git commit. It gives the file names changed and excerpts from the file of the lines that were changed and a few lines above and below for context, with the changed lines in green. All-new files will be shown in their entirety. (A colon at the bottom of the screen means there is more content; use the Return key or down arrows to read further. Tap q to immediately return to the prompt.)
- git log –oneline -3 A terse summary with SHA and commit message. Helps me see context by tracing the last three commits.
- git log –author=”Captain America” If I’m working with a team, I can check out what they’ve done, filtering by author name.
If I’m ready to commit the files to tracking:
git commit -m "This is a note about the commit"
After testing thoroughly, I’ll merge the branch to the master. First step, return to master branch:
git checkout master
I received confirmation:
Checking out files: 100% (495/495), done. Switched to branch 'master'
Next, get a list of all the branches:
Copy the branch name to be merged, and paste it into place in this step:
git merge UPDATE_Add_new_widget
Do a git log to see the commits made so far.
I’ll no longer need the branch once it’s merged, so I can delete it with the -d parameter:
git branch -d UPDATE_Add_new_widget
Deleted branch UPDATE_Add_new_widget (was 4e6b7fe).
Now I’m ready to create a new branch for the next group of files. I can have several branches going at once, each one testing something different, like a branch for a new navigation system for the home page, insert and test a new plugin, a branch for pictures and new gallery, and so on.
My Git Notes
There are more things I can do with git. Here are my personal notes, some of which I haven’t incorporated into the above article.
Download Git Bash console program:
http://git-scm.com (Mac or PC – will auto-detect)
For Mac, downloads a .dmg file; open and double-click on the .pkg file.
Check installation (where it is stored) [$ = your command prompt in the console window – don’t type this!]
$ which git
$ git –version
Go to directory:
$ cd D:\Git
Go backwards 1 directory:
$ cd ..
A colon at left on the console means there is more content. Type q to escape or Enter to continue reading.
See directory listing [these are ells, not ones]:
ls -la [ls to list the directory, -la to show hidden files, like .git]
System-wide setting (the defaults are fine):
PC location (must start from this directory): Program Files/Git/etc/gitconfig
$ git config –system
PC location: Documents and Settings/shusting
$ git config –global
Project (settings specific to a project):
$ git config
More basic configurations:
$ git config –global user.name “name”
$ git config –global user.email “email”
$ git config –list
$ git config –global core.editor “notepad++.exe -wl1″
[above is: w L 1”]
$ git config –global color.ui true
First thing is to bring the git console to the project’s folder and type …
$ git init
… to get a git repo started on the hard drive. This tells Git to create a tracking system there.
$ git help
$ git help <command>
$ q [to quit]
$ cat .gitconfig [look inside the file]
$ ls -la [list the files, including hidden files]
3-tree Architecture, moving from one to the other
Tree: “WORKING” (on hard drive)
Make changes to Working directory, then:
$ git add “note” file.txt [move to Staging Index with note, below]
$ git add . [add all files to Staging Index]
$ git add -am “note” [add and commit ALL working directory files to repo, skipping Staging Index. Not good for new and deleted files, only modifying files.]
Tree: “STAGING INDEX”
Can pick which of the files to send to Repo
$ git commit file.txt [1 file to Repo]
$ git commit -m “describe changes taking place here” [to Repo]
Tree: “REPO” (Git is now tracking these files)
$ git status [tells us the status among the 3 trees]:
Will say what branch we are on
Will list any untracked files
Will give sample commands for what to do next
Writing Commit Messages
Single-line summary, <50 chars.
Optionally followed by a blank line and a more complete description if change is too complicated for 1 line.
Keep lines to <72 chars.
Use present tense. “UPDATE [html,js] Fixes a form bug that ….”
Use asterisks for bullet points.
Use ticket tracking numbers.
Use shorthand to indicate what kind of files were changed. “[css]”
Using Git Log to list things (and why it’s important to have thorough commit messages – to make them searchable by git.)
$ git log -n 5 [List the last 5 commits]
$ git log –since=2012-06-15 [List commits since that date.]
$ git log –until=2013-08-03 [List commits up to that date.]
$ git log –author “Steve” [List all commits with author of Steve.]
$ git log –grep=”init” [List all commits containing that string of chars.]
Referring to Commits
Checksums ensure the data in the commit set is the same (essential for data integrity).
Uses SHA-1 hash algorithm, a 40-char string.
It’s seen next to our commit line in the git log.
A commit set has:
SHA hash value at top
Parent (links to immediately prior SHA or commit)
Tree-ish: something that references a part of the tree; it references a commit, and then to the tree. “-ish” because what that something is can vary widely. A tree is a directory. A blob is a file.
$ git ls-tree HEAD [shows what files are in the HEAD. Current set of repo files.]
$ git ls-tree master www/ [shows commit of master]
$ git ls-tree master^ www/ [shows previous commit/state of master]
$ git ls-tree sha8q9qp4qg1gh1p5g12p5p5 [shows tree/directory’s contents]
Points to next spot, or where last repo stopped; points to tip of current branch in repo. Like a playback-and-record head in a VCR. It points to the SHA of the last parent, for that will be put in the next repo’s SHA, referencing the last parent. It will point to where we will record next, so if we move the Head further back, it will overwrite from there.
$ ls -la [to see list. will see file named HEAD]
$ cat HEAD [will show file structure of HEAD]
$ cd refs [first folder of above structure.]
$ ls -la [to see list. Will see file named heads]
$ cd heads
$ ls -la [to see content list. will see file named master]
$ cat master [result will show 40-char SHA of the commit set]
Ignoring Files: using .gitignore
Use basic regular expr: * ? [aeiou] [0-9]
Negate expressions with !
Ignore all files in a directory with a trailing slash: assets/
Comment lines: # comment
Can create this file with the command line:
$ nano .gitignore
Can globally ignore files so that file applies to all files on my machine.
1. Create the file and contents:
$ nano /Users/Me/.gitignore
2. Add the above to the config file:
git config –global core.excludesfile ~/.gitignore_global
Ignoring tracked files (deletes from the staging index, but not the working):
$ git rm –cached filename.html
Git ignores directories with no files. So create a hidden file with no content in it to track the directory:
$ git log to see what changes have been made.
$ git log –oneline [a terse presentation of the log]
$ git log –oneline -3 [limits list to last 3 commits]
$ git log –since=”2013-08-05″ [entries since that date. May use after instead of since]
$ git log –until=”2013-08-05″ [may use before instead of until]
$ git log –since=”2 weeks ago” –until=”today” [shows commits within time range]
$ git log –author=”Steve H”
Use GREP [GREP = global regular expression]:
$ git log –grep=”TUT” [show lists with those chars]
$ git log -n 5 [to get 5 most recent logs]
$ git log aw4tq4t4.. index.html [show what happened to a file from a particular commit, using SHA.]
$ git show <SHA> [show the difference]
Comparing changed files in master and working trees:
$ git status
$ git diff
$ diff –color-words filename.txt
Comparing files in staged tree to repo:
$ git status
$ git diff –staged
$git diff <SHAa>..<SHAb> <filename.html> [show changes just to that file between those two SHAs]
$ git log –oneline
$ git diff –stat –summary <SHA>..HEAD [show summary of what’s changed]
Deleting files from repo, 2 methods:
Drag file from folder on hard drive to trash can.
$ git rm file-to-delete.txt
$ git commit -m “removed deleted file”
[this method will “save” the file in the trash can for later retrieval]
$ git rm file-to-delete.txt
[this method will completely delete the file from your hard drive; no trash can]
Moving and renaming files
$ git mv file.txt new_folder/renamed_file.txt
Undoing working directory changes
Pulling a file out of Repo, switching from the one in Working
$ git checkout — index.html [the ” — ” means to stay in the same branch. useful in case a branch has the same name.]
Unstaging a file while keeping the working file
$ git reset HEAD filename.txt
This is trickier because changing a commit means if changing the SHA, the snapshots after that would be affected, and this would affect data integrity. So, you can only make changes to the last commit.
$ git log [top of the listing is latest commit we could change]
Put changed files into the staging area, then:
$ git commit –amend -m “note changed”
Or do the above second step by itself if you just want to change the note of the commit.
To change earlier commits, one must make a copy of the version previous to the wrong commit and change and commit that. Steps:
$ git log
copy the SHA of the commit before the wrong file.
$ git checkout <SHA> — filename.txt
$ git status [moved above file into Staging Index]
$ git diff –staged [to see the revisions]
$ git reset HEAD filename.txt [puts it in working directory]
$ git commit -m “note about changed commit”
A faster way than above to revert a commit:
$ git log
copy the SHA of the commit of the prior(?) file
$ git revert <paste SHA here>
My text editor should mention the changes and make them, and give room for me to make a comment of my own about it.
One working directory. Git uses “Fast context switching” when going between branches, making the working directory match the branch.
$ git branch [show all branches]
* master [* next to the branch name indicates the current checked-out branch. What your working directory matches.]
$ cat .git/HEAD [show current tip of branch, where the Head is now]
$ ls -la .git/refs/heads [show all branches listed]
$ cat .git/refs/heads/master [show SHA of current branch tip]
$ git branch UPDATE_Add_New_2013_Pix [create branch; no spaces or punctuation]
$ git branch [shows all branches, including new one made]
$ cat .git/HEAD [shows us the checked out branch]
$ git checkout branch-name [switch to named branch]
$ git checkout -b UPDATE_Add_2014_Pix [create new branch off of the current branch and switch to it]
$ git checkout — filename.html [– means checkout file in same branch, not checkout branch.]
How do I merge a branch back to the master?
$ git checkout master
$ git merge <branch name>