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.
How to force update when doing git pull? - Stack Overflow
version control - How do I force "git pull" to overwrite local files? - Stack Overflow
git - How can I pull updates from a force-pushed branch? - Stack Overflow
How to Perform a Git Force Pull?
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.
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
This should do the trick:
git reset --hard HEAD
git pull
git fetch
git checkout origin/name_of_branch # correct state but in 'head without a name'
git checkout -B name_of_branch # overwrite current tree onto name_of_branch
This checks out the remote tracking branch into a head without a name, then you can have a look and check you're happy. Whenever you want to (even after changes or commits) the second git checkout labels your current tree with 'name_of_branch', even if it has to delete the old name_of_branch to do so.
Edit: 'What a crazy command line syntax'
The syntax of git commands seems unintuitive. In fact it's the Git data model that is unintuitive. This isn't bad design, but because it works with files, branches, commits in ways that are much more flexible and powerful than other version control systems. Once you grok how these things work in Git, the command line will make a lot of sense and you will be able to accurately guess how to do complicated things.
git fetchThis fetches all the updates that have happened on theoriginserver since the last time. Git separates fetching from the server from updating, merging, etc. any of your branches. All the branches calledorigin/XXXare your most recent versions of what's on the server. They are not remote branches but remote tracking branches, local branches which track remote branches. When you dogit fetch, you update them, without touching any of your own branches. When you dogit merge,git rebase, and so on, you use the fetched version, without grabbing a more recent copy from the server. This means you have control over when network requests are made (if you aren't always connected to the server), and you can 'fetch' a snapshot of the server, then merge at your leisure. If in doubt, dogit fetchfirst.git checkout origin/name_of_branchgit checkoutdoes two things. It updates your files to that branch, and it sets yourHEADto that branch. The files things is what you'd expect. TheHEADthings means that when you do commits, they will added to the end of the branch thatHEADpoints to. IOW,checkoutdoes both output - write the right versions of the files, and prepares for input - gets ready to store the commits you are going to do in the right place. If you checkout a branch calledfoo, your tree changes to the state saved infoo, and the next commits you do will be added tofoo. In the case oforigin\xyz, you can't write your changes to anoriginbranch - these track what is on theoriginserver and can't be committed to directly. So the checkout updates the files, and setsHEADto nothing - an unnamed branch. This stops you accidentally committing your newly checked out stuff back onto the previous branch you were using, and in fact you will be heavily discouraged by git from committing at all until you have a destination branch.git checkout -B name_of_branchAs usual, when git does two different things with one command, both of them can be configured separately. So the second part of whatcheckoutdoes, settingHEADto the branch you want to commit to, can be to a new branch, instead of the branch you're checking out, if you use the-Boption. Sogit checkout -B new_stuff old_stuffwill set all your files to the state inold_stuff, but get you ready to write your commits to the new branchnew_stuff. This is a common task, and saves you checking out a branch then forking it, in two steps. Now, almost all arguments to git commands can be omitted, and git will do the most obvious thing. In this case, that is making a new branch based on the one you are on, rather than one you want to checkout. So git takes the unnamed branch you are on, and makes a new branch calledname_of_branch, which you can start committing to. Note that an uppper case letter "B" kind of means 'force'. If you used "-b" git would refuse to overwrite an already existing branch. With "-B" it will go ahead and do it without warning or confirming.
I was able to pull changes from origin/master into master while working in another branch by using this command:
git fetch origin master:master
For a deeper dive into what's going on, check out the excellent answer to this Stack Overflow question. The main take-away for me was that this command only works for a fast-forward merge.
You can use git stash before checking out master and pulling, and after checking out live again use git stash pop (or if your git is older, git stash apply and git stash clear assuming you haven't stashed anything else)
⚠ Warning:
Any uncommitted local change to tracked files will be lost, even if staged.
But any local file that's not tracked by Git will not be affected.
First, update all origin/<branch> refs to latest:
git fetch --all
Backup your current branch (e.g. main):
git branch backup-main
Jump to the latest commit on origin/main and checkout those files:
git reset --hard origin/main
Explanation:
git fetch downloads the latest from remote without trying to merge or rebase anything.
git reset resets the master branch to what you just fetched. The --hard option changes all the files in your working tree to match the files in origin/main.
Maintain current local commits
[*]: It's worth noting that it is possible to maintain current local commits by creating a branch from main before resetting:
git checkout main
git branch new-branch-to-save-current-commits
git fetch --all
git reset --hard origin/main
After this, all of the old commits will be kept in new-branch-to-save-current-commits.
Uncommitted changes
Uncommitted changes, even if staged (with git add), will be lost. Make sure to stash or commit anything you need. For example, run the following:
git stash
And later (after git reset), reapply these uncommitted changes:
git stash pop
Which may create merge conflicts.
This will remove all uncommitted changes, even if staged,
and then pull:
git reset --hard HEAD
git pull
But any local file that's not tracked by Git will not be affected.