tag:blogger.com,1999:blog-6320234206163447562024-03-12T20:06:02.300-07:00Git BlameJunio C Hamano aka <a href="https://plus.google.com/108182106411180467879?rel=author">Gitster</a>'s Blog_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comBlogger225125tag:blogger.com,1999:blog-632023420616344756.post-55857287920284787522016-05-03T14:50:00.003-07:002016-05-03T14:50:59.137-07:00Fun with a new feature in recent GitIt is not exactly a <i>new</i> feature, but I find myself using the <span style="font-family: Courier New, Courier, monospace;">--sort</span><span style="font-family: inherit;"> option of </span><span style="font-family: Courier New, Courier, monospace;">git branch</span><span style="font-family: inherit;"> a lot more often than before these days.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">The way I work is that I review patches that were mailed-in during previous night (my time) in the morning. For each promising new topic, I decide where the topic should eventually be merged (some are fixes that should go to older maintenance tracks, some are new features that we will not want to merge to the maintenance tracks), create a dedicated topic branch for it, apply these patches, re-review them once more and then test the changes in isolation. Each existing topics that is redone in response to previous reviews is handled the same way. Its branch is rewound and the new round of patches are applied instead.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">After accumulating the new and updated topics that way without integrating with anything else, I'd often forget how many topics need to be integrated into the test branches (i.e. </span><span style="font-family: Courier New, Courier, monospace;">jch</span><span style="font-family: inherit;"> and </span><span style="font-family: Courier New, Courier, monospace;">pu</span><span style="font-family: inherit;">), and I can do this:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ git branch --no-merged pu --sort=-committerdate</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This lists the topic branches that are not part of </span><span style="font-family: Courier New, Courier, monospace;">pu</span><span style="font-family: inherit;">, which is the branch that is supposed to contain all the testable things, and sort them according to the commit date (i.e. the time I last touched it) of the tip of the topic branch. There often are topics that were once picked up, but turned out to be not ready even for the </span><span style="font-family: Courier New, Courier, monospace;">pu</span><span style="font-family: inherit;"> branch, and left around without getting merged to anywhere as a reminder for myself (otherwise, I'll forget pinging their authors about them), and they will sink in the older part of the output, while the freshly created and updated ones will float to the top of the output. This reminds me of the topics from the day that I need to reintegrate before starting the integration testing.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">The </span><span style="font-family: Courier New, Courier, monospace;">--sort</span><span style="font-family: inherit;"> option appeared first in Git 2.7.0.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Another command that I use often these days is Michael Haggerty's </span><span style="font-family: Courier New, Courier, monospace;">when-merged</span><span style="font-family: inherit;"> script, available in <a href="https://github.com/mhagger/git-when-merged" target="_blank">his repository at GitHub</a>. After finding a problematic line in the source and identifying the exact commit that introduced the line by using </span><span style="font-family: Courier New, Courier, monospace;">git blame</span><span style="font-family: inherit;">, I can see when it landed in the mainline by doing this:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ git when-merged $that_problematic_commit master | git name-rev --stdin</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This gives the merge commit that brought in the commit as part of a topic to the mainline, and after that, it is just the matter of turning it into a revision name to find the oldest maintenance track that needs to be fixed, which is partially done by passing its output through the </span><span style="font-family: Courier New, Courier, monospace;">name-rev</span><span style="font-family: inherit;"> filter.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-63687783973702465992015-10-15T14:47:00.002-07:002015-10-15T14:47:20.420-07:00Fun with recreating an evil mergeSometimes we wish there were good ways to recreate a complex merge, replaying a previously resolved conflict resolution, and reapplying a previously done evil merge, of a side branch to an updated mainline.<br />
<br />
For example, you have a side-branch that consists of two commits, A and B, and you create a merge with the mainline that ends with X, like so:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> A---B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> / \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ---o---O---X---M</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: inherit;">resulting in a new merge commit M. When you created this merge, it could be that changes A and B overlapped (either textually or semantically) with what was done on the mainline since the side branch forked, i.e. what was done by X. Such an overlap, if it is textual, would result in a merge conflict. Perhaps X added a new line at the same place A and/or B added a different line, resulting in something like:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">original line 1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><<<<<<< HEAD</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">line added by X</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">||||||| O (common ancestor)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">=======</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">l</span><span style="font-family: 'Courier New', Courier, monospace;">ine added by A</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">>>>>>>> B</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">original line 2</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: inherit;">which you may resolve, when recording M, to:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">original line 1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">l</span><span style="font-family: 'Courier New', Courier, monospace;">ine added by A</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">line added by X</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">original line 2</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
Expressed in "git show --cc" format, such a merge result would appear this way:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> ...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> original line 1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> +l</span><span style="font-family: 'Courier New', Courier, monospace;">ine added by A</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">+ line added by X</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> original line 2</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ...</span></div>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
A line with two leading spaces are common lines that both branches agree with, a line with plus at the first column is from the mainline and a line with plus at the second column is from the side branch.</div>
<div>
<br /></div>
<div>
If the overlap were not just textual but semantic, you may have to further update parts of files that did not textually conflict. For example, X may have renamed an existing function F to newF, while A or B added new callsites of F. Such a change is not likely to overlap textually, but in the merge result M, you would need to change the new calls you added to F to instead call newF. Such a change may look like this:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> ...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> original line 1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> +l</span><span style="font-family: 'Courier New', Courier, monospace;">ine added by A</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">+ line added by X</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> original line 2</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ...</span></div>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> -a new call to F() added by A</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">++a new call to newF() added by A</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: inherit;">A line with minus at the second column is what was only in the side branch but that does not appear in the result (i.e. the side branch added the line, but the result does not have it). A line with two pluses at the beginning is what appears in the result but does not exist in either branch.</span></div>
<div>
<br /></div>
<div>
A merge that introduces such a line that did not exist in either branch is called an evil merge. It is something that no automated textual merge algorithm would have produced.</div>
<div>
<br /></div>
<div>
Now, while you were working on producing the merge M, the mainline may have progressed and gained a new commit Y. You would like to somehow take advantage of what you have already done when you created M to merge your side branch to the updated mainline to produce N:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> .---A---B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> / \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ---o---O---X---Y---N</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">A good news is that, when the evil merge is in a file that also has textual conflicts to resolve, "git rerere" will automatically take care of this situation. All you need to do is to set the configuration rerere.enabled to true before attempting the merge between X and B and recording their merge M, and then attempt a new merge between B and Y. Without even having to type "git rerere", the mechanism is invoked by "git merge" to replay the recorded resolution (which is where the name of the machinery "rerere" comes from). A bad news is that when an evil merge has to be made to a file that is not involved in any textual conflict (i.e. imagine the case where we didn't have "line added by A" vs "line added by X" conflict earlier in the same file in the above example), "rerere" does not even kick in. The question is what to do, knowing B, X, and M, to recreate N while keeping the adjustment needed for semantic conflicts to record M.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">One naive approach would be to take a difference between X and M and apply it to Y. In the previous example, X would have looked like:</span><br />
<span style="font-family: inherit;"><br /></span>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">original line 1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">l</span><span style="font-family: 'Courier New', Courier, monospace;">ine added by X</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;">original line 2</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
</div>
<div>
<br /></div>
<div>
and the difference between X and M would be (1) addition of "line added by A", (2) addition of "a new call to newF() added by A", and (3) any other change made by A and B that did not overlap with what X did. Implementation-wise, it is unlikely that we would do this as a "diff | patch" pipeline; most likely we would do it as a three-way merge, i.e.</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ git checkout Y^0</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ git merge-recursive X HEAD M</span></div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">to compute the state we would have obtain by making the same move as going from X to M starting at Y, using the index and the working tree.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">While that approach would work in simple case where Y does not do anything interesting, it would not work well in general. The most obvious case is when Y is actually a merge between X and A:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> .---A---B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> / \ \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ---o---O---X---Y---N</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">The difference between X and M would contain all that was done by A and B, in addition to what was done at M to adjust for textual and semantic conflicts. Replaying that on top of Y, which already contains what was done by A but not B, would end up duplicating what A did. At best, we will get a huge and uninteresting merge conflict. At worst, we will get the same code silently duplicated twice.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">I <i>think</i> the right approach to recreate the (potentially evil) merge M is to consider M as two steps.</span><br />
<span style="font-family: inherit;">The first step is to merge X and B mechanically, and make a tree out of the mechanical merge result, with conflict markers and all. Call it T. The difference between T and M is what the person who made M did to adjust for textual and semantic conflicts.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> A---B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> / \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ---o---O---X---T-M</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
Then, you can think of the process of recreating N in a way similar to M was made as a similar two step process. The first step is to merge Y and B mechanically, and create a tree out of the mechanical merge result, and call it S. Applying the difference between T and M on top of S would give you the textual and semantic adjustments the same way "git rerere" replays the recorded resolution.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> .---A---B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> / (\) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ---o---O---X---Y---S-N</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<span style="font-family: inherit;">This should work better whether Y is a merge with A.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ git checkout X^0</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git merge --no-commit B</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git add -u</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ T=$(git write-tree)</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git reset --hard Y^0</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git merge --no-commit B</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git add -u</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ S=$(git commit-tree $(git write-tree) -p HEAD -m S)</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git checkout $S</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git merge-recursive $T HEAD M</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">would compute the result </span>using the index and the working tree, so after eyeballing the result and making sure it makes sense, the above can be concluded with a<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ git commit --amend</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Of course, this article is only about outlining the idea. If this proves to be a viable approach, it would make sense to do these procedures inside "rebase --first-parent" or something.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span><span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com2tag:blogger.com,1999:blog-632023420616344756.post-40160016858635347062015-07-27T14:18:00.000-07:002015-07-27T14:18:32.708-07:00Git 2.5The latest feature release Git v2.5.0 is now available at the
<a href="http://git-blame.blogspot.com/p/git-public-repositories.html" target="_blank">usual places</a>. It is comprised of 583 non-merge commits since
v2.4.0, contributed by 70 people, 21 of which are new faces.
<br />
<br />
One interesting change is to <span style="font-family: Courier New, Courier, monospace;">git help</span><span style="font-family: inherit;">. We now list commands, grouped by the situation in which you would want to use them. This came from discussion on usability, inspired by one of the talks at GitMerge conference we had in spring.</span><br />
<br />
Among notable new features, some of my favourites are:<br />
<ul>
<li>A new short-hand <span style="font-family: Courier New, Courier, monospace;"><i>branch</i>@{push}</span> denotes the remote-tracking branch that tracks the branch at the remote the <i><span style="font-family: Courier New, Courier, monospace;">branch</span></i> would be pushed to.</li>
<li><span style="font-family: Courier New, Courier, monospace;">git send-email</span><span style="font-family: inherit;"> learned the alias file format used by the sendmail program.</span></li>
<li>Traditionally, external low-level 3-way merge drivers are expected to produce their results based solely on the contents of the three variants given in temporary files named by <span style="font-family: Courier New, Courier, monospace;">%O</span>, <span style="font-family: Courier New, Courier, monospace;">%A</span> and <span style="font-family: Courier New, Courier, monospace;">%B</span> placeholders on their command line. They are now additionally told about the final path (given by <span style="font-family: Courier New, Courier, monospace;">%P</span>).</li>
<li>A heuristic we use to catch mistyped paths on the command line <span style="font-family: Courier New, Courier, monospace;">git <i>cmd</i> <i>revs</i> <i>pathspec</i></span> is to make sure that all the non-rev parameters in the later part of the command line are names of the files in the working tree, but that means <span style="font-family: Courier New, Courier, monospace;">git grep <i>string</i> -- \*.c</span> must always be disambiguated with <span style="font-family: Courier New, Courier, monospace;">--</span>, because nobody sane will create a file whose name literally is asterisk-dot-see. We loosen the heuristic to declare that with a wildcard string the user likely meant to give us a pathspec. So you can now simply say <span style="font-family: 'Courier New', Courier, monospace;">git grep </span><i style="font-family: 'Courier New', Courier, monospace;">string</i><span style="font-family: 'Courier New', Courier, monospace;"> \*.c</span><span style="font-family: inherit;"> without <span style="font-family: 'Courier New', Courier, monospace;">--</span><span style="font-family: inherit;">.</span></span></li>
<li>Filter scripts were run with SIGPIPE disabled on the Git side, expecting that they may not read what Git feeds them to filter. We however treated a filter that does not read its input fully before exiting as an error. We no longer do and ignore EPIPE when writing to feed the filter scripts.<br /><br />This changes semantics, but arguably in a good way. If a filter can produce its output without fully consuming its input using whatever magic, we now let it do so, instead of diagnosing it as a programming error.</li>
<li>Whitespace breakages in deleted and context lines can also be painted in the output of <span style="font-family: Courier New, Courier, monospace;">git diff</span> and friends with the new <span style="font-family: Courier New, Courier, monospace;">--ws-error-highlight</span> option.</li>
<li><span style="font-family: Courier New, Courier, monospace; font-style: normal;">git merge FETCH_HEAD</span><span style="font-family: inherit; font-style: normal;"> </span>learned that the previous "git fetch" could be to create an Octopus merge, i.e. recording multiple branches that are not marked as "not-for-merge"; this allows us to lose an old style invocation <span style="font-family: Courier New, Courier, monospace;">git merge <i>msg</i> HEAD <i>commits</i>...</span> in the implementation of <span style="font-family: Courier New, Courier, monospace;">git pull</span> script; the old style syntax can now be deprecated (but not removed yet).</li>
</ul>
<div>
There are a few "experimental" new features, too. They are still incomplete and/or buggy around the edges and likely to change in the future, but nevertheless interesting.<br />
<div>
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">git cat-file --batch</span> learned the <span style="font-family: Courier New, Courier, monospace;">--follow-symlinks</span> option that follows an in-tree symbolic link when asked about an object via extended SHA-1 syntax. For example, <span style="font-family: Courier New, Courier, monospace;">HEAD:RelNotes</span> may be a symbolic link that points at <span style="font-family: Courier New, Courier, monospace;">Documentation/RelNotes/2.5.0.txt</span>. With the new option, the command behaves as if <span style="font-family: Courier New, Courier, monospace;">HEAD:Documentation/RelNotes/2.5.0.txt</span> was given as input instead.<br /><br />This is incomplete in at least a few ways.<br />(1) A symbolic link in the index, e.g. <span style="font-family: Courier New, Courier, monospace;">:RelNotes</span><span style="font-family: inherit;">, should also be treated the same way, but isn't. (2) Non-batch mode, e.g. </span><span style="font-family: Courier New, Courier, monospace;">git cat-file --follow-symlinks blob HEAD:RelNotes</span><span style="font-family: inherit;">, may also want to behave the same way, but it doesn't.</span></li>
<li>A replacement mechanism for <span style="font-family: Courier New, Courier, monospace;">contrib/workdir/git-new-workdir</span> that does not rely on symbolic links and make sharing of objects and refs safer by making the borrowee and borrowers aware of each other has been introduced and accessible via <span style="font-family: Courier New, Courier, monospace;">git worktree add</span>. This is accumulating more and more known bugs but may prove useful once they are fixed.</li>
</ul>
<div>
<br /></div>
<div>
</div>
</div>
</div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-91019203145762210502015-06-29T09:23:00.001-07:002015-06-29T09:23:21.367-07:00Fun with "git blame -s"<span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;">After applying a patch that moves a bulk of code that was placed in a wrong file to its correct place, a quick way to sanity-check that the patch does not introduce anything unexpected is to run "git blame -C -M" between HEAD^ and HEAD, like this:</span><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;"> </span><span style="background-color: white; color: #404040; font-size: 13px; line-height: 18.2000007629395px;"><span style="font-family: Courier New, Courier, monospace;">$ git blame -C -M HEAD^..HEAD -- new-location.c</span></span><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;">This should show that the lines moved from the old location in the output as coming from there; lines blamed for the new commit (i.e. not coming from the old location) can then be inspected more carefully to see if it makes sense.</span><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;">One problem I had while doing exactly that today was that most of the screen real-estate on my 92-column wide terminal was taken by the author name and the timestamp, and I found myself pressing right and left arrow in my pager to scroll horizontally a lot, which was both frustrating and suboptimal.</span><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;"> </span><span style="background-color: white; color: #404040; font-size: 13px; line-height: 18.2000007629395px;"><span style="font-family: Courier New, Courier, monospace;">$ git blame -h</span></span><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><br style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;" /><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;">told me that there is </span><span style="background-color: white; color: #404040; font-family: Roboto, arial, sans-serif; font-size: 13px; line-height: 18.2000007629395px;">"git blame -s" to omit that information. I thought that I didn't know about the option. Running "git blame" on its source itself revealed that the option was added by me 8 years ago, and it wasn't that I didn't know but I simply forgot ;-)</span>_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-79997654481884025612015-06-25T13:16:00.004-07:002015-06-25T13:16:51.972-07:00Git 2.4.5The latest maintenance release for Git v2.4.x series has been tagged.<br />
<ul>
<li>The setup code used to die when <span style="font-family: Courier New, Courier, monospace;">core.bare</span> and <span style="font-family: Courier New, Courier, monospace;">core.worktree</span> are set inconsistently, even for commands that do not need working tree.</li>
<li>There was a dead code that used to handle <span style="font-family: Courier New, Courier, monospace;">git pull --tags</span> and show special-cased error message, which was made irrelevant when the semantics of the option changed back in Git 1.9 days.</li>
<li><span style="font-family: Courier New, Courier, monospace;">color.diff.plain</span> was a misnomer; give it <span style="font-family: Courier New, Courier, monospace;">color.diff.context</span> as a more logical synonym.</li>
<li>The configuration reader/writer uses mmap(2) interface to access the files; when we find a directory, it barfed with "Out of memory?".</li>
<li>Recent <span style="font-family: Courier New, Courier, monospace;">git prune</span> traverses young unreachable objects to safekeep old objects in the reachability chain from them, which sometimes showed unnecessary error messages that are alarming.</li>
<li><span style="font-family: Courier New, Courier, monospace;">git rebase -i</span> fired post-rewrite hook when it shouldn't (namely, when it was told to stop sequencing with <span style="font-family: Courier New, Courier, monospace;">exec</span> insn).</li>
</ul>
It also contains typofixes, documentation updates and trivial code clean-ups.<br />
<br />
Enjoy._http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-22012399973982132682015-06-25T13:12:00.000-07:002015-06-25T13:12:07.398-07:00Git 2.5-rc0 early previewAn early preview of the upcoming Git 2.5 has been tagged as v2.5.0-rc0. It is comprised of 492 non-merge commits since v2.4.0, contributed by 54 people, 17 of which are new faces.<br />
<div>
<br /></div>
Among notable new features, some of my favourites are:<br />
<br />
<ul>
<li>A new short-hand <branch>@{push} denotes the remote-tracking branch that tracks the branch at the remote the <branch> would be pushed to.</li>
<li>A heuristic we use to catch mistyped paths on the command line <span style="font-family: Courier New, Courier, monospace;">git <i>cmd</i> <i>revs</i> <i>pathspec</i></span> is to make sure that all the non-rev parameters in the later part of the command line are names of the files in the working tree, but that means <span style="font-family: Courier New, Courier, monospace;">git grep <i>string</i> -- \*.c</span> must always be disambiguated with <span style="font-family: Courier New, Courier, monospace;">--</span>, because nobody sane will create a file whose name literally is asterisk-dot-see. We loosen the heuristic to declare that with a wildcard string the user likely meant to give us a pathspec. So you can now simply say <span style="font-family: 'Courier New', Courier, monospace;">git grep </span><i style="font-family: 'Courier New', Courier, monospace;">string</i><span style="font-family: 'Courier New', Courier, monospace;"> \*.c</span><span style="font-family: inherit;"> without <span style="font-family: 'Courier New', Courier, monospace;">--</span><span style="font-family: inherit;">.</span></span></li>
<li>Filter scripts were run with SIGPIPE disabled on the Git side, expecting that they may not read what Git feeds them to filter. We however treated a filter that does not read its input fully before exiting as an error. We no longer do and ignore EPIPE when writing to feed the filter scripts.<br />This changes semantics, but arguably in a good way. If a filter can produce its output without fully consuming its input using whatever magic, we now let it do so, instead of diagnosing it as a programming error.</li>
<li>Whitespace breakages in deleted and context lines can also be painted in the output of <span style="font-family: Courier New, Courier, monospace;">git diff</span> and friends with the new <span style="font-family: Courier New, Courier, monospace;">--ws-error-highlight</span> option.</li>
</ul>
<div>
There are a few "experimental" new features, too. They are still incomplete and/or buggy around the edges and likely to change in the future, but nevertheless interesting.</div>
<div>
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">git cat-file --batch</span> learned the <span style="font-family: Courier New, Courier, monospace;">--follow-symlinks</span> option that follows an in-tree symbolic link when asked about an object via extended SHA-1 syntax. For example, <span style="font-family: Courier New, Courier, monospace;">HEAD:RelNotes</span> may be a symbolic link that points at <span style="font-family: Courier New, Courier, monospace;">Documentation/RelNotes/2.5.0.txt</span>. With the new option, the command behaves as if <span style="font-family: Courier New, Courier, monospace;">HEAD:Documentation/RelNotes/2.5.0.txt</span> was given as input instead.<br />This is incomplete in a few ways.<br />(1) A symbolic link in the index, e.g. <span style="font-family: Courier New, Courier, monospace;">:RelNotes</span><span style="font-family: inherit;">, should also be treated the same way, but isn't. (2) Non-batch mode, e.g. </span><span style="font-family: Courier New, Courier, monospace;">git cat-file --follow-symlinks blob HEAD:RelNotes</span><span style="font-family: inherit;">, may also want to behave the same way, but it doesn't.</span></li>
<li>A replacement mechanism for <span style="font-family: Courier New, Courier, monospace;">contrib/workdir/git-new-workdir</span> that does not rely on symbolic links and make sharing of objects and refs safer by making the borrowee and borrowers aware of each other has been introduced and accessible via <span style="font-family: Courier New, Courier, monospace;">git checkout --to</span>. This is accumulating more and more known bugs but may prove useful once they are fixed.</li>
</ul>
<div>
A draft release notes is <a href="https://raw.githubusercontent.com/gitster/git-htmldocs/d4b043540e056/RelNotes/2.5.0.txt" target="_blank">there</a>.</div>
</div>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-78362550273301078762015-05-26T15:08:00.001-07:002015-05-26T15:08:16.080-07:00Git 2.4.1 and 2.4.2Today, the v2.4.2 maintenance release was tagged. Compared to v2.4.0 that was released end of April 2015 (i.e. last month), in addition to minor typo-fixes, documentation updates and trivial code clean-ups, today's maintenance release contains the following:<div>
<ul>
<li>The usual <span style="font-family: Courier New, Courier, monospace;">git diff</span>, when seeing a file turning into a directory, showed a patchset to remove the file and create all files in the directory, but <span style="font-family: Courier New, Courier, monospace;">git diff --no-index</span> simply refused to work. Also, when asked to compare a file and a directory, imitate POSIX <span style="font-family: Courier New, Courier, monospace;">diff</span> and compare the file with the file with the same name in the directory, instead of refusing to run.<br /></li>
<li>The default <span style="font-family: Courier New, Courier, monospace;">$HOME/.gitconfig</span> file created upon <span style="font-family: Courier New, Courier, monospace;">git config --global</span> that edits it had incorrectly spelled user.name and user.email entries in it.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git commit --date=now</span> or anything that relies on approxidate lost the daylight-saving-time offset.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git cat-file bl $blob</span> failed to barf even though there is no object type that is "bl".<br /></li>
<li>Teach the codepaths that read <span style="font-family: Courier New, Courier, monospace;">.gitignore</span> and <span style="font-family: Courier New, Courier, monospace;">.gitattributes</span> files that these files encoded in UTF-8 may have UTF-8 BOM marker at the beginning; this makes it in line with what we do for configuration files already.<br /></li>
<li>Access to objects in repositories that borrow from another one on a slow NFS server unnecessarily got more expensive due to recent code becoming more cautious in a naive way not to lose objects to pruning.<br /></li>
<li>We avoid setting <span style="font-family: Courier New, Courier, monospace;">core.worktree</span> when the repository location is the <span style="font-family: Courier New, Courier, monospace;">.git</span> directory directly at the top level of the working tree, but the code misdetected the case in which the working tree is at the root level of the filesystem (which arguably is a silly thing to do, but still valid).<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git rev-list --objects $old --not --all</span> to see if everything that is reachable from <span style="font-family: Courier New, Courier, monospace;">$old</span> is already connected to the existing refs was very inefficient.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">hash-object --literally</span> introduced in v2.2 was not prepared to take a really long object type name.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git rebase --quiet</span> was not quite quiet when there is nothing to do.<br /></li>
<li>The completion for <span style="font-family: Courier New, Courier, monospace;">log --decorate=</span> parameter value was incorrect.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">filter-branch</span> corrupted commit log message that ends with an incomplete line on platforms with some <span style="font-family: Courier New, Courier, monospace;">sed</span> implementations that munge such a line. Work it around by avoiding to use <span style="font-family: 'Courier New', Courier, monospace;">sed</span>.<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git daemon</span> failed to build from the source under <span style="font-family: Courier New, Courier, monospace;">NO_IPV6</span> configuration (regression in 2.4).<br /></li>
<li><span style="font-family: Courier New, Courier, monospace;">git stash pop/apply</span> forgot to make sure that not just the working tree is clean but also the index is clean. The latter is important as a stash application can conflict and the index will be used for conflict resolution.<br /></li>
<li>We have prepended <span style="font-family: Courier New, Courier, monospace;">$GIT_EXEC_PATH</span> and the path <span style="font-family: Courier New, Courier, monospace;">git</span> is installed in (typically <span style="font-family: Courier New, Courier, monospace;">/usr/bin</span>) to <span style="font-family: Courier New, Courier, monospace;">$PATH</span> when invoking subprograms and hooks for almost eternity, but the original use case the latter tried to support was semi-bogus (i.e. install <span style="font-family: Courier New, Courier, monospace;">git</span> as <span style="font-family: Courier New, Courier, monospace;">/opt/foo/git</span> and run it without having <span style="font-family: Courier New, Courier, monospace;">/opt/foo</span> on <span style="font-family: 'Courier New', Courier, monospace;">$PATH</span>), and more importantly it has become less and less relevant as Git grew more mainstream (i.e. the users would <i>want</i> to have it on their <span style="font-family: Courier New, Courier, monospace;">$PATH</span>). Stop prepending the path in which <span style="font-family: 'Courier New', Courier, monospace;">git</span> is installed to users' <span style="font-family: 'Courier New', Courier, monospace;">$PATH</span>, as that would interfere the command search order people depend on (e.g. they may not like versions of programs that are unrelated to Git in <span style="font-family: Courier New, Courier, monospace;">/usr/bin</span> and want to override them by having different ones in <span style="font-family: Courier New, Courier, monospace;">/usr/local/bin</span> and have the latter directory earlier in their <span style="font-family: Courier New, Courier, monospace;">$PATH</span>).</li>
</ul>
<div>
Git hopefully continues to improve.</div>
</div>
<div>
Have fun.</div>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-24901311567482124122015-04-25T22:56:00.001-07:002015-04-25T22:56:21.083-07:00Fun with failing cherry-pickI just encountered an interesting cherry-pick failure.<br />
<br />
The change I was trying to cherry-pick was to remove a hunk of text. Its patch conceptually looked like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@@ ... @@</span><br />
<span style="font-family: Courier New, Courier, monospace;"> A</span><br />
<span style="font-family: Courier New, Courier, monospace;">-B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> C</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">even though the pre-context A, removed text B, and post-context C are all multi-line block.</span><br />
After doing a significant rewrite to the same original codebase (i.e. that had A, B and then C next to each other), the code I wanted to cherry-pick the above commit moved the text around and the block corresponding to B is now done a lot later. A diff between that state and the original perhaps looked like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@@ ... @@</span><br />
<span style="font-family: Courier New, Courier, monospace;"> A</span><br />
<span style="font-family: Courier New, Courier, monospace;">-B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> C</span><br />
<span style="font-family: Courier New, Courier, monospace;">@@ ... @@</span><br />
<span style="font-family: Courier New, Courier, monospace;"> D</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">+</span><span style="font-family: 'Courier New', Courier, monospace;">B</span><br />
<span style="font-family: Courier New, Courier, monospace;"> E</span><br />
<br />
And cherry-picking the above change succeeded without doing anything (!?!?).<br />
<br />
Logically, this behaviour "makes sense", in the sense that it can be explained. The change wants to make A and C adjacent by removing B, and the three-way merge noticed that the updated codebase already had that removal, so there is nothing that needs to be done. In this particular case, I did <i>not</i> remove B but moved it elsewhere, so what cherry-pick did was wrong, but in other cases I may indeed have removed it without adding the equivalent to anywhere else, so it could have been correct. We simply cannot say. I wonder if we should at least flag this "both sides appear to have removed" case as conflicting, but I am not sure how that should be implemented (let alone implemented efficiently). After all, the <i>moved</i> block B might have gone to a completely different file. Would we scan for the matching block of text for the entire working tree?<br />
<br />
This is why you should always look at the output from "git show" for the commit being cherry-picked and the output from "git diff HEAD" before concluding the cherry-pick to see if anything is amiss.<br />
<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-55939495676898655732015-04-02T15:47:00.002-07:002015-04-02T15:47:38.082-07:00First release candidate for Git 2.4This release has a few changes in the user-visible output from Porcelain commands. These are not meant to be parsed by scripts, but the users still may want to be aware of the changes.<br />
<div>
<ul>
<li>Output from "<span style="font-family: Courier New, Courier, monospace;">git log --decorate</span>" (and "<span style="font-family: Courier New, Courier, monospace;">%d</span>" format specifier used in the userformat "<span style="font-family: Courier New, Courier, monospace;">--format=<string></span>" parameter "<span style="font-family: Courier New, Courier, monospace;">git log</span>" family of commands take) used to list "HEAD" just like other branch names, separated with a comma in between. E.g.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$ git log --decorate -1 master</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, master)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> ...</span><br />
<span style="font-family: inherit;">This release updates the output slightly when HEAD refers to the tip </span>of a branch whose name is also shown in the output. The above is shown as:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$ git log --decorate -1 master<br />
commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> master)<br />
...</span><br />
</li>
<li>The phrasing "<span style="font-family: Courier New, Courier, monospace;">git branch</span>" uses to describe a detached HEAD has been updated to match that of "<span style="font-family: Courier New, Courier, monospace;">git status</span>". When the HEAD is at the same commit as it was originally detached, they now both show "detached at <commit object name>". When the HEAD has moved since it was originally detached, they now both show "detached from <commit object name>". Earlier "git branch" always used "from", even when the user hasn't moved HEAD since it was detached.</li>
</ul>
</div>
<div>
Otherwise, there are only minor fixes and documentation updates everywhere, and unusually low number of new and shiny toys ;-)</div>
<div>
<ul>
<li>"<span style="font-family: Courier New, Courier, monospace;">git log --invert-grep --grep=WIP</span>" will show only commits that do not have the string "WIP" in their messages.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git push</span>" has been taught a "<span style="font-family: Courier New, Courier, monospace;">--atomic</span>" option that makes push to update more than one ref an "all-or-none" affair.</li>
<li>Extending the "push to deploy" added in 2.3, the behaviour of "<span style="font-family: Courier New, Courier, monospace;">git push</span>" when updating the branch that is checked out can now be tweaked by push-to-checkout hook. The "push to deploy" implementation in 2.3 has a bug that makes it impossible to bootstrap an empty repository (or an unborn branch), but it can be worked around by using this hook.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git send-email</span>" used to accept a mistaken "y" (or "yes") as an answer to "What encoding do you want to use [UTF-8]? " without questioning. Now it asks for confirmation when the answer looks too short to be a valid encoding name.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git archive</span>" can now be told to set the 'text' attribute in the resulting zip archive.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git -C '' subcmd</span>" used to refuse to work in the current directory, unlike "<span style="font-family: Courier New, Courier, monospace;">cd ''</span>" which silently behaves as a no-op.</li>
<li>The <span style="font-family: Courier New, Courier, monospace;">versionsort.prerelease</span> configuration variable can be used to specify that v1.0-pre1 comes before v1.0.</li>
<li>A new "<span style="font-family: Courier New, Courier, monospace;">push.followTags</span>" configuration turns the "<span style="font-family: Courier New, Courier, monospace;">--follow-tags</span>" option on by default for the "<span style="font-family: Courier New, Courier, monospace;">git push</span>" command.</li>
</ul>
Please give it a good beating so that we can ship a successful v2.4 final at around the end of the month without regressions compared to v2.3 series.</div>
<div>
<br /></div>
<div>
Thanks.</div>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-25778831845964523742015-03-30T15:09:00.001-07:002015-03-30T15:09:29.692-07:00Fun with Non-Fast-Forward<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Your push may fail due to “non fast-forward”. You start from a history that is identical to that of your upstream, commit your work on top of it, and then by the time you attempt to push it back, </span><span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">the upstream may have advanced because somebody else was also working on his own changes.</span></div>
<b id="docs-internal-guid-dc8e2178-693e-2ac6-9e88-74476b8c1faf" style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For example, between the upstream and your repositories, histories may diverge this way (the asterisk denotes the tip of the branch; the time flows from left to right as usual):</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Upstream You</span></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C* --- fetch --> ---A---B---C*</span></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E* ---A---B---C</span></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D? D*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E? <-- push --- ---A---B---C</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If the push moved the branch at the upstream to point at your commit, you will be discarding other people’s work. To avoid doing so, git push fails with “Non fast-forward”. </span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The standard recommendation when this happens is to “fetch, merge and then push back”. The histories will diverge and then converge like this:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Upstream You</span></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E* --- fetch --> ---A---B---C---E</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><span style="font-size: x-small;"><br /></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 1</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D---F*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E* ---A---B---C---E</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><span style="font-size: x-small;"><br /></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 1 1</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D---F* D---F*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /2 / /2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E <-- push --- ---A---B---C---E</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now, the updated tip of the branch has the previous tip of the upstream (E) as its parent, so the overall history does not lose other people’s work.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The resulting history, however, is not what the majority of the project participants would appreciate. The merge result records D as its first parent (denoted with 1 on the edge to the parent), as if what happened on the upstream (E) were done as a side branch </span><span style="font-family: Arial; font-size: 15px; line-height: 20.7000007629395px; white-space: pre-wrap;">while F was being prepared and pushed back</span><span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">. In reality, E in the illustration may not be a single commit but can be many commits and many merges done by many people, and these many commits may have been observed as the tips of the upstream’s history by many people before F got pushed.</span><br />
<span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;"><br /></span>
<span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">Even though Git treats all parents of a merge equally at the level of the underlying data model, the users have come to expect that the history they will see by following the first-parent chain tells the overall picture of the shared project history, while second and later parents of merges represent work done on side branches. From this point of view, what "fetch, merge and then push" is not quite a right suggestion to proceed from a failed push due to "non fast-forward".</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">It is tempting to recommend “fetch, merge backwards and then push back” as an alternative, and it almost works for a simple history:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Upstream You</span></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E* --- fetch --> ---A---B---C---E</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><span style="font-size: x-small;"><br /></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D---F*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /1</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E* ---A---B---C---E</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><span style="font-size: x-small;"><br /></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 2 2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> D---F* D---F*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /1 / /1</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E <-- push --- ---A---B---C---E</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Then, if you follow the first-parent chain of the history, you will see how the tip of the overall project progressed. This is an improvement over the “fetch, merge and then push back”, but it </span><span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">has a few problems.</span><br />
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b id="docs-internal-guid-a1912ba2-6c79-2506-d3e1-b7ecd1c9b2a5" style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.8065454483032266; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">One reason why “merge backwards” is wrong becomes apparent when you consider what should happen when the push fails for the second time after the backward merge is made:</span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">Upstream You</span></span></div>
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> D*</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> /</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">---A---B---C---E* --- fetch --> ---A---B---C---E</span></span></div>
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> 2</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> D---F*</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> / /1</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">---A---B---C---E* ---A---B---C---E</span></span></div>
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> 2 2</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> D---F? D---F*</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> / /1 / /1</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">---A---B---C---E---G <-- push --- ---A---B---C---E</span></span></div>
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> 2 2 2</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> D---F? D---F---H*</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;"> / /1 / /1 /1</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">---A---B---C---E---G --- fetch --> ---A---B---C---E---G</span></span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If the upstream side gained another commit G while F was being prepared, “fetch, merge backwards and then push” will end up creating a history like this, hiding D, the only real change you did in the repository, as the tip of the side branch of a side branch!</span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">It also does not solve the problem if the work you did in D is not a single strand of pearls, but has merges from side branches. If D in the above series of illustrations were a few merges X, Y and Z from side branches of independent topics, the picture on your side, after fetching E from the updated upstream, may look like this:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> y---y---y .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / \ .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . x---x \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / \ \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / X---Y---Z*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">That is, hoping that the other people will stay quiet, starting from C, you merged three independent topic branches on top of it with merges X, Y and Z, and hoped that the overall project history would fast-forward to Z. From your perspective, you wanted to make A-B-C-X-Y-Z to be the main history of the project, while x, y, ... were implementation details of X, Y and Z that are hidden behind merges on side branches. And </span><span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">if there were no E, that would indeed have been the overall project history people would have seen after your push.</span><br />
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Merging backwards and pushing back would however make the history’s tip F, with its first parent E, and Z becomes a side branch. The fact that X, Y and Z (more precisely, X^2 and Y^2 and Z^2) were independent topics is lost by doing so:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> y---y---y .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / \ .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . x---x \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / \ \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / X---Y---Z</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / / \2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E-------F*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 1</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span id="docs-internal-guid-a1912ba2-6c03-5833-7c08-591cd514279b"></span><br />
<div dir="ltr" style="line-height: 1.8065454483032266; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So "merge backwards" is not a right solution in general. It is only valid if you are building a topic directly on top of the shared integration branch, which is something you should not be doing in the first place. In the earlier illustration of creating a single D on top of C and pushing it, if there were no work from other people (i.e. E), the push would have fast-forwarded, making D as a normal commit directly on the first-parent chain. If there were work from other people like E, “merge in reverse” would instead have recorded D on a side branch. If D is a topic separate and independent from other work being done in parallel, you would consistently want to see such a change appear as a merge of a side branch.</span></div>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A better recommendation might be to “fetch, rebuild the first-parent chain, and then push back”. That is, you would rebuild X, Y and Z (i.e. “git log --first-parent C..”) on top of the updated upstream E:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> y---y-------y .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / \ .</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . x-------x \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / \ \ \</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> . / X’--Y’--Z’*</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> / /</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">---A---B---C---E</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Note that this will work well naturally even when your first-parent chain has non-merge commits. For example, X and Y in the above illustration may be merges while Z is a regular commit that updates the release notes with descriptions of what was recently merged (i.e. X and Y). Rebuilding such a first-parent chain on top of E will make the resulting history very easy to understand when the reader follows the first-parent chain.</span><br />
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The reason why “rebuild the first-parent chain on the updated upstream” works the best is tautological. People do care about the first-parenthood when viewing the history, and you must have cared about the first-parent chain, too,</span><span style="font-family: Arial; font-size: 15px; line-height: 20.7000007629395px; white-space: pre-wrap;"> when building your history leading to Z</span><span style="font-family: Arial; font-size: 15px; line-height: 1.38; white-space: pre-wrap;">. That first-parenthood you and others care about is what is being preserved here. By definition, we cannot go wrong ;-)</span></div>
<span id="docs-internal-guid-a1912ba2-6c7a-df98-8915-dc838ab80012"></span>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
And of course, this will work against a moving upstream that gained new commits while we were fixing things up on our end, because we won't be piling a new merges on top, but will be rebuilding X', Y' and Z' into X'', Y'', and Z'' instead.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To make this work on the pusher’s end, after seeing the initial “non fast-forward” refusal from “git push”, the pusher may need to do something like this:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git push ;# fails</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git fetch</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git rebase --first-parent @{upstream}</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Note that “git rebase --first-parent” does not exist yet; it is one of the topics I would like to see resurrected from <a href="http://thread.gmane.org/gmane.comp.version-control.git/198125" target="_blank">old discussions</a>.</span><br />
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But before "rebase --first-parent" materialises, in the scenario illustrated above, the pusher can do these instead of that command:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git reset --hard @{upstream}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git merge X^2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git merge Y^2</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ git merge Z^2</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And then, inspect the result thoroughly. As carefully as you checked your work before you attempted your first push that was rejected. After that, hopefully your history will fast-forward the upstream and everybody will be happy.</span></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-28188976065163917492015-03-27T14:14:00.000-07:002015-03-29T11:32:14.276-07:00Stats from recent Git releasesFollowing up to the <a href="http://git-blame.blogspot.com/2015/03/git-24-will-hopefully-be-product.html">previous post</a>, I computed a few numbers for each development cycle in the recent past.<br />
<br />
In all the graphs in this article, the horizontal axis counts the number of days into the development cycle, and the vertical axis shows the number of non-merge commits made.<br />
<br />
<ul>
<li>The bottom line in each graph shows the number of non-merge commits that went to the contemporary maintenance track.</li>
<li>The middle line shows the number of non-merge commits that went to the release but not to the maintenance track (i.e. shiny new toys, oops-fixes to them, and clean-ups that were too minor to be worth merging to the maintenance track), and</li>
<li>The top line shows the total number of non-merge commits in the release.</li>
</ul>
<br />
Even though I somehow have a fond memory of v1.5.3, the beginning of the modern Git was unarguably the v1.6.0 release. Its development cycle started in June 2008 and ended in August 2008. We can see that we were constantly adding a lot more new shiny toys (this cycle had the big "no more git-foo in user's $PATH" change) than we were applying fixes to the maintenance track during this period. This cycle lasted for 60 days, 731 commits in total among which 120 went to the maintenance track of its time.<br />
<iframe frameborder="0" height="358" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/1l9TfZFKI_JXjJEbR4pbFkAEgpWPrC7B_CNYlkIs3hLU/pubchart?oid=491473802&format=image" width="600"></iframe><br />
<br />
During the development cycle that led to v1.8.0 (August 2012 to October 2012), the pattern is very different. We cook our topics longer in the 'next' branch and we can clearly see that the topics graduate to 'master' in batches, which appear as jumps in the graph. This cycle lasted for 63 days, 497 commits in total among which 182 went to the maintenance track of its time.<br />
<iframe frameborder="0" height="371" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/1l9TfZFKI_JXjJEbR4pbFkAEgpWPrC7B_CNYlkIs3hLU/pubchart?oid=1638248137&format=image" width="600"></iframe><br />
<br />
The cycle led to v2.0.0 (February 2014 to June 2014) has a similar pattern, but as another "we now break backward compatibility for ancient UI wart" release, we can see that a large batch of changes were merged in early part of the cycle, hoping to give them better and longer exposure to the testing public; on the other hand, we did not do too many fixes to the maintenance track. This cycle lasted for 103 days, 475 commits in total among which 90 went to the maintenance track of its time.<br />
<br />
<iframe frameborder="0" height="371" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/1l9TfZFKI_JXjJEbR4pbFkAEgpWPrC7B_CNYlkIs3hLU/pubchart?oid=1215002641&format=image" width="600"></iframe><br />
<br />
The numbers for the current cycle leading to v2.4 (February 2015 to April 2015) are not finalized yet, but we can clearly see that this cycle is more about fixing old bugs than introducing shiny new toys from this graph. This cycle as of this writing is at its 50th day, 344 commits in total so far among which 115 went to the maintenance track.<br />
<br />
<iframe frameborder="0" height="371" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/1l9TfZFKI_JXjJEbR4pbFkAEgpWPrC7B_CNYlkIs3hLU/pubchart?oid=305748012&format=image" width="600"></iframe><br />
<br />
Note that we should not be alarmed by the sharp rise at the end of the graph. We just entered the pre-release freeze period and the jump shows the final batch of topics graduating to the 'master' branch. We will have a few more weeks until the final, and during that period the graph will hopefully stay reasonably flat (any rise from this point on would mean we would be doing a last-minute "oops" fixes).<br />
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-54206810526133359282015-03-26T22:34:00.002-07:002015-03-26T22:39:40.468-07:00Git 2.4 will hopefully be a "product quality" releaseEarlier in the day, an early preview release for the next release of Git, 2.4-rc0, was tagged. Unlike many major releases in the past, this development cycle turned out to be relatively calm, fixing many usability warts and bugs, while introducing only a few new shiny toys.<br />
<br />
In fact, the ratio of changes that are fixes and clean-ups in this release is unusually higher compared to recent releases. We keep a series of patches around each topic, whether it is a bugfix, a clean-up, or a new shiny toy, on its own topic branch, and each branch is merged to the 'master' branch after reviewing and testing, and then fixes and trivial clean-ups are also merged to the 'maint' branch. Because of this project structure, it is relatively easy to sift fixes and enhancement apart. Among new commits in release X since release (X-1), the ones that appear also in the last maintenance track for release (X-1) are fixes and clean-ups, while the remainder is enhancements.<br />
<br />
Among the changes that went into v1.9.0 since v1.8.5, 23% of them were fixes that got merged to v1.8.5.6, for example, and this number has been more or less stable throughout the last year. Among the changes in v2.3.0 since v2.2.0, 18% of them were also in v2.2.2. Today's preview v2.4.0-rc0, however, has 333 changes since v2.3.0, among which 110 are in v2.3.4, which means that 33% of the changes are fixes and clean-ups.<br />
<br />
These fixes came from 33 contributors in total, but changes from only a few usual suspects dominate and most other contributors have only one or two changes on the maintenance track. It is illuminating to compare the output between<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">$ git shortlog --no-merges -n -s ^maint v2.3.0..master</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ git shortlog --no-merges -n -s v2.3.0..maint</span><br />
<br />
to see who prefers to work on new shiny toys and who works on product quality by fixing other people's bugs. The first command sorts the contributors by the number of commits since v2.3.0 that are only in the 'master', i.e. new shiny toys, and the second command sorts the contributors by the number of commits since v2.3.0 that are in the 'maint', i.e. fixes and clean-ups.<br />
<br />
The output matches my perception (as the project maintainer, I at least look at, if not read carefully, all the changes) of each contributor's strength and weakness fairly well. Some are always looking for new and exciting things while being bad at tying loose ends, while others are more careful perfectionists.<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com2tag:blogger.com,1999:blog-632023420616344756.post-59104366111090850342015-03-25T13:58:00.002-07:002015-03-28T10:35:53.312-07:00Git Rev NewsChristian Couder (who is known for his work enhancing the "<a href="https://www.youtube.com/watch?v=49OYaF_v7EA">git bisect</a>" command several years ago) and Thomas Ferris Nicolaisen (who hosts a popular podcast <a href="http://gitminutes.com/">GitMinutes</a>) started producing a newsletter for Git development community and named it <a href="http://git.github.io/rev_news/edition-1.html">Git Rev News</a>.<br />
<br />
Here is what the newsletter is about in their words:<br />
<br />
<div style="font-family: sans-serif; margin-left: 4em;">
Our goal is to aggregate and communicate some of the activities on the <a href="http://news.gmane.org/gmane.comp.version-control.git/">Git mailing list</a> in a format that the wider tech community can follow and understand. In addition, we'll link to some of the interesting Git-related articles, tools and projects we come across.<br />
<br />
This edition covers what happened during the month of March 2015.</div>
<br />
As one of the people who still remembers "<a href="https://web.archive.org/web/20050514083018/http://www.kerneltraffic.org/git/gt20050502_1.html">Git Traffic</a>", which was meant to be an ongoing summary of the Git mailing list traffic but disappeared after publishing its first and only issue, I find this a very welcome development. Because our mailing list is a fairly high-volume one, it is almost impossible to keep up with everything that happens there, unless you are actively involved in the development process.<br />
<br />
I hope their effort will continue and benefit the wider Git ecosystem. You can help them out in various ways if you are interested.<br />
<br />
<ul>
<li>They are not entirely happy with how the newsletter is formatted. If you are handy with HTML, CSS or some blog publishing platforms, they would appreciate help in this area.</li>
<li>They are not paid full-time editors but doing this as volunteers. They would appreciate editorial help as well.</li>
<li>You can contribute by writing your own articles that summarize the discussions you found interesting on the mailing list.</li>
</ul>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-86185943896571080212015-02-27T14:01:00.001-08:002015-02-27T14:01:12.388-08:00Nexus 4 still live and kickingMy everyday phone for the past few years has been Nexus 4. I also have a Nexus 5, which is slightly larger and with a much better screen, but I never felt a need to switch (I did try to have "Let's use N5 this week" every once in a while, though). Last year's Nexus 6 simply felt too large for me. Besides, it is too expensive for me to buy.<br />
<br />
I noticed that my N4 recently stopped picking up NFC and charging via wireless. Later I learned that this is a typical sign that its battery needs replacement. Not because the battery got too weak to hold charge, but because the battery started <b>bloating</b>, pushing against the back cover, which necessary antennas are built onto. By slightly raising the back cover by bulging out, the bloated battery breaks the connection from the motherboard to these antennas, which is made only by contact. And that is how NFC and wireless charging are broken.<br />
<br />
At least, that is the story I read.<br />
<br />
After learning <a href="http://www.makeuseof.com/tag/how-to-replace-the-nexus-4-battery-it-can-be-done-android/" target="_blank">how to</a>, and getting a replacement battery and a few small screw/torx drivers, I opened the phone (which took me some time) and saw this bloated battery.<br />
<br />
<a href="http://3.bp.blogspot.com/-J6N5OvpHyfU/VOaPRwTEhxI/AAAAAAAAi10/DwPm8Q0IZtQ/s1600/IMG_20150219_172921.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-J6N5OvpHyfU/VOaPRwTEhxI/AAAAAAAAi10/DwPm8Q0IZtQ/s1600/IMG_20150219_172921.jpg" height="320" width="240" /></a><br />
<br />
<a href="http://3.bp.blogspot.com/-poS8YbBJKtU/VOaPR5lNIII/AAAAAAAAi10/JUHk24vh9uo/s1600/IMG_20150219_172906.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-poS8YbBJKtU/VOaPR5lNIII/AAAAAAAAi10/JUHk24vh9uo/s1600/IMG_20150219_172906.jpg" height="320" width="240" /></a><br />
<br />
<a href="http://3.bp.blogspot.com/-H0pfnSzxaiY/VOaPRyKUGhI/AAAAAAAAi10/zHoMAju2reA/s1600/IMG_20150219_172858.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-H0pfnSzxaiY/VOaPRyKUGhI/AAAAAAAAi10/zHoMAju2reA/s1600/IMG_20150219_172858.jpg" height="320" width="240" /></a><br />
<br />
No wonder the back cover looked warped. After placing the new battery and closing the back, NFC started picking up very reliably and it charges properly on a wireless charger.<br />
<br />
Happy ;-)<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com2tag:blogger.com,1999:blog-632023420616344756.post-39410211026675957322015-02-08T18:25:00.000-08:002015-02-08T18:25:39.101-08:00Fun with "git diff -B -M"Git lets you view a change that renames an original file A to a new location B while doing some minor edits to its contents as a "rename" patch (i.e. "rename A to B, with the following content differences"). You can even view a change that renames two original files, A and B, by swapping their contents and optionally doing some minor edits to them as a patchset that contains two "rename" patches ("rename A to B" and "rename B to A"). These were invented by me early in Git's life, when Linus was still running the project, back in mid 2005. More recently, other tools (including GNU patch) started understanding patches that use these features.<br />
<br />
I however recently noticed a few corner cases that <span style="font-family: Courier New, Courier, monospace;">git diff</span> and friends produce a wrong patchset, or git apply fails to apply correctly constructed patches, and I have been thinking about the right fixes to these issues. This article will illustrate these tricky cases and describe my current thinking.<br />
<br />
In this write-up, I'll use these terms:<br />
<br />
patchset::<br />
Output from a single <span style="font-family: Courier New, Courier, monospace;">git diff</span> invocation, which may contain one or more <i>patch</i>.<br />
<br />
patch::<br />
A part of a <i>patchset</i> from a header line that begins with "<span style="font-family: Courier New, Courier, monospace;">diff --git</span>" up to (but excluding) the next such header line.<br />
<br />
tree::<br />
<span style="font-family: Courier New, Courier, monospace;">git diff</span> compares two collections of files; each collection is a <i>tree</i>. Left and right sides of the comparison are called <i>old tree</i> and <i>new tree</i>, respectively. The <i>tree</i> to which we attempt to apply a patchset is the <i>target tree</i>. The <i>tree</i> we would get after a successful application of a patchset is the <i>resulting tree</i>. A <i>tree</i> does not have to be a tree object—we may be comparing the index and the files in the working tree, for example.<br />
<br />
preimage::<br />
postimage::<br />
The <i>preimage</i> consists of lines in a patch that are prefixed by "<span style="font-family: Courier New, Courier, monospace;">-</span>" (minus) or "<span style="font-family: Courier New, Courier, monospace;"> </span>" (space) but not "<span style="font-family: Courier New, Courier, monospace;">+</span>" (plus) that denote what the patched file ought to have for the patch to apply. The <i>postimage</i> consists of lines that are prefixed by "<span style="font-family: Courier New, Courier, monospace;">+</span>" (plus) or "<span style="font-family: Courier New, Courier, monospace;"> </span>" (space) that denote what the patched result ought to look like.<br />
<br />
<br />
<span style="font-size: large;">1. Basics</span><br />
<br />
First the basics. Let's think about a patchset with a single patch. What does this patchset tell us?<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-08.txt b/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 680c5f6..5de90cb 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ b/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Fortitude.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<br />
It obviously tells us that the new tree changed "Fortitude", that used to be in the old tree, to "Strength", but it actually tells us a bit more about the old tree. For this patchset to apply, the target tree must have a file "major-08.txt" that begins with lines we see as the preimage in the patch.<br />
<br />
<br />
<span style="font-size: large;">2. Renaming a file</span><br />
<br />
Now let's get a bit fancier and study a patchset with a rename patch. What does this patchset tell us?<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git rws/major-08.txt marseille/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 97%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename from major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename to major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 680c5f6..2ab22a0 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- rws/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ marseille/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Fortitude.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +11. Fortitude.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<br />
We can see that this is going from the same old tree as the previous one's old tree, renames major-08 to major-11 with slight modification.<br />
<br />
It tells us more about the trees, compared to the previous example. For this patchset to apply, the target tree must satisfy the same pre-conditon as the previous one about major-08, and in addition it must lack major-11; otherwise we wouldn't be renaming a new file to it.<br />
<br />
So far, things are straight-forward.<br />
<br />
In summary:<br />
<br />
Rule 1.<br />
A patch from file A to file A requires that file A exists in the target tree with contents that match the preimage of the patch.<br />
<br />
Rule 2.<br />
A patch renaming file A to file B requires that file A exists the target tree with contents that match the preimage of the patch. It also requires that file B must not exist in the target tree.<br />
<br />
Rule 3.<br />
A patch that creates file A requires that file A does not exist in the target tree.<br />
<br />
Rule 4.<br />
A patch that deletes file A requires that file A exists in the target tree with contents that match the preimage of the patch.<br />
<br />
The latter two I didn't illustrate with examples, but they should be obvious. Also, we can think of Rule 2 (rename) as a natural extension of Rule 3 (creation) and part of Rule 4 (deletion). When you rename file A to file B, optionally with some content changes, you are:<br />
<br />
<ul>
<li>creating file B, so the target tree must not have file B already.</li>
<li>deleting file A, so the target tree must have file A with the content that matches (part of) it.</li>
</ul>
<div>
Similarly, a patch that creates file B by copying file A, optionally with some content changes, you are creating file B, so the target tree must not have file B already. Also, the target tree must have file A with the contents that match the preimage of the patch.</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<span style="font-size: large;">3. First twist: cross renaming</span><br />
<br />
Now, here is the first twist. What does this patchset mean?<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git rws/major-11.txt marseille/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 99%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename from major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename to major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 517d9f8..44e8d3a 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- rws/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ marseille/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -11. Justice.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +8. La Justice</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> That the Tarot, though it is of all reasonable antiquity, is not of</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git rws/major-08.txt marseille/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 97%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename from major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename to major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 5de90cb..a101d5f 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- rws/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ marseille/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +11. La Force</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<br />
This is a "swap" patchset, that swaps major-08 and major-11 with small edit. You would have done something like this to prepare such a change, starting from an old tree with two files with substantially different contents, both of which are of meaningful sizes:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ mv major-11.txt tmp</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ mv major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ mv tmp major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ edit major-08.txt major-11.txt ;# just a bit</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ git commit -m swap major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ git diff -B -M HEAD^</span><br />
<br />
A patch renaming major-11 to major-08 (i.e. the first one in this two-patch patchset) still requires that major-11 must exist in the target tree for the patchset to apply, which is the first half of Rule 2.<br />
<br />
But the other half of Rule 2 is not satisfied. The target of the rename, major-08, has to exist in the target tree; otherwise we cannot rename it to major-11 in the second patch in the patchset. The rule needs a bit of revising, perhaps like this:<br />
<br />
Rule 2.<br />
A patch renaming file A to file B requires that file A exists with contents that match its preimage. And file B must not exist in the target tree, unless another patch in the patchset renames file B to some other file (possibly but not necessarily file A).<br />
<br />
Of course, for such an "other patch" to be able to rename file B to somewhere else, the target tree is required to have file B.<br />
<br />
It is important to have that "unless" part in the revised Rule 2. We need to make sure that we do not allow the sample patchset in "2. Renaming a file" to overwrite an existing file major-11 in the target tree blindly.<br />
<br />
<span style="font-size: large;">4. Second twist: rewriting and copying</span><br />
<br />
The previous one showed how <span style="font-family: Courier New, Courier, monospace;">git diff -B -M</span> can be used to detect cross renaming files and apply the resulting patchset (you can circularly rename more than two, i.e. A -> tmp, B -> A, ..., Z -> Y, tmp -> Z). It can also detect when you did this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> $ cp major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $ edit major-08.txt ;# extensively</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $ git add major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $ git commit -m 'create 11 out of 08, rewrite 08'</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $ git diff -B -M HEAD^</span><br />
<br />
And you would see:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-08.txt b/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> dissimilarity index 99%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 5de90cb..44e8d3a 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ b/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,10 +1,31 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -This is one of the cardinal virtues, of which I shall speak later.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -...</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -the principle of all force.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +8. La Justice</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +That the Tarot, though it is of all reasonable antiquity, is not of</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +...</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +via prudentiæ.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-08.txt b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 97%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> copy from major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> copy to major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 5de90cb..a101d5f 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +11. La Force</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<br />
The first patch in the patchset is "a patch from file A to file A", even though it is an extensive rewrite. The target tree is required to have major-08 whose contents match the preimage of the patch (Rule 1). The second patch copies from major-08 to create a new file major-11. The target tree is required to lack major-11 (Rule 3; copying into A is creation of A). It also must have major-08 that begins with the preimage of the patch.<br />
<br />
Another thing to note is that an application of a patchset in Git is <i>not</i> incremental. Even though the first patch in the patchset talks about extensively rewriting major-08, and the second patch talks about creating major-11 by copying major-08 and then making a minor edit to it, the latter patch is the difference between the major-08 in the old tree and the major-11 in the new tree. It is <i>not</i> the difference between these two files in the new tree, i.e. it is not "modify major-08 and then copy the result to major-11 and then edit". If you think about it, this is also consistent with the previous "cross renaming" section. The first patch in the patchset renames major-11 to major-08, and the second patch that renames major-08 to major-11 is <i>not</i> about remaing the file that originally was major-11 that the first patch renamed back to its original position. The two patches are not applied incrementally (or sequentially).<br />
<br />
So far, all the examples shown above will work correctly with today's Git (some reimplementations of Git may lack support, but at least the one I maintain does work correctly). When you use the old tree as the target tree, <span style="font-family: Courier New, Courier, monospace;">git apply</span> accepts the patchset and recreates the new tree correctly.<br />
<br />
But if you use the new tree of this example as the target tree and try to use <span style="font-family: Courier New, Courier, monospace;">git apply -R</span> to apply the patchset in reverse, it does <i>not</i> work correctly. It is a bug.<br />
<br />
Currently <span style="font-family: Courier New, Courier, monospace;">git apply -R</span> does a nonsense for a copying patch. To reverse any patch, it just swaps the preimage and the postimage, and then swaps the names of the files in the old tree and in the new tree.<br />
<br />
But the reverse of "create major-11 by copying major-08 into it and then change Strength to La Force" (which is the second patch in the patchset in this section) is <i>not</i> "create major-08 by copying major-11 into it and then change La Force to Strength", which you would get by simply swapping the preimage and the postimage and swapping the names of the files in the second patch.<br />
<br />
What should we do to "reverse" a patchset that has copies?<br />
<br />
Reverse of "create major-11 by copying major-08" should at least be "remove major-11", and preferably accompanied by "while making sure that major-11 matches the postimage of the patch".<br />
<br />
The "preferably" part is a moderately strong preference. When the copying was done without any modification, we would not have any preimage or postimage to enable us to check that the target tree of the reverse application is similar enough to the new tree the patchset was taken from. Instead, we would end up just checking "major-11 exists" and then removing it happily, even if the contents of the file major-11 is vastly different from that of the new tree the patchset was taken from, which feels somewhat unsafe.<br />
<br />
Admittedly, the same "it feels unsafe" factor exists when applying a bog-standard pure rename patch (imagine that the example in "2. Renaming a file" was done without editing the first line and kept the original "8. Fortutide." without renumbering it. We would not have any preimage we can use to make sure we are patching the correct file).<br />
<br />
But as long as we have patch text that we can use for sanity checking, we should use it, I would think.<br />
<br />
<br />
<span style="font-size: large;">5. Third twist: rewriting by copying</span><br />
<br />
If you started from two vastly different files, both of which have contents of meaningful size, and did this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ cp major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ edit major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ rm major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ git commit -m 'rewrite 11 by copying 08' major-08.txt major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> $ git diff -B -M HEAD^</span><br />
<br />
You would see this patchset:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-08.txt b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 97%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename from major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename to major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 5de90cb..a101d5f 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +11. La Force</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<br />
This is another bug. I sent out a warning to both the Git and the Linux kernel mailing list, not to use the "<span style="font-family: Courier New, Courier, monospace;">-B -M</span>" options together for this reason.<br />
<br />
The revised Rule 2. from "3. First twist" tells us that major-08 must exist in the target tree, which is OK, but also major-11, the target of the rename, must not exist. This makes the resulting patchset unapplicable to the old tree the patchset was taken from, which simply does not make sense.<br />
<br />
If you take a diff between states X and Y, you should be able to apply that diff to the state X and the resulting state should be identical to the state Y, and you should be able to apply that diff in reverse to state Y to go back to the state X.<br /><br />Worse, the reverse of this patchset would apply to the new tree without an error, but does not reproduce the old tree correctly, which is a more serious bug. It instead applies the patch in reverse and recreates the original major-08, but the other file, major-11, is lost.<br />
<br />
The patchset does not have enough information for us to recreate its original contents of major-11 we had in the old tree. The patchset says that the contents of major-11 in the new tree came from the contents of major-08 in the old tree, and the major-11 in the new tree does not have any resemblance to major-11 in the old tree. That is not incorrect per-se, but that means that we cannot apply this patchset in reverse.<br />
<br />
One possible way to fix this is to include another patch in the same patchset that shows the deletion of major-11. Rule 2. would be further revised to something like:<br />
<br />
Rule 2 (revised again).<br />
A patch renaming file A to file B requires that file A exists in the target tree with contents that match the preimage. It also requires that file B does not exist in the target tree, unless another patch in the patchset renames file B to some other file (possibly but not necessarily file A) or removes file B.<br />
<br />
Again, that "other patch" in the patchset either renames or removes file B, so that requires that the target tree to have file B with contents that match the preimage of that patch.<br />
<br />
More generally, the revised Rule 2. can be split into two parts; the former becomes an extension to Rule 4, and the latter becomes an extension to Rule 3.<br />
<br />
<br />
<br />
<br />
<ul style="-webkit-text-stroke-width: 0px; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
<li>A patch that causes a file A to disappear (i.e. removing file A, or renaming file A to file B) requires that the target tree to have file A, with contents that match the preimage of the patch.</li>
<li>A patch that causes a file B to appear (i.e. creating file B, or renaming/copying file A to file B) requires the target tree to lack file B, unless another patch in the patchset makes file B disappear (i.e. removing file B or renaming file B to something else).</li>
</ul>
In any case, a fixed patchset would look like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-08.txt b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> similarity index 97%</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename from major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> rename to major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 5de90cb..a101d5f 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-08.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,3 +1,3 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -8. Strength.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +11. La Force</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> This is one of the cardinal virtues, of which I shall speak later.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> diff --git a/major-11.txt b/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> deleted file mode 100644</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> index 517d9f8..0000000</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> --- a/major-11.txt</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> +++ /dev/null</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> @@ -1,31 +0,0 @@</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -11. Justice.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -That the Tarot, though it is of all reasonable antiquity, is not of</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -...</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -via prudentiæ.</span><br />
<br />
And these patches, under the re-revised rules, would apply cleanly to the old tree.<br />
<br />
What about the reverse application? It would be a patchset that creates major-11 from nothingness (which is the reversal of a "deletion" patch), and creates major-08 by renaming major-11 and editing. Is the Rule 2. re-revised above sufficient?<br />
<br />
The new tree (which is the target of the reverse application) only has major-11 and not major-08, so this rename should go through. The reverse of the deletion of major-11 is a creation of it with the contents fully given as the preimage of the (original) patch before reversing it, so that should also be OK with Rule 3 that is revised in a similar way with that "unless" thing. That is, creating major-11 requires that the old tree does not have major-11, but if another patch in the same patchset renames major-11 away or deletes it, then it is OK for a patch to create major-11. And the reversal of the first patch does rename major-11 to major-08, so all is well.<br />
<br />
One disturbing thing about the above plan is that we have this comment at the end of diffcore-rename.c:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * We would output this delete record if:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> *</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * (1) this is a broken delete and the counterpart</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * broken create remains in the output; or</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * (2) this is not a broken delete, and rename_dst</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * does not have a rename/copy to move p->one->path</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * out of existence.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> *</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * Otherwise, the counterpart broken create</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * has been turned into a rename-edit; or</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * delete did not have a matching create to</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * begin with.</span><br />
<br />
That is, we have an explicit logic to omit the missing "delete major-11" patch from the patchset. This comes from the very first commit that introduced "<span style="font-family: Courier New, Courier, monospace;">diff -B</span>" (f345b0a0 (Add -B flag to diff-* brothers., 2005-05-30); it is plausible that the above comment came from lack of thinking in the original and not something we did to fix some bugs (if it were the latter, by showing the deletion in the case under discussion to "fix" the patchset in this example would end up breaking the original "fix").<br />
<br />
So I would think that the right way to fix this is to stop filtering out the deletion half of the broken pair, even when the other creation-half of the pair no longer is in the output.<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-77501636648965316362015-02-05T14:54:00.001-08:002015-02-05T14:54:58.556-08:00Git 2.3The latest feature release of Git version control system, version 2.3, is now available at <a href="http://git-blame.blogspot.com/p/git-public-repositories.html" target="_blank">the usual places</a>.<br />
<br />
This one ended up to be a release with lots of small corrections and improvements without big uncomfortably exciting features. It is a lot smaller release than other recent feature releases, consisting of 255 non-merge commits (version 2.0, 2.1 and 2.2 had 475, 698 and 556 commits, respectively) by 61 contributors (among which 19 are new people—welcome!).<br />
<br />
The recent <a href="http://git-blame.blogspot.com/2014/12/git-1856-195-205-214-and-221-and.html" target="_blank">security fix</a> that went to 2.2.1 and older maintenance tracks is also contained in this update.<br />
<div>
<br /></div>
<div>
One of my favorite small changes in this release is that the "Conflicts:" section that is prepared in the buffer to write your commit log message during a merge is now commented out, just like all the other hints to help you prepare the log message (e.g. the list of files with changes you might want to mention in the log, and the list of untracked files you might have forgot to "git add"). For the full text of the release notes, please visit <a href="http://permalink.gmane.org/gmane.comp.version-control.git/263411" target="_blank">the list archive</a>.</div>
<div>
<br /></div>
<div>
Enjoy.</div>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-39487518720583035372014-12-22T11:51:00.003-08:002014-12-22T14:01:56.645-08:00On CVE-2014-9390 and Git 2.2.1Now the security-fix releases are behind us, let's briefly talk about the ramifications.<br />
<br />
The recent Git/Hg vulnerability on case-insensitive or normalizing filesystems are serious for people who fetch and integrate (either pull or pull --rebase) from untrusted sources.<br />
<br />
When you grab a tree that records a malicious path, say, ".Git/hooks/post-checkout" using an older version of Git on such a filesystem (e.g. Windows NTFS or Mac OS X HFS+), Git will tell the filesystem to check it out at ".Git/hooks/post-checkout", but the filesystem overwrites a file different from what Git asked it to write, namely ".git/hooks/post-checkout", which is a path reserved for you to store an executable hook that is run after running "git checkout".<br />
<br />
For an attacker to victimize you through this vector, the attacker has to have a write access to a repository you pull from. As long as you do not interact with untrustworthy strangers (e.g. only pull from the projects' official history), you will not be affected. That is often true in corporate setting, where the access to the central repository everybody in the product group uses is tightly controlled, and if an untrustworthy stranger has a write access there, you already have a bigger problem.<br />
<br />
But the open-source is all about collaboration, and we need to meet and interact with new people every day while doing so. The prudent thing to do is to (1) update to the version of Git recently released to work around this issue, and then (2) respond to a pull request from a stranger, in this order. Don't do it the other way around!<br />
<br />
Thanks.<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-46973818520083722602014-12-18T13:20:00.000-08:002014-12-22T12:23:48.640-08:00Git 1.8.5.6, 1.9.5, 2.0.5, 2.1.4 and 2.2.1 and thanking friends in Mercurial landWe have a set of urgent maintenance releases. Please update your Git if you are on Windows or Mac OS X.<br />
<br />
Git maintains various meta-information for its repository in files in <span style="font-family: Courier New, Courier, monospace;">.git/</span> directory located at the root of the working tree. The system does not allow a file in that directory (e.g. <span style="font-family: Courier New, Courier, monospace;">.git/config</span>) to be committed in the history of the project, or checked out to the working tree from the project. Otherwise, an unsuspecting user can run <span style="font-family: Courier New, Courier, monospace;">git pull</span> from an innocuous-looking-but-malicious repository and have the meta-information in her repository overwritten, or executable hooks installed by the owner of that repository she pulled from (i.e. an attacker).<br />
<br />
Unfortunately, this protection has been found to be inadequate on certain file systems:<br />
<ul>
<li>You can commit and checkout to <span style="font-family: Courier New, Courier, monospace;">.Git/<i><anything></i></span> (or any permutations of cases <span style="font-family: Courier New, Courier, monospace;">.[gG][iI][tT]</span>, except <span style="font-family: Courier New, Courier, monospace;">.git</span> all in lowercase). But this will overwrite the corresponding <span style="font-family: Courier New, Courier, monospace;">.git/<i><anything></i></span> on case-insensitive file systems (e.g. Windows and Mac OS X).</li>
<li>In addition, because HFS+ file system (Mac OS X) considers certain Unicode codepoints as ignorable; committing e.g. .<span style="font-family: Courier New, Courier, monospace;">g\u200cit/config</span>, where U+200C is such an ignorable codepoint, and checking it out on HFS+ would overwrite <span style="font-family: Courier New, Courier, monospace;">.git/config</span> because of this.</li>
</ul>
The issue is shared with other version control systems and has serious impact on affected systems (CVE-2014-9390).<br />
<br />
Credit for discovering this issue goes to our friends in the <a href="http://mercurial.selenic.com/wiki/WhatsNew#Mercurial_3.2.3_.282014-12-18.29" target="_blank">Mercurial</a> land (most notably, the inventor of Hg, Matt Mackall himself). The fixes to this issue for various implementations of Git (including mine, libgit2, JGit), ports using these implementations (including Git for Windows, <a href="http://blogs.msdn.com/b/bharry/archive/2014/12/18/git-vulnerability-with-git-config.aspx" target="_blank">Visual Studio</a>) and also Mercurial have been coordinated for simultaneous releases. GitHub is running an updated version of their software that rejects trees with these confusing and problematic paths, in order to protect its users who use existing versions of Git (also see <a href="https://github.com/blog/1938-vulnerability-announced-update-your-git-clients" target="_blank">their blog post</a>).<br />
<br />
A huge thanks to all those who were involved.<br />
<br />
New releases of Git for Windows, Git OSx Installer, JGit and libgit2 have been prepared to fix this issue. Microsoft (which uses libgit2 in their Visual Studio products) and Apple (which distributes a port of Git in their Xcode) both have fixes, as well.<br />
<div>
<br /></div>
For people building from the source, fixed versions of Git have been released as versions v1.8.5.6, v1.9.5, v2.0.5, v2.1.4, and v2.2.1 for various maintenance tracks.<br />
<br />
Thanks._http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-12889775208397514872014-09-30T16:26:00.000-07:002015-09-21T14:08:15.454-07:00Fun (?) with GnuPGWe use GnuPG as part of the infrastructure to certify authenticity of development history in Git in various places:<br />
<ul>
<li>Signed tags created by <span style="font-family: Courier New, Courier, monospace;">git tag -s</span> is to say "This tag was created by me, the holder of the private GnuPG key that signed this object". Because the object name of any Git object is computed as a cryptographic hash over what the object records, and because a signed tag object records the object name of a tagged object (typically a commit) and the human readable name (typically a release number or name) the tagger wants to give the tagged object, an attacker cannot forge a phony tag that points at a different commit signed with the private key the attacker does not have. You are saying "You can verify that it is true that I wanted to make that commit release X" safely because of this. Also, because the commit object records all the objects and their location in a project tree, and the parent commit objects, such a signed tag also ensures that all the development history behind such a tagged commit cannot be tampered with.</li>
<li>When you merge a signed tag (either done by <span style="font-family: Courier New, Courier, monospace;">git merge</span> or <span style="font-family: Courier New, Courier, monospace;">git pull</span>), the content of the tag with its GnuPG signature is copied to the resulting commit object. This lets you ensure that the history behind the side branch that was merged to the history cannot be tampered with and the signature certifies that it came from the signer (typically a subsystem lieutenant).</li>
<li>Signed commits created by <span style="font-family: Courier New, Courier, monospace;">git commit -S</span> is a way to say "This commit was created by me", and ensures that the history behind the commit cannot be tampered with and certifies that the change it introduces came from the signer.</li>
<li>Still under development is <span style="font-family: 'Courier New', Courier, monospace;">git push --signed</span>, a way to certify that you wanted to put a particular commit at the tip of a particular branch.</li>
</ul>
<div>
GnuPG is also used as a mechanism to ensure the integrity and authenticity of tarballs that are sent to the <span style="font-family: Courier New, Courier, monospace;">kernel.org</span> servers, which is a common distribution point for open source projects like the Linux kernel and Git itself. A maintainer prepares a tarball and a detached signature, uploads them, and the receiving end will verify that the signature is good.</div>
<div>
<br /></div>
<div>
It is a common practice to specify the expiration date when creating a signing key. For example, the <a href="http://pgp.mit.edu/pks/lookup?op=vindex&search=0x20D04E5A713660A7">key</a> I have been using to sign Git release tags was originally set up to expire in 3 years since the key was created. But the thing is, a project may outlive that expiry date. An interesting question is what happens to the existing tags when the key expires.</div>
<div>
<br /></div>
<div>
Unluckily, the right thing happens. If the holder of the key does not do anything, the key becomes expired, and the signatures in the signed tags stops validating. Luckily, the validity of a key can be extended by the holder of the key, and once it is done, the signatures made before the key's original expiration date will continue to validate fine.</div>
<div>
<br /></div>
<div>
At least, that is the theory ;-)<br />
<br />
As my key was originally set to expire early next month, I've extended the lifespan of the key 96AFE6CB I have been using a few days ago and uploaded the updated key to pgp keyservers, so existing signed tags (e.g. v2.0.0) should continue to be valid.</div>
<div>
<br /></div>
<div>
A few tips:</div>
<div>
<ul>
<li>Although <a href="https://wiki.debian.org/Subkeys">this page</a> is a specific instruction to Debian contributors, it was very helpful when I had to figure out how to futz with GnuPG subkeys. It does not talk about how to update the expiration date for a subkey, though (you use "gpg --edit-key" and then choose the subkey with the "key N" command and finally use the "expire" command).</li>
<li>In order to force a specific subkey to be used when signing for Git, you would need to use the ! suffix to the GnuPG key-id, e.g. in my ~/.gitconfig file:<br /> [user] signingkey = 96AFE6CB!<br />Without the ! suffix, GnuPG tries to use the newest subkey you have associated with the same primary key, which may not be the subkey you would want to use.</li>
</ul>
<div>
I signed a new v2.1.2 maintenance release with the same key today. Hopefully it will validate OK for you (otherwise, you may have to fetch the public key from the <a href="http://pgp.mit.edu/pks/lookup?op=get&search=0x20D04E5A713660A7">keyserver</a>).</div>
</div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com0tag:blogger.com,1999:blog-632023420616344756.post-28053952926302787732014-05-28T15:28:00.000-07:002014-05-28T15:28:01.865-07:00Git 2.0The real "Git 2.0" is finally out.<br />
<br />
From the point of view of end users who are totally new to Git, this release will give them the defaults that are vastly improved compared to the older versions, but at the same time, for existing users, this release is designed to be as low-impact as possible, as long as they have been following recent releases along (instead of sticking to age-old releases like 1.7.x series). Some may even say, without remembering why it was a big deal to bring these new default behaviours to help new users, that the new release does not offer anything exciting—and that is exactly what we want to hear from existing users. In recent releases for the past year or so, we have added knobs to allow users to enable these new defaults before 2.0 happens, and added warnings to let users know when they perform an operation whose outcome will be different between 1.x series and 2.0 release. The existing users are hopefully very well prepared by now, and "Git 2.0" is designed to be the final "flipping the default" step.<br />
<br />
We had to delay the final release by a week or so because we found a few problems in earlier release candidates (request-pull had a regression that stopped it from showing the "tags/" prefix in "Please pull tags/frotz" when the user asked to compose a request for 'frotz' to be pulled; a code path in git-gui to support ancient versions of Git incorrectly triggered for Git 2.0), which we had to fix in an extra unplanned release candidate.<br />
<br />
Hopefully the next cycle will become shorter, as topics that have been cooking on the 'next' branch had extra time to mature, so it all evens out in the end ;-).<br />
<br />
Have fun.<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-65771416648774858552014-04-25T15:50:00.001-07:002014-04-25T20:35:01.121-07:00Git 2.0 release candidate 1This is the first release candidate for the upcoming Git 2.0. There are usual sort of updates and fixes one would expect to see between any two feature releases, but the primary reason why its name begins with "2" (as opposed to the last feature release whose name was "Git 1.9") is because it has a few backward incompatible changes that are all meant to improve the end-user experiences.<br />
<br />
<ul>
<li>People almost always push to a single place, and many people would push a single branch they are currently on. The default behaviour of "git push" (that does not say which branches to push out to where on the command line) has been updated to better support this mode of working (as opposed to working on making all branches they are going to publish ready and then push all of them in one go). The old default of pushing out all the matching branches is available by setting the <span style="font-family: Courier New, Courier, monospace;">push.default</span><span style="font-family: inherit;"> configuration variable to </span><span style="font-family: Courier New, Courier, monospace;">matching</span><span style="font-family: inherit;">.</span></li>
<li><span style="font-family: inherit;">Even though "git commit -a" can be run from any subdirectory to commit changes to all the tracked paths in the working tree, "git add -u" and "git add -A" (without specifying any path on the command line) used to operate only inside the current directory. This inconsistency bothered many people, and these commands have been updated to operate on all modified (for "-u") or all (for "-A") paths. Use "git add -u ." and "git add -A ." to restrict the command to the current directory.</span></li>
<li><span style="font-family: inherit;">"git add <i>path</i>" is now the same as "git add -A <i>path</i>" now, so that </span>"git add <i>directory/</i>" will notice paths you removed from the directory and record the removal. In older versions of Git, it used to ignore removals. You can say "git add --ignore-removal <i>path</i>" to add only added or modified paths, if you really want to.</li>
</ul>
<br />
Some of the readers may remember that we didn't give users a very good transition experience when we introduced a backward incompatible change in Git 1.6.0. We used to install all the "git-cmd"s in the same directory as "git" itself and people were used to that "git commit" and "git-commit" can be used interchangeably before that release. Then we stopped installing what does not have to be on user's $PATH at that release, which is a change that breaks people's finger-memory and existing scripts. All we did to prepare users for that change was to warn about it in release notes since Git 1.5.4 and it was apparently not enough. Many people were unhappy.<br />
<br />
In retrospect, perhaps we could have done better by adding code to somehow detect when "git-cmd" is invoked as the top-level command and warn that such usage would break in future versions to train users to use "git cmd" form way before releasing the version that actually delivered the change.<br />
<br />
This time around, we have been trying to be a lot more careful. For the past handful of releases, we have added extra code to detect cases where exiting versions of Git and the upcoming Git 2.0 will behave differently and to warn about the upcoming change. As the result, the actual difference between Git 1.9 and Git 2.0 is mostly "flipping the default" for these changes.<br />
<br />
Have fun.<br />
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-43753712489749958772014-03-18T15:14:00.000-07:002014-03-18T15:22:03.154-07:00Git 1.9.1Traditionally, releases numbered with three Dewey-decimal digits were major releases that add new features, while ones with four were maintenance releases with only fixes. This was meant to give us some flexibility to say that the difference between 1.7.12 and 1.8.0 are larger than the difference between 1.8.1 and 1.8.2 (1.7.12 was the last major release in the 1.7.x series), while reserving the difference in the first digit for really big changes (i.e. 2.0 may finally toggle a switch that makes Git incompatible with older 1.x releases out of the box).<br />
<br />
But we found out that in practice, we do not need to have three levels of changes (an incremental that changes the third digit between 1.8.1 to 1.8.2, a larger update that changes the second digit between 1.7.12 to 1.8.0, and a huge update that changes the first digit between 1.9 and 2.0). Hence the last major release was officially called "Git 1.9" when it was released on February 14, 2014.<br />
<br />
It logically follows that, because we are dropping the third digit (or the second, depending on how you look at it) from the numbering of major releases, the first maintenance release for Git 1.9 is named with three digits, not four.<br />
<br />
Git 1.9.1 is such a release. Among many changes we have been cooking on the development front towards the next major release, which will be called Git 2.0, this maintenance release contains only the fixes, and everybody is encouraged to upgrade to it.<br />
<br />
Fixes since Git 1.9 are as follows:<br />
<ul>
<li>"git clean -d pathspec" did not use the given pathspec correctly and ended up cleaning too much.</li>
<li>"git difftool" misbehaved when the repository is bound to the working tree with the ".git file" mechanism, where a textual file ".git" tells us where it is.</li>
<li>"git push" did not pay attention to branch.*.pushremote if it is defined earlier than remote.pushdefault; the order of these two variables in the configuration file should not matter, but it did by mistake.</li>
<li>Codepaths that parse timestamps in commit objects have been tightened.</li>
<li>"git diff --external-diff" incorrectly fed the submodule directory in the working tree to the external diff driver when it knew it is the same as one of the versions being compared.</li>
<li>"git reset" needs to refresh the index when working in a working tree (it can also be used to match the index to the HEAD in an otherwise bare repository), but it failed to set up the working tree properly, causing GIT_WORK_TREE to be ignored.</li>
<li>"git check-attr" when working on a repository with a working tree did not work well when the working tree was specified via the --work-tree (and obviously with --git-dir) option.</li>
<li>"merge-recursive" was broken in 1.7.7 era and stopped working in an empty (temporary) working tree, when there are renames involved. This has been corrected.</li>
<li>"git rev-parse" was loose in rejecting command line arguments that do not make sense, e.g. "--default" without the required value for that option.</li>
<li>include.path variable (or any variable that expects a path that can use ~username expansion) in the configuration file is not a boolean, but the code failed to check it.</li>
<li>"git diff --quiet -- pathspec1 pathspec2" sometimes did not return correct status value.</li>
<li>Attempting to deepen a shallow repository by fetching over smart HTTP transport failed in the protocol exchange, when no-done extension was used. The fetching side waited for the list of shallow boundary commits after the sending end stopped talking to it.</li>
<li>Allow "git cmd path/", when the 'path' is where a submodule is bound to the top-level working tree, to match 'path', despite the extra and unnecessary trailing slash (such a slash is often given by command line completion).</li>
</ul>
<div>
Have fun.</div>
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-73938717440145794022013-11-27T20:00:00.000-08:002013-11-27T20:00:03.753-08:00Git 1.8.5The latest release Git 1.8.5 is out. Among many incremental improvements, there are a handful of changes that are worth mentioning:<br />
<br />
<ul>
<li>Magic pathspecs like "<span style="font-family: Courier New, Courier, monospace;">:(icase)makefile</span>" (matches both <span style="font-family: Courier New, Courier, monospace;">Makefile</span> and <span style="font-family: Courier New, Courier, monospace;">makefile</span>) and "<span style="font-family: Courier New, Courier, monospace;">:(glob)foo/**/bar</span>" (matches "<span style="font-family: Courier New, Courier, monospace;">bar</span>" in "<span style="font-family: Courier New, Courier, monospace;">foo</span>" and any subdirectory of "<span style="font-family: Courier New, Courier, monospace;">foo</span>") can be used in more places.</li>
<li>The "<span style="font-family: Courier New, Courier, monospace;">http.*</span>" configuration variables can now be specified for individual URLs. E.g<br /><span style="font-family: 'Courier New', Courier, monospace;"><br />[http]</span><span style="font-family: 'Courier New', Courier, monospace;"> sslVerify = true<br /></span><span style="font-family: 'Courier New', Courier, monospace;">[http "https://weak.example.com/"]</span><span style="font-family: Courier New, Courier, monospace;"> sslVerify = false<br /></span><br /><span style="font-family: 'Times New Roman';">would turn on </span><span style="font-family: Courier New, Courier, monospace;">http.sslVerify</span><span style="font-family: 'Times New Roman';"> for everybody, except when talking with the specified URL.</span></li>
<li><span style="font-family: inherit;">"</span><span style="font-family: Courier New, Courier, monospace;">git mv A B</span><span style="font-family: inherit;">" when moving a submodule has been taught to </span><span style="font-family: inherit;">relocate the submodule's working tree and to adjust the paths in the </span><span style="font-family: Courier New, Courier, monospace;">.gitmodules</span><span style="font-family: inherit;"> file.</span></li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git blame</span>" can now take more than one <span style="font-family: Courier New, Courier, monospace;">-L</span> option to discover the origin of multiple blocks of lines.</li>
<li>The http transport clients can optionally ask to save cookies with the <span style="font-family: Courier New, Courier, monospace;">http.savecookies</span> configuration variable.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git push</span>" learned a more fine grained control over a blunt "<span style="font-family: Courier New, Courier, monospace;">--force</span>" when requesting a non-fast-forward update with the "<span style="font-family: Courier New, Courier, monospace;">--force-with-lease=</span><refname><span style="font-family: Courier New, Courier, monospace;">:</span><expected object name>" option.</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git diff --diff-filter=</span><classes of changes>" can now take lowercase letters (e.g. "<span style="font-family: Courier New, Courier, monospace;">--diff-filter=d</span>") to mean "show everything but these classes". "<span style="font-family: Courier New, Courier, monospace;">git diff-files -q</span>" is now a deprecated synonym for "<span style="font-family: Courier New, Courier, monospace;">git diff-files --diff-filter=d</span>".</li>
<li>"<span style="font-family: Courier New, Courier, monospace;">git gc</span>" exits early without doing any work when it detects that another instance of itself is already running.</li>
</ul>
<br />_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-51461269644692318172013-11-26T20:00:00.000-08:002013-11-26T20:00:04.089-08:00The Codebreakers<br />
<div style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
<a href="http://www.amazon.com/gp/product/0684831309/"><img alt="The Codebreakers" border="0" height="200" src="http://ecx.images-amazon.com/images/I/51oEJqoe5RL._SL500_PIsitb-sticker-arrow-big,TopRight,35,-73_OU01_SL135_.jpg" width="136" /></a><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;">Every once in a while, I receive gifts from satisfied Git friends, chosen from my Amazon </span><a href="http://www.amazon.com/gp/registry/wishlist/1513KNZE30W63" rel="nofollow" style="background-color: white; color: #888888; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px; text-decoration: none;">Wish list.</a> <span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;">And today was such a day. As I have been fairly busy cleaning up the fallout from our recent move and finally things are beginning less hectic, it turns out to be a perfect distraction gift for me, too ;-)</span></div>
<br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;"><br /></span><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.46875px;">I only read the first few sections so far (</span><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;">it is a big, thick book and it would take me forever to finish reading and then write about it and thanking the person). </span><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;">Thanks, </span><span style="color: #333333; font-family: Georgia, serif;"><span style="background-color: #f3f3f3; font-size: 14px; line-height: 21px;">MTM!</span></span><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;"><br />
</span>_http://www.blogger.com/profile/04508668132209394366noreply@blogger.comtag:blogger.com,1999:blog-632023420616344756.post-65687972202203941372013-11-08T13:38:00.000-08:002013-11-08T13:38:28.384-08:00Git 1.8.4.3The latest maintenance release Git v1.8.4.3 has been tagged and is available at the usual places (see the <a href="http://git-blame.blogspot.com/p/git-public-repositories.html">list of public repositories</a>). The fixes that have already merged to the 'master' branch for the upcoming Git v1.8.5 feature release are all there.<br />
<br />
Here are the highlights, relative to the previous maintenance release v1.8.4.2:<br />
<br />
<ul>
<li>The interaction between use of Perl in our test suite and NO_PERL has been clarified a bit.<br /></li>
<li>A fast-import stream expresses a pathname with funny characters by quoting them in C style; remote-hg remote helper (in contrib/) forgot to unquote such a path.<br /></li>
<li>One long-standing flaw in the pack transfer protocol used by "git clone" was that there was no way to tell the other end which branch "HEAD" points at, and the receiving end needed to guess. A new capability has been defined in the pack protocol to convey this information so that cloning from a repository with more than one branches pointing at the same commit where the HEAD is at now reliably sets the initial branch in the resulting repository.<br /></li>
<li>We did not handle cases where http transport gets redirected during the authorization request (e.g. from http:// to https://).<br /></li>
<li>"git rev-list --objects ^v1.0^ v1.0" gave v1.0 tag itself in the output, but "git rev-list --objects v1.0^..v1.0" did not.<br /></li>
<li>The fall-back parsing of commit objects with broken author or committer lines were less robust than ideal in picking up the timestamps.<br /></li>
<li>Bash prompting code to deal with an SVN remote as an upstream were coded in a way not supported by older Bash versions (3.x).<br /></li>
<li>"git checkout topic", when there is not yet a local "topic" branch but there is a unique remote-tracking branch for a remote "topic" branch, pretended as if "git checkout -t -b topic remote/$r/topic" (for that unique remote $r) was run. This hack however was not implemented for "git checkout topic --".<br /></li>
<li>Coloring around octopus merges in "log --graph" output was screwy.<br /></li>
<li>We did not generate HTML version of documentation to "git subtree" in contrib/.<br /></li>
<li>The synopsis section of "git unpack-objects" documentation has been clarified a bit.<br /></li>
<li>An ancient How-To on serving Git repositories on an HTTP server lacked a warning that it has been mostly superseded with a more modern way.</li>
</ul>
<br />
<div>
<br /></div>
_http://www.blogger.com/profile/04508668132209394366noreply@blogger.com