git fetch
writes the references it fetches to .git/FETCH_HEAD
(one per line). If the upstream branch is set, the corresponding reference is marked for merging. FETCH_HEAD
is the reference (i.e. the remote-tracking branch) marked for merging if the upstream branch is set, or the first reference in .git/FETCH_HEAD
otherwise.
Basically after git fetch
(or git pull
) FETCH_HEAD
points to the tip of the upstream branch, that you want to merge or rebase onto.
The relevant docs:
The names of refs that are fetched, together with the object names they point at, are written to
.git/FETCH_HEAD
. This information may be used by scripts or other git commands, such as git-pull[1].
https://git-scm.com/docs/git-fetch#_description
it tells
git fetch
the default refspec to be marked for merging inFETCH_HEAD
https://git-scm.com/docs/git-config#Documentation/git-config.txt-branchltnamegtmerge
FETCH_HEAD
records the branch which you fetched from a remote repository with your last
git fetch
invocation.
https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-codeFETCHHEADcode
a.bats
:
strict() { set -euo pipefail; shopt -s inherit_errexit; "$@"; }
setup() {
[ "$BATS_LIB_PATH" = /usr/lib/bats ] && BATS_LIB_PATH=$HOME/.bats/lib:$BATS_LIB_PATH
bats_load_library bats-support
bats_load_library bats-assert
strict
}
# the state of the cloned repository (2 commits, 1 local branch ba)
# a (origin/ba) --- b (HEAD -> bb, origin/bb)
@test ".git/FETCH_HEAD contains all the fetched refs" {
start_cloned_repo
git fetch
assert_equal "`cut -f1 .git/FETCH_HEAD | sort`" \
"`
git show-ref \
| awk '{p = "^refs/remotes/origin/"} $2 ~ p' \
| grep -Fv '/HEAD' \
| cut -f1 -d' ' \
| sort
`"
}
@test "first comes the ref that corresponds to the upstream branch" {
start_cloned_repo
git fetch
assert_equal "`head -1 .git/FETCH_HEAD | cut -f1`" \
"`git rev-parse bb`"
}
@test "the first ref is marked for merging if the upstream branch is set" {
start_cloned_repo
git fetch
assert_equal "`cut -f2 .git/FETCH_HEAD`" \
$'\nnot-for-merge'
}
@test "no refs are marked for merging if no upstream branch is set" {
start_cloned_repo
git branch --unset-upstream
git fetch
assert_equal "`cut -f2 .git/FETCH_HEAD`" \
$'not-for-merge\nnot-for-merge'
}
@test "FETCH_HEAD is the first ref in .git/FETCH_HEAD if the upstream branch is set" {
start_cloned_repo
git fetch
assert_equal "`git rev-parse FETCH_HEAD`" \
"`head -1 .git/FETCH_HEAD | cut -f1`"
}
@test "FETCH_HEAD is the first ref in .git/FETCH_HEAD if no upstream branch is set" {
start_cloned_repo
git branch --unset-upstream
git fetch
assert_equal "`git rev-parse FETCH_HEAD`" \
"`head -1 .git/FETCH_HEAD | cut -f1`"
}
start_cloned_repo() {
(mkrepo)
cd "$BATS_TEST_TMPDIR"
git clone a b
cd b
}
mkrepo() {
cd "$BATS_TEST_TMPDIR"
mkdir a
(cd a
git init
git branch -m ba
git config user.email [email protected]
git config user.name "Your Name"
git commit --allow-empty -m a
git checkout -b bb
git commit --allow-empty -m b)
}
$ docker run --rm -itv "$PWD":/app -w /app alpine:3.21
/ # apk add git bash ncurses
/ # git clone https://github.com/bats-core/bats-core ~/.bats
/ # git clone https://github.com/bats-core/bats-support ~/.bats/lib/bats-support
/ # git clone https://github.com/bats-core/bats-assert ~/.bats/lib/bats-assert
/ # ~/.bats/bin/bats .