Version Control with Git
Setting up a Git project
If you want to work with an existing project, clone it:
$ git clone <url>
If you do not have an existing git project, create one:
$ cd project/ $ git init # initializes the repository $ git add . # add those 'unknown' files $ git commit # commit all changes, edit changelog entry $ git rm --cached <file>... # ridiculously complicated command to undo, in case you forgot .gitignore
Git will look for a file named **.gitignore** in the root of your repository which contains a set of shell patterns to ignore in file paths.
Branching and merging
$ git checkout -b linux-work # create a new branch named "linux-work" $ <make changes> $ git commit -a $ git checkout master # go back to master branch $ git merge linux-work # merge changesets from linux-work (Git >= 1.5) $ git pull . linux-work # merge changesets from linux-work (all Git versions)
$ git apply < ../p/foo.patch $ git commit -a
Exporting a patch
$ <make changes> $ git commit -a -m "commit message" $ git format-patch HEAD^ # creates 0001-commit-message.txt # (HEAD^ means every patch since one revision before the # tip of the branch, also known as HEAD)
# clone from the primary Git repo $ git clone git://git.kernel.org/pub/scm/git/git.git $ cd git
# pushing changes to a remote repo with SSH $ git push email@example.com:my-repository.git/
# fetch changes to a remote branch into a local branch $ git fetch firstname.lastname@example.org:my-repository.git/ remote-branch:local-branch
# merge changes from a remote machine bar$ git pull git://foo/repo.git/ branch
# Serve repository via git protocol $ cd /my/repository/ $ touch .git/git-daemon-export-ok $ git daemon # now others can fetch from git://your.machine/my/repository/.git/
# Set up a bare (= without working directory) repository (e.g. on a webserver) $ mkdir my-repo.git $ cd my-repo.git $ git --bare init $ chmod a+x hooks/post-update # this is needed for HTTP transport # you need to populate this repository via push
see Remote (bare) repository for more
# inspect history visually $ gitk # this opens a Tk window, and shows you how the revisions are connected
# inspect history $ git log # this pipes a log of the current branch into your PAGER $ git log -p # ditto, but append a patch after each commit message $ git log -S'string' --oneline # search for string in all patches $ git log -G'regex' --oneline # search for regex in all patches
# inspect a specific commit $ git show HEAD # show commit info, diffstat and patch # of the tip of the current branch
Referring to revisions
# by name $ git log v1.0.0 # show history leading up to tag "v1.0.0" $ git log master # show history of branch "master"
# relative to a name $ git show master^ # show parent to last revision of master $ git show master~2 # show grand parent to tip of master $ git show master~3 # show great grand parent to tip of master (you get the idea)
# by output of "git describe" $ git show v1.4.4-g730996f # you get this string by calling "git describe"
# by hash (internally, all objects are identified by a hash) $ git show f665776185ad074b236c00751d666da7d1977dbe $ git show f665776 # a unique prefix is sufficient
# tag a revision $ git tag v1.0.0 # make current HEAD known as "v1.0.0" $ git tag interesting v1.4.4-g730996f # tag a specific revision (not HEAD)
# diff between two branches $ git diff origin..master # pipes a diff into PAGER $ git diff origin..master > my.patch # pipes a diff into my.patch
# get diffstat of uncommitted work $ git diff --stat HEAD
Cherry picking patches
$ git cherry-pick other-branch~3 # apply 4th last patch of other-branch to current branch
Remote (bare) repositories
create a bare Git repository to store changes
$ ssh remotehost $ mkdir -p scm/myapp.git $ cd scm/myapp.git $ git --bare init $ exit
then go to your project and push your changes to the remote repository
$ cd ~/Sites/myapp $ git remote add origin ssh://remotehost/scm/myapp.git $ git push origin master
now if you want to share this repository with others all they need to do is
$ cd ~/Sites $ git clone ssh://remotehost/scm/myapp.git
Note that you can also push a new branch to a remote repository by simply doing:
$ git checkout -b newbranch # make changes and commit them $ git checkout master $ git push ssh://remotehost/scm/myapp.git newbranch
That creates a new remotes/origin/newbranch branch on the remote origin (shared repository). Users doing //git pull// will get this branch
You can then make git pull --rebase [origin]; git push [origin] work by just doing
git config branch.master.merge refs/heads/master git config branch.master.remote origin
Removing Files from history
Say you have a large file that is making your repository too big as git maintains multiple copies of its history (say a binary file). If you decided that it was not worthy keeping this file in your repository, you can do the following to re-write history and remove the file. Be sure to archive a copy of your repository before typing these commands:
git filter-branch --tree-filter 'rm -f filename' HEAD git prune --expire=now git reflog expire --expire-unreachable=now --rewrite --all git repack -a -d git prune-packed
Say you do:
and it shows
* () * master
And all your changes were committed to "* ()" by mistake and you switch back to master and now your changes are lost! Don't despair!
In git nothing is lost, so you can simply use the reflogs to recover your changes:
git log --walk-reflogs HEAD git log --walk-reflogs master
Then once you have the id that you need, you can proceed with:
git show 375703efa1c465671723aac9ad43aa25cd5494f7 > /tmp/patch.diff
And apply your patch as you normally would.
git config --global alias.logline "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
Your logs will now have color and easier to read:
538c0f9 - (HEAD, origin/master, origin/HEAD, master) return same output as rpm -q (48 minutes ago) <My Name>
git config --global alias.logr "log --oneline -G"
git logr 'rm.*reboot' e9ade4e adds support for new kernel cd0de3b adds new kernel 49da89c fixed ips of servers 84da5dc change to version to foo 3.10
git symbolic-ref refs/heads/trunk refs/heads/master git branch trunk -> master
And now you can use this name "trunk" where you'd normally use "master"
git checkout trunk
Use this whenever you need to transfer a branch or series of patches from one machine to another that are not directly connected via SSH or any other protocol.
git bundle create /tmp/foo-repo-from-origin-to-master origin/master..master