http://hades.name/blog/tag/git/Hades Blag blog posts with tag intersection git2010-12-02T17:53:52ZEdwarddjango-atompubhttp://hades.name/blog/2010/12/02/your-own-git-hosting-gitolite/Your Own Git Hosting: Gitolite2010-12-02T17:53:52Z2010-12-02T14:59:55Z<p>So, let&#8217;s start with setting up <a href="https://github.com/sitaramc/gitolite">gitolite</a> to host your repositories and provide <span class="caps">SSH</span> access to them. There is also a tool called gitosis, but it is not as supported and featurefull as&nbsp;gitolite. </p> <p>So what does it actually do? In essence, all the developers that will access your repositories will login to your server as user &#8220;git&#8221;, run server-side git daemon and sync data with it. Gitolite will determine if a user has access to perform operations he is going to. Ok, but why bother with all this crap, and not just create a bunch of users on the server and tell them where is the repository? There is a couple of&nbsp;reasons.</p> <p>Firstly, you may not want to give your developers shell access to your server. Why wouldn&#8217;t you? Who knows, probably because they are stupid or malicious, or whatever. With gitolite they won&#8217;t get a shell access, because they will only be able to login with their <span class="caps">SSH</span> keys and that <span class="caps">SSH</span> keys will be restricted to invoking gitolite only. At this point you may want to read up <span class="caps">SSH</span> manual on keys and command restrictions, if you do not yet know about&nbsp;it.</p> <p>Secondly, you may want to impose certain access restrictions on them. Gitolite allows to restrict read write and rewrite down to per-branch&nbsp;level.</p> <p>Thirdly, with local multiuser git access you have to fiddle a little with umasks or write a hook that fixes the permissions, but that&#8217;s unimportant and&nbsp;uninteresting.</p> <p>Fourthly, you may even not have a root access. That&#8217;s right, gitolite allows you to setup multi-user repositories on systems where you have only one non-root&nbsp;account.</p> <p>So let&#8217;s go ahead with installation. The <a href="https://github.com/sitaramc/gitolite/blob/pu/doc/1-INSTALL.mkd"><span class="caps">INSTALL</span></a> doc is rather straightforward and you should in fact read it instead of this blog post. <b>I am not offering the text below as a setup instructions, but merely as a log of how I installed it on my&nbsp;server.</b></p> <p>First off, we require some git on our server. Please be careful to use as fresh git as possible, because it generally tends to gets even more super awesome with time. Also gitolite requires at least git 1.6.2 at the time of writing of this post. Unless you use especially sucky distribution (<em>ahem</em> debian <em>ahem</em>), you should be fine with git from your repository. I just told Portage to install me&nbsp;one:</p> <div class="code"><pre> emerge -av git </pre></div> <p>Although gitolite has an ebuild in Gentoo, I set it up manually and will walk you along the procedure. First, lets obtain the&nbsp;sources:</p> <div class="code"><pre> git clone git://github.com/sitaramc/gitolite.git </pre></div> <p>This will create a &#8220;gitolite&#8221; directory with gitolite sources. Let&#8217;s create a system directory for gitolite. I use /opt for all non-Portage packages, so let&#8217;s go ahead&nbsp;with:</p> <div class="code"><pre> GITOLITE=/opt/gitolite sudo mkdir -p ${GITOLITE}/{bin,conf,hooks} sudo chown -R `whoami` ${GITOLITE}/{bin,conf,hooks} </pre></div> <p>You may of course use another set of directories if you want. Next, we let gitolite install itself wherever we want&nbsp;it:</p> <div class="code"><pre> ./src/gl-system-install ${GITOLITE}/{bin,conf,hooks} </pre></div> <p>This takes three arguments: directory for binaries, directory for configs and directory for hooks. Also this is the same command you would use to update your gitolite installation after you git pull the new&nbsp;sources.</p> <p>We would now require a user account for git. Let&#8217;s create&nbsp;them!</p> <div class="code"><pre> sudo groupadd -r git sudo useradd -d /srv/git -g git -m -r -s `which bash` git </pre></div> <p>This creates a system (-r) group git and a system (-r) user git with home directory (-d) /srv/git and shell (-s) bash, in group (-g) git, and creates its home directory (-m). Now login into your new git account. Don&#8217;t forget to add your ${<span class="caps">GITOLITE</span>}/bin directory to the .bashrc if it is not in the&nbsp;<span class="caps">PATH</span>:</p> <div class="code"><pre> sudo su &mdash; git echo PATH='${PATH}':/opt/gitolite/bin/ >> .bashrc source .bashrc which gl-setup </pre></div> <p>Now copy over your public key to a file called username.pub and finalize gitolite setup by&nbsp;running:</p> <div class="code"><pre> gl-setup username.pub </pre></div> <p>After that, follow the instructions, they should be fairly straightforward. Congratulations, you&#8217;re done! The gitolite&#8217;s configuration is stored in a Git repository under gitolite, so you&#8217;d want to clone it from your computer (i.e. where you have the private key for&nbsp;username.pub):</p> <div class="code"><pre> git clone git@yourservername:gitolite-admin cd gitolite-admin vim conf/gitolite.conf </pre></div> <p>The file gitolite.conf is in fact your gitolite config file. After you edit it, save it, commit it and push to the gitolite-admin repository on your server, gitolite checks the config and makes appropriate changes to the repositories. To add users, just place their keys into keydir directory. It&#8217;s that simple! You probably would want to read <a href="https://github.com/sitaramc/gitolite/blob/pu/doc/2-admin.mkd">official admin doc</a> just about&nbsp;now.</p> http://hades.name/blog/2010/09/07/your-own-git-hosting-prologue/Your Own Git Hosting: Prologue2010-09-07T15:49:55Z2010-09-07T15:49:22Z<p>As you might know, Git itself does not deal with collaboration, letting you choose any adequate model. So how does one go about publishing his repository? Or letting someone push into their repository? The answers are multiple and confusing. <a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#sharing-development">Official Git Manual</a> gives a dry summary of the basic options, which you may read now, or at your leisure. I&#8217;ll just note the few key&nbsp;points.</p> <p>Limiting the discussion to network exchange, Git supports three basic protocols: git protocol, <span class="caps">HTTP</span> and <span class="caps">SSH</span>. All of them support pulling and pushing, however each of them has drawbacks. Git protocol does not support any kind of authentication, so it is mostly used for read-only public access. <span class="caps">HTTP</span> is slow and stupid (which means that it allows only file transfer, so you can&#8217;t use Git hooks). <span class="caps">SSH</span> is great in all respects, but it implies that every person that has access to your repository has an account on the server, where it is&nbsp;hosted.</p> <p>In the majority of the cases, two protocols are set up for Git repository: public read-only git protocol access and private read/write <span class="caps">SSH</span> access. However I can name you upon request at least one real-world case, when git protocol was successfully used for unauthenticated read/write access :). <span class="caps">HTTP</span> protocol is usually used in those morbid cases where you can in no conceivable way get rid of it (imagine a firewall that blocks everything except port 80 or&nbsp;443).</p> <p>So how do you setup a Git hosting? There are a lot of web Git hostings (<a href="http://gitorious.org">gitorious.org</a>, <a href="http://github.com">github.com</a>), and project hostings with Git support (<a href="http://sf.net">sf.net</a>) out there. Mostly they provide free hosting for open-source projects and charge a fee for private&nbsp;repositories.</p> <p>However, public Git hostings can not satisfy everyone. There are closed projects, that could not be trusted to a third-party. There are closed projects that do not have spare money for Git hosting. Also, it is hard to integrate hosted Git repository with other development tools (buildbot, bugzilla, etc.), mainly because custom hooks are not supported. So that brings us to the following&nbsp;problem.</p> <p>Given:</p> <ul> <li>a&nbsp;server.</li> </ul> <p>Required:</p> <ul> <li>hosting of any number of Git&nbsp;repositories;</li> <li>public read-only access to a subset of them via git&nbsp;protocol;</li> <li>read/write access for authorized users via&nbsp;<span class="caps">SSH</span>;</li> <li>web interface to the&nbsp;repositories.</li> </ul> <p>In the following posts, I will tell you how I solved the problem for myself using the following&nbsp;tools:</p> <ul> <li><a href="http://github.com/sitaramc/gitolite">gitolite</a> for <span class="caps">SSH</span> access&nbsp;management;</li> <li><a href="http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html">git-daemon</a> for anonymous git protocol&nbsp;access;</li> <li><a href="http://hjemli.net/git/cgit/">cgit</a> for web&nbsp;interface.</li> </ul> <p>Please stay&nbsp;tuned!</p> <p>P.S: I&#8217;ve heard some concerns regarding cgit not working properly in some cases. I can neither confirm this nor disprove (since I rarely use web frontends for code browsing), but I&#8217;ll look into&nbsp;it.</p> http://hades.name/blog/2010/03/03/git-your-friend-not-foe-vol-4-rebasing/Git Is Your Friend not a Foe Vol. 4: Rebasing2010-03-03T21:02:23Z2010-03-03T20:03:17Z<p>This time I&#8217;ll talk about more complex things, which give developers more power over their life. Actually, they just look complex. In fact these are quite natural operations over Git commit history structure, which was described already in my previous posts and gazillions of posts by other&nbsp;people.</p> <p>So, let&#8217;s start with the simplest. Mr. Cleverhead sometimes fails to remember which branch he is currently on. He commits to a branch <code>master</code>, while in fact he should have committed that to <code>staging</code>. What can he do to fix it? He decides to run <code>git show</code>, save the commit as a patch, then checkout branch <code>staging</code>, apply patch there and commit with the same commit message. Well, it happens so that Git already has a command that does exactly this automatically! It is called <code>git cherry-pick</code>. Besides fixing Mr. Cleverhead&#8217;s reputation, it is also quite often used for example to backport commits to release&nbsp;branches.</p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-cherry-pick.png" alt="Git cherry-pick" /></div> <p>Note, however, that this still requires Mr. Cleverhead to remove his commit from master. We believe in&nbsp;him.</p> <p>The next big complex thing is a branch-wise cherry-pick. This is called a <em>rebase</em> and often casts a great deal of confusion upon novice Git users. But actually rebase is to cherry-pick as is multiplication to addition: <strong>by doing rebase you just cherry-pick a series of commits on another branch</strong>. Although <a href="http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html">git-rebase</a> manual page is ugly and unfriendly, it tells the same basic thing: rebase is a series of cherry-picks, followed by a branch&nbsp;reset.</p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-rebase.png" alt="Git rebase" /></div> <p>Note the desaturated old commits. Despite Git changed the branch head, it <strong>didn&#8217;t remove these old commits</strong>. They are still accessible through reflog, or by their <span class="caps">SHA1</span> ids, in case you realise you&#8217;ve made a&nbsp;mistake.</p> <p>There are many use-cases for <code>git rebase</code>, from Mr. Cleverhead committing several commits in a row to a wrong branch, to complex integration and release cycle management workflows. See, for example, <a href="http://nvie.com/git-model">http://nvie.com/git-model</a>.</p> <p>There is also an interactive mode for <code>git rebase</code>. And it is truly <em>awesome</em>! It allows you to edit your branch in any way you want: remove commits, edit commits, squash commits, even change commit order. So try it out.&nbsp;Now.</p> <p>The post would be incomplete if I didn&#8217;t mention <code>git filter-branch</code>. It is basically the same as rebase, but it usually affects the whole branch up to the initial commit and for every commit Git performs a certain action. It is very complex and powerful tool that is quite rarely needed and quite more rarely used. Its uses include: removing a file from the whole project history (for example because of license issues, or because Mr. Cleverhead accidentally added his grandmother&#8217;s recipe book five years ago); fixing author&#8217;s name in commit messages; creating a separate Git repository from a subdirectory. All this comes free with Git and doesn&#8217;t require you to spend weeks doing this any other clumsy&nbsp;way.</p> <p>Last thing I would like to mention today is pull-rebasing. This refers to the following problem: by default <code>git pull</code> means <code>git fetch</code> followed by <code>git merge</code>, which is perfectly fine if you haven&#8217;t committed anything locally. But if you have, this creates a merge commit. This is perfectly fine either. But if you do small commits often, or work on a big feature in your branch and merge master often to be in sync with updates, this will create a so-called &#8220;loopy history&#8221;, which usually pisses people off. Especially Linus. So if you have committed a small fix that you can&#8217;t push because Mrs. Slowrunner managed to push a commit before you, use <code>git pull --rebase</code>. This will rebase your work upon Mrs. Slowrunner&#8217;s work and no merge commit will be created. If you work on a topic branch and would like to sync it with master, simply run <code>git rebase master</code>. This will reduce pissed off people count&nbsp;too.</p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-loopy.png" alt="Git loopy and normal history" /></div> <p><strong>Note, however, that rebase rewrites history!</strong> This means, that if you have published your work somewhere, <strong>you shouldn&#8217;t rebase it</strong>, unless you have warned people that they may expect history rewriting. This is usually refered to as throw-away branches (for example branch <code>pu</code> of git.git). If you have published your work, rewritten it and try to publish it again, <code>git push</code> won&#8217;t let you. If you force it to, expect angry people to come to your house with your local analogue of baseball&nbsp;bats.</p> <p>Regarding angry people: some workflows require topic branches to be squashed to a single commit before merging to mainline. This is easy in Git: just use the <code>--squash</code> option of <code>git merge</code>, and everyone will be happy. If you want to squash only some of them (for example, make 5 commits out of 20), you can use aforementioned interactive&nbsp;rebase.</p> <p>This pretty much concludes this series of Git posts. If you feel that I have left something unveiled, please tell me that! I appreciate all the&nbsp;comments.</p> <p>Previous&nbsp;posts:</p> <ul> <li><a href="http://hades.name/blog/2010/01/17/git-your-friend-not-foe/">Volume 1, on the distributed <span class="caps">VCS</span>&nbsp;concepts</a></li> <li><a href="http://hades.name/blog/2010/01/22/git-your-friend-not-foe-vol-2-branches/">Volume 2, on branches and&nbsp;merging</a></li> <li><a href="http://hades.name/blog/2010/01/28/git-your-friend-not-foe-vol-3-refs-and-index/">Volume 3, on refs and staging&nbsp;area</a></li> </ul> <p><a href="http://hades.name/blog/tag/git/">All posts about&nbsp;Git</a></p> http://hades.name/blog/2010/01/28/git-your-friend-not-foe-vol-3-refs-and-index/Git Is Your Friend not a Foe Vol. 3: Refs and Index2010-03-03T20:44:18Z2010-01-28T14:08:59Z<p>Let&#8217;s take a walk along Git repository structure. The central square is Git Object Database. Objects reference each other by 160-bit unique IDs with a certain semantics (for example, commit-object references its parent commit(s) and the tree that corresponds to project&#8217;s root directory; tree-object references blob-objects that correspond to file content and tree-objects that correspond to subdirectories; etc., see <a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial-2.html">gittutorial-2(7)</a> for details). For the sake of simplicity, let&#8217;s forget about trees and blobs for now, and look at commits&nbsp;only.</p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-norefs.png" alt="Git with only commits" /></div> <p>We now have a bunch of commits that know who were their parents. We can trace history from any given commit back to the very beginning. But how do we know what is the current state of things? What was the latest commit in the history? To answer that let&#8217;s look at Git <em>refs</em> (short for references). They are basically named references for Git commits. There are two major types of refs: <em>tags</em> and <em>heads</em>. Tags are fixed references that mark a specific point in history, for example <code>v2.6.29</code>. On the contrary, heads are always moved to reflect the current position of project&nbsp;development. </p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-refs.png" alt="Git with refs" /></div> <p>Now we know what is happening in the project. But to know what is happening right here, right now there is a special reference called <span class="caps">HEAD</span>. It serves two major purposes: it tells Git which commit to take files from when you checkout and it tells Git where to put new commits when you commit. When you run <code>git checkout <em>ref</em></code> it points <span class="caps">HEAD</span> to the <em>ref</em> you&#8217;ve designated and extracts files from it. When you run <code>git commit</code> it creates a new commit object, which becomes a child of current <span class="caps">HEAD</span>. Normally <span class="caps">HEAD</span> points to one of the heads, so everything works out just&nbsp;fine. </p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-head.png" alt="Git with branch HEAD" /></div> <p>But if you checkout a specific commit instead of a branch, your <span class="caps">HEAD</span> starts pointing at this commit. This is referred to as <em>detached head</em> and you may be told that <em>you are not on a branch</em> (git branch says &#8220;(no branch)&#8221;). This is perfectly fine, but if you commit anything to it, your commits won&#8217;t have a known ref, so if you checkout another branch, you can lose&nbsp;them. </p> <div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-detached.png" alt="Git with detached HEAD" /></div> <p>Having said about committing, can&#8217;t help stopping by the process of committing itself. You may already know that the Git&#8217;s &#8220;add&#8221; operation differs from almost every other <span class="caps">VCS</span> in that you have to &#8220;add&#8221; not only files that are not yet known to Git, but also files that you have just modified. This is because <strong>Git takes content for next commit not from your working copy, but from a special temporary area</strong>, called <em>index</em>. This allows finer control over what is going to be committed. You can not only exclude some files from commit, you can exclude even certain pieces of files from commit (try <code>git add -i</code>). This helps developers stick to <em>atomic commits</em>&nbsp;principle.</p> <p>And if you have inhuman ability of creating only perfect committs and need stupid <span class="caps">VCS</span> only to obey your orders, then you can just use option &#8220;-a&#8221; for git-commit. And I envy&nbsp;you.</p> <p>Another special kind of refs are <em>remotes</em>. Whenever you run <code>git fetch</code>, it asks the remote repository, what heads and tags does it have, downloads missing objects (if any) and stores remote refs under refs/remotes prefix. The remote heads are displayed if you run <code>git branch -r</code>.</p> <p>Some of your branches (notably <em>master</em>) may be what is called <em>tracking</em> branches. That means that a certain branch &#8220;tracks&#8221; its remote counterpart. Physically that means that when you run <code>git pull</code> on that branch, the corresponding remote branch gets automatically merged into your local branch. Fairly recent versions of Git set up tracking automatically when you checkout a remote branch (for example, <code>git checkout -b stable origin/stable</code>). Note, however, that sometimes it&#8217;s better to <em>rebase</em> instead of&nbsp;merge.</p> <p>But that&#8217;s a whole new&nbsp;story&#8230;</p> <p>Previous&nbsp;posts:</p> <ul> <li><a href="http://hades.name/blog/2010/01/17/git-your-friend-not-foe/">Volume 1, on the distributed <span class="caps">VCS</span>&nbsp;concepts</a></li> <li><a href="http://hades.name/blog/2010/01/22/git-your-friend-not-foe-vol-2-branches/">Volume 2, on branches and&nbsp;merging</a></li> </ul> <p>Next&nbsp;post:</p> <ul> <li><a href="http://hades.name/blog/2010/03/03/git-your-friend-not-foe-vol-4-rebasing/">Volume 4, on cherry-picking and&nbsp;rebasing</a></li> </ul> <p><a href="http://hades.name/blog/tag/git/">All posts about&nbsp;Git</a></p> http://hades.name/blog/2010/01/22/git-your-friend-not-foe-vol-2-branches/Git Is Your Friend not a Foe Vol. 2: Branches2010-03-03T20:42:12Z2010-01-22T10:13:19Z<p>So if you worked with some version control systems for a bit, you&#8217;ve probably heard of a concept called <em>branches</em>. It is quite a simple concept: you can perform several development processes in parallel without them interfering with each other. Most projects use branches for experimental features that could set hell loose and for backporting bugfixes to older releases. Subversion and <span class="caps">CVS</span> people usually dislike branches, because they involve lots of uninteresting and painful work that they don&#8217;t want to do. That is easily explained by the way branches are implemented&nbsp;there.</p> <p>As you might know, branches in <span class="caps">SVN</span> are implemented in a very interesting fashion. They are not, in fact, implemented <strong>at all</strong>. <span class="caps">SVN</span> branch is just a folder, which is created when a branch is started. If you want to merge it back, you need to remember the revision number, when you created the branch, and use that magical number in a complex &#8220;svn merge&#8221; command. But still, <span class="caps">SVN</span> project history remains a straight&nbsp;line.</p> <p><img src="http://hades.name/media/git/svn-history.png" alt="SVN History" /></p> <p>What&#8217;s wrong with this way of interpreting the branch concept? Nothing. It&#8217;s completely fine, if you don&#8217;t want to work with branches. And you <em>should</em> want to work with branches, because they are actually awesome! Especially if implemented as in&nbsp;Git.</p> <p>Instead of <span class="caps">SVN</span>-y linear development history, Git&#8217;s commit history is a more complex structure: each commit can have multiple parents and multiple children. In computer science this is called a Directed Acyclic Graph (and if this rings any bells you may want to read Tv&#8217;s article <a href="http://eagain.net/articles/git-for-computer-scientists/">&#8220;Git for Computer Scientists&#8221;</a>). In practice that means that you are not restricted to developing upon the latest revision in project&#8217;s history. Instead, you can take any existing commits and start creating commits off it. If you want to merge them, you create a commit that is a child of two commits (such children are called merge&nbsp;commits).</p> <p>This way you get a graph with several commits with no children (let&#8217;s call them branch heads for now). Every commit has a reference to its parent. So if we take the branch head, we can trace back the project history to the very beginning. This is why the Git branch is simply a reference to its head (you can go ahead and look into the files in .git/refs/heads directory of any of your Git&nbsp;repositories).</p> <p><img src="http://hades.name/media/git/git-history.png" alt="Git History" /></p> <p>Most of the time you will have a checked-out branch (the special reference <span class="caps">HEAD</span> points to the current branch, see .git/<span class="caps">HEAD</span> for example). When you commit something, your commits are attached to it and the branch reference is moved to the new commit. Simple. But sometimes your <span class="caps">HEAD</span> may point to something other than a branch head (for example, when you checkout an older revision by its <span class="caps">ID</span> or tag). This is called a <strong>detached head</strong>. It is a very simple, important and confusing situation. There&#8217;s nothing wrong about it, but it hides a peril: if you commit to a detached head, Git creates a new commit and attaches it to the current commit, forming a branch. But this branch has no name! It will just grow sideways as a normal branch without a name. Here&#8217;s what&#8217;s wrong with&nbsp;it:</p> <ul> <li>it is confusing, because commits do not go to master, or whatever branch you had checked out&nbsp;before;</li> <li>if you check out another branch, you won&#8217;t be able to return to this branch by its name, it simply doesn&#8217;t have&nbsp;any.</li> </ul> <p>Note, that Git won&#8217;t let you lose data easily and won&#8217;t force you to do unneeded work. Let me tell you what to do in case you have committed to a detached head. Suppose you created just one single commit to a detached head and now just sit and look at it. You have two&nbsp;options:</p> <ul> <li>create a new branch with the current commit as a head: <code>git branch <em>branchname</em></code>,</li> <li>attach the new commit to another branch (suppose it is branch <em>master</em>): remember the <span class="caps">ID</span> of the new commit, checkout the required branch (<code>git checkout master</code>), cherry-pick your commit to it (<code>git cherry-pick <em>id</em></code>).</li> </ul> <p>If you find yourself in the second situation (you&#8217;ve just committed to a detached head, checked out another branch and don&#8217;t remember the commit id), you may use Git&#8217;s reflog (<code>git reflog</code>, or <code> git log -g</code>). This will list the history of your <span class="caps">HEAD</span> (checkouts, commits and the such), where you can take commit <span class="caps">ID</span> and use it&nbsp;wisely.</p> <p>Merging is an important part of Git workflow. You will, in fact, do merges frequently even if you don&#8217;t use branches other than <em>master</em>, provided you use more than one repository. That is because <em>master</em> of one repository and <em>master</em> of another repository are, in general, different branches. So when you do push or pull to/from another repository you do a merge. Git differentiates two merge types (suppose you attempt to merge branch B into branch&nbsp;A):</p> <ul> <li><strong>fast-forward merge</strong>. This happens when B is a direct descendant of A. This is resolved trivially: Git simply moves reference A to point to B, <center><img src="http://hades.name/media/git/git-ff.png" alt="Git Fast-Forward" /></center></li> <li><strong>non fast-forward merge</strong>. This covers all the remaining cases, and requires a merge commit to be created (merge commit is a commit with at least two parents). <center><img src="http://hades.name/media/git/git-noff.png" alt="Git Fast-Forward" /></center></li> </ul> <p>This differentiation is important because the fast-forward merge can be performed automatically without human intervention. That&#8217;s why this is the <em>only</em> merge possible during Git push. The non fast-forward merge may result in edit conflicts (the situation when two lines of development changed the same line of the same file differently), so a human intervention may be required. This is what is meant by a (not immediately clear) git-push message &#8220;remote rejected: non fast-forward&#8221;: sorry, I can&#8217;t push your modifications, because remote branch has diverged, please resolve this manually. Most often this occurs when another developer managed to push his changes first. In this case just run &#8220;git pull&#8221;, resolve conflicts (if any), then run &#8220;git push&#8221;. Less often this occurs when a remote branch has been changed completely (for example, branch <em>pu</em> of <a href="http://git.kernel.org/?p=git/git.git;a=summary">Git Git repository</a> is changed very frequently and is not supposed to be developed upon). This means that either you or the remote repository owner screwed up, so you&#8217;d better talk to each other. Sometimes this occurs when you try to push to a completely unrelated repository. So just be careful&nbsp;there.</p> <p>I should note here, that the &#8220;&#8212;force&#8221; option to git-push along with +refspec notation is <strong>not</strong> going to solve your problems automagically. It will simply <strong>destroy the remote history, replacing with your own</strong>. So you should never use it, unless you know <em>exactly</em> what you are&nbsp;doing.</p> <p>Next up: rebasing and staging&nbsp;area.</p> <p>Previous&nbsp;post:</p> <ul> <li><a href="http://hades.name/blog/2010/01/17/git-your-friend-not-foe/">Volume 1, on the distributed <span class="caps">VCS</span>&nbsp;concepts</a></li> </ul> <p>Next&nbsp;posts:</p> <ul> <li><a href="http://hades.name/blog/2010/01/28/git-your-friend-not-foe-vol-3-refs-and-index/">Volume 3, on refs and staging&nbsp;area</a></li> <li><a href="http://hades.name/blog/2010/03/03/git-your-friend-not-foe-vol-4-rebasing/">Volume 4, on cherry-picking and&nbsp;rebasing</a></li> </ul> <p><a href="http://hades.name/blog/tag/git/">All posts about&nbsp;Git</a></p>