<br><br><div class="gmail_quote">On Sat, Feb 9, 2013 at 12:39 PM, Jed Brown <span dir="ltr"><<a href="mailto:jedbrown@mcs.anl.gov" target="_blank">jedbrown@mcs.anl.gov</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr"><div class="im">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><div class="gmail_extra">
<div class="gmail_quote"><div class="im">
<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><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><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>(master) $ git pull --ff-only</div><div><br></div><div>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>2. Since I put __git_ps1 in my bash prompt, I see the current branch (and sometimes other useful info).</div><div><br></div><div>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><br></div><div>(master) $ emacs broken-file.c makefile</div><div>(master) $ make runex42_3 DIFF=diffupdate # my script to refresh output</div><div>(master) $ git add output/ex42_3.out # new file</div>
<div>(master) $ git commit -am'Fix bug X introduced in <SHA1>, add runex42_3'</div><div>(master) $ git push</div><div><br></div><div>If there is a conflict here, I just</div><div>
<br></div><div>(master) $ git pull --rebase</div><div>(master) $ git push</div><div><br></div><div>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><br></div><div>(master) $ git checkout -b jed/feature1 # create a branch and check it out</div>
<div>(jed/feature1) $ emacs file-to-modify.c && git commit -am'implement first part of feature1'</div><div><br></div><div>and another</div><div><br></div><div>(jed/feature1) $ git checkout -b jed/fetaure2 master # base this on 'master' because it is independent of feature1</div>
<div>(jed/feature2) $ emacs file-to-modify.c # oops, same file, and some changes conflict</div><div>(jed/feature2) $ git commit -am'first part of feature2, I might not know that it conflicts with feature1'</div>
<div><br></div><div>Now I want to see what's happening upstream:</div><div><br></div><div>$ git checkout master</div><div>(master) $ git pull</div><div><br></div><div>and to find out how my patches will appear if merged into upstream:</div>
<div><br></div><div>(master) $ git checkout -b jed/test</div><div>(jed/test) $ git merge jed/feature1 # applies cleanly, cool</div><div>(jed/test) $ git merge jed/feature2 # conflicts</div><div>
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>Automatic merge failed; fix conflicts and then commit the result.</div>
<div><br></div><div>(I'll explain the bold part later.) I will resolve this merge and commit the result:</div><div><br></div><div><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></div></div></blockquote><div>So, this resolution is applied to jed/test and also saved [I'm guessing the detached HEAD is this stashed resolution?) to be applied again later to master when jed/feature2 is finally merged with the upstream. Meanwhile you work on jed/feature2 without this resolution applied, so you don't actually see the code as it will end up. Wouldn't that be confusing? I imagine this workflow works and "preserves the ... testing" because the testing is done on jed/test, which contains the resolutions of all of the conflicts with the upstream. I feel like I would find it disorienting working on one branch, testing in another, then fixing whatever problems in the first, testing again in the second, and so on. What am I missing?</div>
<div><br></div><div>Dmitry.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>
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><br></div><div>$ git checkout jed/feature1</div><div>(jed/feature1) $ emacs && make all alltests</div><div>(jed/feature1) $ git commit -am'finish implementing feature1, add tests, etc'</div>
<div><br></div><div>Now I'm ready to publish feature1, so I</div><div><br></div><div>(master) $ git pull</div><div>(master) $ git merge jed/feature1 && make alltests</div><div>
(master) $ git push</div><div><br></div><div>Now I work on feature2 a bit more and integrate all the latest</div><div><br></div><div>(jed/test) $ git merge master # get upstream stuff</div><div>
(jed/test) $ git merge jed/feature2 # get new feature2 stuff</div><div><br></div><div>then go back to feature2 and finish up</div><div><br></div><div><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>and now it's time to publish</div><div><br></div><div>(master) $ git merge jed/feature2</div>
<div><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><b>Explanation of the bold:</b></div><div>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></div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">
<div><br></div><div>I find this mechanism super convenient, but it's disabled by default, presumably because it can feel like magic. Enable it with</div><div><br></div><div>$ git config rerere.enabled true</div>
<div><br></div><div>or globally with</div><div><br></div><div>$ git config --global rerere.enabled true</div><div><br></div><div>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><br></div><div><a href="http://git-scm.com/2010/03/08/rerere.html" target="_blank">http://git-scm.com/2010/03/08/rerere.html</a><br></div><div><a href="http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html" target="_blank">http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html</a><br>
</div><div><a href="http://gitster.livejournal.com/41795.html" target="_blank">http://gitster.livejournal.com/41795.html</a><br></div><div><br></div><div><br></div><div>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><br></div><div>If something shows up in 'master' that I need to complete my work on feature3, then I make an explicit merge</div><div><br></div><div>(jed/feature3) $ git merge master # explain what functionality I'm obtaining in commit message</div>
<div><br></div><div>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><br></div><div>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><br></div><div><b>Throw-away integration branches</b></div><div>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><br></div><div>(jed/feature4) $ git checkout -b jed/test-pu # create temporary branch at same state as jed/feature4</div><div>(jed/test-pu) $ git merge origin/pu</div><div>test things out, go back to work, eventually discard jed/test-pu</div>
<div>$ git branch -D jed/test-pu</div><div><br></div><div>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 class="im">
<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><div>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>
</blockquote></div><br><br>