<div dir="ltr">On Fri, Feb 8, 2013 at 7:48 PM, Satish Balay <span dir="ltr"><<a href="mailto:balay@mcs.anl.gov" target="_blank">balay@mcs.anl.gov</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div><br>
> > - *never* sync with petsc-dev until this work is done.<br>
> ><br>
> > - merge with petsc-dev when its done. [either merge - or rebase it over]<br>
> ><br>
> > The *never* sync with petsc-dev is a drawback for this.<br>
><br>
> You could just `hg pull --rebase`? Unless you mean don't push to<br>
> petsc-dev, then yes, don't push to petsc-dev until the feature is done.<br>
<br>
</div></div>'hg pull --rebase' would be great for a single developer of the<br>
feature.  But with 2 developers commiting/communicating commits - one<br>
would have to 'strip out the old changes' - as you put it - either<br>
manually or with mercurial tools - and then propogate this to remote<br>
repo aswell.  So its easy to make mistakes in the workflow?<br></blockquote><div><br></div><div>A feature like MINRESQLP should be able to go a very long time before conflicting. It's usually considered bad practice to constantly merge (because most merge commits don't convey useful content), but it's also useful to know when something will automerge successfully and sometimes we want to test with all known patches applied. In git, I use a personal testing branch for this (jed/test in the discussion below). I explain my git workflow below. It's mildly advanced, but hopefully explains how to achieve</div>
<div><br></div><div><b>1.</b> Many people can work independently with minimal interruptions.</div><div><b>2.</b> Every commit that eventually appears in a release (to be tagged from 'master') is semantically significant and preserves the integrity and testing performed the first time it is committed with intent to publish. (You can rework locally as much as you want, but the SHA1 is indelible once you decide that a commit is complete.) This implies zero content-free merges and zero rebases for topic branches.</div>
<div style><b>3.</b> Every commit can be reviewed before it graduates to 'master'.</div><div><b>4.</b> The process can be applied recursively and scales naturally to an arbitrary number of contributors working on an arbitrary number of projects.<br>
</div><div><br></div><div>$ cd the-repo && git checkout master # 'master' is the default branch<br></div><div style>(master) $ git pull --ff-only</div><div style><br></div><div style>Comments:<br>1. The --ff-only option tells 'pull' to abort if I have any changes in 'master' that are not already upstream (not fast-forward). I use it here only for explicitness.</div>
<div style>2. Since I put __git_ps1 in my bash prompt, I see the current branch (and sometimes other useful info).</div><div style><br></div><div style>I always keep my 'master' branch clean. I use it to test the upstream version of the code and to apply isolated bug fixes. Those look like the following (though I usually commit from emacs using magit)</div>
<div style><br></div><div style>(master) $ emacs broken-file.c makefile</div><div style>(master) $ make runex42_3 DIFF=diffupdate # my script to refresh output</div><div style>(master) $ git add output/ex42_3.out # new file</div>
<div style>(master) $ git commit -am'Fix bug X introduced in <SHA1>, add runex42_3'</div><div style>(master) $ git push</div><div style><br></div><div style>If there is a conflict here, I just</div><div style>
<br></div><div style>(master) $ git pull --rebase</div><div style>(master) $ git push</div><div style><br></div><div style>because this spot bug-fix doesn't have any useful history that I can maintain. Now let's consider a more interesting feature</div>
<div style><br></div><div style>(master) $ git checkout -b jed/feature1 # create a branch and check it out</div>
<div style>(jed/feature1) $ emacs file-to-modify.c && git commit -am'implement first part of feature1'</div><div style><br></div><div style>and another</div><div style><br></div><div style>(jed/feature1) $ git checkout -b jed/fetaure2 master # base this on 'master' because it is independent of feature1</div>
<div style>(jed/feature2) $ emacs file-to-modify.c # oops, same file, and some changes conflict</div><div style>(jed/feature2) $ git commit -am'first part of feature2, I might not know that it conflicts with feature1'</div>
<div style><br></div><div style>Now I want to see what's happening upstream:</div><div style><br></div><div style>$ git checkout master</div><div style>(master) $ git pull</div><div style><br></div><div style>and to find out how my patches will appear if merged into upstream:</div>
<div style><br></div><div style>(master) $ git checkout -b jed/test</div><div style>(jed/test) $ git merge jed/feature1 # applies cleanly, cool</div><div style>(jed/test) $ git merge jed/feature2 # conflicts</div><div style>
Auto-merging file-to-modify.c</div><div>CONFLICT (content): Merge conflict in file-to-modify.c</div><div><b>Recorded preimage for 'file-to-modify.c'</b></div><div style>Automatic merge failed; fix conflicts and then commit the result.</div>
<div><br></div><div style>(I'll explain the bold part later.) I will resolve this merge and commit the result:</div><div style><br></div><div style><div>(jed/test) $ git commit -a -m 'test resolution'</div><div>
<b>Recorded resolution for 'file-to-modify.c'.</b></div><div>[detached HEAD 2fe010b] test resolution</div></div><div style><br></div><div style>Then test in the 'jed/test' branch. Maybe I build other applications that will be users of feature1 and feature2. Now I go back to working on feature1:</div>
<div style><br></div><div style>$ git checkout jed/feature1</div><div style>(jed/feature1) $ emacs && make all alltests</div><div style>(jed/feature1) $ git commit -am'finish implementing feature1, add tests, etc'</div>
<div style><br></div><div style>Now I'm ready to publish feature1, so I</div><div style><br></div><div style>(master) $ git pull</div><div style>(master) $ git merge jed/feature1 && make alltests</div><div style>
(master) $ git push</div><div style><br></div><div style>Now I work on feature2 a bit more and integrate all the latest</div><div style><br></div><div style>(jed/test) $ git merge master # get upstream stuff</div><div style>
(jed/test) $ git merge jed/feature2 # get new feature2 stuff</div><div style><br></div><div style>then go back to feature2 and finish up</div><div style><br></div><div style><div>(jed/feature2) $ emacs && make all alltests</div>
<div>(jed/feature2) $ git commit -am'finish implementing feature2, add tests, etc'</div><div><br></div><div style>and now it's time to publish</div><div style><br></div><div style>(master) $ git merge jed/feature2</div>
<div style><div>Auto-merging file-to-modify.c</div><div>CONFLICT (content): Merge conflict in file-to-modify.c</div><div><b>Resolved 'file-to-modify.c' using previous resolution.</b></div><div>Automatic merge failed; fix conflicts and then commit the result.</div>
</div></div><div><br></div><div style><b>Explanation of the bold:</b></div><div style>So what happened here? We resolved that conflict in jed/test, but jed/test is messy and may have lots of incomplete stuff in it. We never merge jed/test anywhere and we might throw it away at any time. However, since we resolved this conflict before (even though it was in a different branch that we won't use now), git can REuse the REcorded REsolution. Git tells me there was a merge conflict and doesn't auto-commit the merge (I need to run 'git commit' to complete the process), but I don't have to manually resolve this time. (The fact that Hg has no equivalent functionality perplexes me, but explains why Hg projects with many contributors are always cluttered with meaningless merges.)</div>
<div style><br></div><div style>I find this mechanism super convenient, but it's disabled by default, presumably because it can feel like magic. Enable it with</div><div style><br></div><div style>$ git config rerere.enabled true</div>
<div style><br></div><div style>or globally with</div><div style><br></div><div style>$ git config --global rerere.enabled true</div><div style><br></div><div style>As a user, the effect is that I only ever need to resolve conflicts once. Git remembers that resolution and will reuse it anywhere that I merge similar content. There is technical documentation for the feature, but I used it for years before reading these:</div>
<div style><br></div><div style><a href="http://git-scm.com/2010/03/08/rerere.html">http://git-scm.com/2010/03/08/rerere.html</a><br></div><div style><a href="http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html">http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html</a><br>
</div><div style><a href="http://gitster.livejournal.com/41795.html">http://gitster.livejournal.com/41795.html</a><br></div><div style><br></div><div style><br></div><div style>This "topic branch" workflow lets me have long-lived feature branches that have linear history (no merges from upstream into the feature branch), but in which the combined state is frequently tested and the eventual merge to 'master' is painless.</div>
<div style><br></div><div style>If something shows up in 'master' that I need to complete my work on feature3, then I make an explicit merge</div><div style><br></div><div style>(jed/feature3) $ git merge master # explain what functionality I'm obtaining in commit message</div>
<div style><br></div><div style>This merge is semantically important and unavoidable so there is no reason to try to avoid it. We're only trying to avoid the meaningless merges "some other stuff happened, don't know if it affects me so I'll merge it".</div>
<div style><br></div><div style>Note that it's fine to have many people working on the same topic branch. When you push to a topic branch, you are "publishing" to _those_ people. If that group is sizable, you'll still have a personal branch that you use to manage and test your patches before publishing to that topic branch. (Just apply the workflow above recursively, with 'master' replaced by 'topic-branch-with-several-people'.)</div>
<div style><br></div><div style><b>Throw-away integration branches</b></div><div style>If many people are working concurrently, it's sometimes useful to have a snapshot of what a merge would look like with everyone's latest (still incomplete) work. In the kernel/git workflow, that is provided by a branch they call 'pu' (Proposed Updates). It is blown away and rebuilt periodically, but then we can easily check whether our new stuff conflicts with anything anyone else is working on by running</div>
<div style><br></div><div style>(jed/feature4) $ git checkout -b jed/test-pu # create temporary branch at same state as jed/feature4</div><div style>(jed/test-pu) $ git merge origin/pu</div><div style>test things out, go back to work, eventually discard jed/test-pu</div>
<div style>$ git branch -D jed/test-pu</div><div style><br></div><div style>If we discover some bad conflict, this experiment might prompt a design discussion with the people working on a component that we thought was independent of our work.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div>
> Erase the command `hg branch` from your vocabulary.<br></div></div></blockquote><div><br></div><div style>I wish the Hg developers would admit they made a mistake and erase 'hg branch' from Hg's vocabulary. Users that really want that ridiculous thing can add it to their hgrc.</div>
</div></div></div>