Home > OS >  How to use "git describe" with dev and main (with tags) branches
How to use "git describe" with dev and main (with tags) branches

Time:05-04

I'm trying to setup a repository as if it there will be collaboration in the future, but for now it's just me using it.

My intention is to use three branch tiers

  1. main: An always working, release branch where every commit is a tagged merge commit from pull requests only (protected).
  2. dev: Where development occurs, including small changes.
  3. feature branches: for larger/grouped changes, merged into dev

When it comes time for a release, I plan to get dev into the state the repository needs to be for that version, then pull request dev -> master and use GitHub actions to do build checks and ensure the state is valid according to some rules. Then when the pull request is merged, another workflow will tag the release according to more rules (i.e. v1.0.0 and the like).

So far so good, with things looking like this:

------------------D (main: v1.0.2)
-----A------B---C/  (dev, C is commit that was used for pull request)
      \E---F/       (my-feature, example feature branch)

The problem is that within my build system in several places I want to use:

git describe --match v*.* --dirty --always

with the intention being that the next commit made after D here would be something like:

v1.0.2-1-g7259g4f

which would be the case if everything was done on main; however, with this branch setup and the next commit presumably occurring on dev (or a new feature branch) since it would have no direct path backwards to D, describe would report based off the previous common ancestor between dev/main, which may also be nothing if this is early enough in the history (just giving a commit hash if --always is used). This would mean that describe would only produce meaningful results (in my use case) when run on main only, while I need it to "work" for all branches so that every commit that occurs after a release version is merged into and tagged in main is described relative to that last tag.

This way there is a general sense of progression:

  • For dev/feature branch builds: Oh this build is based on version 1.0.2, its 24 commits ahead with this hash for the latest one, and the local repo had uncommitted changes, regardless of which exact branch its on, as that can be added separately or discerned from the commit hash).
  • For main builds: This is a build of release version v1.0.2, v1.0.3, etc.

So far I've thought of two workarounds:

  1. After the pull request merge commit in main (D here) is tagged, immediately merge it back into dev to establish a common ancestor and backwards path for describe:

     ------------------D   (main: v1.0.2)
     -----A------B---C/\G--(dev, G merge back, will describe like v1.0.2-1-g723...)
           \E---F/         (my-feature, example feature branch)
    

    it works, but feels awkward since the merge is essentially just for the tag.

  2. Tag each commit in dev that is to be used for pull requests into main with something like dv1.0.2. This way all decedents of that commit on dev and derivative branches will react to describe as I want, just with 'dv' instead, while the merge commits in main will still be just 'v'. Practically this will work and allow for identifying builds just as easily, it just adds an extra tag step/more workflow jobs and doesn't look quite as clean.

Is there a better way to achieve this usage of git describe or am I stuck using one of the above methods?

CodePudding user response:

Just for posterity I will turn joanis' comments into an answer.

While there are many ways to manage git history, what ended up working for me (in order to enable use of git describe as described above), was to handle my branches such that when a release is ready, denoted by a merge into main, that dev and any derivative branches all converge to the same point, such that the head of dev and main point to the same commit immediately afterwards.

This can be accomplished by doing the following (assuming dev is the source branch):

  1. git checkout main
  2. git pull (if needed)
  3. git merge dev --no-ff
  4. git tag vX.Y.Z (whatever tag you want, if any)
  5. 'git checkout dev`
  6. git merge main --ff-only

Of course, main can be substituted for any branch you want (e.g. release, staging, 2.01, etc.).

After the next merge into main this creates a subjectively nice git history view with clear demarcations for each development cycle, as described by joanis:

enter image description here

Before that next merge the following changes on dev will appear along the same "track" as main.

  • Related