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.