I am currently working on reordering, squashing and changing some stuff in a git branch which has a lot of pending commits (currently around 300) that needs to be merged. I am facing difficulties working on it simultaneously.
Consider that the branch currently has commits A-B-C-D-E-F-G-...
and so on, where A is the oldest commit that is not merged to the target branch. Now I make some changes, to say commit D (squash some bug to it, reorder it, etc.). Now my branch would look like A-B-C-D1-E1-F1-G1-H1-I1-...
and so on (the commit hash changes for D and any commits newer than D).
Suppose at the same time another person does some other change to say, commit H. Now on his local branch, it would seem like A-B-C-D-E-F-G-H2-I2-J2-K2-...
and so on.
Now, either of us pushed our changes to the remote branch (suppose I do it). Now on remote branch, the commits are A-B-C-D1-E1-F1-G1-H1-I1-...
and so on, while on person B's local branch, it is A-B-C-D-E-F-G-H2-I2-J2-K2-...
and so on.
My main issue is, how can person B rebase his local branch in a manner that would allow him to pull the changes pushed to the remote branch, while keeping his changes which he made in the local branch (something like A-B-C-D1-E1-F1-H3-I3-J3-...
and so on. I am okay with some merge conflicts arising, but don't want to lose changes made by either person A or person B). Can someone suggest a good approach to tackle this problem?
CodePudding user response:
Consider that the branch currently has commits A-B-C-D-E-F-G-... and so on... Now I make some changes, to say commit D (squash some bug to it, reorder it, etc.)... Suppose at the same time another person does some other change to say, commit H.
Stop. Do not suppose that. No one — that is, no one — should ever make changes to an existing commit in a branch that is shared with anyone else.
If both you and "another person" are able to make changes directly to the same branch,1 then neither of you must ever, ever make any change to the existing history of the branch. That gets you into exactly the situation you have described, and that situation is utterly untenable.
The first rule of Git ethics is: do not rebase (or otherwise modify the history of) a shared branch. And this branch, by hypothesis, is shared.
1. But we can go further. This supposition that you and "another person" are able to make changes directly to the same branch should not be the case in the first place! That is arguably a total misuse of Git. Different people should work on different branches, and their work should be united only by merging. Branches are incredibly lightweight in Git. Use them.
CodePudding user response:
I'll disagree very slightly with Matt here. The way I like to put it is that "history rewriting" (via rebase or any other method where we remove or replace some existing commit with some new-and-improved replacement) requires in-advance agreement between all parties that are using the existing commits.
That is, suppose there's a branch named "proposal", that many people read and some occasionally write with git push
. It's agreed, by all parties, that any given proposal can be withdrawn or modified. Proposals that don't depend on earlier proposals will just be rebased in this case. Proposals that do depend on earlier proposals will be dropped or rewritten. Since everyone has agreed to this in advance, if you decide you wish to drop some proposal you've made, you simply bring in the current version of the branch, rebase to drop your proposal, and push the result—unless, that is, dropping your proposal damages someone else's. In that case you contact the someone else (by email perhaps, or phone) and the two of you work out what to do.
If you're about to make a proposal and you run git fetch
and find that the branch has been rewritten to remove a proposal that you depended on, you either adopt that proposal yourself—it's now your responsibility—and put it back, or you contact the owner of the original proposal and work out what to do.
If you're about to make a proposal that doesn't depend on anyone else's, you're free to fetch, add, and push.
If a proposal is complex and needs multiple users to agree and/or needs a long-lived branch, you (and anyone else involved) create a separate "proposal branch" and begin using it. All parties to the proposal agree, or don't, that this branch also has certain rewrite rules. This way everyone is prepared in advance for whatever comes down the line.
If you have a "private" proposal that goes into a shared repository (so that it can become a shared proposal if/as needed), and you're the only one working on it at this time, you merely need to agree with one person—yourself—whenever you choose to rewrite it. This is usually fairly easy.