2

There's a project I'm working on that accesses an FTP server to upload an image. When developing locally, it can't access the FTP server as it is only accessible within a certain virtual private cloud.

In order to test it locally, I need to rewrite parts of the code to skip the FTP upload. The obvious answer would be to add some kind of check for an environment variable or something, and have it upload or not upload depending on the environment. However, when I've asked for permission to make this change, it has been consistently put off due to being low priority.

The problem is, I know that eventually I'm going to make these temporary changes and then accidentally commit them. I've done it once before but luckily realized my mistake in time to revert the changes.

Is there any way that I can make the necessary temporary changes, and then immediately git prevent-commit filename.php or something like that on the related files, so that git yells at me if I try to commit those changes in the future, or something along those lines?

GChuf
  • 1,135
  • 1
  • 17
  • 28
Michael
  • 1,075
  • 1
  • 10
  • 24
  • Write the filename in .gitignore – David Yappeter Jan 18 '22 at 04:33
  • I don't want to ignore the file. I want the file and future changes to the file to be tracked by git, I just want to make changes to a specific file that is meant to be temporary, and then prevent myself from ever accidentally committing those changes. – Michael Jan 18 '22 at 04:34
  • A common pattern for this is to have the custom stuff included from another file, and that file is untracked and ignored. Imagine if the file in question had a line like "include if exists: custom-file-here" and anyone who wants to use it can create that custom file and populate it with their local settings. – TTT Jan 18 '22 at 05:10
  • 3
    Why not use pre-commit hooks? – Zahid Khan Jan 18 '22 at 05:12
  • @TTT Well the easiest way to go would be to add an environment variable to the project's env file that's like, "IS_LOCAL", and then not upload to the FTP server if it equals 1 or something. But the problem is that due to the customer's priorities, I can't make any changes that actually involve refactoring code in anyway, or doing anything that will actually get pushed to the remove repository. – Michael Jan 18 '22 at 06:46
  • @ZahidKhan Could this be done with client side hooks? And if so could you explain what to do? To be honest I don't have much experience with Git Hooks. – Michael Jan 18 '22 at 06:48
  • If you can't follow @TTT's advice, your only option is utmost scrutiny, i.e., carefully check your commits before you push them to the public. You can automate scrutiny to some degree using a pre-commit hook. – j6t Jan 18 '22 at 06:59
  • You could try hooks or smudge/clean filters. – ElpieKay Jan 18 '22 at 07:16
  • My approach would be a pre-commit hook indeed, as suggested already. Pre-commit hooks run locally when you commit, and can reject a commit if some test fails. For example, that test could be grepping your source code for a do-not-commit marker of your choice. – joanis Jan 18 '22 at 22:19
  • Your first inclination was the correct solution. You do not however need an environment variable. This is the idea behind .ENV and the other variations that .ENV libraries support. In the location of the "ftp" routine you want to short circuit, add some code that looks for a semaphore file. It could be as simple as the existence of a file, or a .ini or .env etc. If that exists, and/or reads some boolean value, then you skip the routine, otherwise, you proceed as normal. You of course gitignore this semaphore file. For your dev environment the file exists, but in production it won't. – gview Jan 19 '22 at 01:18

2 Answers2

2

This is essentially a Git FAQ: How do I tell Git to ignore tracked files? It's important to emphasize that there is no "real" way to do this. However, setting the --skip-worktree flag on the index entry will be close enough for your particular purposes. You will need to remember to unset the flag at times. See also Git - Difference Between 'assume-unchanged' and 'skip-worktree'

torek
  • 448,244
  • 59
  • 642
  • 775
2

TL;DR

Pre-commit hooks are designed to do just that: refuse any future commits with some testable characteristics.

Details

You can create a pre-commit hook to reject any commits that contain some do-not-commit marker. Pre-commit hooks are run on your local machine, before actually creating the commit, so if they fail, you don't even get to write a commit message.

Here is the simplest pre-commit hook that would reject any commit with DO-NOT-COMMIT found in the changes being committed:

#!/bin/sh
exec 1>&2 # redirect output to stderr
if git diff --cached | grep DO-NOT-COMMIT; then
    echo "DO-NOT-COMMIT found - rejecting commit"
    exit 1
fi

Save this file as .git/hooks/pre-commit in your sandbox, make it executable with chmod +x .git/hooks/pre-commit, and next time you try to commit a file with DO-NOT-COMMIT anywhere, Git will yell at you, as you desire.

Then, we you modify that program for local testing, start your changes with a # DO-NOT-COMMIT comment and you know you won't commit it by accident.

Install this in every sandbox

The nuisance with pre-commit hooks is that they have to be installed and enabled in each sandbox separately. So if you're looking for a solution for you personally, install the pre-commit hook in your sandboxes and you're good to go. But if you're looking for something organization wide, they're not the right tool. Server-side hooks would be needed in that case.

But that can also be a feature: pre-commit hooks are local and fully under your control. No need to get anyone's permission to enable them for yourself.

joanis
  • 10,635
  • 14
  • 30
  • 40