0

I have two branches in a repo: master and dev.

State of dev is

- A - S1 - S2 - ... - SN - B - C

State of master is

- A - S

Where S commit is the result of "squash and merge" of S1, ..., SN from dev to master.

Now, when I compare the branches, git shows a lot of changes, but actually they are B and C.

  1. What the best way to sync the branches?
  2. What the proper workflow to avoid such situations?
Stepan Zakharov
  • 547
  • 2
  • 11
  • how are you running diff? `git diff dev..master`? `git diff dev...master`? Can you include that in the question? – eftshift0 Mar 18 '22 at 13:44
  • 1
    About the general questions: **unless you know what you are doing**, squashing and merging won't fly if you mean to have some relation between the branches because git is _not_ able to see how the branches are related past `A` (because you are not creating common history between them). To git, S is just a revision on top of A that has **no relationship whatsoever with S1..SN**. – eftshift0 Mar 18 '22 at 13:47
  • I faced the problem trying to merge `dev` into `main`. I [compare](https://github.com/vvpisarev/CubicEoS.jl/compare/dev) the branches as `main...dev` on github. The real changes in `dev` (labeled as `B - C` in questions) are [commits](https://github.com/vvpisarev/CubicEoS.jl/commits/dev) since 17 February (six last commits in `dev`). – Stepan Zakharov Mar 18 '22 at 14:44
  • @eftshift0, I can find commits (`B` and `C`) that are actually changes on top of `S`. Is it possible to "detach" `-B-C` chain and merge into `main` only this chain? – Stepan Zakharov Mar 18 '22 at 14:56
  • You could cherry-pick B and C onto `main`, but if `dev` is a long-living branch, it's best to do a normal merge. Squash merges are useful for short-lived branches that you delete after the merging, not for long-living ones. – joanis Mar 18 '22 at 16:11

1 Answers1

2

Ok.... your comments explain what's going on. So, github will use triple dots when doing a diff. So, if you tried git diff master..dev, you would only see what B and C introduced. But github will use master...dev (or viceversa, does not matter). Try with git with triple dot and you will see that it will also include the changes introduces by S, and that is because when you do master...dev, git won't just compare master and dev. It will first find the last common ancestor between them (A) and then git diff A..dev, which will include the changes introduced by S1..SN... same thing if you tried dev...master. It would end up doing git diff A..master (which would include changes from S). And that is because when you squashed/merge, there was no real merge.

The way to kind of get this working again would be to set dev to have B and C on top of current master:

git rebase --onto master SN dev

That should get you what you want, but you lose the history of S1~..SN. Another way would be to get this properly merged..... but hacking a little bit so that you won't have to redo yourself (say, did you have to solve conflicts and stuff? I don't know.... so), you could try this:

git commit-tree -p A -p SN -m "Merging S" S^{tree}
# this will create a new _merge_ revision having A and SN as parents
# the content of the files will be the same as S
# the command will print the ID of a revision
# take that revision ID and let's call it X
# branch dev can live on the way it is.... we just need to put master where X is
git checkout master # if you are not in master already
# make sure you have no changes uncommitted as the next command will destroy those changes
git reset --hard X 
# now master is on top of X, the way it should have been

Now, do not ever try squashing/merging ever again unless you know what you are doing.

eftshift0
  • 26,375
  • 3
  • 36
  • 60
  • Thank you for productive answer and discussion! – Stepan Zakharov Mar 19 '22 at 11:35
  • After some testing, I came up with this solution, but I notice, that my repository is small and maintaining mostly by me. So. Locally, I made a branch `dev_local` from `dev` and rebased local branch as `git rebase -r --onto master SN dev_local` ([`-r` option](https://stackoverflow.com/questions/24786404/merge-commits-dont-appear-in-git-rebase-interactive)). Then I created a remote branch `dev_new` from `master` and merged locally `dev_local` into `dev_new`. After that, I removed `dev` in repo and renamed `dev_new` to `dev`. – Stepan Zakharov Mar 21 '22 at 09:18