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.
CodePudding user response:
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.