Tom, thanks for having the patience to try to explain this to me!
Since no one else has jumped into this conversation, I'm wondering
if this is all just completely clear to everyone else and they don't
understand why I'm so slow, or if everyone else is confused as
well! :-)
More comments below...
Tom Jenkinson wrote on 12/10/18 04:41 AM:
Tom Jenkinson wrote on 12/
7/18 02:34 AM:
Tom Jenkinson
wrote on 12/6/18 1:49 PM:
Tom Jenkinson wrote on
12/6/18 3:38 AM:
As soon
as a commit in
your tree does
not have
identical SHA
to what is in
the main repo
it won't push
cleanly.
I don't understand.
How are two commits
considered to be "the
same" if not by their
SHA?
If there's a commit in
my repo that's not in
the remote, and
there's a commit in
the remote, that's not
in my repo, I
understand. But if I
do a "pull -r", how
can there be a commit
in the remote that I
don't have? Doesn't
"pull -r" pull down
everything from the
remote and add my
stuff on top of it,
without changing what
it pulled down?
I tried
to simulate it
a bit with
creating two
branches using
your current
master and
then on one of
the branches
doing a "git
commit --amend
--no-edit" so
although they
are both
functionally
identical both
branches have
a different
SHA for the
head commit.
"commit --amend" is
effectively the same
as completely removing
that commit and
replacing it with a
new commit, right?
I understand how that
would get things out
of sync, but I wasn't
doing that.
git diff
test2 (my
second branch)
- shows no
differences
but if I
do "git rebase
test2" it
changes the
branch I am on
to use the SHA
from the test2
branch.
History looks
clean still
but it can't
be clean
pushed.
If I do
"git merge
test2"
instead, it
can be pushed
but history
does not look
nice.
Here are
the branches:
There
reason they
all have
different SHA
is because the
second two
commits are in
a different
order. If
master was
going to have
exactly the
same commits
in the exact
same order you
could have
done "git
rebase EE4J_8"
each time and
it should have
pulled in the
lastest
commits
without
changing their
SHAs. In
practice I
don't see how
that would
have been
possible over
time as at
some point
they would
diverge.
Whenever
I try to sync
two branches I
cherry-pick
commits from
the branch
that is ahead
onto the other
branch. That
means that
history is not
re-written on
the branch I
am
cherry-picking
to and so I
don't need to
force push.
So you're saying that
rebase might rewrite
commits on the main
branch, not just add
commits from the other
branch? Ouch!
How does it know which
commits to rewrite?
From what I know, it
will rewrite anything
that is different,
because you diverged
after
beab9265aa39a4c3c4a2e220b1e4c198060803a5
then anything after that
would be changed.
I don't understand what you mean by
"anything after that would be
changed".
Yes, the EE4J_8 branch forked from
the master after the first commit to
the master.
If you do "git rebase
EE4J_8" on master it
will be made to look
like the EE4J_8 branch
where the commits are
the same.
I don't understand "made to look
like".
I think this is the crucial thing,
these two commits are not the same:
When you do a rebase, then git will
try to make them the same (and in your
case it is able to do that)
Yes, they're two completely different commits that
happen to make exactly the same change. How does
git "make them the same"? Does it throw away one
of them because it does the same change as the
other one? Does it create a new commit that
replaces the two existing commits?
Git makes them the same in the following way -
when you "git rebase EE4J_8" on master then you will
see that 7be4f44afd920e35ede59aa06221cedc7b9bd12c
will overwrite
b21b640514fd66a198d87d4c7b096dcea4dbd7bc on that
master branch (and the same happens for all the
previous commits too).
It's this overwriting/changing of existing commits on the master
that seems surprising to me, and that I haven't seen described
anywhere.
Surely there must be a description of how this
works somewhere in the git documentation,
right?... :-) (Although too much of the git
documentation is written for the people who
implemented git, not the people who use it, and
thus is impenetrable.)
Although it seems to relate primarily to a
different cautionary note, I think that the
following is the closest to what is going on here:
Right, and that's exactly what I expected.
The examples in that link don't show any cases where existing
commits on the master are changed.
I do see that there's one part I've been ignoring. The examples
show "merging" the master and branch by "fast-forwarding" the
branch. I haven't been doing that. I've just been abandoning the
branch, and planning to delete it.
I think the key to understanding the problem is the "patch-id" they
talk about briefly.
I managed to reproduce my problem locally. With identical commits
on master and the branch, the rebase replaced the commits on the
master with commits from the branch. That still seems like the
wrong thing to me; it seems like it should always favor the commits
on the master.
If I follow that with "git pull --rebase", I end up with what I
expect - the duplicate commits from the branch thrown away and the
unique commits from the branch applied to the end of master.
I guess the bottom line here
is that if people would stop making the same
change to both master and EE4J_8, we wouldn't have
this problem, right? Why isn't everyone just
making the changes to EE4J_8 and then merging or
rebasing that on master?
I am not sure it is as straight forward as that.
As soon as you a commit on master that isn't in
EE4J_8 branch (and doesn't want to be) you will get
this problem so at some point as a rebase.
By "doesn't want to be" do you mean because it duplicates a change
on the EE4J_8 branch?
In the Basic Rebase case, there are commits on the master that
aren't on the branch, and that doesn't cause any problem.
The best way to deal with Git in my opinion is to
put commits on to a feature branch first (probably
for us it is the EE4J_8 branch at the moment) and
then to "git cherry-pick" the ones you need to
backport onto another branch (in our case master) -
thus avoiding rebase and merge commands between
branches. It does mean you have to expliciting know
all the commits you are moving between the branches.
I was expecting that rebase was just like cherry-pick, except it
picked them all.
Is there a way to tell cherry-pick to "pick everything on the
branch"?
Personally I use rebasing when I am developing on
my own fork of a branch so that I know that any
commits I am offering for pull request will be able
to be merged to the upstream version of that branch
cleanly: "git pull --rebase --ff-only"
I always use "git pull --rebase". I don't understand what effect
-ff-only has in this case.
|