Github let's you overwrite on protected branch when freshly pulled repo clone

I don’t think --force means what you think it means.

Here is where your repository was:

Here is where your repository went to:

This is the difference:

If you look at the commits list for where you are now, you’ll see that the parent is where you were before.

--force is used for when you’re asking git to effectively remove commits from the chain leading up to a point.

You aren’t doing that, and thus --force was ignored.

Say you had:

as your HEAD, and you tried pushing (don’t do this, test either in a pair of local repositories, or in some unrelated test repositories in your user’s space). By default w/o --force, you’d get an error:

Here’s a long chain of commands that you could try to follow to understand what’s happening in the basic cases:

% cd $(mktemp -d); git init a; (cd a; touch a; git add a; git commit -m a); git clone a b; (cd b; git checkout -b ignore-this); git clone a c; (cd c; git checkout -b ignore-this); (cd a; echo a >> a; git add a; git commit -m A; git checkout -b ignore-this; git fetch ../b; git push ../b main); for a in *; do (cd $a; echo $a; git log main --oneline); done; (cd c; git fetch ../b; git push ../b main; echo 'well that did not work -- try forcing it!'; git push ../b main --force); for a in *; do (cd $a; echo $a; git log main --oneline); done
Initialized empty Git repository in /private/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.UlNnUFSW/a/.git/
[main (root-commit) 639fd66] a
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a
Cloning into 'b'...
done.
Switched to a new branch 'ignore-this'
Cloning into 'c'...
done.
Switched to a new branch 'ignore-this'
[main a60c634] A
 1 file changed, 1 insertion(+)
Switched to a new branch 'ignore-this'
From ../b
 * branch            HEAD       -> FETCH_HEAD
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 240 bytes | 240.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To ../b
   639fd66..a60c634  main -> main
a
a60c634 (HEAD -> ignore-this, main) A
639fd66 a
b
a60c634 (main) A
639fd66 (HEAD -> ignore-this, origin/main, origin/HEAD) a
c
639fd66 (HEAD -> ignore-this, origin/main, origin/HEAD, main) a
From ../b
 * branch            HEAD       -> FETCH_HEAD
To ../b
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '../b'
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.
well that did not work -- try forcing it!
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To ../b
 + a60c634...639fd66 main -> main (forced update)
a
a60c634 (HEAD -> ignore-this, main) A
639fd66 a
b
639fd66 (HEAD -> ignore-this, origin/main, origin/HEAD, main) a
c
639fd66 (HEAD -> ignore-this, origin/main, origin/HEAD, main) a

Admittedly, the GitHub docs on allow-force-push are not end-user resilient, but I don’t have the energy to fix them.
https://docs.github.com/en/github/administering-a-repository/defining-the-mergeability-of-pull-requests/about-protected-branches#allow-force-pushes

1 Like