How should I indicate to git that changes are transient and shouldn't be committed?

Viewed 450

When maintaining a live system, I find that it is sometimes necessary to make ad-hoc temporary changes to files - changing logging levels, adding trace options to scripts etc.

When I do this, my semi-automated mechanisms for finding uncommitted changes and unmerged branches often show up false positives:

  • If I leave changes uncommitted, or just staged, then my checker script flags up the repo as dirty.
  • If I commit them as a "temporary changes commit", they get flagged up as 'changes ahead of the remote branch'
  • If I commit them on a new branch without a remote, they get flagged up as a 'branch without a remote'.

Normally, all of these are needed to find changes which haven't been merged up, but this also means that every way of 'hiding' temporary changes is blocked off too.

Note that I don't want to --assume-unchanged as the same file will often contain both temporary changes (which I don't want to be reminded about) and permanent changes (which I do), and looking through Handling temporary changes (not to be committed) in Git has no suggestions which address all of these requirements.

With Mercurial, I would look into using Mercurial Queues to get somewhere close to what I want. I would create a patch with my temporary changes, then if my analysis utility found a patch queue it would pop them, perform the analysis and then push them back. This would effectively remove only the temporary changes, perform the analysis on only the changes I haven't deemed temporary, and then re-apply those changes.

The trouble with any approach which changes the working directory is that this would affect the behaviour of the live system - for instance, our logging system checks for updates to the logging configuration every 10 seconds or so.

So, how can I best indicate to git that some changes are transient and shouldn't be committed and/or merged, while others should?

3 Answers

For each of those files, you can setup a clean script which will be in charge of restoring the original content of those file as they were initially checked out.
That script can simply perform a git checkout -- afile, in order to restore its content to HEAD (discarding any local changes).

The restoration of the file through that script is automated through a content filter driver, using a .gitattributes declaration.

https://i.stack.imgur.com/tumAc.png
(image from "Customizing Git - Git Attributes" from "Pro Git book"))

Once you declare that content filer driver in your local git config, it will automatically, on git commit, restore the file.
Or it will consider the file as unchanged on git diff/git status.

See a complete example in "Best practice - Git + Build automation - Keeping configs separate".

the same file will often contain both temporary changes (which I don't want to be reminded about) and permanent changes (which I do)

  • If I commit [the temporary changes] as a "temporary changes commit", they get flagged up as 'changes ahead of the remote branch'
  • If I commit them on a new branch without a remote, they get flagged up as a 'branch without a remote'.

If I were doing this with mercurial I would use Mercurial Queues to put insignificant changes into a patch, and pop it before analysis, pushing it back on afterwards.

Git's your servant. You decide what commits mean. Commit your changes and use Git to distribute the hunks so they have the most useful to you commit sequence[s] and boundaries. Keep insignificant changes in an "insignificant changes" commit, or have an "insignificant changes" branch, or whatever works best. Teach your checker to identify insignificant-changes commits.

From what you've given here a single ordinary "local" branch with a tip commit dedicated to config changes should do it, when you make a "significant" change, commit and use interactive or autosquash rebase to record the change behind the tip. Tell your checker to ignore anything in the local branch's tip; to update the local config, change it and git commit --amend --no-edit it, or if you goof and commit it separately then squash it with interactive rebase or equivalently just git reset --soft @~ and do the --amend --no-edit commit you meant to do. There's no need for special facilities, you get the full toolkit for whatever work you're doing. If there are commits regarded as particularly meaningful, put them someplace reserved for commits with that particular meaning.

A few shots in the dark, trying to read between the lines with your ultimate goal/use case. This depends on exactly what you are able/willing to change in either your system or the semi-automated "repo health" system you have.

  1. Modify the system so that the configuration items that you need to change have both a "master/default" config file, and an untracked local/user config file. Any settings in the user config override the defaults.

    • Advantage: You can update your "repo health" scripts to WARN you about existing temporary settings (without requiring action), either all the time, or after a certain amount of time, etc.
    • Advantage: No need to do anything in Git itself.
    • Disadvantage: No tracking of what these settings were over time.
  2. Use special branch names/extensions, or use special tags to capture temporary setting commits, and update your "repo health" scripts to ignore those branches/tags (or have it WARN you, rather than force something?).

    • Example - name the branches that capture these with something special (always start with "tempsetting-", end with ".tmp", etc.), or commit them with a tmp branch, then tag them (again, probably with some special naming convention).
    • Advantage: Your temporary settings are captured in the repo, if that is desired
    • Disadvantage: More to do here - need to actively manage more than just a config file or user settings, etc.
Related