1. Basics
  2. Rebase (My Favorite way to resolve conflicts)
  3. Branches
  4. Tags
    1. Remote Tracking Branches
  5. Setup and Config
  6. A "Blessed" or "Upstream" Repo
  7. Stash
  8. Reverting Changes
  9. Diffs
  10. Links and Resources
  11. LF vs CRLF
  12. Reflog
  13. git-svn
    1. Add svn meta data back to a git clone
    2. git svn dcommit fails for whatever reason
  14. Resolving Conflicts

Basics

Create a new repo

cd new-project-dir
git init

Add files not yet tracked

git add <file>

Stage changes

git stage <file>

Create a commit with a message

git commit -m "shiny new commit"

Create a commit and automatically include all changes (without having to manually stage each of them)

git commit -am "All the changes"

Get a copy of the code

git clone <repo-url>

repo-urls can start with several different protocol identifiers, such as http://, https:// and git://. git will talk over these protocols to download the code.

Associate local code to remote repo

git remote add <remote-name> <repo-url>

List associated remote repositories

git remote

See if there's any differences and/or changes

git status

Rebase (My Favorite way to resolve conflicts)

If you've changed the same files locally that were also changed recently by someone else and pushed to remote master, my favorite way to resolve the conflicts is using rebase. I prefer rebase over merge. If you use merge it will create an extra commit for merging your changes with changes found on remote. I think rebase is cleaner.

I try to always work on a branch. If you're working on master, just create a branch with your local changes. For example, let's call this branch dev

First, pull latest into master

git checkout master
git pull origin master

Then, switch to your branch, and rebase ontop of master

git checkout dev
git rebase -i master

In emacs magit, I think the command is C-g, and then r, and then choose master

Merge, pick, and squash commits. Try to keep other people's commit's intact.

Then, merge back into master

git checkout master
git merge dev

Branches

Most common command I use all the time to create a branch and switch to it:

git checkout -b my-new-branch

List branches

git branch -a

Create a new (local) branch

git branch newbranch

Switch back and forth between branches:

git checkout newbranch
git checkout master

Merge stuff from one branch into another

git checkout branch-to-merge-into
git merge branch-to-merge-from

Push a branch to remote repo

git push origin <branchname>

Clean up your branches by deleting them:
git branch -d <branchname>

If you haven't merged a branch, that command will fail, If you want to throw it away, then use -D to force deletion

Setup a local branch that tracks a remote branch and automatically switch to it

git remote show origin
git fetch
git checkout -b local-name origin/remote-name

To delete a remote branch, prepend the name of the branch with a colon

git push origin :remote-branch-name

Tags

List tags

git tag

Search for tags (I never do this though)

git tag -l 1.1.*

In general, best practice seems to be to create "annotated" tags, so pass -a switch when creating tags

Push tags to remote

git push REMOTENAME TAGNAME

To push all tags while pushing another branch, you can use git push REMOTENAME BRANCHNAME --tags

Remote Tracking Branches

Git automatically sets up several branches that track remote branches, you can see these using the following. But I usually use the `checkout -b` to setup local tracking branch

git branch -r

Setup and Config

First, set it up

git config --global core.editor "emacs"
git config --global user.name "Your Name"
git config --global user.email "your email@gmail.com"

Or, for per project, don't use global

To ignore files across all git repositories first tell git where the "global" excludes file is located:

git config --global core.excludesfile ~/.gitignore

Now ~/.gitconfig looks something like:

[core]
editor = emacs excludesfile = ~/.gitignore

To ignore temporary files with tilda for all projects, add this to ~/.gitignore

*.*~

A "Blessed" or "Upstream" Repo

Sometimes it's helpful (especially for teams) to setup a remote repository that everyone agrees is the "blessed" repository. A best practice is to name this repo "upstream"

git remote add upstream git@github.com:<foo>/<repo>.git

Configure the blessed repo so that only fast forwards are possible

git config branch.master.mergeoptions "--ff-only"

Stash

git stash save "desc"
git stash list

The list command will show something like stash@{0}

To apply the stash at id 0

git stash apply stash@{0}

To throw it away

git stash drop stash@{0}

On windows, in cygwin you have to escape the brackets: git apply stash@&#123;0&#125;

Reverting Changes

Note for people moving from SVN, git revert is NOT the same as svn revert.

To revert all changes including anything staged

git reset --hard HEAD

To revert single file

git checkout <filename>

Or, alternative, use stash to get rid of only stuff that isn't staged

git stash save --keep-index

Then, drop the stash created

Diffs

git diff HEAD^ HEAD^^

# Patches

Apply a git patch file

patch -p1 < patchfile

Links and Resources

LF vs CRLF

Handy when working with people who are using Windows because windows will add the annoying ^M character at the end of each line

core.autocrlf

Can be true, false or input

If true, makes git convert CRLF at the end of lines in text files to LF when reading from the filesystem, and convert in reverse when writing to the filesystem. The variable can be set to 'input', in which case the conversion happens only while reading from the filesystem but files are written out with LF at the end of lines. Currently, which paths to consider "text" (i.e. be subjected to the autocrlf mechanism) is decided purely based on the contents.

To get rid of ^M chars in emacs: M-% C-Q C-M Enter Enter

Reflog

If you ever think you've lost any changes, git reflog has you covered.

git-svn

First, we need to fetch a copy of the repository. Choose some recent-ish commit

git svn clone -s -r 40000:HEAD

-s is for --stdlayout which presumes the svn recommended layout for tags, trunk, and branches.

-r is for the revision to start taking history from. If you want to include all of the history, just leave that option off, but it will take a very long time, and you really don't need all of it.

To get latest from svn

git svn rebase

To commit changes

git svn dcommit

To get all branches

git svn fetch

Add svn meta data back to a git clone

Here's the situation: you or someone else used git svn to create git repo and then pushed it up to github or somewhere. Now you use git clone to grab that git repo. The .git/svn dir will be empty so git svn won't know how to operate with the original svn repo.

To solve this, add the following to .git/config

[svn-remote "svn"] url = http://host/svn/path/to/top-level/repo fetch = relative/path/to/project/trunk:refs/remotes/trunk branches = relative/path/to/project/branches/:refs/remotes/ tags = realative/path/to/project/tags/:refs/remotes/tags/

Then, you can do this to update to latest code:

git svn fetch -r <revision id>:HEAD

Use the -r to make sure you don't fetch the entire svn history (unless that's what you want)

git svn dcommit fails for whatever reason

For example it might return message "Item already exists". Seems that sometimes it gets in a state that it can't recover from. In this case, do the following:

  • Remove .git/svn directory
  • Remove .git/refs/remotes/trunk file
  • Then try git svn fetch -r <revision id>:HEAD

Resolving Conflicts

Accept all mine or theirs for convlict resolution

Add this to .gitconfig inside [alias]

 accept-ours = "!f() { files=\"$@\"; [ -z $files ] && files='.'; git checkout --ours -- $files; git add -u $files; }; f"
 accept-theirs = "!f() { files=\"$@\"; [ -z $files ] && files='.'; git checkout --theirs -- $files; git add -u $files; }; f"