[U-Boot] U-Boot git usage model

Stephen Warren
2012-10-10T15:55:33Z

On 10/09/2012 06:20 PM, Scott Wood wrote:
> On 10/09/2012 06:25:47 PM, Stephen Warren wrote:
>> On 10/09/2012 05:00 PM, Scott Wood wrote:
>> > On 10/09/2012 05:14:23 PM, Stephen Warren wrote:
>> >> I don't quite follow that; linux-next is also purely merge-based. Are
>> >> you referring to the fact that it's re-created every day, and the
>> >> source branches that go into the merge can be rebased if needed?
>> >
>> > What's the difference between "re-created every day" and "rebased every
>> > day"?
>>
>> The linux-next model (and what I mean by "re-created every day") is
>> roughly the following approximately daily:
>>
>> git fetch --all
>> git branch -D tmp
>> git checkout -b tmp u-boot/master # or latest rc in fact
>> git merge u-boot-arm/next
>> git merge u-boot-i2c/next
>> git merge u-boot-video/next
>> etc.
>> git tag next-${datestamp}
>>
>> I'm not sure what "rebased every day means"; perhaps it's running the
>> following on u-boot/next every day?
>>
>> git rebase u-boot/master
>>
>> That doesn't pull in any new commits from child trees though.
>
> By "rebasing" I was referring to rewriting history in any form. It
> looks like the difference is that linux-next gives the result a new name
> each time, instead of working a branch with a fixed name.

It's not really re-writing history though, just an issue with how you
name the history. I guess that's nit-picking to a slight degree, but
with git the two are pretty decoupled whereas with many historical
systems they aren't.

Do note that linux-next doesn't become the next Linux kernel version
either; it's just a preview of the merges Linus will do. Linus re-does
all the merges based on the pull requests people actually send him. So,
the model is very different to u-boot/next.

>> > How does merging back down prevent incremental pull requests?
>>
>> It doesn't prevent incremental pull requests, but it does pollute the
>> history if you merge back down. Instead of a fairly simple:
>>
>> (M* == main branch, B* == side branch)
>>
>> B1-B2-B3-B4-B5-B6
>> / \ \
>> M1-M2-M3-M4-M4-M5-M6-M7
>>
>> you might end up with:
>>
>> B1-B2-B3-B4-X1-B6
>> / \ / \
>> M1-M2-M3-M4-M4-M5-M6-M7
>>
>> ... where X1 is the merge back from main to the side-branch. That
>> doesn't look a lot more complex, but once there are many side-branches,
>> and the master branch ends up merging a whole bunch of side-branches
>> between M4 and M5 above, the commits in B* that add actual new work are
>> split between a point before the X1 merge-back and after it. This can
>> make tracking down what exactly will get merged into M* when B* is
>> re-merged a bit trickier. git log M..B can probably show it fine, but if
>> you start looking at gitk it'll look quite complex.
>
> I don't use gitk much, but wouldn't it just show the mergeback as
> another edge in the graph (plus the merge commit itself of course)? It
> doesn't seem like a big deal.

One big problem is the ability to look back and see easily what's been
merged and what work has been committed since then.

If I run "git log u-boot-xxx/master", and look backwards through the
list of commits, looking for those committed by the owner of u-boot-xxx,
and stop when I see a commit by someone else, I'll end up stopping at
the merge commit where u-boot/master was merged back down. If there
commits to u-boot-xxx/master between the point where u-boot/master
merged u-boot-xxx/master and where u-boot-xxx/master merged
u-boot/master back down, then they'll be hidden before that merge point.

Now, I probably could just do git log u-boot/master..u-boot-xxx/master,
but that's a but more complicated (and I can never remember which order
to give the two branches).

If there were no merge-downs, a simple "git log" would be much more
easily interpretable.

>> >> >> Or often when u-boot/master has made a complete new release
>> >> >> does:
>> >> >>
>> >> >> b) Creates a new branch based on the latest rc or release from
>> >> >> u-boot/master.
>> >
>> > That's a rebase. How is that better than a (likely fast-forward)
>> merge?
>>
>> No, that's not a rebase.
>
> Fine, a reset. Or a new branch name, which in practice is the same
> thing except with a much more cluttered branch list, unless you have a
> specific need to refer to an older iteration of this process.
>
>> Rebase is when you take some existing commits
>> based on one commit and apply them to a different baseline commit
>> instead. If you're creating a new branch to take commits for a new
>> release, you're simply not applying the commits for release N+1 until
>> there's a branch ready to take them.
>
> There is a branch ready to take them -- the custodian tree. Why wait
> until there's an upstream tree ready to pull?

Well, the two possibilities are:

a) Send pull request
b) Wait for pull request to be merged
c) Here, or later, merge back down u-boot/master. Note this cannot
happen before (b) has completed, or the merge of this branch upstream
may pick up extra commits that weren't in the pull request.
d) Continue merging commits to the same branch without reset/...

or:

a) Send pull request
b) Wait for pull request to be merged
c) Reset u-boot-xxx/master to u-boot/master or some rc or ...
d) Continue merging commits

In either case, one must always wait for the pull request send in (b) to
be completely merged so that when the pull request is merged, it doesn't
pick up commits to the branch that were added after the pull request was
sent. So, there isn't a tree ready to take new patches until a pull
request has been completely processed.

>> >> >> (in practice, downstream branches typically end up with something
>> >> >> like for-3.5 based on v3.4-rcN, for-3.6 based on v3.5-rcN,
>> >> >> for-3.7 based on v3.6-rcN, some running in parallel containing
>> >> >> either important bugfixes for the release or new development as
>> >> >> determined by the current state of the various releases in the
>> >> >> mainline tree).
>> >
>> > I thought you said your way was less work? :-)
>>
>> And I believe it is; no rebasing required.
>> The difference probably isn't
>> that big though I admit. Still, creating a fresh branch from scratch for
>> each release one time and only then applying patches for that release
>> seems a lot simpler that constantly rebasing stuff all over the place.
>
> We've already dropped the rebasing.

The whole reason I started this thread was because rebasing was still
being used.

> I'd rather do merges than constantly create new branches.

>> >> but with the Linux model, you simply:
>> >>
>> >> a) Send pull request.
>> >>
>> >> Admittedly the recipient then might need to resolve some merge
>> >> conflicts. However, hopefully people have been planning for these and
>> >> have avoided them.
>> >
>> > How do you plan for them and avoid them, and how is that less work that
>> > what we do now?
>>
>> People have to be aware what is going on.
>>
>> If you're submitting a bunch of patches which depend on each-other, the
>> submitter had better call that out when sending the patch series.
>
> Sometimes it's not obvious in advance. Not all conflicts (whether they
> be merge conflicts, build breaks, or runtime failures) come from
> intrusive tree-wide changes.

Since u-boot/next appears to be a rolling/parallel model, where changes
can be pulled into it at arbitrary times even when u-boot/master is
being used to stabilize a release, the way to resolve conflicts for
U-Boot is simply to have the branch containing the dependency push their
/next into u-boot/next, then the branch needing the dependency to branch
from or merge u-boot/next into their /next, then apply the patch with
the dependency.