0

I have a feature branch that should have all its commits as ahead of master, however when I try to merge master into my feature branch like so:

(feature)$ git merge master

All of my changes in the feature branch gets removes. I also tried to use rebase but I keep getting the same result.

(feature)$ git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded feature to master.
(feature)$ git checkout master
(master)$ git merge feature
Already up-to-date.

I only did the git merge feature to test if the rebase worked, which it didn't as it is Already up-to-date.

It is like somehow at some point my feature branch got behind master, I am not sure how and when this happened. it might be that the feature branch was merged to master branch then removed with a new commit, however when I am done with the feature branch I would like to add it to master at some point in the future when I want to deploy it.

My question is, how can I move all the commits that where made to the feature branch ahead of the master branch

Or can I recommit all the changes that are currently in feature branch after I do a git merge master

C1(feature branch) <-- C2(merge master into feature) <-- C3(recommit C1)

Notes:

  • all of what I tried to solve this is on my local machine.
  • I work in a team.

Update

I figured out what exactly happened, somebody created a new branch (feature-B) from feature branch instead of creating one from master branch and then merged feature-B into master branch:

(feature)$ git checkout -b feature-B
...
...
...
(feature-B)$ git checkout master
(master)$ git merge feature-B
(master)$ git push

and then after figuring out the problem, the same developer reverted the merge of feature-B into master

Waqleh
  • 9,741
  • 8
  • 65
  • 103
  • The `git rebase` command is going to be your solution, but you would need to show us what you've tried so far for us to be able to help you out. – larsks Jan 05 '18 at 16:22
  • @larsks I added some more information, do you need anything else? – Waqleh Jan 05 '18 at 16:37
  • 1
    The fact that git-rebase master fast forwards the feature branch would indicate that all the commits in the feature branch are already in master. Why do you think you have commits that are not in master? Can you identify one? – William Pursell Jan 05 '18 at 16:42
  • @WilliamPursell you might be correct it is like the feature branch was merged to master branch then removed with a new commit (all feature branch changes are gone), however when I am done with the feature branch I would like to add it to master. – Waqleh Jan 05 '18 at 16:47
  • Like William said, there are probably no commits that aren't already in master. If that's the case, you don't need to do anything else with the feature branch; it's safe to delete. This command will list commits that are in `feature` but not in `master`: `git rev-list feature ^master`. – mkasberg Jan 05 '18 at 17:03
  • @mkasberg you are not getting what I want, my changes are still in feature and are getting removed when I merge master into feature!. – Waqleh Jan 05 '18 at 17:18
  • @Waqleh : You had two users spend time giving correct answers to your question. To add your own answer and accept it is very poor form, your specific variation on the solution notwithstanding. Torek's answer is the better researched and IMO should've been accepted. – Mark Adelsberger Jan 08 '18 at 14:50
  • @Waqleh - If you want to question my motivations, consider that if I were trying to hoard reputation I'd have recommended my own answer as the one that should've been accepted, which I did not. If you believe your answer is more accurate in relation to what someone searching keywords would be looking for, I respectfully disagree; and my point about poor form stands regardless. – Mark Adelsberger Jan 08 '18 at 15:04
  • @Waqleh - Your opinions, both of how you might better use your "accept" and of how others should vote, are noted. Also you've seen my opinion. So I'm done discussing this. – Mark Adelsberger Jan 08 '18 at 15:29

3 Answers3

4

... it might be that the feature branch was merged to master branch then removed with a new commit

This is pretty likely to be the case. But note the following things:

  • All commits are just snapshots of some source tree, plus some metadata: specifically, who made this commit and when (in two parts, "author"—the person who wrote it—and "committer", the person who added it to the repository), plus a commit message, plus the hash ID of a parent commit, or for a merge commit, two or more parent commits.
  • A new commit never removes anything. It just adds a commit.
  • To see what's different between any two commits, you (or Git) extract each commit, then compare the two snapshots.

When you say removed with a new commit what you mean is: someone authored a commit that backed out every change brought in by merging the feature branch.

however when I am done with the feature branch I would like to add it to master at some point in the future when I want to deploy it.

This, then, is the real problem. Someone else already added it, then added a new commit that said: no, undo it all. Git is now certain (and correct) that it's already added and (because of the added commit) that the correct final state is don't use it.

What this means for you is that these commits are no good to you any more. They're already added and then a new state is imposed upon them that backs out what they did. You can't add them again: they're already in there. What you need are new commits, or to revert the reversion.

Here, you are in luck. See Re-doing a reverted merge in Git (both the question and J-16 SDiZ's answer), and then see also Linus Torvald's article on the general topic of faulty merges, paying specific attention to the addendum: recreating a topic branch with new commits, using the original (now-reverted) commits.

torek
  • 448,244
  • 59
  • 642
  • 775
2

I'm afraid some non-standard terminology that you're using might be clouding my understanding of the issue. However, you suggest a couple times that the branch "might have been" merged into master, and then its changes undone in master. That might look like this:

x -- O -- x -- x -- M -- W -- x <--(master)
      \            /
       A --- B -- C <--(feature)

This is at least plausibly consistent with the behavior you describe. In this scenario, someone merged feature to master prematurely (M), then reverted the merge (W) thinking that would resolve the issue. The problem is that this makes git think the changes in feature will never be wanted in master.

(This is documented behavior, though I think it was originally an unintended consequence; bottom line is, any future merge between feature and master will treat C as the merge base; so merging feature into master is just a fast-forward (or in any event excludes the changes made by A, B, and C), and merging master into feature would bring the "revert" changes from W onto the feature branch (undoing all the work from A, B, and C, as you observed).)

One way to fix this is to tell git to recreate the feature branch from new commits. For example if you say

git rebase -f `git merge-base feature master` feature

this will give you

       A' -- B' -- C' <--(feature)
      /
x -- O -- x -- x -- M -- W -- x <--(master)
      \            /
       A --- B -- C

Now if you try to merge between feature and master the merge base will be O and you'll get the expected results.

Of course, if feature has been pushed to the remote, then a subsequent attempt to push feature will be rejected (non-fast-forward move of the ref). You can force the push

git push -f

but then you have to coordinate with all other users of the repo to clean up their local copies (see the git rebase docs under "recovering from upstream rebase").

If that kind of clean up / coordination is a problem, there is an alternative: You can "revert the revert". It's a bit messy, but again starting from

x -- O -- x -- x -- M -- W -- x <--(master)
      \            /
       A --- B -- C <--(feature)

you would

git checkout feature
git merge master

Now you have

x -- O -- x -- x -- M -- W -- x <--(master)
      \            /           \
       A --- B -- C ----------- M2 <--(feature)

and because M2 pulled W into feature, it seems the work on feature has been undone. So next (still having feature checked out):

git revert W

(where you replace W with the the ID of - or some other name for - the original revert commit). For example in the above diagram you could say

git revert master^

because master^ resolves to commit W. This will give you

x -- O -- x -- x -- M -- W -- x <--(master)
      \            /           \
       A --- B -- C ----------- M2 -- ~W <--(feature)

where ~W redoes the changes that were undone by W.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Note that in my "revert the revert" example, I assumed you intend to merge all `master` changes into `feature`, because it's something you indicated you'd tried to do. Other variations are possible, perhaps the simplest being to revert `W` on `master` just before re-merging `feature`. – Mark Adelsberger Jan 05 '18 at 19:10
0

So after figuring out exactly what happened using git log, I created a new branch from the feature branch:

(feature)$ git checkout -b feature-v2
(feature-v2)$ git merge master

Then I reverted the revert (git revert <SHA>) by replacing the with the revert commit :

(feature-v2)$ git revert d992f10ab1106f774e10766be8735a66aeb9eadc

fixed some merge conflicts, and then pushed the commit and made sure that nobody uses the old feature branch again and use feature-v2 instead

Waqleh
  • 9,741
  • 8
  • 65
  • 103