Git Notes
- Basics
- Branches
- Tags
- Setup and Config
- A "Blessed" or "Upstream" Repo
- Rebase and Rebasing
- Stash
- Reverting Changes
- Diffs
- Links and Resources
- LF vs CRLF
- Reflog
- git-svn
- 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
Branches
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 = ~/.gitignoreTo 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"
Rebase and Rebasing
git rebase -i HEAD~3
Or, in emacs magit, use E
for interactive rebase.
Pick, squash, etc commits.
After rebasing, you often will need to force an update to the blessed repo:
git push blessed +branch
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@{0}
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^^
# PatchesApply 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"