Git get working copy SHA

I have a git repo that contains

  • master (production ready)
  • development (reasonably stable development
    branch)

We are working with feature branches and in general follow gitflow.

We have quite a few production servers that are running a specific SHA/commit of master, they are not all running the same one, since it is different clients that have different needs with regards to updates.

Those same clients also have test servers on which they like to trial new functionality from the development branch. This is seldom HEAD. But rather often a more robust commit in development where we have made some additional effort in making sure the software is ready to be seen by customers (so an Alpha/Beta version, but not a raw development version).

Since we have quite a few servers we have automated deployment script that deploys a specific commit to a server.

In raw git commands it would be something like the below (very simplified)

Date X

client A test server (already on development branch):

git pull --rebase
git checkout <SPECIFIC_ALPHA_BETA_SHA> .

now client A is testing and trialing and 1 month goes by and now client B asks for a new trial release

Date X + 1 month (or so)

client B test server (already on development branch):

git pull --rebase
git checkout <SPECIFIC_ALPHA_BETA_SHA_LATER_THAN_CLIENT_A> .

Question

Is there any way I can get the working copy SHA for actual files checked out?

git rev-parse HEAD does not work since it is reporting the actual revision of HEAD, not the files that are checked out.

So if we assume that on git pull / git checkout time (keeping the SHA numerical here just to make is easier to illustrate in what order they came)

HEAD = 999
ALPHA_BETA TRIAL = 900

git pull --rebase (now at 999)
git checkout 900 .

if I use
git rev-parse HEAD

It will give me 999

What I would like is 900.

Is there a git command that will give the the revision of the checked out files?

Background

We have fairly recently moved from Subversion to Git so this question is affected by previous practices in Subversion and possible misconceptions on how Git works.

For client “demo/test” servers we previously used a revision number as a TAG rather than actually tagging in Subversion (since tagging for each client install would lead to us having 100’s of tags). As part of the deployment of a given “revision/commit/TAG”, this revision was stamped in a version file.

Now we have moved to git, and the clients still request frequent updates of their “demo/test” systems. We have not wished to track an update of the “demo/test” system as a tag/release, but wanted to continue to use the “revision/SHA” as a tag.

When stamping the revision in the version file we do not to take this value from the parameter input to the deployment script since the deployment script is not “transaction safe”, and an fatal error might leave the repository in one revision and the version file stating another revision. So to make sure the version file reported the actual “revision” of the files on the filesystem, we have previously asked the revision control system to give us the workingcopy current “revision number”.

This question is asking how to do this in Git.

  • Starteam to SVN migration, alternatives to Polarion?
  • git (any SCM) and compiling object files, switching branches, physiology thereof
  • Should .nuget folder be added to version control?
  • Best practice for versioning .swf file
  • Mercurial branching and merging without having to push branch
  • Very long-historied file in Git repo suddenly has blank log and is invisible to “git status”
  • Split svn2git in multiple revisions
  • .gitignore not working after adding it to already modified repo.
  • 4 Solutions collect form web for “Git get working copy SHA”

    There are a number of ways to achieve what you are looking to do. Probably the most “gitish” would be to use tags, and it makes sense to do this. From your description, different clients are running different “releases” of the software (each release identified by a SHA).

    Any attempt to record the SHA elsewhere is liable to bit-rot, lost bits of paper, and so on. Tagging allows you to keep the information that “this was ALPHA_BETA_TRIAL_1” tightly associated with the SHA in the git repository. That way it travels with the code as other machines/users clone or fetch updates over time. And it’s a lot easier to look back in a one-line log to find the relevant commit.

    Thus

    $ git tag -a -m "ALPHA_BETA_TRIAL_1" ALPHA_BETA_TRIAL_1
    $ git push --tags
    

    marks your upstream (from which clients clone) clearly for all to see.

    If you really need the SHA, then

    $ git show-ref ALPHA_BETA_TRIAL_1
    

    is all it takes.

    If, instead, you record the revision information in the commit messages, you can use

    $ git log --grep="Revision\:" --oneline --decorate
    

    to get a log of only those commits with the string “Revision:” in their commit message. The “oneline” and “decorate” commands will provide a nice dense log output which gives the short SHA, commit summary, and any associated tags for each commit which matches the pattern.

    If I’m interpreting the question right, what you’re doing with the git checkout $SPECIFIC_ALPHA_BETA_SHA -- . is an unrecorded merge, using the merge strategy “overwrite from every current file in the upstream history while ignoring deletions from it”. Git doesn’t have its own name for that strategy, so what? It’s easy, you’re already doing it, the only thing left is to record it properly:

    # Merge from $SPECIFIC_ALPHA_BETA_SHA using our own merge strategy:
    git merge -s ours --no-commit $SPECIFIC_ALPHA_BETA_SHA
    
    # our merge strategy:
    git checkout $SPECIFIC_ALPHA_BETA_SHA -- .
    
    # commit the result
    git commit -m "Incorporating upstream"
    

    and now git’s toolkit always knows where to look for relevant commits.

    Save yourself some typing on a very popular set of log options, do

    git config --global alias.lgdo 'log --graph --decorate --oneline'
    

    (--global doesn’t make a systemwide alias, it’s just you, but you can use it anywhere)

    Various ways to list commits that have affected the content of a checked-out path:

    git lgdo -1 --no-merges -- path/to/file  # last ordinary commit affecting path
    git lgdo --no-merges -- path/to/file     # all ordinary commits affecting path
    git lgdo -- path/to/file                 # above, plus full merge history
    
    # ordinary commits as above plus all searched commits w/ branch or tag names
    git lgdo --no-merges --simplify-by-decoration -- path/to/file
    

    Though that’s barely even a start on the ways you can hunt down content changes I’m thinking one or more of those will serve here.

    For a perhaps likelier possibility, where each client is maintaining a private branch based off one of the upstream branches, you don’t want git pull --rebase because it rebases onto the tip of the fetched branches. Instead,

    git fetch                             # just fetch
    git rebase $SPECIFIC_ALPHA_BETA_SHA   # rebase to specific stable commit
    git merge-base @ @{u}                 # show where my history meets upstream's
    

    To get a little fancier with that last command you could

    git log --oneline --decorate -1 $(git merge-base @ @{u})
    

    which will show you the merge base’s commit subject and any tags or other references on that commit.

    Just thought I would share what has ended up working for us, after some trial and error, based on the input here.

    On the individual client server, when we want to target a specific revision for the build script we make a new “local” branch on that server.

    If the revision/commit we are interested in is 7d65769ae9ba4ac9f92349feca8be3c70aacfcd6 then we run the following command

    git checkout -b 7d65769ae9ba4ac9f92349feca8be3c70aacfcd6 7d65769ae9ba4ac9f92349feca8be3c70aacfcd6
    

    This gives us a local branch where the latest revision number is 7d65769ae9ba4ac9f92349feca8be3c70aacfcd6

    Now running

    git rev-parse --abbrev-ref HEAD
    

    returns the expected revision/commit (7d65769ae9ba4ac9f92349feca8be3c70aacfcd6 – obviously), so the build script runs. We do not add any remote tracking (since there is no remote equivalent branch, and we do not push this local branch to origin) thus we are not polluting the remote/origin with branches or tags which essentially is a pointer to a client specific test install.

    So in conclusion – a combination of

    git checkout -b <commitSHA> <commitSHA>
    git rev-parse --abbrev-ref
    

    Gives the same results as the old subversion commands

    svn up -r <revisionNumber>
    svn info -R | grep "Revision\:" | sort -k2nr | head -n1
    (get revision info recursively, order by revision number desc, limit 1)
    

    Thank you to all that took the time to answer.

    Git Baby is a git and github fan, let's start git clone.