Reputation: 165322
OK, I thought this was a simple git scenario, what am I missing?
I have a master
branch and a feature
branch. I do some work on master
, some on feature
, and then some more on master
. I end up with something like this (lexicographic order implies the order of commits):
A--B--C------F--G (master)
\
D--E (feature)
I have no problem to git push origin master
to keep the remote master
updated, nor with git push origin feature
(when on feature
) to maintain a remote backup for my feature
work. Up until now, we're good.
But now I want to rebase feature
on top of the F--G
commits on master, so I git checkout feature
and git rebase master
. Still good. Now we have:
A--B--C------F--G (master)
\
D'--E' (feature)
Problem: the moment I want to backup the new rebased feature
branched with git push origin feature
, the push is rejected since the tree has changed due to the rebasing. This can only be solved with git push --force origin feature
.
I hate using --force
without being sure I need it. So, do I need it? Does the rebasing necessarily imply that the next push
should be --force
ful?
This feature branch is not shared with any other devs, so I have no problem de facto with the force push, I'm not going to lose any data, the question is more conceptual.
Upvotes: 1383
Views: 512287
Reputation: 127
Update master branch:
git checkout master
git pull
Switch to feature branch and rebase on top of master:
git checkout feature
git rebase master
You can see how your commits have stacked up on the master branch changes:
git log -<number of commits>
We will need to force push this rebased feature branch, since its history does not match the remote branch commit log history we will need to force push it:
git push --force origin feature
Upvotes: -2
Reputation: 11761
Instead of using -f
or --force
developers should use
--force-with-lease
Why? Because it checks the remote branch for changes which is absolutely a good idea. Let's imagine that James and Lisa are working on the same feature branch and Lisa has pushed a commit. James now rebases his local branch and is rejected when trying to push. Of course James thinks this is due to rebase and uses --force
and would rewrite all Lisa's changes. If James had used --force-with-lease
he would have received a warning that there are commits done by someone else. I don't see why anyone would use --force
instead of --force-with-lease
when pushing after a rebase.
Upvotes: 992
Reputation: 1511
I would do as below
rebase feature
git checkout -b feature2 origin/feature
git push -u origin feature2:feature2
Delete the old remote branch feature
git push -u origin feature:feature
Now the remote will have feature(rebased on latest master) and feature2(with old master head). This would allow you to compare later if you have done mistakes in reolving conflicts.
Upvotes: -1
Reputation: 27
Fetch new changes of master and rebase feature branch on top of latest master
git checkout master
git pull
git checkout feature
git pull --rebase origin master
git push origin feature
Upvotes: 1
Reputation: 5886
I would use instead "checkout -b" and it is easier to understand.
git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature
when you delete you prevent to push in an exiting branch that contains different SHA ID. I am deleting only the remote branch in this case.
Upvotes: 72
Reputation: 1006
For me following easy steps works:
1. git checkout myFeature
2. git rebase master
3. git push --force-with-lease
4. git branch -f master HEAD
5. git checkout master
6. git pull
After doing all above, we can delete myFeature branch as well by following command:
git push origin --delete myFeature
Upvotes: 4
Reputation: 401
My way of avoiding the force push is to create a new branch and continuing work on that new branch and after some stability, remove the old branch that was rebased:
Upvotes: 16
Reputation: 457
The following works for me:
git push -f origin branch_name
and it does not remove any of my code.
But, if you want to avoid this then you can do the following:
git checkout master
git pull --rebase
git checkout -b new_branch_name
then you can cherry-pick all your commits to the new branch.
git cherry-pick COMMIT ID
and then push your new branch.
Upvotes: 4
Reputation: 10416
As the OP does understand the problem, just looks for a nicer solution...
How about this as a practice ?
Have on actual feature-develop branch (where you never rebase and force-push, so your fellow feature developers don't hate you). Here, regularly grab those changes from main with a merge. Messier history, yes, but life is easy and no one get's interupted in his work.
Have a second feature-develop branch, where one feature team member regulary pushes all feature commits to, indeed rebased, indeed forced. So almost cleanly based on a fairly recent master commit. Upon feature complete, push that branch on top of master.
There might be a pattern name for this method already.
Upvotes: 2
Reputation: 47668
The problem is that git push
assumes that remote branch can be fast-forwarded to your local branch, that is that all the difference between local and remote branches is in local having some new commits at the end like that:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch
When you perform git rebase
commits D and E are applied to new base and new commits are created. That means after rebase you have something like that:
A--B--C------F--G--D'--E' <- feature-branch
\
D--E <- origin/feature-branch
In that situation remote branch can't be fast-forwarded to local. Though, theoretically local branch can be merged into remote (obviously you don't need it in that case), but as git push
performs only fast-forward merges it throws and error.
And what --force
option does is just ignoring state of remote branch and setting it to the commit you're pushing into it. So git push --force origin feature-branch
simply overrides origin/feature-branch
with local feature-branch
.
In my opinion, rebasing feature branches on master
and force-pushing them back to remote repository is OK as long as you're the only one who works on that branch.
Upvotes: 1038
Reputation: 10034
It may or may not be the case that there is only one developer on this branch, that is now (after the rebase) not inline with the origin/feature.
As such I would suggest to use the following sequence:
git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2
Yeah, new branch, this should solve this without a --force, which I think generally is a major git drawback.
Upvotes: 16
Reputation: 18946
Other's have answered your question. If you rebase a branch you will need to force to push that branch.
Rebase and a shared repository generally do not get along. This is rewriting history. If others are using that branch or have branched from that branch then rebase will be quite unpleasant.
In general, rebase works well for local branch management. Remote branch management works best with explicit merges (--no-ff).
We also avoid merging master into a feature branch. Instead we rebase to master but with a new branch name (e.g adding a version suffix). This avoids the problem of rebasing in the shared repository.
Upvotes: 19
Reputation: 467921
One solution to this is to do what msysGit's rebasing merge script does - after the rebase, merge in the old head of feature
with -s ours
. You end up with the commit graph:
A--B--C------F--G (master)
\ \
\ D'--E' (feature)
\ /
\ --
\ /
D--E (old-feature)
... and your push of feature
will be a fast-forward.
In other words, you can do:
git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature
(Not tested, but I think that's right...)
Upvotes: 21
Reputation: 12198
What is wrong with a git merge master
on the feature
branch? This will preserve the work you had, while keeping it separate from the mainline branch.
A--B--C------F--G
\ \
D--E------H
Edit: Ah sorry did not read your problem statement. You will need force as you performed a rebase
. All commands that modify the history will need the --force
argument. This is a failsafe to prevent you from losing work (the old D
and E
would be lost).
So you performed a git rebase
which made the tree look like (although partially hidden as D
and E
are no longer in a named branch):
A--B--C------F--G
\ \
D--E D'--E'
So, when trying to push your new feature
branch (with D'
and E'
in it), you would lose D
and E
.
Upvotes: 10