{"id":5532,"date":"2013-09-19T14:44:54","date_gmt":"2013-09-19T11:44:54","guid":{"rendered":"http:\/\/railsware.com\/blog\/?p=5532"},"modified":"2021-08-11T18:10:08","modified_gmt":"2021-08-11T15:10:08","slug":"taming-the-git-daemon-to-quickly-share-git-repository","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/taming-the-git-daemon-to-quickly-share-git-repository\/","title":{"rendered":"Taming The Git-Daemon To Quickly Share Git Repository"},"content":{"rendered":"I was once in a hurry to share GitHub repository with a colleague who didn&#8217;t have access to it and we decided to use local git-daemon. However, handling all the little quirks that would make it work took a lot more efforts than just dropping a repository archive via Skype.\n\nFrom this article you will learn how to easily share read\/write access to the local git repository. Additionally, I will share two simple aliases for git that will make this task a real no-brainer for anyone.\n<h2>Disclaimer<\/h2>\nPlease note that this is an insecure way of sharing access to git repository and should be used only in a friendly LAN-environment. If you need secured solution, consider using <a href=\"http:\/\/git-scm.com\/book\/en\/Git-on-the-Server-The-Protocols#The-SSH-Protocol\">SSH-protected way<\/a>.\n<h2>Sharing read-only access<\/h2>\nNext command shares read access(clone\/pull) to any repository in current directory:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose\n<\/pre>\nWhere:\n<ul>\n \t<li>&#8211;export-all &#8211; shares all the repositories in a folder from &#8220;&#8211;base-path&#8221; option<\/li>\n \t<li>&#8211;base-path=. &#8211; daemon looks for repositories in a current directory(&#8220;.&#8221;)<\/li>\n \t<li>&#8211;reuseaddr &#8211; allows to restart server quickly<\/li>\n \t<li>&#8211;informative-errors &#8211; provides cleaner error message for clients<\/li>\n \t<li>&#8211;verbose &#8211; notifies about each operation with the repository<\/li>\n<\/ul>\n<h3>Sample flow<\/h3>\n1) Run git-daemon in directory with your repos:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ cd my-repos\n$ ls\nfacebook-killer better-twitter instapound\n\n$ git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose\n[8322] Ready to rumble\n<\/pre>\n2) Now clients can clone\/pull this repository:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git clone git:\/\/127.0.0.1\/facebook-killer\nCloning into 'facebook-killer'...\nremote: Counting objects: ...\n...\n\n$ git pull\nAlready up-to-date.\n<\/pre>\nInstead of the &#8220;127.0.0.1&#8221; client should use the IP of your computer.\n<h2>Sharing push access<\/h2>\nAdd &#8220;&#8211;enable=receive-pack&#8221; option and git-daemon starts supporting push access:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git daemon --base-path=. --export-all --enable=receive-pack --reuseaddr --informative-errors --verbose\n<\/pre>\nThere is one quirk: client can&#8217;t push into your active git branch. Before pushing, user on the server should change the branch, if client wants to push to this branch.\n\nAnother option can be for the client to create a new branch and push it to your server. Then you can merge it into a required branch.\n<h3>Sample flow<\/h3>\n1) Run git-daemon in read\/write mode:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git daemon --base-path=. --export-all --enable=receive-pack --reuseaddr --informative-errors --verbose\n[8322] Ready to rumble\n<\/pre>\n2) Client clones repository:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git clone git:\/\/127.0.0.1\/facebook-killer\nCloning into 'facebook-killer'...\nremote: Counting objects: ...\n...\n<\/pre>\n3) Client branches-off, makes changes and pushes back new branch:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git checkout -b sharing\n# made some changes ...\n$ git commit -am \"add sharing feature\"\n$ git push -u origin sharing\n...\n* [new branch]      sharing -&gt; sharing\n...\n<\/pre>\n4) Now on Server you can merge this branch:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git checkout master\n$ git merge sharing\n<\/pre>\n<h2>Sharing only one repository<\/h2>\nIf you want to share only some repositories, you&#8217;ll need to remove &#8220;&#8211;export-all&#8221; option and create &#8220;git-daemon-export-ok&#8221; file in .git directory of the appropriate repositories.\n<h3>Sample flow<\/h3>\n1) Create magic file:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ cd my-repos\n$ ls\nfacebook-killer better-twitter instapound\n\n$ touch facebook-killer\/.git\/git-daemon-export-ok\n<\/pre>\n2) Run git-daemon without &#8220;&#8211;export-all&#8221; option:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git daemon --base-path=. --enable=receive-pack --reuseaddr --informative-errors --verbose\n<\/pre>\n3) Client can&#8217;t access non-shared repository:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git clone git:\/\/127.0.0.1\/better-than-twitter\nCloning into 'better-than-twitter'...\nfatal: remote error: repository not exported: \/better-than-twitter\n<\/pre>\n4) Client can access shared repository:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git clone git:\/\/127.0.0.1\/facebook-killer\nCloning into 'facebook-killer'...\nremote: Counting objects: ..., done.\n...\n<\/pre>\n<h2>Making life simpler with aliases<\/h2>\nLet&#8217;s create git aliases for read-only and read\/write sharing. Here is what it should look like in .gitconfig:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\" title=\".gitconfig\"># .gitconfig\n[alias]\n    serve = !git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose\n    hub = !git daemon --base-path=. --export-all --enable=receive-pack --reuseaddr --informative-errors --verbose\n# ...\n<\/pre>\nNotice &#8220;!&#8221;-symbol in front of the aliases. This is a way to alias external shell command, and with this trick we can call these commands outside of git repository.\n\nNext commands automatically put these aliases into .gitconfig:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git config --global alias.serve '!git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose'\n$ git config --global alias.hub '!git daemon --base-path=. --export-all --enable=receive-pack --reuseaddr --informative-errors --verbose'\n<\/pre>\nNow with &#8220;git serve&#8221; you can share read access and with &#8220;git hub&#8221; &#8211; read\/write access to our repositories. &#8220;git serve&#8221; resembles Mercurial &#8220;hg serve&#8221; which performs exactly the same operation. And &#8220;git hub&#8221; feels to be just right for read\/write sharing, don&#8217;t know why.\n\nOnce the aliases are added, we can run and see &#8220;hub&#8221; command in action:\n<pre class=\"theme:tomorrow-night lang:sh nums:false\">$ git hub\n[19178] Ready to rumble\n<\/pre>\nYay, it works!\n\nThat&#8217;s it, and as I promised &#8211; it&#8217;s a real no-brainer to share anything using these magic aliases.","protected":false},"excerpt":{"rendered":"<p>I was once in a hurry to share GitHub repository with a colleague who didn&#8217;t have access to it and we decided to use local git-daemon. However, handling all the little quirks that would make it work took a lot more efforts than just dropping a repository archive via Skype. From this article you will&#8230;<\/p>\n","protected":false},"author":25,"featured_media":9467,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["Sergii Boiko"],"class_list":["post-5532","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/themes\/railsware\/vendors\/images\/article-thumbnail-default.jpg","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5532","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=5532"}],"version-history":[{"count":58,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5532\/revisions"}],"predecessor-version":[{"id":13931,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/5532\/revisions\/13931"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/9467"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=5532"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=5532"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=5532"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=5532"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}