问题
I'm the only developer working in a repository, so there's no issue with ruining peoples' flow. However when I rebase locally and then try and push it to Bitbucket, it comes back telling me I need to pull the latest changes. I do that, and the rebase has completely ruined my clean tree.
Is there a way to push a rebase to the server without then having an additional "Merge branch" commit as part of it?
Thanks!
回答1:
Rebase is fundamentally a "copy some commits, then discard the old commits in favor of the new and supposedly improved commits" operation.
Consider, for instance, this situation:
...--A--B--E--F <-- master
\
C--D--G <-- feature (HEAD)
You've finished your feature feature
, but for whatever reason, you had to go create two commits on master
while you were working. So now feature
could stand to be re-written.
No commit can ever change, so it's not actually possible to replace C
with a new-and-improved variant, but we can make a new-and-improved C'
to replace C
anyway, using a temporary branch or Git's "detached HEAD" mode:
C' <-- HEAD
/
...--A--B--E--F <-- master
\
C--D--G <-- feature
Commit C'
does to commit F
what commit C
does to commit B
. The old (and now lousy) C
has B
as its parent, while the new improved C'
has F
as its parent. So now we need to copy D
to a new-and-improved D'
, and then do the same again for G
:
C'--D'--G' <-- HEAD
/
...--A--B--E--F <-- master
\
C--D--G <-- feature
We're now ready for git rebase
's last trick. It peels the name feature
off of commit G
and make feature
point to G'
instead:
C'--D'--G' <-- feature (HEAD)
/
...--A--B--E--F <-- master
\
C--D--G [abandoned]
Since we can't even see the abandoned commits, in the local repository on your laptop, it looks as though history has always been this way: that you wrote commit C'
based on F
, and so on. The hash IDs look random; no one but you will ever know about all this.
Only ... you did a git push
of commits C-D-G
, or at least some of them, to Bitbucket. They have your old-and-lousy commits, pointed-to by their branch name feature
. You send them your shiny new ones—git push origin feature
—and at the end of this, your Git asks them politely to move their feature
name to point to commit G'
instead of G
.
This would, of course, cause them to abandon commit G
in favor of the new and improved G'
. That's what you want them to do. But they will say: No, if I do that, I'll lose my precious commit G
!
All you have to do is tell them—or have your Git tell them—yes, I know you could lose some commits, but do it anyway! That is, instead of a polite request, you have your Git send them a forceful command.
The way you do this is to add --force
or --force-with-lease
to your git push
command. That turns the polite request, Please, if it's OK, set your feature
to a command: Set your feature!
The difference between --force
and --force-with-lease
is that the latter adds a safety check first. Instead of just saying Set your name feature
to point to commit G'
!, your Git will say: I think, based on my information, that your feature
points to commit G
. If so, set it to point to G'
instead. If not, let me know that I goofed.
The safety check is obviously usually good, but it's also unnecessary if you're the only one who ever puts new commits into the repository over on Bitbucket.
来源:https://stackoverflow.com/questions/60199314/how-to-rebase-pushed-branches-without-ruining-tree