File inc/git.inc.php changed (mode: 100644) (index 614f334..4c5129a) |
... |
... |
function rg_git_fatal($msg) |
40 |
40 |
exit(1); |
exit(1); |
41 |
41 |
} |
} |
42 |
42 |
|
|
|
43 |
|
/* |
|
44 |
|
* Locks a repo agains concurrent updates |
|
45 |
|
* @timeout - in seconds |
|
46 |
|
*/ |
|
47 |
|
function rg_git_lock($repo_path, $timeout) |
|
48 |
|
{ |
|
49 |
|
global $rg_git_lock; |
|
50 |
|
|
|
51 |
|
rg_prof_start('git_lock'); |
|
52 |
|
|
|
53 |
|
$ret = FALSE; |
|
54 |
|
while (1) { |
|
55 |
|
$f = @fopen($repo_path . '/rg_lock', 'w'); |
|
56 |
|
if ($f === FALSE) { |
|
57 |
|
rg_git_set_error('cannot lock repo (open)'); |
|
58 |
|
break; |
|
59 |
|
} |
|
60 |
|
|
|
61 |
|
$_s = time(); |
|
62 |
|
$_exit = FALSE; |
|
63 |
|
while (1) { |
|
64 |
|
$r = @flock($f, LOCK_EX | LOCK_NB, $would_block); |
|
65 |
|
if ($r === TRUE) |
|
66 |
|
break; |
|
67 |
|
|
|
68 |
|
if ($would_block != 1) |
|
69 |
|
rg_git_set_error('cannot lock repo (flock)'); |
|
70 |
|
$_exit = TRUE; |
|
71 |
|
break; |
|
72 |
|
|
|
73 |
|
$_now = time(); |
|
74 |
|
if ($_now > $_s + $timeout) { |
|
75 |
|
$_exit = TRUE; |
|
76 |
|
break; |
|
77 |
|
} |
|
78 |
|
|
|
79 |
|
sleep(1); |
|
80 |
|
} |
|
81 |
|
if ($_exit) { |
|
82 |
|
fclose($f); |
|
83 |
|
break; |
|
84 |
|
} |
|
85 |
|
|
|
86 |
|
$rg_git_lock[$repo_path] = $f; |
|
87 |
|
$ret = TRUE; |
|
88 |
|
break; |
|
89 |
|
} |
|
90 |
|
|
|
91 |
|
return $ret; |
|
92 |
|
} |
|
93 |
|
|
|
94 |
|
/* |
|
95 |
|
* Unlocks a repo |
|
96 |
|
*/ |
|
97 |
|
function rg_git_unlock($repo_path) |
|
98 |
|
{ |
|
99 |
|
global $rg_git_lock; |
|
100 |
|
|
|
101 |
|
if (!isset($rg_git_lock[$repo_path])) |
|
102 |
|
return; |
|
103 |
|
|
|
104 |
|
$f = $rg_git_lock[$repo_path]; |
|
105 |
|
@flock($f, LOCK_UN); |
|
106 |
|
fclose($f); |
|
107 |
|
} |
|
108 |
|
|
43 |
109 |
/* |
/* |
44 |
110 |
* Returns the limit for diff for 'git log --patch' |
* Returns the limit for diff for 'git log --patch' |
45 |
111 |
*/ |
*/ |
|
... |
... |
function rg_git_short($ref) |
73 |
139 |
return $ref; |
return $ref; |
74 |
140 |
} |
} |
75 |
141 |
|
|
|
142 |
|
/* |
|
143 |
|
* 'master' -> 'refs/heads/master' |
|
144 |
|
* 'refs/heads/master' -> same |
|
145 |
|
*/ |
|
146 |
|
function rg_git_name2ref($name) |
|
147 |
|
{ |
|
148 |
|
if (strpos($name, '/') !== FALSE) |
|
149 |
|
return $name; |
|
150 |
|
|
|
151 |
|
return 'refs/heads/' . $name; |
|
152 |
|
} |
|
153 |
|
|
76 |
154 |
function rg_git_info($band, $msg) |
function rg_git_info($band, $msg) |
77 |
155 |
{ |
{ |
78 |
156 |
echo $band; |
echo $band; |
|
... |
... |
function rg_git_whitespace_ok($old, $new) |
479 |
557 |
} |
} |
480 |
558 |
|
|
481 |
559 |
/* |
/* |
482 |
|
* Loads refs/heads/BRANCH |
|
|
560 |
|
* Loads refs/heads/REF |
483 |
561 |
*/ |
*/ |
484 |
562 |
function rg_git_load_ref($repo_path, $ref) |
function rg_git_load_ref($repo_path, $ref) |
485 |
563 |
{ |
{ |
|
... |
... |
function rg_git_load_ref($repo_path, $ref) |
503 |
581 |
} |
} |
504 |
582 |
|
|
505 |
583 |
/* |
/* |
506 |
|
* Returns a common ancestor between two commits |
|
|
584 |
|
* Returns a common ancestor between two commits (FALSE on error) |
507 |
585 |
* TODO: Unit testing |
* TODO: Unit testing |
508 |
586 |
*/ |
*/ |
509 |
587 |
function rg_git_merge_base($repo_path, $a, $b) |
function rg_git_merge_base($repo_path, $a, $b) |
|
... |
... |
function rg_git_merge_base($repo_path, $a, $b) |
566 |
644 |
/* |
/* |
567 |
645 |
* Safely update a reference - used to update main namespace from other ns |
* Safely update a reference - used to update main namespace from other ns |
568 |
646 |
* If @new is empty, we assume a delete |
* If @new is empty, we assume a delete |
|
647 |
|
* Returns FALSE on error, TRUE on success. |
569 |
648 |
* TODO: Unit testing |
* TODO: Unit testing |
570 |
649 |
*/ |
*/ |
571 |
650 |
function rg_git_update_ref($repo_path, $ref, $old, $new, $reason) |
function rg_git_update_ref($repo_path, $ref, $old, $new, $reason) |
572 |
651 |
{ |
{ |
573 |
|
rg_prof_start("git_update_ref"); |
|
|
652 |
|
rg_prof_start('git_update_ref'); |
574 |
653 |
rg_log_enter("git_update_ref: ref=$ref old=$old new=$new reason=$reason"); |
rg_log_enter("git_update_ref: ref=$ref old=$old new=$new reason=$reason"); |
575 |
654 |
|
|
576 |
655 |
$ret = FALSE; |
$ret = FALSE; |
|
... |
... |
function rg_git_update_ref($repo_path, $ref, $old, $new, $reason) |
582 |
661 |
if (!empty($reason)) |
if (!empty($reason)) |
583 |
662 |
$cmd .= " -m " . escapeshellarg($reason); |
$cmd .= " -m " . escapeshellarg($reason); |
584 |
663 |
|
|
|
664 |
|
$ref = rg_git_name2ref($ref); |
|
665 |
|
|
585 |
666 |
if (empty($new)) |
if (empty($new)) |
586 |
667 |
$cmd .= " -d " . escapeshellarg($ref); |
$cmd .= " -d " . escapeshellarg($ref); |
587 |
668 |
else |
else |
|
... |
... |
function rg_git_update_ref($repo_path, $ref, $old, $new, $reason) |
591 |
672 |
if (!empty($old)) |
if (!empty($old)) |
592 |
673 |
$cmd .= " " . escapeshellarg($old); |
$cmd .= " " . escapeshellarg($old); |
593 |
674 |
|
|
594 |
|
$a = rg_exec($cmd, '', FALSE, FALSE); |
|
595 |
|
if ($a['ok'] != 1) { |
|
596 |
|
rg_git_set_error("error on update-ref (" . $a['errmsg'] . ")"); |
|
|
675 |
|
$r = rg_exec($cmd, '', FALSE, FALSE); |
|
676 |
|
if ($r['ok'] != 1) { |
|
677 |
|
rg_git_set_error( |
|
678 |
|
'error on update-ref (' . $r['errmsg'] . ')'); |
597 |
679 |
break; |
break; |
598 |
680 |
} |
} |
599 |
681 |
|
|
|
... |
... |
function rg_git_update_ref($repo_path, $ref, $old, $new, $reason) |
602 |
684 |
} |
} |
603 |
685 |
|
|
604 |
686 |
rg_log_exit(); |
rg_log_exit(); |
605 |
|
rg_prof_end("git_update_ref"); |
|
|
687 |
|
rg_prof_end('git_update_ref'); |
606 |
688 |
return $ret; |
return $ret; |
607 |
689 |
} |
} |
608 |
690 |
|
|
|
... |
... |
function rg_git_log_simple($repo_path, $max, $from, $to, $also_patch, $files, |
1065 |
1147 |
|
|
1066 |
1148 |
$cmd = RG_GIT_CMD . " --no-pager" |
$cmd = RG_GIT_CMD . " --no-pager" |
1067 |
1149 |
. " --git-dir=" . escapeshellarg($repo_path) |
. " --git-dir=" . escapeshellarg($repo_path) |
|
1150 |
|
. " -c core.quotePath=false" |
1068 |
1151 |
. " log" |
. " log" |
1069 |
1152 |
. " --find-copies" |
. " --find-copies" |
1070 |
1153 |
. " --find-renames" |
. " --find-renames" |
|
... |
... |
function rg_git_log_simple($repo_path, $max, $from, $to, $also_patch, $files, |
1184 |
1267 |
//rg_log_ml('DEBUG: numstat: ' . print_r($numstat, TRUE)); |
//rg_log_ml('DEBUG: numstat: ' . print_r($numstat, TRUE)); |
1185 |
1268 |
$tc = count($numstat); |
$tc = count($numstat); |
1186 |
1269 |
while ($tc > 0) { |
while ($tc > 0) { |
1187 |
|
$a = explode("\t", array_shift($numstat)); $tc--; |
|
|
1270 |
|
$a = explode("\t", array_shift($numstat), 3); $tc--; |
1188 |
1271 |
//rg_log_ml('DEBUG: a: ' . print_r($a, TRUE)); |
//rg_log_ml('DEBUG: a: ' . print_r($a, TRUE)); |
1189 |
1272 |
|
|
1190 |
1273 |
// We may have an empty commit |
// We may have an empty commit |
|
... |
... |
function rg_git_log($repo_path, $max, $from, $to, $also_patch, $patch_limit) |
1395 |
1478 |
break; |
break; |
1396 |
1479 |
} |
} |
1397 |
1480 |
|
|
1398 |
|
//if ($rg_git_debug > 90) |
|
1399 |
|
// rg_log_ml('DEBUG: stat: ' . print_r($stat, TRUE)); |
|
|
1481 |
|
if ($rg_git_debug > 90) |
|
1482 |
|
rg_log_ml('DEBUG: stat: ' . print_r($stat, TRUE)); |
1400 |
1483 |
if (empty($from)) { |
if (empty($from)) { |
1401 |
1484 |
$from = $stat[0]['vars']['sha1']; |
$from = $stat[0]['vars']['sha1']; |
1402 |
1485 |
if ($rg_git_debug > 50) |
if ($rg_git_debug > 50) |
|
... |
... |
function rg_git_diff($id, $a, $template_file) |
1647 |
1730 |
$ret .= "<tr>\n"; |
$ret .= "<tr>\n"; |
1648 |
1731 |
$ret .= " <td class=\"numbers\">...</td>\n"; |
$ret .= " <td class=\"numbers\">...</td>\n"; |
1649 |
1732 |
$ret .= " <td class=\"numbers\">...</td>\n"; |
$ret .= " <td class=\"numbers\">...</td>\n"; |
1650 |
|
$ret .= " <td style=\"background: #dddddd\" colspan=\"2\"><i>" . $ci['section'] . "</i></td>\n"; |
|
|
1733 |
|
$ret .= " <td style=\"background: #dddddd\" colspan=\"2\"><i>" |
|
1734 |
|
. rg_xss_safe($ci['section']) . "</i></td>\n"; |
1651 |
1735 |
$ret .= "</tr>\n"; |
$ret .= "</tr>\n"; |
1652 |
1736 |
} |
} |
1653 |
1737 |
|
|
|
... |
... |
function rg_git_merge_without_conflict($repo_path, $a, $b) |
2433 |
2517 |
} |
} |
2434 |
2518 |
|
|
2435 |
2519 |
/* |
/* |
2436 |
|
* Do a merge |
|
2437 |
|
* @ff - 0 = no fast-forward, 1 = fast-forward allowed |
|
|
2520 |
|
* Do a merge in a bare repo |
|
2521 |
|
* @ff - 0 = fast-forward not allowed, 1 = fast-forward allowed |
2438 |
2522 |
* @msg - merge message |
* @msg - merge message |
2439 |
|
* Returns the output of the command or FALSE |
|
|
2523 |
|
* Returns TRUE or FALSE |
|
2524 |
|
* Thanks to https://stackoverflow.com/questions/7984986/git-merging-branches-in-a-bare-repository |
|
2525 |
|
* TODO: we may prepend to @msg some more info (mr id etc.) |
2440 |
2526 |
*/ |
*/ |
2441 |
|
function rg_git_merge($repo_path, $a, $b, $ff, $msg) |
|
|
2527 |
|
function rg_git_merge($repo_path, $ref_name, $new, $ff, $msg) |
2442 |
2528 |
{ |
{ |
2443 |
2529 |
global $rg_git_zero; |
global $rg_git_zero; |
2444 |
2530 |
global $rg_git_empty; |
global $rg_git_empty; |
2445 |
2531 |
|
|
2446 |
2532 |
rg_prof_start('git_merge'); |
rg_prof_start('git_merge'); |
2447 |
|
rg_log_enter('git_merge' . ' a=' . $a . ' b=' . $b . ' ff=' . $ff |
|
2448 |
|
. ' msg=' . $msg); |
|
|
2533 |
|
rg_log_enter('git_merge' . ' ref_name=' . $ref_name |
|
2534 |
|
. ' new=' . $new . ' ff=' . $ff . ' msg=' . $msg); |
2449 |
2535 |
|
|
2450 |
2536 |
$ret = FALSE; |
$ret = FALSE; |
2451 |
2537 |
while (1) { |
while (1) { |
|
... |
... |
function rg_git_merge($repo_path, $a, $b, $ff, $msg) |
2454 |
2540 |
else |
else |
2455 |
2541 |
$add = ' --git-dir=' . escapeshellarg($repo_path); |
$add = ' --git-dir=' . escapeshellarg($repo_path); |
2456 |
2542 |
|
|
2457 |
|
$work_tree = rg_tmp_path('git_merge_' . rg_id(10)); |
|
2458 |
|
$r = @mkdir($work_tree, 0700, TRUE); |
|
2459 |
|
if ($r !== TRUE) { |
|
2460 |
|
rg_git_set_error('cannot create temporary dir for merge'); |
|
|
2543 |
|
// TODO |
|
2544 |
|
//if ($ff == 1) |
|
2545 |
|
// $add_ff = ' --ff'; |
|
2546 |
|
//else |
|
2547 |
|
// $add_ff = ' --no-ff'; |
|
2548 |
|
|
|
2549 |
|
$r = rg_git_lock($repo_path, 60); |
|
2550 |
|
if ($r === FALSE) |
|
2551 |
|
break; |
|
2552 |
|
|
|
2553 |
|
@unlink($repo_path . '/index'); |
|
2554 |
|
if (file_exists($repo_path . '/index')) { |
|
2555 |
|
rg_git_set_error('cannot unlink index'); |
2461 |
2556 |
break; |
break; |
2462 |
2557 |
} |
} |
2463 |
|
$add .= ' --work-tree ' . escapeshellarg($work_tree); |
|
2464 |
2558 |
|
|
2465 |
|
if ($ff == 1) |
|
2466 |
|
$add_ff = ' --ff'; |
|
2467 |
|
else |
|
2468 |
|
$add_ff = ' --no-ff'; |
|
|
2559 |
|
$mb = rg_git_merge_base($repo_path, $ref_name, $new); |
|
2560 |
|
if ($mb === FALSE) |
|
2561 |
|
break; |
2469 |
2562 |
|
|
2470 |
|
$cmd = 'git' |
|
2471 |
|
. $add |
|
2472 |
|
. ' merge' |
|
2473 |
|
. $add_ff |
|
2474 |
|
. ' --stat' |
|
2475 |
|
. ' -m ' . escapeshellarg($msg) |
|
2476 |
|
. ' ' . escapeshellarg($a) |
|
2477 |
|
. ' ' . escapeshellarg($b); |
|
2478 |
|
$a = rg_exec($cmd, '', FALSE, FALSE); |
|
2479 |
|
rg_rmdir($work_tree); |
|
2480 |
|
if ($a['ok'] != 1) { |
|
2481 |
|
rg_git_set_error('error on git merge (' |
|
2482 |
|
. $a['errmsg'] . ')'); |
|
|
2563 |
|
rg_log('DEBUG: mb=' . $mb); |
|
2564 |
|
|
|
2565 |
|
$e_mb = escapeshellarg($mb); |
|
2566 |
|
$e_ref_name = escapeshellarg($ref_name); |
|
2567 |
|
$e_new = escapeshellarg($new); |
|
2568 |
|
|
|
2569 |
|
$cmd = RG_GIT_CMD |
|
2570 |
|
. $add . ' read-tree -i -m ' |
|
2571 |
|
. $e_mb . ' ' . $e_ref_name . ' ' . $e_new; |
|
2572 |
|
$r = rg_exec($cmd, '', FALSE, FALSE); |
|
2573 |
|
if ($r['ok'] != 1) { |
|
2574 |
|
rg_git_set_error('error on merge (read-tree) (' |
|
2575 |
|
. $r['errmsg'] . ')'); |
2483 |
2576 |
break; |
break; |
2484 |
2577 |
} |
} |
2485 |
2578 |
|
|
2486 |
|
$ret = trim($a['data']); |
|
|
2579 |
|
$cmd = RG_GIT_CMD . $add . ' write-tree'; |
|
2580 |
|
$r = rg_exec($cmd, '', FALSE, FALSE); |
|
2581 |
|
if ($r['ok'] != 1) { |
|
2582 |
|
rg_git_set_error('error on merge (write-tree) (' |
|
2583 |
|
. $r['errmsg'] . ')'); |
|
2584 |
|
break; |
|
2585 |
|
} |
|
2586 |
|
$tree = $r['data']; |
|
2587 |
|
|
|
2588 |
|
$cmd = RG_GIT_CMD . $add . ' commit-tree ' |
|
2589 |
|
. escapeshellarg($tree) |
|
2590 |
|
. ' -p ' . $e_ref_name . ' -p ' . $e_new |
|
2591 |
|
. ' -m ' . escapeshellarg($msg); |
|
2592 |
|
$r = rg_exec($cmd, '', FALSE, FALSE); |
|
2593 |
|
if ($r['ok'] != 1) { |
|
2594 |
|
rg_git_set_error('error on merge (commit-tree) (' |
|
2595 |
|
. $r['errmsg'] . ')'); |
|
2596 |
|
break; |
|
2597 |
|
} |
|
2598 |
|
$commit = $r['data']; |
|
2599 |
|
|
|
2600 |
|
$r = rg_git_update_ref($repo_path, $ref_name, |
|
2601 |
|
'' /*old*/, $new, $msg); |
|
2602 |
|
if ($r !== TRUE) |
|
2603 |
|
break; |
|
2604 |
|
|
|
2605 |
|
$ret = TRUE; |
2487 |
2606 |
break; |
break; |
2488 |
2607 |
} |
} |
|
2608 |
|
@unlink($repo_path . '/index'); |
|
2609 |
|
rg_git_unlock($repo_path); |
2489 |
2610 |
|
|
2490 |
2611 |
rg_log_exit(); |
rg_log_exit(); |
2491 |
2612 |
rg_prof_end('git_merge'); |
rg_prof_end('git_merge'); |