Git pull after forced update
Pull with rebase
A regular pull is fetch + merge, but what you want is fetch + rebase. This is an option with the pull
command:
git pull --rebase
In your particular case, commits have been removed which you don't want to be reapplied. This has to be done manually. Therefore, the rebase needs to be interactive so these commits can be skipped:
git pull --rebase=interactive
or as of Git 2.26 can be shortened to:
git pull --rebase=i
To fetch changes from the remote repository into your local repo:
git fetch
Rename the tracking branch:
git branch -m <old-branch-name> <new-name>
Create a new local branch tracking the remote branch:
git checkout -b <old-branch-name>
To receive the new commits
git fetch
Reset
You can reset the commit for a local branch using git reset
.
To change the commit of a local branch:
git reset origin/main --hard
Be careful though, as the documentation puts it:
Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.
If you want to actually keep whatever changes you've got locally - do a --soft
reset instead. Which will update the commit history for the branch, but not change any files in the working directory (and you can then commit them).
Rebase
You can replay your local commits on top of any other commit/branch using git rebase
:
git rebase -i origin/main
This will invoke rebase in interactive mode where you can choose how to apply each individual commit that isn't in the history you are rebasing on top of.
If the commits you removed (with git push -f
) have already been pulled into the local history, they will be listed as commits that will be reapplied - they would need to be deleted as part of the rebase or they will simply be re-included into the history for the branch - and reappear in the remote history on the next push.
Use the help git command --help
for more details and examples on any of the above (or other) commands.
This won't fix branches that already have the code you don't want in them (see below for how to do that), but if they had pulled some-branch and now want it to be clean (and not "ahead" of origin/some-branch) then you simply:
git checkout some-branch # where some-branch can be replaced by any other branch
git branch base-branch -D # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch # recreating branch with correct commits
Note: You can combine these all by putting && between them
Note2: Florian mentioned this in a comment, but who reads comments when looking for answers?
Note3: If you have contaminated branches, you can create new ones based off the new "dumb branch" and just cherry-pick commits over.
Ex:
git checkout feature-old # some branch with the extra commits
git log # gives commits (write down the id of the ones you want)
git checkout base-branch # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch
Now feature-new is your branch without the extra (possibly bad) commits!