gitgithub

Make changes to tag and push to a new tag


This is what I want to do with git via GitHub.

I have a main branch, which can only be merged to via PR. I have argoCD looking at a release.yaml file which contains tags of various applications inside that repo. This is what the release file looks like:

deploy:
  - name: tempo
    targetRevision: 0.0.27-tempo
- name: tempo-agent
    targetRevision: 0.0.20-tempo-agent

The release file is in main and argo looks at this in main only.

I want to check out only 0.0.27-tempo, make some changes to it and then push to a new tag called 0.0.28-tempo and merge that to main also.

Normally I would fetch and pull main, make my change then tag it with 0.0.28-tempo and push it up. However the problem is that I don't want other things that have been pushed into main by others to be part of my tag. For example there may be a shared component between applications and another team has updated that component in main already. But I'd like to only keep a specific version of that component for my tag/release.

This way I only make incremental changes to an existing deployed tag that I intend. e.g. change a single value and push that up to a new tag by modifying my existing 0.0.27-tempo deployed tag.

I should note that it is important that I get the new changes for my specific app into main also via a PR.


Solution

  • I have already added a comment saying that I think you should fix this an the build infrastructure level by making it possible to build from different branches..... but, anyway, let's try to solve this problem with your current restrictions.

    So, you want to be able to start from a tag A so that you are able to release a tab B by adding some adjustments. The release has to be created from main branch and there are already changes in main past the point where tag A was created that you do not want to include in your B tag. Also, main works by PRs only.

    With all of those restrictions in place, it is almost impossible to achieve what you want..... we can get very close to achieving the whole thing so let's try.

    First, make sure that no one will work on that repo while you are doing this work, otherwise it will be possible that you mess up history while you are at it.

    Assumptions: we are dealing with real merges.... you do not work with rebases when merging PRs, you do not do fast-forwards when merging PRs, and you most definitely do not use squashes when you merge into main branch.

    Create a couple of branches from current main. Let's call one what-will-be-B and the other one will be called recovery.

    git branch what-will-be-B origin/main
    git branch recovery origin/main
    

    Now, in what-will-be-B we will take contents of the branch back to what it was like when you released A. So, assuming that the tag is created from main and that there are no changes between the point from main where A was started and the tag itself (or if the tag is directly created from a commit on main branch itself`), you could do:

    git checkout what-will-be-B
    git restore --worktree --staged --source $( git merge-base origin/main A ) -- .
    git commit -m "We are reverting contents of main back to what it was when we released A"
    

    Yeah, that looks scary, right??? Yeah!!! And it should. What we are doing here is not for the faint of heart.... but fear not, for what awaits those with a brave heart in the end is a lifetime of reward, a kingdom full of happy peasants willing to sheer on their new hero and sing his/her praises.... or it could be a warm cup of coffee, whatever the budget of the project allows as we do not live in a leninist paradise (at least most of us do not... and the ones that do are actually fooling themselves at believing so.... but anyway, we are getting waaaaaay carried away so back to the recipe).

    So, now that you got your branch to look like A, add the changes you want to include for B in this branch. When you are ready with that, push your branch and wait for it to be merged. When it is merged do whatever is needed to release B and then let's continue working so that we get the contents of main back to what it was so that we do not bust its content for everybody.

    git fetch origin # sync up with the repo so you can see the busted main branch
    git checkout recovery
    git merge -s ours -m "tadaaaaaaaa: Recovering main so that it's like nothing ever happened" origin/main
    

    By using -s ours, you will merge the history of what is in origin/main but actually nothing in the working tree will change so, all in all, it's like nothing happened, at least content-wise. Now, push this branch and get it merged (no rebase, no ff and definitely no squash). It would be better if you are able to push this into main directly because the first parent of this last merge commit is main the way it was before you took all those changes back to create B. The sooner this is merged after you merged the first branch, the better.

    PS You never know when inspiration will kick in. :-D