1

We have a repo with 2 branches. One named dev and the other prd. We follow a normal process to sending pull requests from our Forks to merge our changes with dev. Afterwards, a pull request and merge is made from dev into prd to make these updates Live.

The problem is at one point while merging from dev to prd, the prd branch became permanently 'ahead' of dev (sometimes the commits ahead stack). The opposite effect will happen if we try to merge prd back into dev, except it will then be behind.

How can we get both of branches back in sync because these statuses are causing confusion for the team.

Note: it is ahead with no file changes, only commits are being recorded.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Apocist
  • 51
  • 1
  • 10
  • 1
    What is the output of `git log --oneline --left-right dev...prd`? (Hint: it should give you a list of all commits that are on one branch but not the other.) – Oliver Charlesworth Dec 10 '14 at 23:59

1 Answers1

6

Because of the way merges work in Git, this is normal behavior.

In Git, a merge is a commit like any other, it just has two (or more) parents. It contains the changes necessary to merge the content. When you merge a branch into another, the source branch is not changed. So when dev is merged into prod, only prod changes.

Here's a visual example. Let's say dev was branched off prod at commit 3. prod is now at commit 7 and dev is at E. prod is checked out.

1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 [prod] [HEAD]
           \
            A -- B -- C -- D -- E [dev]

When dev is merged into prod with the command git merge dev, this the the result.

1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 [prod] [HEAD]
           \                      /
            A -- B -- C -- D -- E [dev]

The merge results in a new commit whose parents are both 7 and E. It contains all the changes necessary to merge them together. prod is advanced to this new commit. dev remains at E.

This is why prod will always ahead of dev after merging. The exception is "fast forwarding". Let's say this happens.

1 -- 2 -- 3 -- 4 [prod] [HEAD]
                \
                 A -- B -- C [dev]

dev was branched off of prod at 4. Work has been done on dev but not prod. prod is checked out. When git merge dev is done, git will recognize there is no need for a merge and do a "fast forward".

1 -- 2 -- 3 -- 4
                \
                 A -- B -- C [dev] [prod] [HEAD]

prod is advanced to C, the same place dev is. You can override this behavior with git merge --no-ff for "no fast-forward". This is recommended for feature branches, where retaining the fact that a set of commits was all part of a cohesive feature is important, but unnecessary if you're just making a production branch catch up to development.

The fact that your merges are not fast-forwarding indicates that commits were made directly to prod, those are commits 4 - 7 in our example. In many workflows this should not happen, commits should only be made to dev and then merged into prod. You should investigate that, there could be changes in prod which are not in dev. Somebody probably hot patched prod.

The simplest way to fix this situation is to merge dev into prod and then immediately delete dev and branch it again off prod. Don't worry, branch history will be preserved.

1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 [prod] [dev] [HEAD]
           \                      /
            A -- B -- C -- D -- E

git branch -d dev will prevent you from deleting a branch which has not been fully merged. For example, if the repository looked like this...

1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 [prod] [HEAD]
           \                      /
            A -- B -- C -- D -- E -- F -- G [dev]

And you ran git branch -d dev, git would refuse to delete the branch. DO NOT use -D or -f to force it else you will lose work from dev. Simply merge dev into prod and then try again.

There are other ways to handle this situation, but that is the simplest. After that, your commits should fast forward.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • Assuming that a commit was sent directly to `prd`, wouldn't merging `prd` back down to `dev` sync both of the branches? – Apocist Dec 12 '14 at 00:45
  • @Apocist No, for the same reasons merging dev into prod doesn't sync them. The source branch never moves in a merge, only the checked out branch does. I've updated my recommendation for how you can fix this situation. Long story short, rebranch dev off of prod. – Schwern Dec 12 '14 at 03:10
  • @Schwerm Thanks! That worked, we'll try to make sure this doesn't get off track again – Apocist Dec 12 '14 at 22:29