BLog

ImprintImpressum
PrivacyDatenschutz
DisclaimerHaftung
Downloads 

Git’s Integration Manager Workflow for Non-Wizards

I like Subversion and I would continue to use it for all my VCS needs if my favorite development environment Xcode wouldn’t have abandoned it. Now I was in need for a workflow similar to Subversion’s vendor branches mechanism. By reading the Git documentation and other resources, I was convinced that Git’s Integration Manager Workflow would come close enough to what I need and so I wanted to implement the IMW.

Git is a distributed VCS while Subversion is a centralized one. The main flaw of distributed version control systems is, that code and structural improvements are smeared around a number of repositories up to a point where nobody can follow it up anymore, and eventually good work becomes lost. For example, take any of the popular projects on GitHub, and count the there called forks, and find tons of them which got local changes (perhaps valuable ones - who knows) which never made it, and never will make it into the master repository. For me as a physical chemist this is nothing else than generation of entropy, i.e. hot air. A centralized VCS inherently urges everybody to have more self-discipline. We know the saying, When the cat leaves the house, the rats are dancing on the table. So, from the Cat’s point of view Subversion is great. Those, who don’t like discipline too much, perhaps might like Git more. That said, the pragmatic approach is to take that what is available, that’s Git, and ranting is irrelevant.

The project under version control

The actual project got a few years of history by a single developer (me) using Subversion (a few hundreds of commits and about 100 source files). I managed already to git svn clone ... the whole original Subversion history into a bare Git repository on a dedicated server (FreeBSD), and I called this one Commons.git. I am able to clone a working copy of it to my development machine, and pushing/pulling does work as expected, also the whole SVN commit history is accessible, so up to this point everything looks fine.

Now, I want to set up the requisites for the Integration Manager Workflow for more developers, and reading some tutorials, I am stuck already right at the beginning. Some start by setting up empty repositories from the scratch, what does not match my case. In another tutorial I read 1. Fork your existing repository ..., however the actual Git commands, on how to fork are missed out, and Git does not have a fork command, I can clone something or create branches, though. While Wizards find their way through all these doubts and over all these obstacles, by enchanting something like Abracadabra and/or Sim Sala Bim, non-Wizards are stuck to enchant the actual Git commands into the terminal, which all are not very different yet. Git is a you ask for it, you get it tool - complicated, cryptic, powerful, unforgiving, dangerous, and non-Wizards better stay on the narrow road.

So here we go:

  1. Generate the bare derivate repositories, for example Derivate-A.git and Derivate-B.git from the common repository Commons.git on the server:
      cd /usr/local/git-repositories/TheProject
      git clone --bare Commons.git Derivate-A.git
      git clone --bare Commons.git Derivate-B.git
      ...
  2. For each of the derivates rename its respective master branch to working, and branch of a new master. This approach avoids later on the freaking detached HEAD issue. On the server:
      cd /usr/local/git-repositories/TheProject/Derivate-A.git
      git branch -m master working
      git branch working master

      cd /usr/local/git-repositories/TheProject/Derivate-B.git
      git branch -m master working
      git branch master

      ...

      git branch --list -a
      master
    * working
      chown -R git:git /usr/local/git-repositories/TheProject
      chmod -R go-rwx  /usr/local/git-repositories/TheProject
  3. The Integration Manager clones all repositories to his/her machine and adds the master branches of the derivates as remotes to Commons:
      git config --global pull.rebase false
      git clone ssh://git@server:11/~/TheProject/Commons.git TheProject/Commons
      git clone ssh://git@server:11/~/TheProject/Derivate-A.git TheProject/Derivate-A
      git clone ssh://git@server:11/~/TheProject/Derivate-B.git TheProject/Derivate-B
      ...
      cd TheProject/Commons
      git remote add Derivate-A ssh://git@server:11/~/TheProject/Derivate-A.git
      git remote add Derivate-B ssh://git@server:11/~/TheProject/Derivate-B.git
      ...
      git fetch --all
      git branch --list -a
    * master
      remotes/Derivate-A/master
      remotes/Derivate-A/working
      remotes/Derivate-B/master
      remotes/Derivate-B/working
      ...
      remotes/origin/HEAD -> origin/master
      remotes/origin/master
  4. Developer A, Developer B, etc. then would simply clone respective working copies to their local development machines and would start working, e.g. A:
      git clone ssh://git@server:11/~/TheProject/Derivate-A.git TheProject/Derivate-A
  5. Developer A does some changes and commits & pushes these into the origin/working branch of Derivate-A.git on the server:
      cd TheProject/Derivate-A
      git commit -a -m "description of the changes"
      git push
  6. The IM pulls the changes into his/her origin/working of Derivate-A, picks the very changes for passing it into origin/master of Derivate-A and finally pushes it to the server:
      cd TheProject/Derivate-A
      git pull
      git checkout master
      git pull
      git cherry-pick working
      git push
      git checkout working
  7. The IM switches to his/her working copy of Commons, pulls the changes from Derivate-A/master and pushes these into the origin/master branch of Commons.git on the server as well:
      cd TheProject/Commons
      git pull Derivate-A master:master
      git push

    Now he/she pushes the changes into each of the masters of the other derivates on the server as well (e.g. Derivate-B):
      git push Derivate-B master:master
      ...
  8. Finally, the IM switches to each of his working copies of the other derivates, then pulls the changes from the origin/master branch and pushes these into the origin/working branch of the respective derivate repository, for example Derivate-B.git, on the server:
      cd TheProject/Derivate-B.git
      git pull origin master:working
      git push

      cd TheProject/Derivate-nn.git
      git pull origin master:working
      git push
      ...
  9. The developers are urged to pull the changes into their local working copy before they would be able to commit & push anything to the server.

If something goes wrong in any stage, make a clone(1) of the local working copies and the respective repository directories - see also: https://github.com/cyclaero/clone. Then hard reset all affected working copies and branches to a common known good stage, for example:
  git reset --hard master~3
  git reset --hard working~1
  ...

Ranting is irrelevant, but I can’t help, I did not love Git before, and neither do I love it now nor will I love it anytime in the future. All this pushing and pulling feels like using the Plunger for clearing blockages in the flush toilet. Occasionally, you have to use it, but you don’t love it, and once the job has been done, you stow this ugly tool out of sight.

Copyright © Dr. Rolf Jansen - 2020-08-29 18:26:27

Discussion on Twitter: 1300091709855084546