* Overview Git is a distributed vesioning control system. * References ** Overviews *** DONE [[http://importantshock.wordpress.com/2008/08/07/git-vs-mercurial/][Git vs. Mercurial blog entry: MacGyver vs. Bond]] CLOSED: [2008-08-28 Thu 05:06] - State "DONE" [2008-08-28 Thu 05:06] - State "TODO" [2008-08-28 Thu 05:06] A nice, touchy-feely intro to the difference between Git and Mercurial. Despite the one-stop-shopping-appeal of Mercurial, I will go with my command-line-linux-philosophy-loving, blogs-with-nanoblogger heart and head into git-land. ** Tutorials *** TODO [[http://rubinius.lighthouseapp.com/projects/5089/using-git][Rubinius git page]] Get going fast - State "TODO" [2008-08-28 Thu 05:06] *** TODO [[http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html][gittutorial]] The official intro ;), looks fairly readable… - State "TODO" [2008-08-28 Thu 05:11] *** TODO [[http://www.kernel.org/pub/software/scm/git/docs/everyday.html][Everyday GIT With 20 Commands Or So]] Nicely broken down by goal - State "TODO" [2008-08-28 Thu 05:06] *** TODO [[http://book.git-scm.com/][Git Community Book]] Open source wiki/howto website - State "TODO" [2008-08-28 Thu 05:06] ** Interface with SVN *** TODO [[http://newartisans.com/blog_files/diving.into.git.php][Diving into git blog entry]] Importing the Subversion history - State "TODO" [2008-08-28 Thu 05:06] *** TODO [[http://git.or.cz/course/svn.html][Git - SVN Crash Course]] ? - State "TODO" [2008-08-28 Thu 05:06] *** TODO [[http://utsl.gen.nz/talks/git-svn/intro.html][An introduction to git-svn for Subversion/SVK users and deserters]] - State "TODO" [2008-08-28 Thu 06:09] Lots of political digression, but also lots of useful info. Your call. ** Enforcing development policies *** TODO [[http://www.kernel.org/pub/software/scm/git/docs/howto/update-hook-example.txt][Push hooks]] - State "TODO" [2008-08-28 Thu 05:16] Push hooks *** DONE [[http://blog.offbytwo.com/2008/04/16/running-nosetests-as-a-git-pre-commit-hook/][Pre commit hooks]] CLOSED: [2008-09-02 Tue 08:48] - State "DONE" [2008-09-02 Tue 08:48] - State "TODO" [2008-09-02 Tue 08:46] Basically, put whatever you want in .git/hooks/pre-commit. For example, I added: ./.git/hooks/pre-commit-make-check || exit 1 right after the initial comments with $ cat .git/hooks/pre-commit-make-check make check Don't forget to chmod 744 both scripts to make them executible. Also note that these scripts are run from the base repo directory, which is why I had to include the relative path to pre-commit-make-check, and didn't need `cd ../../' in the check script. *** DONE [[http://changelog.complete.org/posts/586-Rebase-Considered-Harmful.html][Rebase Considered Harmful]] CLOSED: [2008-08-28 Thu 05:27] - State "DONE" [2008-08-28 Thu 05:27] - State "TODO" [2008-08-28 Thu 05:18] A “keep the warts” vs. “stay true to history” monologue. Advocates against rebasing public repos because (quotes from the git-rebase manpage): "When you rebase a branch, you are changing its history in a way that will cause problems for anyone who already has a copy of the branch in their repository and tries to pull updates from you." Personally, I feel like a middle ground, where private mini-branches get a little constructive history tweaking is a good thing. Noone cares about typos in comments, and it adds noise to the development signal, so fix those commits in your private branch. Once you go public though, don't mess with the history, since it would be even more confusing to have conflicting histories in seperate public repositories. Anything serious enough to require a altering the author field should probably not be changed. My thoughts are shared by others, for example commenter #7 Jing Xue. However, commenter #8 links to [[http://www.reddit.com/r/programming/comments/6ube0/synchronizing_development_rebase_vs_pullmerge_git/?sort=top][Synchronizing development: rebase vs. pull+merge, GIT vs. Mercurial]], where oddbod points out that the real problem when “mid-level”, public repos rebase to avoid sending known-bugged patches upstream. He says they avoid the obviously better solution of sending up the bad patch with a patch-patch hard on its heels, which would avoid rebasing a public repo, and still preserve the spirit and authorship of the changes. **** Aside: rebase etymology I just realized that “rebasing” is attaching your branch to a different base point on the tree. Afterward, it looks like you made all of your adjustments right now, not in parallel with a bunch of other fixes on the main branch. ** Setting a description for your repo Edit .git/description * Peripherals ** GitTorrent People are indeed working on [[http://gittorrent.utsl.gen.nz/rfc.html][the obvious protocol]]. * Case studies ** Gitting chem_web, my first git project *** Repository creation and setup Following the [[*Git Community Book]]. *** Install $ apt-get install git-core gitk *** Setup from the [[http://book.git-scm.com/2_setup_and_initialization.html][Git Community Book]]. By default that file is ~/.gitconfig and the contents will then look like this: [user] name = W. Trevor King email = wking at drexel dot edu *** Initialize repository from the [[http://book.git-scm.com/3_getting_a_git_repository.html][Git Community Book]]. $ cd ~/rsrch/chem_web $ git init *** Add some files to the repository from the [[http://book.git-scm.com/3_normal_workflow.html][Git Community Book]]. $ git add README *.py docs templates $ git status Oops, git add add's all of a directory's contents too. Remove some of the automatically generated files. `git rm' removes a file from both the working directory and the index. I wish I could just remove from the index, but I'm not sure how yet. Ah well, the reason I want to remove them is that they are automatically generated ;). $ git rm -f docs/*.pdf ... a bunch of other work while I clean up the mess I've made. Keep going until `git status' looks right. *** Commit the code to the master branch from the [[http://book.git-scm.com/3_normal_workflow.html][Git Community Book]]. $ git commit Or you can automatically add any changed tracked-files with $ git commit -a *** Creating the development branch from the [[http://book.git-scm.com/3_basic_branching_and_merging.html][Git Community Book]]. My workflow will be in two branches: * master, the current stable/working release * dev, the feature development branch I will develop new code in the dev until I am happy with it's performance, and then merge back into the master branch. Old bugs will be fixed in the master branch, and then cherry-picked into the dev branch. That's the current plan anyway ;). Create the dev branch with $ git branch dev *** Changing branches and coding from the [[http://book.git-scm.com/3_basic_branching_and_merging.html][Git Community Book]]. List branches with $ git branch Change to dev with $ git checkout dev Now add that cool new feature, NFPA diamonds for the cabinets :p. When you feel it is appropriate, commit your changes in the local branch with $ git commit -a *** Correcting private commit mistakes from the [[http://book.git-scm.com/4_undoing_in_git_-_reset%2C_checkout_and_revert.html][Git Community Book]]. Oops, I forgot X or made a typo in my commit message. My dev branch is not public, so go ahead and fix the mistake. Then run $ git commit --amend This may leave some danglers $ git fsck dangling blob 03cabac5fa426ca8df4dff1fdb2596b68d2f4c5a dangling blob 87488a0b4ea976127d6b9171ef6f10941a1dd74e ... which you can clean up with $ git prune *** Bring the master branch up to speed from the [[http://book.git-scm.com/3_basic_branching_and_merging.html][Git Community Book]]. $ git checkout master $ git merge dev You may have to deal with a [[*conflicting merge]]. *** Delete a branch from the [[http://book.git-scm.com/3_basic_branching_and_merging.html][Git Community Book]]. $ git branch -d dev The `-d' ensures the changes have already been merged back into the current branch. If you want to kill the brach without merging use $ git branch -D dev *** Repository maitenance from the [[http://book.git-scm.com/4_maintaining_git.html][Git Community Boogk]]. Recompress (to keep the compression most effective) $ git gc Check repository consitency $ git fsck Both should be run manually from time to time. *** Working over a network from the [[http://book.git-scm.com/3_distributed_workflows.html][Git Community Boogk]]. **** Grab a remote repository A remote friend wants to work on your code, or more likely, you're at home and you want to work on your code at work. Grab the repo using ssh with $ git clone ssh://wking@loki/~/rsrch/chem_inventory ci using the ssh://[user@]host.xz/~/path/to/repo.git git URL notation listed in man `git-clone'. **** Possibly remove the reference to the remote repository If you're decomissioning the remote repository, you can remove it from the current one with git remote rm **** Work on the repository Nothing changes here. **** Get your remote partner to pull your changes back upstream $ git remote add bob /home/bob/repo $ git fetch remote $ git log -p dev remotes/bob/master $ git merge remotes/bob/master and possibly $ git remote rm bob ** Gitting sawsim, migration from svn *** Install git apt-get install git-core git-svn gitk *** Repository migration from svn Following [[http://github.com/maddox][Jon Maddox]] at the [[http://www.simplisticcomplexity.com/2008/03/05/cleanly-migrate-your-subversion-repository-to-a-git-repository/][Simplistic Complexity blog]]. **** Create the decoy directory git-svn keeps some info about the svn repository, to make it easier to keep the two in sync. However we are not interested in staying in sync, we just want to move to git. Create a decoy git version of the repo with $ mkdir sawsim.svn $ cd sawsim.svn $ git-svn init svn://abax.physics.drexel.edu/sawsim/trunk/ $ cat >> .git/config < users.txt < EOF $ git-svn fetch Jon Maddox suggests using $ git config svn.authorsfile ~/Desktop/users.txt instead of my manual .git/config editing, but my stock Debian git (1.4.4.4) doesn't seem to have git-config. No big deal. Check that this worked and translated your users correctly with $ git log ***** Warning: here documents Some shell's might not like my [[http://tldp.org/LDP/abs/html/here-docs.html][here document]] Bash syntax. In that case, write the files another way. **** Create the clean directory When we clone the decoy directory, all the svn junk gets left behind. First, leave the sawsim.svn directory $ cd .. And clone like you normally would $ git clone sawsim.svn sawsim You don't need the [svn] stuff in .git/config anymore either. I don't remember if they came over on their own or not… I removed the origin information with $ rm .git/remotes/origin *** Setup **** gitignore from `man gitignore' The sawsim code is mostly in a single now-web file. Extracting all the source from the file creates lot of indirectly versioned clutter. To avoid having all your `git status' calls swamped with untracked files, Just add the filenames (globbing allowed) to .gitignore. The sawsim code is mostly in a single now-web file. Extracting all the source from the file creates lot of indirectly versioned clutter. To avoid having all your `git status' calls swamped with untracked files, Just add the filenames (globbing allowed) to .gitignore. **** [[Push hooks]] TODO *** Making your repository public/Publishing your repository From the [[http://book.git-scm.com/4_setting_up_a_public_repository.html][Git Community Book]] To distribute your repo via HTTP (easier on someone else's server). user@devel$ ssh server server$ cd ~/public_html server$ git clone --bare ssh://user@devel/~/path/to/repo.git repo.git server$ cd repo.git server$ touch git-daemon-export-ok server$ git --bare update-server-info server$ chmod a+x hooks/post-update Others can clone or pull from your URL with anon$ git clone http://server/~you/repo.git from the [[http://book.git-scm.com/3_distributed_workflows.html][Git Community Book]] Once you've set up your repo, you can push changes to it with ssh devel$ git push ssh://user@server/~/public_html/repo.git master To save typing, add [remote "public"] url = ssh://user@server/~/public_html/repo.git to .git/config, after which you can push with devel$ git push public master Note that you may need to copy .git/description over by hand. I wrote up a [[http://www.physics.drexel.edu/~wking/code/index.shtml#git-publish][git-publish]] script to automate this. ** Gitting comedi, using Git as a frontend for CVS http://issaris.blogspot.com/2005/11/cvs-to-git-and-back.html *** Repository creation and setup This is quite similar to [[*Repository migration from svn]] **** Create the decoy directory mkdir comedi.cvs cd comedi.cvs #cvs -d :pserver:anonymous@cvs.comedi.org:/cvs/comedi login git-cvsimport -p x -v -d :pserver:anonymous@cvs.comedi.org:/cvs/comedi comedi the login line may not be necessary for other CVS projects. arguments to git-cvsimport -p x (pass -x to cvsps, which ignores any ~/.cvsps/cvsps.cache file) -v (verbose) -d ... (from http://www.comedi.org/download.html) **** Create the clean directory cd .. git clone comedi.cvs comedi *** Do your work like normal in comedi *** Update with the latest cvs $ cd comedi.cvs $ git-cvsimport -p x -v -d :pserver:anonymous@cvs.comedi.org:/cvs/comedi comedi $ cd ../comedi $ git pull You may have to deal with a [[*conflicting merge]]. *** Create a patch against the cvs source git-format-patch origin * Other useful examples ** Purge all knowledge of a given file or subdir from history For example, in case you accidentally started versioning /etc/shadow, or some other document containing sensative information. $ git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch /etc/shadow' $ git reflog expire --expire=0 --all $ git prune $ git repack -adf ** Rewrite the repository to look as if foodir/ had been its project root Discarding all other history $ git filter-branch --subdirectory-filter foodir -- --all ** Cherry pick a commit from another repository First, give the remote repository a nickname (optional) $ git remote add bob /home/bob/myrepo Then fetch the remote repo $ git fetch bob You can merge all the changes Bob made to his master branch with $ git pull . remotes/bob/master Or cherry-pick a particular one, e.g. commit 1d8fb1fe41dfc1b1eb38c7b5d574577c4b341c58 $ git cherry-pick 1d8fb1fe41dfc1b1eb38c7b5d574577c4b341c58 When a particular remote repo no longer contains interesting material, you can purge the fetched tags and objects with $ git remote rm bob $ git remote prune bob ** Move master.HEAD to a different location Sometimes you screw up and want to drop the thread you've been working on. Place the HEAD of the master branch on commit XYZ with $ git checkout XYZ $ git branch -D master $ git branch master XYZ $ git checkout master Note that this may remove some information from your .git/config's [branch "master"] entry. You should save your earlier .git/config before doing it, and make any appropriate corrections afterwards. ** Git submodules, nesting/tracking sub-repositories. This is a nice way of grouping associated projects. The submodules are included as stand-alone repositories, and the super-project has pointers picking out a particular revision of each submoduel. See the related [[*Git subtrees]] for an alternate approach. *** References [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] [[http://book.git-scm.com/5_submodules.html][Git Book]] [[http://speirs.org/2009/05/11/understanding-git-submodules/][Fraser Speirs: Understanding Git Submodules]] *** Setup a super-module [[http://book.git-scm.com/5_submodules.html][Git Book]] $ git submodule add ~/path/to/submoduleX $submoduleX Warning: Do not use local URLs here if you plan to publish your supermodule. git submodule add * clones the submodule under the current directory and by default checks out the master branch. * adds the submodule's clone path to the gitmodules file and adds this file to the index, ready to be committed. * adds the submodule's current commit ID to the index, ready to be committed. $ git submodule init *** Cloning a super-module [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] Grab the content living in the super module itself $ git clone ~/subtut/public/super See how the submodules look $ git submodule status -d266b9873ad50488163457f025db7cdd9683d88b a ... Add submodule repository URLs to .git/config $ git submodule init Check that they're there if you like $ git config -l ... submodule.a.url=/home/moses/subtut/public/a/.git Now check out the reverenced submodules $ git submodule update *** Changing submodules from supermodules [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] To update a submodule, remember that it's just a checked-out branch in your supermodule. Create and publish the change using the usual method: $ cd a a$ git branch * (no branch) master a$ git checkout master a$ echo "adding a line again" >> a.txt a$ git commit -a -m "Updated the submodule from within the superproject." a$ git push $ cd .. Now point the supermodule at the new commit. Warning: don't use `git add a/` or git will think you mean to add the contents of the directory. For submodule updates, you must leave off the trailing slash. $ git add a $ git commit -m "Updated submodule a." $ git show ... diff --git a/a b/a index d266b98..261dfac 160000 --- a/a +++ b/a @@ -1 +1 @@ -Subproject commit d266b9873ad50488163457f025db7cdd9683d88b +Subproject commit 261dfac35cb99d380eb966e102c1197139f7fa24 Take a look at the submodule changes from the supermodule. $ git submodule summary HEAD^ * a d266b98...261dfac (1): > Updated the submodule from within the superproject. Publish your updated supermodule. $ git push *** Removing submodules [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] 1. Delete the relevant line from the .gitmodules file. 2. Delete the relevant section from .git/config. 3. Run git rm --cached path_to_submodule (no trailing slash). 4. Commit and delete the now untracked submodule files. *** Warnings [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] It's not safe to run "git submodule update" if you've made changes within a submodule. They will be silently overwritten: **** Example [[http://git.or.cz/gitwiki/GitSubmoduleTutorial][Git Wiki]] a$ cat a.txt module a a$ echo line added from private2 >> a.txt a$ git commit -a -m "line added inside private2" $ cd .. $ git submodule update Submodule path 'a': checked out 'd266b9873ad50488163457f025db7cdd9683d88b' $ cat a/a.txt module a The changes are still visible in the submodule's reflog: $ git log -g --pretty=oneline d266b9873ad50488163457f025db7cdd9683d88b HEAD@{0}: checkout: moving to d266b9873ad50488163457f025db7 4389b0d8e22e616c88a99ebd072cfebba40797ef HEAD@{1}: commit: line added inside private2 d266b9873ad50488163457f025db7cdd9683d88b HEAD@{2}: checkout: moving to d266b9873ad50488163457f025db7 ** Git subtrees, merging an entire repository into a subdirectory of your repository *** Setup [[http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html][kernel.org: merge-subtree]] Name the other project "Bproject", and fetch. $ git remote add -f Bproject /path/to/B Prepare for the later step to record the result as a merge. ("-s ours" selects the merge strategy as "keep our version") $ git merge -s ours --no-commit Bproject/master Read "master" branch of Bproject to the subdirectory "dir-B". $ git read-tree --prefix=dir-B/ -u Bproject/master Record the merge result. $ git commit -m "Merge B project as our subdirectory" *** Keeping up to date with the sub-repository source Maintain the result with subsequent pulls/merges using "subtree" $ git pull -s subtree Bproject master *** Pulling changes back into the sub-repository source [[http://github.com/apenwarr/git-subtree/tree/master][git-subtree]] The super-project makes some local alterations. Pull/merge them with git-subtree. * Troubleshooting ** Git commit hangs with no output You probably corrupted something in .git. git gc git fsck fixed the problem for me. git blame comedi/drivers/ni_mio_common.c da96d940a9353160390869c504bad73b909adfcb ** Conflicting merge git-pull or git-merge aborts with `merge-failed' or some such. This leaves your checked out branch in a state where $ git diff shows the merge difficulties. You can either [[*abort the merge]], or [[*merge by hand]]. *** Abort the merge $ git reset --hard *** Merge by hand Edit the marked packages as you see fit. Then let Git know you've accepted your changes with either $ git update-index or $ git add CONFLICT_FILE Then commit with $ git commit -a