1

Situation I think a picture is a better explanation:

enter image description here

As you can see, we have several branches, most of them solution-xyz-foo for varying numbers xyz. solution-12 builds on solution-11 and so on. There also are some deviations from this rule, e.g. the branch hystrix-dashboard-demo.

Motivation The code in the branches is used by course participants in a classroom style course. As such, participants solve the exercises and, at the end of the course, end up with code similar to what we provided in the solution-24 branch. In case a participants gets outpaced or faces some other issue, he can easily checkout the corresponding branch and continue with the rest of the exercises.

Furthermore it is possible to look at the solutions of each exercise, which are provided as a single commit.

In other words, for the course participants the branches/solutions building on top of each other serve a big advantage which we would like to keep (this builds on feedback of multiple courses held so far).

As a developer of the course (preparing the exercises and solutions, presenting the content to the participants etc.) we need to update parts of the code from time to time. For example it could be the case that we want to fix an issue in solution-3. In order to make this fix visible in solution-4 etc., we need to either merge/rebase/cherry-pick the commit containing the fix. In order to avoid a huge mess, we decided to squash all updates of each solution into a single commit, and then re-build the somewhat linear structure shown in the picture using a few rebases.

Issue As you might have guessed, doing the rebases is a lot of work. Even with a helper script (that re-attaches the branches to the commits after a rebase, but needs to be maintained in case of new/changed branch names) we still need to do the rebase, fix conflicts, re-attach the branches, and push the changes back into the repository (using a force push).

In addition to the actual work involved, this is something only team members with lots of git experience are confident to do. In other words, those that are not as confident complain about the procedure (which I clearly understand).

As a side note, we lose the obvious advantage of git: there is no change history (and old versions are lost). Furthermore, developers need to collaborate and communicate changes to the code.

Question Can you recommend ANY tag/branch/rebase/... workflow that solves the following issues?

  • course participants can easily checkout an up-to-date solution for the exercise they are currently working on (EDIT: Currently, doing this with the mouse in Eclipse is the preferred way)
  • solutions for each exercise are provided in a convenient way (i.e. a single commit)
  • developers can easily integrate fixes and updates to individual solutions so that also the later solutions building on it are updated accordingly
  • [optional] the change history is retained

As a note, you may assume that the code does not change while a course is in progress (so no git remote update is necessary on the participants' computers).

C-Otto
  • 5,615
  • 3
  • 29
  • 62

2 Answers2

1

Instead of accessing each 'solution-xyz-foo' commit as separate branches, Try accessing it as a searched ancestor commit in the chain.

git checkout -b MyWorkingBranch remotes/origin/LAST_COMMIT_IN_COURSE^\{/solution-xyz\}

then checkouts subsequent to 'rebase --onto IMPROVED_COMMIT' will produce branches based on the IMPROVED_COMMIT

see

git help revisions

if you use tags instead of branches, you can use

git filter-branch --tag-name-filter <rename command>

to update all the tags that reference all the changed commits. See 'git help filter-branch'. Again students could get branches directly from the tag names with 'git checkout -b TAGNAME' and the history would be available.

Gregg
  • 2,444
  • 1
  • 12
  • 21
  • This is promising. I fear the issue is usability on the participant's side (git in Eclipse). I'll give it a try tomorrow, thanks! – C-Otto Jun 27 '16 at 19:18
  • Using `tag-name-filter` I can only update names of already existing tags, so I'd have to add more `filter-branch` magic to do the actual rebase. Instead, I think I'm quite happy with first doing a rebase (of the latest commit on top of the change), then running a tiny script using the revision trick you mentioned in your answer to attach tags. – C-Otto Jun 28 '16 at 09:46
0

So it sounds like a surgical rebase in the middle of the chain to fix up some commit followed by another rebase of the (previously) following commits --onto the newly fixed up commit. So I'm confused by the comment "...Even with a helper script (that re-attaches the branches to the commits after a rebase, but needs to be maintained in case of new/changed branch names)...". That would seem to be (possibly) as simple as a rebase --onto your updated commit, so there is no need to maintain it for new/changed branch names - all that stuff is carried through with the rebase, no?

David Neiss
  • 8,161
  • 2
  • 20
  • 21
  • What you describe is what we did first. The current approach is to just do one rebase (`solution-24` on top of the fixed commit), and then attach `solution-23` to `solution-24^`, `solution-22` to `solution-23^`, etc. This is what the helper script does. The issue is to update the lower branches after the rebase. – C-Otto Jun 27 '16 at 19:21
  • So if you have a bug fix to solution-X, you do your change to that commit and maybe rebase squash that change with the original solution-X to get a solution-X' commit. Now, once you rebase solution-(X+1) onto Solution-X' all Solution-(X+N)'s will get the change your added in the first step. All Solution-(X-N) (from before Solution-X) will presumably not need the fix so they remain as is. If not, then I clearly dont understand what you are trying to do and lets just leave it at that. – David Neiss Jun 27 '16 at 19:29
  • I appreciate your interest! If I rebase solution-9 on top of the updated solution-8 branch, ONLY solution-9 (and, of course, solution-8) are correct. Solution-10 still points to the old commits corresponding to solutions 9 and 8 without the fix. As such, I also need to rebase ALL branches following solution-8 (9, 10, ..., 24). EDIT: If you repeat the rebase for increasing values of N, you end up with several copies of the lower solution commits (one appearing for each rebase). This can be circumvented by rebasing step by step, always on just the previous branch starting at the bottom. – C-Otto Jun 27 '16 at 19:37
  • 1
    ah, ok, sorry, now see the problem you are having. You really want to transplant a tree with the rebase. There were some solutions at http://stackoverflow.com/questions/5600659/rebasing-a-branch-including-all-its-children. Although at the end there, someone mentions to just use merge instead to avoid this headache. – David Neiss Jun 27 '16 at 19:57
  • BTW, have you looked at http://stackoverflow.com/questions/3150685/can-tags-be-automatically-moved-after-a-git-filter-branch-and-rebase? – David Neiss Jul 05 '16 at 16:04
  • Yup. Thank you, though :) – C-Otto Jul 05 '16 at 17:20