1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use std::path::Path;
use std::process::Command;
// Mirrors git's own sanitize_repo_env: `git rev-parse --local-env-vars` minus
// GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT. Git exports these to hooks, so
// pray started from a hook would otherwise run every cache command against the
// host repository. The two config variables pass through, as they do when git
// enters a submodule, because callers such as CI jobs use them to hand git
// credentials or URL rewrites, and they cannot select a repository.
const REPOSITORY_LOCAL_VARIABLES: [&str; 13] = [
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
"GIT_CONFIG",
"GIT_OBJECT_DIRECTORY",
"GIT_DIR",
"GIT_WORK_TREE",
"GIT_IMPLICIT_WORK_TREE",
"GIT_GRAFT_FILE",
"GIT_INDEX_FILE",
"GIT_NO_REPLACE_OBJECTS",
"GIT_REPLACE_REF_BASE",
"GIT_PREFIX",
"GIT_SHALLOW_FILE",
"GIT_COMMON_DIR",
];
/// Remove git repository-local variables that hooks export into child processes.
pub fn clear_repository_local_env(command: &mut Command) {
for name in REPOSITORY_LOCAL_VARIABLES {
command.env_remove(name);
}
}
// Credential, SSH, proxy and global config variables still pass through, so
// the environment is pruned rather than cleared.
pub(crate) fn git_command(repository: &Path) -> Command {
let mut command = Command::new(git_program());
command.current_dir(repository);
clear_repository_local_env(&mut command);
command
}
fn git_program() -> &'static str {
[
"/usr/bin/git",
"/opt/homebrew/bin/git",
"/usr/local/bin/git",
"git",
]
.into_iter()
.find(|candidate| Path::new(candidate).exists())
.unwrap_or("git")
}