1

Consider that I have 3 branches: main, dev, and release The dev branch was created using main branch, and is ahead of main branch. The dev branch has a new folder which has a few new files.

In GitHub, I mistakenly merged from dev branch directly to release branch, whereas dev has to be first merged to main branch, and only main branch has to be merged with release branch. At this point, the new folder which was there in dev branch, got created in the release branch.

Immediately I reverted the merge in release branch. As a result of the revert, the new folder got deleted in the release branch.

Next I merged the dev branch with main branch (which is what I should have done in the first place), and then main branch with release branch.

However, the new folder that is there in dev branch is now present only in main branch, and the folder and its files are not getting re-created in the release branch, because the folder was deleted due to the revert of the 1st merge.

If I try to create a new merge request from main to release branch, GitHub displays that release branch is up to date with all commits from main, and release is ahead of main.

What is the solution to merge main into release, so that the new folder which came from dev branch into main gets re-created in the release branch?

EDIT 1:

Whatever I merged from dev to release was correct code, but just that I am not supposed to merge directly from dev to release as a practice.

AllSolutions
  • 1,176
  • 5
  • 19
  • 40
  • 2
    git doesn't care much about files; it cares even less about folders. What's actually happening here is that the **commits** which you reverted are not being merged to the release branch, because as far as git is concerned *you already merged them*. So now you need to "revert the revert" - see https://stackoverflow.com/questions/8728093/how-do-i-un-revert-a-reverted-git-commit and https://stackoverflow.com/questions/5354682/how-can-i-fix-a-reverted-git-commit and probably lots of other similar questions. – IMSoP Dec 15 '21 at 15:51
  • In the above posts, it is not getting clear to me, how does reverting the revert enables a fresh merge from main to release branch with the folder/file getting created. What happens under the hood / what makes it work? I do not want to try out something on production repo without understanding. – AllSolutions Dec 15 '21 at 18:05
  • If we revert the revert, how does Git understand that those commits from main branch are no longer already merged in the release branch? – AllSolutions Dec 15 '21 at 18:07
  • My question is also slightly different from the other posts because whatever I merged from dev to release was correct code, but just that I am not supposed to merge directly from dev to release as a policy. – AllSolutions Dec 15 '21 at 18:15
  • As for the policy aspect, it doesn't matter _why_ you've ended up in this situation, the fact is that you _are_ in the situation: you have reverted something, and now you want it back. There are only two ways to do that: 1) rewrite history (tricky to get right, and dangerous to get wrong); 2) create a new commit re-introducing the reverted changes. That's just how git works. – IMSoP Dec 15 '21 at 18:17
  • Is it not possible to make a dummy commit in the dev branch, by just adding a space or similar character in all the files (there are around 5 files), and merge this commit "dummy1" from dev to main branch, and trick git so that this commit "dummy1" is not found in the release branch and when git merges this commit, the folder and all the 5 files get created in the release branch? Will this work? – AllSolutions Dec 15 '21 at 18:27
  • You said in your 1st comment that "as far as git is concerned you already merged them". So if we have already applied a commit c1 from branch1 to branch2, and in branch2, we have applied a few more commits on top of the commit c1, like c2 and c3, and then we want to reapply the c1 from branch1 to branch2, is it not possible to do in git, because c1 is already there in the commit history of branch2? – AllSolutions Dec 15 '21 at 18:29
  • But then even if revert the revert, the faulty commit c1 still stays in the history of release branch, isn't it? So why now the same commit c1 from main branch is able to merge with release branch, when it is not able to do so without reverting the revert? – AllSolutions Dec 15 '21 at 18:31
  • Ok. "you have reverted something, and now you want it back" - I want to qualify it by saying that I want it back via the main branch, so that release is always same as or behind the main branch, never ahead of it. – AllSolutions Dec 15 '21 at 18:47

1 Answers1

1

git doesn't care much about files; it cares even less about folders. What's actually happening here is that you have some commits which git doesn't think need merging. That's because, as far as git is concerned, you already merged them.

The key point here is that reverts don't record what commit they're reverting; each time you run git revert, it just creates a new commit which is like a mirror image of the original. Lets say you create commit abc123, then run git revert abc123: that creates a new commit, def456, which undoes the changes of abc123; but it doesn't undo the existence of commit abc123 in that branch's history.

Let's say your original change was commit b1b1b1, and abc123 was you merging it to release; your history might now look something like this:

                                       release
                                          |
                                          v
               +---------<* abc123 <- def456
              /          /
... <- 000aaa           /
             \         /
              <- b1b1b1
                   ^        
                   |        
               my_branch

Now, whenever you try to merge "my_branch" into "release", git will look for commits which don't already exist on that branch. The commit abc123 is still part of the branch, and since that records b1b1b1 as its parent, b1b1b1 is part of the branch as well. So a merge will simply skip that commit - it doesn't know that you've later reverted the changes.

So, you need to "revert the revert" - see How do I "un-revert" a reverted Git commit? and How can I fix a reverted git commit? and probably lots of other similar questions.

In this case, if you run git revert def456, you create a third commit, 789aaa, which undoes the undoing - in other words, it recreates the original changes from commit abc123. If you think of a revert as a mirror image, then reverting a revert is a mirror image of a mirror image - the same as the original.

Given the diagram above, we might first merge "release" to "my_branch", so that abc213 and def456 are on that branch. That way, we have somewhere to put our "revert of the revert" without committing directly on "release". Then when we revert def456, the result is this:

                                       release
                                          |
                                          v
               +---------<* abc123 <- def456
              /          /                 \
... <- 000aaa           /                   \
             \         /                     \
              <- b1b1b1 ---------------------<* c2c2c2 <- 789aaa
                                                            ^        
                                                            |        
                                                        my_branch

Now if we ask git to merge "my_branch" into "release", it looks again for commits that don't already exist on the target branch. In this case, it finds commits c2c2c2 (a merge commit with no changes) and 789aaa (the reverted revert).

                                                                  release
                                                                    |
                                                                    v
               +---------<* abc123 <- def456 -------------------*> 999fff
              /          /                 \                   /
... <- 000aaa           /                   \                 /
             \         /                     \               /
              <- b1b1b1 ---------------------<* c2c2c2 <- 789aaa
                                                            ^        
                                                            |        
                                                        my_branch

In all of these, what git is applying is a change: creating a file is a change, and the mirror image of that is deleting the file; adding a line in a file would also be a change, and the mirror image would be deleting that line. There's no way to simply "remind git that a file exists" - if you try to make a change in the "missing" file and merge that, you'll get a conflict, because there's nowhere for that change to be made.

The bottom line is this: to re-create the files on the release branch, you need to create a new commit which creates those files.

That commit needs to be on a branch where the files don't already exist, so in your situation I believe you need to:

  • Merge "release" into "main": it is currently ahead of "main" because of the accidental commit, and the commit where you reverted it.
  • Once that's done, the files will be deleted on "main". To get them back, you need to revert the revert.
  • That will essentially create a new copy of the original change, recreating the files.
  • Merging "main" into "release" will now create the files, as you want.
IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • In your explanation,, I have not understood how the commit b1b1b1 is able to merge into release branch AFTER doing revert of the revert. Even a revert of the revert will not remove b1b1b1 from the history of release branch, right? – AllSolutions Dec 15 '21 at 18:56
  • @AllSolutions No, as you can see in the diagram, commit b1b1b1 still exists in exactly the same place; it is already in the history of both my_branch and release. But now we have a new commit, 789aaa, which adds the files again. It is _that_ commit which will be merged to the release branch. – IMSoP Dec 15 '21 at 18:58
  • Just for understanding, if I do not merge release back into my_branch, and I just do revert of the revert in the release branch and say this commit is 789aaa, and now I try to merge my_branch into release, then my_branch will still be on the original commit b1b1b1, which is already in the history of release branch, so just doing a revert of the revert will not allow merge from my_branch to release branch, but in this case it may be ok, because both branches (after the revert of the revert) have the same set of files. – AllSolutions Dec 15 '21 at 19:05
  • If I do revert of the revert in the release branch, and later I add more commits in my_branch, those commits will be directly mergeable into release branch, assuming no other commits have been added into release branch in the mean time, is this understanding correct? – AllSolutions Dec 15 '21 at 19:06
  • @AllSolutions I'm not 100% sure, but I think attempting a revert on the wrong branch will just give you an error. Remember that "revert" means "apply the mirror image of the changes". So git will say "OK, I need to create this file", and find that _the file already exists_; it will then panic, and ask you what to do. Just try to think how git will: "what commits are already in this branch's history" and "what changes do the new commits make". – IMSoP Dec 15 '21 at 19:07
  • As per all the other links that you shared, revert of the revert is to be done in the release branch. What I am asking is: If I do revert of the revert in the release branch, and later I add more commits in my_branch, those commits will be directly mergeable into release branch, assuming no other commits have been added into release branch in the mean time, is this understanding correct? – AllSolutions Dec 15 '21 at 19:10
  • So if I have to indeed do a revert of the revert, it means that the 1st revert was not required in the 1st place, as a revert of the revert will bring back the original changes! So I should not have done the revert in the 1st place? – AllSolutions Dec 15 '21 at 19:11
  • I sincerely appreciate your time and effort. – AllSolutions Dec 15 '21 at 19:12
  • I did the revert, not because I did not want the changes yet. I indeed wanted the changes but I wanted them to come from dev to main to release, and not directly from dev to release branch, thats why I reverted. So now if I have to revert the revert, it means I should not have done the 1st revert. – AllSolutions Dec 15 '21 at 19:14
  • This is not a forum or chat room, and I'm struggling to keep up with your comments. The bottom line is: you reverted something; now you want to un-revert it; I've linked to the how, and tried to explain the why. My last tip for you is this: branches are just names; what matters is the **chain of ancestors** of a commit. So any revert, revert-of-a-revert, or merge, can happen under any branch name you like, *as long as it has the ancestors that you need to be there for it to make sense*. – IMSoP Dec 15 '21 at 19:17
  • 1
    Thanks for all your time. I have no intention of offending you. I am summarizing here: if I pushed a commit c1 directly from dev to release, whereas my intention was to push it from dev to main to release, there was no need for me to revert. I could have simply pushed the same commit c1 to main as well. However, now that I have done the revert (c2), it is better to revert the revert (c3) and merge it back into main, so that main and release have the same commit c3, and any future commits into main will be mergeable with release without creating conflict as both will have same ancestor c3 – AllSolutions Dec 15 '21 at 19:27
  • @AllSolutions That sounds pretty much spot on. – IMSoP Dec 15 '21 at 19:29