How to restore a branch after someone did a git push --force
You are sharing a branch with another developer and this developer did a git push --force and you want to resume work on that branch without losing your local commits.
The initial setup is as follows:
- A branch
b1
has been created out ofmain
. b1
has been pushed to the remote repository.- Both Alina and Blake are working on that branch.
- New commits were pushed on
main
.
There is only one file being edited: file.txt
.
The commit tree is as follows:
On main
, when the branch b1
was created, the file was at commit a9e37e2
.
A
After the branch b1
was created, the file on main
was changed to commit 417701d
.
A:1
X:24
Alina changes the file on b1
to commit 91c8e94
.
A
B
Alina and Blake are both working on that branch from that initial state.
Alina does a git rebase
Alina decides to rebase the branch b1
on main
in order to sync with the latest changes on main
.
alina
alina git:( b1 ) git rebase origin/main
Rebasing (1/1)
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
error: could not apply 91c8e94... add line B
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 91c8e94... add line B
alina █
Due to the incompatible changes between the two branches, the rebase fails with a conflict and Alina must resolve the conflict manually.
Alina edits the file file.txt
and resolves the conflicts by removing the markers while fixing the content:
alina
alina git:( b1 ) cat file.txt
A:1
B
X:24
alina git:( b1 ) █
Alina then finishes the rebase.
alina
alina git add file.txt
alina git rebase --continue
Successfully rebased and updated refs/heads/b1.
alina git:( b1 ) █
Because Alina performed a rebase, she must do a push --force
to update the remote branch.
alina
alina git:( b1 ) git push --force
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 279 bytes | 279.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a new pull request for 'b1':
remote: http://localhost:3030/gitpowerup/arenas/compare/main...b1
remote:
remote: . Processing 1 references
remote: Processed 1 references in total
To ssh://remote.mygit.com/gitpowerup/arenas.git
+ 91c8e94...0f6f7bf b1 -> b1 (forced update)
alina git:( b1 ) █
And Alina’s commit graph is now:
On the server, the commit graph is:
back to Blake
Blake, who is also working on the branch b1
, changes the file file.txt
to be:
A
B
C
And commits the change.
blake
blake git:( b1 ) git add file.txt
blake git:( b1 ) git commit -m 'add line C'
[b1 9c5b6bd] add line C
1 file changed, 1 insertion(+)
blake git:( b1 ) █
But when she tries to push her change, she gets an error.
blake
blake git:( b1 ) git push
To ssh://remote.mygit.com/gitpowerup/arenas.git
! [rejected] b1 -> b1 (fetch first)
error: failed to push some refs to 'ssh://remote.mygit.com/gitpowerup/arenas.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
blake git:( b1 ) █
Blake syncs up her local with a git fetch
.
blake
blake git:( b1 ) git fetch --all
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 259 bytes | 129.00 KiB/s, done.
From ssh://remote.mygit.com/gitpowerup/arenas
+ 91c8e94...0f6f7bf b1 -> origin/b1 (forced update)
blake git:( b1 ) █
A git status
shows the divergence between her local branch b1
and the remote branch b1
:
blake
blake git:( b1 ) git status
On branch b1
Your branch and 'origin/b1' have diverged,
and have 2 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
blake git:( b1 ) █
Blake’s commit graph is:
Blake:
- Has 2 commits that are not on the remote branch
b1
:9c5b6bd
and91c8e94
. - Is missing the 2 commits that are on the remote branch
b1
:0f6f7bf
and417701d
.
Git suggests performing a git pull
:
blake
blake git:( b1 ) git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
blake git:( b1 ) █
Blake can either merge or rebase her commits onto the remote branch b1
. She could also have done a git reset --hard
to fully reconcile her local branch b1
with the remote branch b1
, but she would have lost her local commits.
Blake performs a rebase.
blake
blake git:( b1 ) git pull --rebase
Rebasing (1/1)
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
error: could not apply 9c5b6bd... add line C
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 9c5b6bd... add line C
blake █
There is also a conflict as git doesn’t know how to add the line C
in the file file.txt
.
Blake resolves the conflict by editing the file file.txt
to be:
alina
alina git:( b1 ) cat file.txt
A:1
B
C
X:24
alina git:( b1 ) █
Blake finishes the rebase.
blake
blake git add file.txt
blake git rebase --continue
Successfully rebased and updated refs/heads/b1.
blake git:( b1 ) █
Blake can now push her changes.
blake
blake git:( b1 ) git status
On branch b1
Your branch is ahead of 'origin/b1' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
blake git:( b1 ) git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 281 bytes | 281.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a new pull request for 'b1':
remote: http://localhost:3030/gitpowerup/arenas/compare/main...b1
remote:
remote: . Processing 1 references
remote: Processed 1 references in total
To ssh://remote.mygit.com/gitpowerup/arenas.git
0f6f7bf..9336d1f b1 -> b1
blake git:( b1 ) █
Blake’s commit graph is now:
back with Alina
Alina can now retrieve Blake’s change.
alina
alina git:( b1 ) git fetch --all
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 261 bytes | 130.00 KiB/s, done.
From ssh://remote.mygit.com/gitpowerup/arenas
0f6f7bf..9336d1f b1 -> origin/b1
alina git:( b1 ) git pull
Updating 0f6f7bf..9336d1f
Fast-forward
file.txt | 1 +
1 file changed, 1 insertion(+)
alina git:( b1 ) █
Alina’s commit graph is now in sync with Blake’s.
And now they have the same file.txt
.
alina
alina git:( b1 ) cat file.txt
A:1
B
C
X:24
alina git:( b1 ) █
Alina goes back to the main
branch.
alina
alina git:( b1 ) git switch main
Switched to branch 'main'
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
alina git:( main ) █
Where the file file.txt
is still in its original content.
alina
alina git:( main ) cat file.txt
A
alina git:( main ) █
The git status
indicates that the local main
branch is behind the remote main
branch by 1 commit.
alina
alina git:( main ) git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
alina git:( main ) █
Alina syncs up the local branch.
alina
alina git:( main ) git pull
Updating a9e37e2..417701d
Fast-forward
file.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
alina git:( main ) █
The content is now updated.
alina
alina git:( main ) cat file.txt
A:1
X:24
alina git:( main ) █
As the branch b1
has been rebased on top of main
, a fast-forward merge is possible.
alina
alina git:( main ) git merge --ff-only origin/b1
Updating 417701d..9336d1f
Fast-forward
file.txt | 2 ++
1 file changed, 2 insertions(+)
alina git:( main ) █
That command brings the new commit graph on Alina’s machine.
And now the last content of file.txt
is available.
alina
alina git:( main ) cat file.txt
A:1
B
C
X:24
alina git:( main ) █