Путеводитель по Руководству Linux

  User  |  Syst  |  Libr  |  Device  |  Files  |  Other  |  Admin  |  Head  |



   gitfaq    ( 7 )

Часто задаваемые вопросы об использовании Git (Frequently asked questions about using Git)

  Name  |  Synopsis  |  Description  |  Configuration  |  Credentials  |  Common issues  |    Merging and rebasing    |  Hooks  |  Cross-platform issues  |

MERGING AND REBASING

What kinds of problems can occur when merging long-lived branches with squash merges? In general, there are a variety of problems that can occur when using squash merges to merge two branches multiple times. These can include seeing extra commits in git log output, with a GUI, or when using the ... notation to express a range, as well as the possibility of needing to re-resolve conflicts again and again.

When Git does a normal merge between two branches, it considers exactly three points: the two branches and a third commit, called the merge base, which is usually the common ancestor of the commits. The result of the merge is the sum of the changes between the merge base and each head. When you merge two branches with a regular merge commit, this results in a new commit which will end up as a merge base when they're merged again, because there is now a new common ancestor. Git doesn't have to consider changes that occurred before the merge base, so you don't have to re-resolve any conflicts you resolved before.

When you perform a squash merge, a merge commit isn't created; instead, the changes from one side are applied as a regular commit to the other side. This means that the merge base for these branches won't have changed, and so when Git goes to perform its next merge, it considers all of the changes that it considered the last time plus the new changes. That means any conflicts may need to be re-resolved. Similarly, anything using the ... notation in git diff, git log, or a GUI will result in showing all of the changes since the original merge base.

As a consequence, if you want to merge two long-lived branches repeatedly, it's best to always use a regular merge commit.

If I make a change on two branches but revert it on one, why does the merge of those branches include the change? By default, when Git does a merge, it uses a strategy called the recursive strategy, which does a fancy three-way merge. In such a case, when Git performs the merge, it considers exactly three points: the two heads and a third point, called the merge base, which is usually the common ancestor of those commits. Git does not consider the history or the individual commits that have happened on those branches at all.

As a result, if both sides have a change and one side has reverted that change, the result is to include the change. This is because the code has changed on one side and there is no net change on the other, and in this scenario, Git adopts the change.

If this is a problem for you, you can do a rebase instead, rebasing the branch with the revert onto the other branch. A rebase in this scenario will revert the change, because a rebase applies each individual commit, including the revert. Note that rebases rewrite history, so you should avoid rebasing published branches unless you're sure you're comfortable with that. See the NOTES section in git-rebase(1) for more details.