Hi Yuri,
On 2023-10-20 15:46, Yuri wrote:
I use git-p4 to use the perforce repository through git.
There are 3 branches:
* master
remotes/p4/HEAD -> p4/master
remotes/p4/master
git-p4 syncs remotes/p4/HEAD with the perforce repository.
Then the user (me) needs to merge remotes/p4/HEAD into master.
Initially such merge doesn't cause "Merge remote-tracking branch
'remotes/p4/HEAD'" commits.
But then, after several cycles of submit/sync something happens, and git
forces me to commit with the "Merge remote-tracking branch
'remotes/p4/HEAD'" comment.
What makes the merge from remotes/p4/HEAD into master to require "Merge
remote-tracking branch 'remotes/p4/HEAD'"?
I believe what is happening is once other developers merge code in the
same branch your master branch ends up like a topic branch that never
merge back to the remote tracking branch.
I've worked a lot more with git-svn but both behaves somewhat similarly
AFAIK - when you "send" your commit upstream (I'm using "send" as I
don't recall the exact terminology for git-p4) what really happen is
like if your commit was cherry-picked on top of the remote branch - P4
tracks commits linearly and has an incompatible concept of merges.
When you sync later, it will get both your commits and other developer's
commit, but because they don't have the same history anymore git has no
choice but to merge the branches (this doesn't happen initially if
you're the only committer as your branch remain sync with the remote).
What does this mean?
What is changed in remotes/p4/HEAD or master that later requires this?
How to eliminate the need for "Merge remote-tracking branch
'remotes/p4/HEAD'"?
You probably don't "need" to eliminate this, you can just keep creating
new commits on top and pushing them. The end result will be the same for
other p4 users.
If you still want to re-sync with upstream all you have to do is to
rebase on top of the remote tracking branch. You'll end up with the same
work tree but your history will get "linearized" based on the commits in p4.
Let's take for example this branch:
A---B---C [master, remotes/p4/HEAD]
Now imagine you and another developer both work on the repo separately
(let's assume different files, no possible conflicts) and the other
developer commits before you in p4, you end up with:
A---B---C---E [remotes/p4/HEAD]
\
`-D [master]
When you send *your* change, D, on the p4 repo, it cannot merge like git
does. It will instead apply your commit on top of E - we'll call your
commit D' as it's now a different commit hash, although it's the same
change:
A---B---C---E---D' [remotes/p4/HEAD]
\
`-D [master]
Now if you sync with p4, git can't fast-forward anymore because D and D'
are different commits (and don't even have the same parent!) therefore
it will merge (F) with the remote tracking branch:
A---B---C---E---D' [remotes/p4/HEAD]
\ \
`-D-----+-F [master]
F and D' are identical, they have the same work tree contents, but have
a different commit hash (implied by the difference in parents). If you
rebase master to remotes/p4/HEAD git will discard the duplicate D commit
from your branch and restore it at the tip of remotes/p4/HEAD. If you
has any new commit after F, those would be applied after D', for ex:
A---B---C---E---D' [remotes/p4/HEAD]
\ \
`-D-----+-F---G [master]
Rebases to:
A---B---C---E---D' [remotes/p4/HEAD]
\
`-G' [master]
Personally I would always rebase with the remote repo, and with git-svn
I was actually doing that systematically before pushing anything (I
think I had no choice anyway, or maybe I just didn't want any local
merge commits...) In any case you should be able to rebase with the p4
remote tracking branch before or after committing into p4 and that will
keep your history in line with p4's history.
Regards,
-
Thomas