Git pull after forced update
Asked Answered
O

5

528

I just squashed some commits with git rebase and did a git push --force (which is evil, I know).

Now the other software engineers have a different history and when they do a git pull, Git will merge. Is there a way to fix this, except doing a rm my-repo; git clone [email protected]:my-repo.git?

I need something like the opposite of git push --force, but git pull --force did not give the intended results.

Operculum answered 21/3, 2012 at 22:30 Comment(3)
they can delete their branch and re create it too, without having to delete the whole repo: git checkout master && git branch -D test && git checkout -b test origin/testHyperaesthesia
Possible duplicate of Force Git to overwrite local files on pullGlosseme
Possible duplicate of Reset local repository branch to be just like remote repository HEADCharo
F
758

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.

Fleabane answered 21/3, 2012 at 22:36 Comment(6)
@Operculum When your colleague use `git reabse origin/master', and mean while, they already had some commit before, git will write your commit to the behind of their commit.Hibernate
Might be worth mentioning that if this is for a different branch: git reset origin/otherbranch --hardBight
So, to clarify, this is either: Option 1: reset --hard, or Option 2: reset --soft + rebase, right?Grannie
@Grannie No. git reset --soft origin/master will change commit history to match the remote and stage differences to the remote which then be committed. There'd be no need to rebase in that scenario (and you'd be prevented from doing so because of the uncommitted changes) because there's no difference in commit history. The two options are reset or rebase - not a combination of both. Please ask a question if your scenario is different than the one I've answered here.Fleabane
@Bight Check out the other branch first! If you want to go with option 1 for a any branch, you have to check it out first. git reset will operate on whatever branch you're currently on.Zeculon
@illis The branch referenced isn't a local branch, it's a remote branch (which is why it's prefixed with origin/Bight
M
114

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
Malacology answered 28/5, 2020 at 7:23 Comment(6)
I use this all the time to get the latest code from master into my feature branch without having all those merge commits in the history.Malacology
This is much simpler than git reset origin/master --hard or git rebase origin/master especially if there are no local commits. Thanks!Dahna
Thank you! This worked for me when I rebased my feature branch on master, force pushed it and then git pull --rebase d it on another machine.Lipo
If the current branch is not tracking the remote branch as its "upstream", then you will need to manually specify which branch you want to pull from: git pull --rebase origin <branch-name>.Esdras
I haven't investigated, but I think this will only work correctly if only new commits have been added—rather than old commits being removed or changed. (Say, if one branch was rebased onto another, or the ordering of commits were changed.) Otherwise, you will end up re-adding the removed commits. I think that is the reason for needing git reset.Esdras
@NeilTraft Indeed that is why the accepted answer includes rebasing in interactive mode. This is also possible in case off pulling with rebase, so I've updated my answer. Reset is not necessary (it is one of the two options in the accepted answer).Malacology
M
21

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!

Mcglynn answered 29/8, 2013 at 16:32 Comment(3)
This is what I really wanted. Someone rebased the master branch (for god knows what reason) but I had no local changes on it that I wanted to commit or anything. So all I had to do was delete my local master branch (which felt really weird) and do a checkout again. Thanks!Centigrade
@peter-mortensen Edits should be substantial according to stackoverflow.com/help/editingMcglynn
for the the last step, you can also use git checkout -b base-branch origin/base-branch with git checkout --track origin/base-branchJakob
D
13

To fetch changes from the remote repository into your local repo:

git fetch --all

Rename the tracking branch:

git branch -m <old-branch-name> <new-name>

Create a new local branch tracking the remote branch:

git checkout <old-branch-name>
Dolmen answered 9/9, 2021 at 5:18 Comment(5)
I think command 3 should be git checkout <old-branch-name>, right?Katelin
@Katelin Yeah, it's the third. You just have to execute the commands in the same order as shown in the answer.Dolmen
without -b rightKatelin
@Katelin No -b is required to create a tracking branch (which tracks the changes of the remote branch that has the same name as <old-branch-name>).Dolmen
@Katelin Sorry you were right. -b flag is not required.Dolmen
B
1

TLDR:

git switch master
git pull
git branch -D featureBranch  // careful! FORCE DELETE
git switch featureBranch

So in your case the branches are already tracked locally. Make sure master is checked out. On master git pull is sufficient to update all your branches including your feature branch. You can have a look with git branch -vv to see the branch where a git push --force happened, you will see something like ...ahead 2, behind 7...

Now with git branch -D featureBranch you do a force delete of your local feature branch.

Last step: git switch featureBranch, which checks out the before pulled feature branch locally again and sets it up to track the remote branch.

Butta answered 15/5, 2023 at 8:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.