0

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?

sytech
  • 29,298
  • 3
  • 45
  • 86
  • 1
    I think you should avoid rebase at all costs, when working with that many commits on a shared branch. Does each commit have a lot of updates? Maybe each should have been on their own branch with multiple smaller commits. Person B can try to re-clone the repo and migrate their changes manually into a separate branch. [Read some of the points here](https://medium.com/@harishlyadav/when-to-use-git-rebase-explained-3c8192cba5c7) before you try to rebase the repo. – treckstar Jun 21 '22 at 12:30
  • 1
    Typically, rebasing is something you do with your *private* branches, to clean things up before pushing it out for others to see. Once the branch is public, its history should be treated as read-only. – chepner Jun 21 '22 at 19:34
  • 1
    There is no good approach to tackle this problem. Instead, **don't get into this problem**. Don't change the history of a shared branch, there is no way git can help you. Instead, if you need to rebase, squash, etc. then wait until you're *both* ready to be done with the branch and then *one of you* does this before you finally merge the branch into your mainline. Basically, get to a point where you can step away from the sharing part and let one person take responsibility for cleaning up the branch before your pull request. Don't do this along the way. – Lasse V. Karlsen Jun 21 '22 at 19:43
  • Yeah, even we reached the same consensus that 2 people should not tinker with the history of the branch at the same time. So, it was only one person who was handling this stuff. This is a throwaway branch with a merge request raised to mainline. Everything is done, only some new commits need to be added and squashed to earlier commits (currently only one person is doing this) as per reviewer's comments. Just wanted to know if there was a way to get multiple people involved simultaneously. Thanks for the help. – Kushan Shekhar Jun 22 '22 at 10:26

2 Answers2

3

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.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks for the help. We need to do some changes because we got some comments from reviewers. Its a feature we introduced, and as it goes, we changed approach as we got deep into the feature implementation. Its a throwaway branch, so once merged to mainline, it will be deleted. To fix comments from reviewers, we need to make changes and squash them to earlier commits (essentially changing history of that branch). The current way we are going with is only one person to do the changes, but I was hoping there might be a way for more than one person to work together on this. – Kushan Shekhar Jun 22 '22 at 10:18
  • Maybe I should not have said rebase, but it has been a while since I have used git merge. I usually use rebase or cherry-pick for some reason. In the same scenario, is it possible to merge both the branches. Consider that commit A-B-C-D1-E1... is in branch A, while commits A-B-C-D-E-F-G-H2-I2-J2.. are on branch B. Can we merge branch 1 into branch 2 so that commit look like A-B-C-D1-E1-F1-G1-H3-I3-J3-....? – Kushan Shekhar Jun 22 '22 at 10:23
  • But that totally changes the proposition. Your question supposes that you and your colleague are modifying _the same_ branch. – matt Jun 22 '22 at 13:07
1

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.

torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    I'm going to chip in my two cents here and say that I disagree very slightly with your approach and say that I instead agree with Matt's. The reason for this is that I have seen multiple teams try to adopt such a workflow and none of them have worked. It has always ended badly where they ended up having to start one new fresh branch before they messed up, and then slowly cherry-pick the "good commits" to this new branch, rewriting along the way. If you have a highly disciplined team, then this might work, but rarely is this the case... at least in my experience. – Lasse V. Karlsen Jun 21 '22 at 21:07
  • 2
    That is, it's not the approach that I disagree with, it's people's ability to use git correctly. This is a highly complex scenario and needs everyone to not only be on board on the decision on how to do it, but also fully grasp how git works and how to utilize git to do the right thing, at all times. In my experience, this has never been the case. – Lasse V. Karlsen Jun 21 '22 at 21:09
  • @LasseV.Karlsen: I've had success, but only with people who really know what they're doing. I agree that it's hard. – torek Jun 21 '22 at 22:36