Coming to GitHub from Dropbox, Google Docs, etc. can be a rough ride, since some aspects of the system are a bit counterintuitive. There are numerous git cheat sheets out there, so I recommend you look for them. I like these:
The basic thing to keep in mind is that the system allows you a lot of control over what gets synced and when, and things aren’t called what you might expect them to be called. Also, a lot of things that you might expect to happen in a single step require multiple steps (e.g., there is no “sync” in the command line version; you have to commit, pull, and push separately).
Initial git setup
Once you have created a directory called “git”:
$ git init
Set up SSH and add an SSH key for the new machine:
On a Mac:
$ ssh-keygen -t rsa -b 4096 -C "firstname.lastname@example.org"
When prompted, agree to the location for saving the key:
/home/yourname/.ssh/id_rsa OR /Users/yourname/.ssh/id_rsa
Check ssh-agent and enter password when prompted:
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_rsa
Copy the SSH key from terminal to the GitHub site. On Mac OS, do this:
$ pbcopy < ~/.ssh/id_rsa.pub
On Linux, they have this xclip thing, but the SSH key is just a block of meaningless text so you can use your preferred text editor to copy and paste.
$ xclip -sel clip < ~/.ssh/id_rsa.pub
Once this is done, test that SSH is working:
$ ssh -T email@example.com
Cloning a repo
Once you have git set up on your machine, navigate to the git directory and copy (clone) your repositories into it one by one. The repos have to exist, and the easiest way to make them is through the GitHub website.
$ pwd ~/git $ git clone firstname.lastname@example.org:username/reponame.git
Some useful global settings
The global settings are kept in the git config file.
$ vim ~/.gitconfig
Add the following to the git config file
$ git config --global user.name "Your Name" $ git config --global user.email email@example.com $ git config --global core.editor vim
This sets up Text Wrangler as your diff tool, so you can compare versions and decide which to keep:
[diff] tool = "twdiff" [difftool] prompt = false [difftool "twdiff"] cmd = /usr/local/bin/twdiff --wait --resume "$LOCAL" "$REMOTE" [merge] tool = "twdiff" [mergetool] prompt = false [mergetool "twdiff"] cmd = /usr/local/bin/twdiff --wait --resume "$LOCAL" "$REMOTE"
For Linux, a good GUI diff tool is meld:
[core] editor = vim [diff] tool = "meld" [difftool] prompt = false [merge] tool = "meld" [mergetool] prompt = false
In addition to this, each repository should have a .gitignore file. You can look around for other people’s .gitignore files, but here’s an example of the contents of some of mine:
*.swp *.pyc *.swo .DS_Store ethumbs.db *.lyx~ *.py~ temp/* code/stuff_i_dont_want_people_to_see
Find out what’s new, if anything:
$ git status
^ All this does is compare the current state of the stuff inside your repository to the previously synced version; it does not actually connect to the internet. For that, you’d want to do a dry run (see below).
If checking git status turns up an untracked file or several, that means you haven’t committed certain changes, so do this:
$ git add /path/toyour/file.py
$ git commit -m 'removed a TypeError bug from file.py'
You can commit them individually or do the following. If you take this step, make sure your .gitignore file has at least some stuff in it–otherwise all sorts of garbage will turn up in the master version of your repository.
$ git add --all
If you run git status again, you will see that the path to file.py (or all the files, if you did –all) appears as “new file”, as “changes to be committed”. Once you’ve committed, git status will tell you that there is nothing to commit. This does not mean your stuff is online yet, because that requires a separate step:
$ git pull origin master
^ This gets stuff from repo into your local git copy. Do this first before attempting to push to it, in case new changes have been introduced by others.
$ git push origin master
^ This puts stuff into the official master copy of the repository online.
$ git rm path/filename
^ This removes the file from the list of files that git will track. It does not remove the file from your repository; if you want it there but untracked, you might want to put the partial path to it in your .gitignore file.
$ git add path/filename
^ If a new file has been added or a file has been modified, this will add it to the git status record so it will be included in future sync attempts.
$ git mv path/filename
^ This is the way to move things around to organize them. If files are moved using the regular file manager methods instead, you can end up with duplicate files on unsynced machines. See “counterintuitve notes” below.
$ git diff
^ This is only relevant if you are collaborating with people on code; they might have introduced a change that conflicts with yours. You have to reconcile the differences using a merge tool (see the git config stuff earlier). The other time this can arise is if you have multiple machines and didn’t pull from the repository before adding changes; the conflicts will show up as if two people made changes. If you have used Dropbox or similar in the past, this should look familiar.
Branches: creation and deletion
Add a new branch called “test”:
$ git branch test
Switching between branches:
$ git checkout test
$ git checkout master
Syncing the new branch to the remote server:
$ git push -u origin test
Deleting a branch locally:
$ git branch -d test
And on the git server:
$ git push origin --delete test
Undoing a push
$ git revert HEAD
This undoes the last commit.
Further counterintuitive notes
GitHub tolerates directory structures but does not directly support them. That means it will respect paths when syncing repository content but it doesn’t have a native way to create folders or move files up or down. If you want things to appear in folders, do it through your OS, then do the “git add” or “git rm” steps as applicable above.
“Commit” and “push” are separate steps (unlike the little “sync” button in the GitHub Desktop thing). Commit just records changes in the local config file and in the versioning system; this is why it requires a comment. “Push” actually puts things in the repo, via SSH in my case. Ditto for “pull”.
To see what the differences are between the server repo and your local repo, do a dry run:
git fetch && git diff --stat origin/master
If GitHub is refusing to let you commit or push even though the file differences have been reconciled, git add the file. That should fix it.