4

I am developing an internal web application for a company I am doing some work for. It is hosted on a private github repository, but most of my development is done on my linux desktop at home, and the web server for this is hosted in the companies office on a small raspberry pi. It is essentially nginx front end proxying the /api url to a nodejs application supported by pm2.

I deploy by git pushing to the github repository from my home and git pulling the production branch in the server. A git hook post-commit script runs a npm install in a build directory before temporarily stopping the production api server, copying over the node_modules directory and running a script which in essence does git describe --abbrev=0 --tags to get and store the version number in a .env file for the production server to announce its version to clients.

If I run git describe at home it gives version v4.2.2, but in the clinic I get v4.1.17 and I cannot see why

In the image below the left hand part is the output of gitk --all on my home repository and with only terminal access in the clinic, you can see from the right hand part pretty much the same graph using git log - with commits missing that are not relevant to either the master or production branch. v4.2.2 is only two commits away, whereas v4.1.17 is at least 10 away.

Why is git describe behaving the way it is?

EDIT: I sort of know the answer - on the server there is a post-commit hook that ended up making a commit on the branch, even though it wasn't supposed to - it was only supposed to be doing it on the development machine.

Composite gitk graph from my git repo

akc42
  • 4,893
  • 5
  • 41
  • 60
  • @TTT, when [`git describe`](http://git-scm.com/docs/git-describe) outputs `v4.1.17-34-g4c13fe5c` it is describing a commit 34 commits after tag `v4.1.17` at commit hash `4c13fe5c`. See the last section of [this answer](https://stackoverflow.com/a/23809024/354577), for example. – ChrisGPT was on strike Sep 21 '21 at 21:02
  • 1
    This likely has to do with how Git orders parents in merge commits. I'm not sure if `git describe` always follows the first parent or something? Will dig into the documentation and see what I can find. – ChrisGPT was on strike Sep 21 '21 at 21:05
  • @chris - that is only the last few days - this project goes back to 2013, with a proper start in late 2016 – akc42 Sep 21 '21 at 21:26
  • This doesn't answer your question, but it might help solve your problem. Perhaps if you change your describe command on the server to specify `origin/production` (or `@{u}`) you'll at least get the tag you want. – TTT Sep 21 '21 at 21:27
  • @TTT interesting that seems to work - but why – akc42 Sep 21 '21 at 21:29
  • @akc42 Your machine is on `origin/production` since that's what you pushed. So we can assume that if the server runs `describe` against `origin/production` it will get the same thing. The server's local `production` branch is ahead of `origin/production`, so it isn't searching the exact same thing, and it's getting a different result. I don't know enough about how describe works to know why the extra merge commit causes it to prefer a different path in its search. – TTT Sep 21 '21 at 22:16
  • 1
    Side note, maybe the cause of the problem is that you intended the server local `production` branch to be the same as your home branch, but it isn't. So every time it does a pull it's making a new merge commit. Maybe the server should push out its version (if you want to keep that), or, maybe the server should get the latest with a `git fetch && git reset --hard @{u}` instead of with `git pull`. (If the server shouldn't be making it's own commits.) – TTT Sep 21 '21 at 22:23
  • 1
    It's very hard to, um, describe, how `git describe` really works. But a brief comment to @Chris, `git describe` doesn't just follow first-parent by default; see [this question](https://stackoverflow.com/q/4154485/1256452) and its answers. – torek Sep 22 '21 at 06:08
  • 2
    @TTT you nailed the problem. I had a bug in my build script a few versions ago that was making a commit of its own on the production server- should have only being doing that on my development environment. The git reset --hard origin/production fixed it – akc42 Sep 22 '21 at 06:16
  • @akc42 Could you try this command on the server? It might tell us how far away it thinks tag 4.2.2 is: `git describe --tags --debug 4c13f35c` (I specified the commit ID since I'm guessing you already reset by now. It should still know about that commit though.) – TTT Sep 22 '21 at 15:17
  • 1
    @TTT I have completely sorted stuff now by doing a hard reset to origin/production. I sort of know the answer to your question as I already did that. If I remember 4.1.17 was 34 commits away, whilst 4.2.2 was in the 70s. – akc42 Sep 23 '21 at 18:42

2 Answers2

0

answered by @TTT in his comment :

maybe the cause of the problem is that you intended the server local production branch to be the same as your home branch, but it isn't. So every time it does a pull it's making a new merge commit. Maybe the server should push out its version (if you want to keep that), or, maybe the server should get the latest with a git fetch && git reset --hard @{u} instead of with git pull. (If the server shouldn't be making it's own commits.)

LeGEC
  • 46,477
  • 5
  • 57
  • 104
0

Git 2.40 (Q1 2023), clarifies what you must do for environment variables set when hooks are invoked.
That would help git describe to behave as expected in a hook.

See commit 772f8ff (09 Jan 2023) by Eric Sunshine (sunshineco).
(Merged by Junio C Hamano -- gitster -- in commit fc2735f, 21 Jan 2023)

githooks: discuss Git operations in foreign repositories

Signed-off-by: Eric Sunshine
Acked-by: Jeff King

Hook authors are periodically caught off-guard by difficult-to-diagnose errors when their hook invokes Git commands in a repository other than the local one.
In particular, Git environment variables, such as GIT_DIR and GIT_WORK_TREE, which reference the local repository cause the Git commands to operate on the local repository rather than on the repository which the author intended.
This is true whether the environment variables have been set manually by the user or automatically by Git itself.
The same problem crops up when a hook invokes Git commands in a different worktree of the same repository, as well.

Recommended best-practice$ for avoiding this problem is for the hook to ensure that Git variables are unset before invoking Git commands in foreign repositories or other worktrees:

unset $(git rev-parse --local-env-vars)

However, this advice is not documented anywhere.
Rectify this shortcoming by mentioning it in githooks.txt documentation.

See also:

githooks now includes in its man page:

Environment variables, such as GIT_DIR, GIT_WORK_TREE, etc., are exported so that Git commands run by the hook can correctly locate the repository.

If your hook needs to invoke Git commands in a foreign repository or in a different working tree of the same repository, then it should clear these environment variables so they do not interfere with Git operations at the foreign location.

For example:

local_desc=$(git describe)
foreign_desc=$(unset $(git rev-parse --local-env-vars); git -C ../foreign-repo describe)
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250