Fast-forward, rebased, or merged: how a pull lands
A pull that brings something in lands in one of three ways, and Git names each. Which one you get depends on whether you had commits of your own, and on whether you asked for a rebase.
Fast-forward: you had nothing new
$ git pull
From ../origin
ab5768d..7a20dd4 main -> origin/main
Updating ab5768d..7a20dd4
Fast-forward
api.py | 1 +
1 file changed, 1 insertion(+)
The fetch reports the remote's move, old tip to new with two dots: the new tip follows from the old. Your
main was at the old one with nothing of its own, so Git simply moves it there:
Updating, Fast-forward, and the files that changed. No new commit is made, and your
history is now exactly the remote's. It is the same move a push needs, seen from the other side (the
non-fast-forward page).
Rebased: you had commits, and asked for a rebase
$ git pull --rebase Successfully rebased and updated refs/heads/main. $ git push To ../origin.git 7a20dd4..febe3f7 main -> main
You had a commit the remote didn't. --rebase takes it off, moves main to the
remote's tip, and replays your commit on top:
Successfully rebased and updated refs/heads/main. Your commit's hash changes, since it has a new
parent, and the history stays one straight line. The push after it is a fast-forward for the remote. If the
replay hits a line both commits changed, it stops on a conflict instead.
Merged: you had commits, and didn't ask
$ git pull --no-rebase Merge made by the 'ort' strategy. api.py | 1 + 1 file changed, 1 insertion(+) $ git push To ../origin.git 7a20dd4..31ac6fe main -> main
Without --rebase, Git keeps both histories and ties them with a merge commit:
Merge made by the 'ort' strategy. (ort is the name of Git's merge engine.) Your
commit keeps its hash, and the history forks and rejoins. The push sends two commits, yours and the merge.
Which of the two to prefer is a team's policy; Git only insists that you choose, the first time the branches
diverge, and remembers the choice in pull.rebase.
Why the game does this to you
The pack's pull is Git's. With nothing of yours it fast-forwards, even under --rebase, and the
day log prints Fast-forward; with commits of yours it rebases or merges as the op says. In
Git Game a plain pull costs one op and a rebase two, and a plain pull that merges something of yours takes a
merge token, one of the game's three penalty tokens. A fast-forward takes none, because Git makes no merge
commit.
Play a day where this happens
One tap starts a game against the bot, and the hub shows what your pull would do before you send it.
Output captured from Git 2.50.1 (Apple Git-155) by scripts/git-output.sh, in a scratch repository with two clones, ana's and bot's, and fixed dates, so the hashes are the same on every run. It is captured again at every Git release.