Skip to content

Commit e2bc846

Browse files
committed
Re-base branch to current master - squashed commit of the following:
commit 6ecab80 Author: Markus Hoffrogge <[email protected]> Date: Mon Feb 2 01:05:54 2026 +0100 Re-base branch to current master - add missing files - align GH actions - align *.md files - align plugin.info.txt commit 52c67e4 Author: Markus Hoffrogge <[email protected]> Date: Mon Feb 2 00:29:24 2026 +0100 Re-base branch to current master commit 99861f0 Author: Markus Hoffrogge <[email protected]> Date: Mon Feb 2 00:41:40 2026 +0100 Re-base branch to current master - split GitRepo.php from Git.php, no code changes commit 31ed615 Author: Markus Hoffrogge <[email protected]> Date: Mon Feb 2 00:31:09 2026 +0100 Re-base branch to current master - move lib -> classes, no code changes commit 57bb453 Author: Markus Hoffrogge <[email protected]> Date: Fri May 6 01:52:59 2022 +0200 Allow using several git repos - improved German description of config settings commit d2a66e7 Author: Markus Hoffrogge <[email protected]> Date: Fri May 6 01:22:29 2022 +0200 Allow using several git repos - improved description of config settings - set default value to empty string for $conf['repoPath'] and $conf['repoWorkDir'] - changed position of config setting 'autoDetermineRepos' to be listed before 'repoPath' commit 8e783f4 Author: Markus Hoffrogge <[email protected]> Date: Fri May 6 01:17:30 2022 +0200 Allow using several git repos - editcommit.php: - improved to be backward compatible with existing single repo path configured installations commit ee6827c Author: Markus Hoffrogge <[email protected]> Date: Sun Mar 20 17:12:11 2022 +0100 Allow using several git repos - Git.php: - in case of auto determined repos: - use git rev-parse --git-dir option rather than --absolute-git-dir to support a maximum range of git versions - function absolute_git_dir($path): - extended the logic to ensure to return an absolute repo_path in any case commit ff5ae89 Author: Markus Hoffrogge <[email protected]> Date: Sat Mar 19 22:34:17 2022 +0100 Allow using several git repos - editcommit.php: - added a restriction not to use auto determined git repos found in directories above the DokuWiki configured $conf['savedir']. commit dbee1e7 Author: Markus Hoffrogge <[email protected]> Date: Fri Feb 11 15:24:25 2022 +0100 Allow using several git repos - editcommit.php, Git.php: - fixed issue for non git repo related paths in case of auto determining repos commit 718bdcd Author: Markus Hoffrogge <[email protected]> Date: Thu Feb 10 01:23:29 2022 +0100 Allow using several git repos - editcommit.php: - another simplification of the code - made ->initRepo(...) work for both: a file path name as well as a directory path name commit 634ce79 Author: Markus Hoffrogge <[email protected]> Date: Tue Feb 8 23:16:30 2022 +0100 Allow using several git repos - editcommit.php: - streamlined the code of initRepo to improve readability commit 5e54101 Author: Markus Hoffrogge <[email protected]> Date: Tue Feb 8 20:11:59 2022 +0100 Allow using several git repos - fix for auto determining the next parent repo path: - Git.php: - fixed type declaration of $plugin for null initialization - replaced method is_in_git_repo($path) by absolute_git_dir($path) - added method get_repo_path() - editcommit.php: - clear repoWorkDir in case of auto determined repo_path - add --work-tree option only, if repoWorkDir is not empty Fixes #47 commit 8be0bb0 Author: Markus Hoffrogge <[email protected]> Date: Sun Feb 6 00:47:37 2022 +0100 Allow using several git repos - improvements due to code review: - changed config 'initRepo' -> 'autoDetermineRepos' to leverage self explanation - added missing language description for this config Fixes #47 commit 8574d38 Author: Markus Hoffrogge <[email protected]> Date: Sun Feb 6 00:00:09 2022 +0100 Fix editcommit.php line 56: missing variable assignment commit d3a61cd Author: Olivier Churlaud <[email protected]> Date: Thu Jan 13 17:39:18 2022 +0100 Allow using several git repos Fixes #47
1 parent f8541e5 commit e2bc846

File tree

6 files changed

+144
-21
lines changed

6 files changed

+144
-21
lines changed

action/editcommit.php

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,75 @@ public function register(EventHandler $controller)
5050
$controller->register_hook('DOKUWIKI_DONE', 'AFTER', $this, 'handlePeriodicPull');
5151
}
5252

53-
private function initRepo()
54-
{
55-
//get path to the repo root (by default DokuWiki's savedir)
56-
$repoPath = GitBackedUtil::getEffectivePath($this->getConf('repoPath'));
53+
/**
54+
* Create a GitRepo class instance according to this plugins config.
55+
* If auto determination of git rpos is configured, this method will return null,
56+
* if there is no git repo found.
57+
*
58+
* @access private
59+
* @param string path to the file or directory to be commited (required for auto determination only)
60+
* @return GitRepo instance or null if there is no repo related to fileOrDirPath
61+
*/
62+
private function initRepo($fileOrDirPath="") {
63+
global $conf;
64+
65+
//set the path to the git binary
5766
$gitPath = trim($this->getConf('gitPath'));
5867
if ($gitPath !== '') {
5968
Git::setBin($gitPath);
6069
}
61-
//init the repo and create a new one if it is not present
62-
io_mkdir_p($repoPath);
63-
$repo = new GitRepo($repoPath, $this, true, true);
64-
//set git working directory (by default DokuWiki's savedir)
65-
$repoWorkDir = $this->getConf('repoWorkDir');
66-
if (!empty($repoWorkDir)) {
67-
$repoWorkDir = GitBackedUtil::getEffectivePath($repoWorkDir);
70+
71+
$configuredRepoPath = trim($this->getConf('repoPath'));
72+
$configuredRepoWorkDir = trim($this->getConf('repoWorkDir'));
73+
if (!empty($configuredRepoPath)) {
74+
$configuredRepoPath = GitBackedUtil::getEffectivePath($configuredRepoPath);
75+
}
76+
if (!empty($configuredRepoWorkDir)) {
77+
$configuredRepoWorkDir = GitBackedUtil::getEffectivePath($configuredRepoWorkDir);
78+
}
79+
$isAutoDetermineRepos = $this->getConf('autoDetermineRepos');
80+
if ($isAutoDetermineRepos) {
81+
if (empty($fileOrDirPath)) {
82+
return null;
83+
}
84+
$repoPath = is_dir($fileOrDirPath) ? $fileOrDirPath : dirname($fileOrDirPath);
85+
$repo = new GitRepo($repoPath, $this, false, false);
86+
$repoPath = $repo->get_repo_path();
87+
if (empty($repoPath)) {
88+
return null;
89+
}
90+
// Validate that the git repoPath found is within or below the DokuWiki 'savedir' configured:
91+
if (strpos(realpath($repoPath), realpath($conf['savedir'])) === false) {
92+
//dbglog("GitBacked - WARNING: repoPath=" . $repoPath . " is above the configured savedir=" . realpath($conf['savedir'])." => this git repo will be ignored!");
93+
return null;
94+
}
95+
$repoWorkDir = '';
96+
if (!empty($configuredRepoPath)) {
97+
// For backward compatibility to legacy configuration:
98+
// We will use the configured workDir, in case we have determined
99+
// the repoPath configured.
100+
if (realpath($configuredRepoPath) === realpath($repoPath)) {
101+
$repoWorkDir = $configuredRepoWorkDir;
102+
//dbglog("GitBacked - INFO: repoPath=" . $repoPath . " is the one explicitly configured => we use the configured workDir=[" . $repoWorkDir . "]");
103+
}
104+
}
105+
//dbglog("GitBacked - AUTO_DETERMINE_USE_CASE: repoPath=" . $repoPath);
106+
//dbglog("GitBacked - AUTO_DETERMINE_USE_CASE: repoWorkDir=" . $repoWorkDir);
107+
} else {
108+
//get path to the repo root from configuration (by default DokuWiki's savedir)
109+
$repoPath = $configuredRepoPath;
110+
//init the repo and create a new one if it is not present
111+
io_mkdir_p($repoPath);
112+
$repo = new GitRepo($repoPath, $this, true, true);
113+
//set git working directory from configuration (by default DokuWiki's savedir)
114+
$repoWorkDir = $configuredRepoWorkDir;
115+
//dbglog("GitBacked - CONFIG_USE_CASE: configured repoPath=" . $repoPath);
116+
//dbglog("GitBacked - CONFIG_USE_CASE: configured repoWorkDir=" . $repoWorkDir);
68117
}
118+
69119
Git::setBin(empty($repoWorkDir) ? Git::getBin()
70-
: Git::getBin() . ' --work-tree ' . escapeshellarg($repoWorkDir));
120+
: Git::getBin().' --work-tree ' . escapeshellarg($repoWorkDir));
121+
71122
$params = str_replace(
72123
['%mail%', '%user%'],
73124
[$this->getAuthorMail(), $this->getAuthor()],
@@ -98,8 +149,10 @@ private function commitFile($filePath, $message)
98149
{
99150
if (!$this->isIgnored($filePath)) {
100151
try {
101-
$repo = $this->initRepo();
102-
152+
$repo = $this->initRepo($filePath);
153+
if (is_null($repo)) {
154+
return;
155+
}
103156
//add the changed file and set the commit message
104157
$repo->add($filePath);
105158
$repo->commit($message);
@@ -178,6 +231,9 @@ public function handlePeriodicPull(Event &$event, $param)
178231
if ($lastPull + $timeToWait < $now) {
179232
try {
180233
$repo = $this->initRepo();
234+
if (is_null($repo)) {
235+
return;
236+
}
181237
if ($enableIndexUpdate) {
182238
$localPath = $this->computeLocalPath();
183239

classes/GitRepo.php

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,15 @@ public function setRepoPath($repo_path, $create_new = false, $_init = true)
120120
if ($new_path = realpath($repo_path)) {
121121
$repo_path = $new_path;
122122
if (is_dir($repo_path)) {
123+
$next_parent_repo_path = $this->absoluteGitDir($repo_path);
124+
if (!empty($next_parent_repo_path)) {
125+
$this->repo_path = $next_parent_repo_path;
126+
$this->bare = false;
123127
// Is this a work tree?
124-
if (file_exists($repo_path . "/.git") && is_dir($repo_path . "/.git")) {
128+
} elseif (file_exists($repo_path . "/.git") && is_dir($repo_path . "/.git")) {
125129
$this->repo_path = $repo_path;
126130
$this->bare = false;
127-
// Is this a bare repo?
131+
// Is this a bare repo?
128132
} elseif (is_file($repo_path . "/config")) {
129133
$parse_ini = parse_ini_file($repo_path . "/config");
130134
if ($parse_ini['bare']) {
@@ -136,6 +140,10 @@ public function setRepoPath($repo_path, $create_new = false, $_init = true)
136140
if ($_init) {
137141
$this->run('init');
138142
}
143+
} elseif (!$_init) {
144+
// If we do not have to init the repo, we just reflect that there is no repo path yet.
145+
// This may be the case for auto determining repos, if there is no repo related to the current resource going to be commited.
146+
$this->repo_path = '';
139147
} else {
140148
throw new \Exception($this->handleRepoPathError(
141149
$repo_path,
@@ -168,6 +176,17 @@ public function setRepoPath($repo_path, $create_new = false, $_init = true)
168176
}
169177
}
170178

179+
/**
180+
* Get the path to the repo directory
181+
*
182+
* @access public
183+
* @return string
184+
*/
185+
public function getRepoPath()
186+
{
187+
return $this->repo_path;
188+
}
189+
171190
/**
172191
* Get the path to the git repo directory (eg. the ".git" directory)
173192
*
@@ -201,6 +220,46 @@ public function testGit()
201220
return ($status != 127);
202221
}
203222

223+
/**
224+
* Determine closest parent git repository for a given path as absolute PHP realpath().
225+
*
226+
* @access public
227+
* @return string the next parent git repo root dir as absolute PHP realpath() or empty string, if no parent repo found
228+
*/
229+
public function absoluteGitDir($path)
230+
{
231+
$descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
232+
$pipes = [];
233+
// Using --git-dir rather than --absolute-git-dir for a wider git versions compatibility
234+
//$command = Git::getBin() . " rev-parse --absolute-git-dir";
235+
$command = Git::getBin() . " rev-parse --git-dir";
236+
//dbglog("GitBacked - Command: ".$command);
237+
$resource = proc_open($command, $descriptorspec, $pipes, $path);
238+
$stdout = stream_get_contents($pipes[1]);
239+
$stderr = stream_get_contents($pipes[2]);
240+
foreach ($pipes as $pipe) {
241+
fclose($pipe);
242+
}
243+
244+
$status = trim(proc_close($resource));
245+
if ($status == 0) {
246+
$repo_git_dir = trim($stdout);
247+
//dbglog("GitBacked - $command: '" . $repo_git_dir . "'");
248+
if (!empty($repo_git_dir)) {
249+
if (strcmp($repo_git_dir, ".git") === 0) {
250+
// convert to absolute path based on this command execution directory
251+
$repo_git_dir = $path . '/' . $repo_git_dir;
252+
}
253+
$repo_path = dirname(realpath($repo_git_dir));
254+
//dbglog('GitBacked - $repo_path: ' . $repo_path);
255+
if (file_exists($repo_path . "/.git") && is_dir($repo_path . "/.git")) {
256+
return $repo_path;
257+
}
258+
}
259+
}
260+
return '';
261+
}
262+
204263
/**
205264
* Run a command in the git repository
206265
*
@@ -212,6 +271,10 @@ public function testGit()
212271
*/
213272
protected function runCommand($command)
214273
{
274+
//dbglog("Git->run_command: repo_path=[" . $this->repo_path . "])");
275+
if (empty($this->repo_path)) {
276+
throw new Exception($this->handleRepoPathError($this->repo_path, "Failure on GitRepo->runCommand(): Git command must not be run for an empty repo path"));
277+
}
215278
//dbglog("Git->runCommand(command=[".$command."])");
216279
$descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
217280
$pipes = [];

conf/default.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
$conf['commitPageMsgDel'] = 'Wiki page %page% deleted with reason [%summary%] by %user%';
1515
$conf['commitMediaMsg'] = 'Wiki media %media% uploaded by %user%';
1616
$conf['commitMediaMsgDel'] = 'Wiki media %media% deleted by %user%';
17-
$conf['repoPath'] = $GLOBALS['conf']['savedir'];
17+
$conf['autoDetermineRepos'] = 1;
18+
$conf['repoPath'] = ''; //$GLOBALS['conf']['savedir']
1819
$conf['repoWorkDir'] = '';
1920
$conf['gitPath'] = '';
2021
$conf['addParams'] = '-c user.name="%user%" -c user.email="<%mail%>"';

conf/metadata.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
$meta['commitPageMsgDel'] = array('string');
1515
$meta['commitMediaMsg'] = array('string');
1616
$meta['commitMediaMsgDel'] = array('string');
17+
$meta['autoDetermineRepos'] = array('onoff');
1718
$meta['repoPath'] = array('string');
1819
$meta['repoWorkDir'] = array('string');
1920
$meta['gitPath'] = array('string');

lang/de/settings.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
$lang['commitPageMsgDel'] = 'Commit Kommentar für gelöschte Seiten (%user%,%summary%,%page% werden durch die tatsächlichen Werte ersetzt)';
1515
$lang['commitMediaMsg'] = 'Commit Kommentar for media Dateien (%user%,%media% werden durch die tatsächlichen Werte ersetzt)';
1616
$lang['commitMediaMsgDel'] = 'Commit Kommentar für gelöschte media Dateien (%user%,%media% werden durch die tatsächlichen Werte ersetzt)';
17-
$lang['repoPath'] = 'Pfad des git repo (z.B. das <code>savedir</code> ' . $GLOBALS['conf']['savedir'] . ')';
18-
$lang['repoWorkDir'] = 'Pfad des git working tree. Dieser muss die "pages" and "media" Verzeichnisse enthalten (z.B. das <code>savedir</code> ' . $GLOBALS['conf']['savedir'] . ')';
17+
$lang['autoDetermineRepos'] = 'Findet das nächste git Repo oberhalb des Pfades der geänderten Datei. Wenn gesetzt, dann werden mehrere Repos z.B. in Namespaces oder separate Repos für Pages und Media generisch unterstützt.';
18+
$lang['repoPath'] = '<b>Veraltete Konfiguration:</b> Pfad des git Repo (z.B. das <code>savedir</code> <code>$GLOBALS[\'conf\'][\'savedir\']</code>)<br><b>Hinweis:</b> Diese Einstellung ist nur für Rückwärtskompatibilität einer vorhandenen Konfiguration gedacht. Wenn <code>autoDetermineRepos</code> aktiviert ist, dann sollte diese Einstellung für neue Installationen nicht gesetzt werden.';
19+
$lang['repoWorkDir'] = '<b>Veraltete Konfiguration:</b> Pfad des git working tree. Dieser muss die "pages" and "media" Verzeichnisse enthalten (z.B. das <code>savedir</code> <code>$GLOBALS[\'conf\'][\'savedir\']</code>)<br><b>Hinweis:</b> Diese Einstellung wird nur berücksichtigt, wenn <code>repoPath</code> gesetzt ist. In diesem Fall wird es nur für das Repo in <code>repoPath</code> angewandt.';
1920
$lang['gitPath'] = 'Pfad zum git binary (Wenn leer, dann wird der Standard "/usr/bin/git" verwendet)';
2021
$lang['addParams'] = 'Zusätzliche git Parameter (diese werden dem git Kommando zugefügt) (%user% und %mail% werden durch die tatsächlichen Werte ersetzt)';
2122
$lang['ignorePaths'] = 'Pfade/Dateien die ignoriert werden und nicht von git archiviert werden sollen (durch Kommata getrennt)';

lang/en/settings.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
$lang['commitPageMsgDel'] = 'Commit message for deleted pages (%user%,%summary%,%page% are replaced by the corresponding values)';
1515
$lang['commitMediaMsg'] = 'Commit message for media files (%user%,%media% are replaced by the corresponding values)';
1616
$lang['commitMediaMsgDel'] = 'Commit message for deleted media files (%user%,%media% are replaced by the corresponding values)';
17-
$lang['repoPath'] = 'Path of the git repo(s) (e.g. the savedir ' . $GLOBALS['conf']['savedir'] . ')';
18-
$lang['repoWorkDir'] = 'Path of the git working tree, must contain "pages" and "media" directories (e.g. the savedir ' . $GLOBALS['conf']['savedir'] . ')';
17+
$lang['autoDetermineRepos'] = 'Auto determine the next git repo path upwards from the path of the file to commit. If enabled, then multiple repos e.g. within namespaces or separate repos for pages and media are supported in a generic way.';
18+
$lang['repoPath'] = '<b>Legacy config:</b> Path of the git repo (e.g. the <code>savedir</code> <code>$GLOBALS[\'conf\'][\'savedir\']</code>)<br><b>NOTE:</b> This config is for backward compatibility of an existing configuration only. If <code>autoDetermineRepos</code> is on, then this config should not be set for new installations.';
19+
$lang['repoWorkDir'] = '<b>Legacy config:</b> Path of the git working tree, must contain "pages" and "media" directories (e.g. the <code>savedir</code> <code>$GLOBALS[\'conf\'][\'savedir\']</code>)<br><b>NOTE:</b> This config is considered only, if <code>repoPath</code> is set. In this case it does apply for the repo in <code>repoPath</code> only.';
1920
$lang['gitPath'] = 'Path to the git binary (if empty, the default "/usr/bin/git" will be used)';
2021
$lang['addParams'] = 'Additional git parameters (added to the git execution command) (%user% and %mail% are replaced by the corresponding values)';
2122
$lang['ignorePaths'] = 'Paths/files which are ignored and not added to git (comma-separated)';

0 commit comments

Comments
 (0)