Track files without including them in the commits

Viewed 64

So it happened a couple of times when I would be working on connected projects that this scenario took place:

  1. I would make a minor change to one of the config files or comment out something in a file am not tracking to test stuff.
  2. Forget to revert the changes.
  3. Come back after a while to test things that work with the initial version of the file.
  4. Waste lots of time debugging to find out step 2 was the problem.

Now I was wondering, is it possible to track some files but automatically ignore them when committing ? Think of it as a more lenient version of the .gitignore where I can choose some files to track while am developing locally, but they would never be committed. I was thinking I could make a script that unstages those specific files in the then runs the commit. However, is there something I should be paying attention to ? Or perhaps there's already a way my quick search didn't pick up?

3 Answers

Keep a template for a configuration file in source control. When it comes time to actually configure a service, edit a copy of the template to provide a valid configuration. The actual configuration file never gets tracked.

The painless, non-special, straight forward way to do this is to track test stuff by creating separate commits for this, with a commit message having a format that stands out clearly.

What I do is to check in such changes with commit messages on the format "==== ...details... ====". No normal commits have these equal sign pre/post-fixes, so with this it is simple to remove them with interactive rebase before doing a final merge.

Example:

Say you add a console.log statement for debugging but this is not something you want to push in the end when you are finished, but for now you want to have it present. Solution: Add that console.log statement as its own commit and check in with commit message "==== added debug in somefile.ts ====.

Say you have some untracked files in the repository that are local to you only (draft emails, file copies, log files or whatever) and not something other team members should have their .gitignore polluted with. But those files represent noise for you when running git status and prevents using git add . etc. Solution: Add all your untracked files to .gitignore and check in with commit message "==== my local .gitignore ====".

Say you want to temporarily limit unit tests to just the ones that are relevant to the part you are working on (e.g. fdescribe using jasmine). Solution: Check in that as "==== fdescribe some-thing.spec.ts ====" (be a bit careful with excluding tests like this and ALWAYS run git-test on all the commits on the branch without excluding any tests before the end).

In this example imagine that the branch ends up with the following commits in the end:

pick 100001 Created somefile.ts
pick 100002 Moved stuff from otherfile.ts to somefile.ts
pick 100003 ==== added debug in somefile.ts ====
pick 100004 Fix for some bug detected
pick 100005 ==== my local .gitignore ====
pick 100006 Add unit tests for something
pick 100007 ==== fdescribe some-thing.spec.ts ====
pick 100008 Delete no longer used function

Se how trivial it is to clean up every single bit of "test stuff" with zero mental effort required? (remember running git-test on this branch)

pick 100001 Created somefile.ts
pick 100002 Moved stuff from otherfile.ts to somefile.ts
pick 100004 Fix for some bug detected
pick 100006 Add unit tests for something
pick 100008 Delete no longer used function

The benefits of committing all such test stuff as normal commits are that they are not hidden and they receive all of git's normal benefits:

  • They can be cherry-picked.
  • They can be rebased.
  • They can quickly be temporary disabled with git revert.
  • They could eventually be shared with other people (they just need to be aware with your naming convention).
  • Should they be accidentally be pushed to upstream branches they stick out as a sore thumb and can easily be identified and reverted.

And there is no git repo specific configuration!


But I might get rebase conflicts when I remove those commits in an interactive rebase!

Use my script git-resolve-conflict-using-kdiff3. KDiff3 automatically resolves lines removed next to lines above/below that are changes (and if manual conflict resolution should be required KDiff3 is an awesome tool to use for that as well).

What you want here is to enable --skip-worktree bit for the configuration file.

First, ensure that git tracks the file existence by committing it at least once:

% git add Config.file
% git commit -m 'Configuration added'

Then flip the --skip-worktree bit:

% git update-index --skip-worktree Config.file

From this point forward all changes you make to the file will be ignored by git.

In order to see the changes and restore the file you can get use of the following git aliases:

[alias]
    diffsw = !git update-index --no-skip-worktree $1 && git diff -- $1 && git update-index --skip-worktree $1 && :
    restoresw = !git update-index --no-skip-worktree $1 && git restore -- $1 && git update-index --skip-worktree $1 && :

The first one shows the changes of the untracked file and can be used like this:

% git diffsw Config.file

The second one restores the file to the state it was last time commited:

% git restoresw Config.file

P.S. This, however, affects only local repo, you cannot push this bit.

Related