Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ee4j-build] git question



On Mon, 10 Dec 2018 at 21:26, Bill Shannon <bill.shannon@xxxxxxxxxx> wrote:
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:


On Fri, 7 Dec 2018 at 19:52, Bill Shannon <bill.shannon@xxxxxxxxxx> wrote:
Tom Jenkinson wrote on 12/ 7/18 02:34 AM:


On Thu, 6 Dec 2018 at 22:14, Bill Shannon <bill.shannon@xxxxxxxxxx> wrote:
Tom Jenkinson wrote on 12/6/18 1:49 PM:


On Thu, 6 Dec 2018 at 18:54, Bill Shannon <bill.shannon@xxxxxxxxxx> wrote:
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:
My simulation of your master: https://github.com/tomjenkinson/javamail/commits/test (originally exactly like your master - but now the result of running git merge test2)
My simulation of your EE4J_8 branch: https://github.com/tomjenkinson/javamail/commits/test2 (note the SHA is different on the commit "Support building mbox native code on Linux; fix building on JDK 9." - like your commits in EE4J_8 branch have different SHA

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.

I think it is this bit I quoted from the rebase doc that describes it: "abandoning existing commits and creating new ones that are similar but different" - it seems to cover the idea that the rebase would abandon b21b640514fd66a198d87d4c7b096dcea4dbd7bc and create the new one (from that branches perspective at least) of 7be4f44afd920e35ede59aa06221cedc7b9bd12c (I realise 7be4f44afd920e35ede59aa06221cedc7b9bd12c is not truly a new commit but it is new to master).




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:
"When you rebase stuff, you’re abandoning existing commits and creating new ones that are similar but different." (https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
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.

When I do  git pull --rebase upstream EE4J_8 on your javamail master what I see is that the duplicate commits on master are thrown away and replaced with the ones from EE4J_8 branch, then the unique commits from master are appended. That branch would need to be force pushed as to git they look like new commits.



 
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?

By that I simply mean a commit you have on master that you personally do not want 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.
In my experience it is not, it will rewrite history and hence a force push is the only way to push them back to the repo.


Is there a way to tell cherry-pick to "pick everything on the branch"?

This might work (at least it seens to for the current state of the branches):
for i in `git cherry master EE4J_8 | grep "+ " | cut -f 2 -d " "`; do git cherry-pick $i; done



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.

Sorry, the ff-only is not used interpretted by git in my example and so it is as you have it, it means that my local commits must be fit cleanly on top of the remote upstream branch but that is what I want.

Back to the top