0

My team squashes feature commits and rebases the primary branch to keep our history linear.

For this question let's say we have 3 branches

  • dev (default/primary)
  • prod (once the commits are verified we deploy using this branch. During a deployment we create a commit, so prod is then merged into dev)
  • my-feature
git checkout dev
git checkout -b my-feature
// do work
git commit -m "some work"
// another commit merges/is added to dev
git pull --rebase origin dev
git push origin HEAD

That last command pushes the current branch to the remove branch.

Now let's say I'm doing a deployment

git checkout prod

git status
On branch prod
Your branch is behind 'remotes/origin/prod' by 2 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean

git pull --rebase origin HEAD
From xxx
 * branch              HEAD       -> FETCH_HEAD
Successfully rebased and updated refs/heads/prod.

git status
On branch prod
Your branch is ahead of 'remotes/origin/prod' by 3 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

Why did git pull --rebase origin HEAD pull from the dev branch when I'm on the prod branch? Is that normal?

If I leave off HEAD I get what I expect (prod == origin/prod) git pull --rebase origin

I've noticed when I'm on my feature branch .git/HEAD holds the value I expect...

git checkout my-feature
cat .git/HEAD
ref: refs/heads/my-feature

git checkout prod
cat .git/HEAD
ref: refs/heads/dev

So the question is, why is HEAD different for the prod branch?

I frequently push my feature branch with git push -f origin HEAD, so I really don't want to find one day it's trying to push to our dev branch.

I don't think it should matter, but we use GitLab as our host.

This question is similar, but all of the top answers describe the reverse of what I'm experiencing

  • HEAD is just a special pointer that points to the local branch you’re currently on.
  • Head is your current branch
  • HEAD always refers to the most recent commit on the current branch.
  • HEAD is the "tip" of the current branch.
  • HEAD is a symbolic reference pointing to wherever you are in your commit history.

So the question stands, why does this happen:

git checkout prod
cat .git/HEAD
ref: refs/heads/dev
Graham Walters
  • 2,054
  • 2
  • 19
  • 30
  • 3
    Does this answer your question? [What is HEAD in Git?](https://stackoverflow.com/questions/2304087/what-is-head-in-git) – jonrsharpe Oct 30 '20 at 19:16
  • I would appreciate it if you could link to an answer instead of the question. The top two answers don't explain why HEAD would point to the wrong branch. The third answer echos what I expect to happen "HEAD is just a special pointer that points to the local branch you’re currently on." – Graham Walters Oct 30 '20 at 19:27
  • 1
    That's how the duplicate functionality works, it links to questions. You're expected to read through the answers yourself (and to do that research before posting). – jonrsharpe Oct 30 '20 at 19:29
  • I did go over that question before posting, but clearly git is doing something different or there's a bug in my version of git. Does that mean all those answers are wrong? – Graham Walters Oct 30 '20 at 19:36
  • 3
    "clearly git is doing something different or there's a bug in my version of git" Oh, I can think of more and likelier possibilities. Maybe you are just making some false assumptions. I mean, look, you're digging under the hood and looking directly at something you're not supposed to look at, making some assumptions about what it means, and then being surprised. What if those assumptions are wrong? The way to know what branch you are on is not to peer at the symbolic refs, it's to ask git in the normal way what branch you are on. You're on `prod`. – matt Oct 30 '20 at 20:31
  • That's great, but I know how to tell what branch I'm on...`git checkout prod`. It should be clear to everyone I'm on the prod branch. Now explain why HEAD refers to dev. – Graham Walters Oct 31 '20 at 03:49
  • What version of Git are you running? I wrote up an answer but then went back and checked your sequence of commands, and I think you may have found a bug in Git. – torek Oct 31 '20 at 05:54
  • I'm running git version 2.28.0 locally. The gitlab server is running Gitaly 13.5.1 with git 2.28.0. I just upgraded my local copy to version 2.29.2, but I get the same results. – Graham Walters Oct 31 '20 at 14:52

1 Answers1

1

Refer to concrete git references when using git commands that operate on multiple references. e.g. use dev instead of HEAD, if your intention is to do something with dev.

The HEAD file (and reference) is written to by git when you execute commands like git checkout (What is HEAD in Git?) , git rebase, etc, and can change meaning all of a sudden at gits behest.

HEAD will change meaning during git rebase because (in your case) git will check out dev (and write dev inside the HEAD file, even if you executed the command from prod) and cherry-pick all the commits from prod (And subsequent events according to the workings of git rebase https://git-scm.com/docs/git-rebase )

zrrbite
  • 1,180
  • 10
  • 22
  • Thanks for answering. Can you clarify why "git will check out dev" if I'm on the prod branch? My intention is for it to rebase the remote prod branch, so that's what's tripping me up – Graham Walters Oct 30 '20 at 21:37
  • Is `dev` and `prod` pointing to the same commit? Also, your command git pull --rebase origin dev` was executed from the `prod` branch, which is why git will modify `HEAD` during the `rebase` command. – zrrbite Oct 30 '20 at 21:55
  • Oh sorry, I get the confusion. I understand how `git pull --rebase origin dev` works. The issue is only for the deployment where I've checked out prod and I'm running `git pull --rebase origin HEAD`. In the example local prod is 2 commits behind remote prod and remote prod is 3 commits behind remote dev. Refer to the second code block in the question – Graham Walters Oct 30 '20 at 22:50